aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorsten Töpper <atsutane@freethoughts.de>2025-06-20 01:45:13 +0200
committerThorsten Töpper <atsutane@freethoughts.de>2025-06-20 01:45:13 +0200
commit49997ac30b46c42a0366423cb2048f8257774805 (patch)
tree6ff70c9eecf1276a64360840d697516400e3dcb1
parent522ff099416b66868ef5782b6548d28917369b47 (diff)
downloaddir_monitor-49997ac30b46c42a0366423cb2048f8257774805.tar.gz
dir_monitor-49997ac30b46c42a0366423cb2048f8257774805.tar.bz2
Store everything from lstat()
-rw-r--r--include/list_management.h12
-rw-r--r--include/options.h1
-rw-r--r--src/dir_monitor.c2
-rw-r--r--src/list_management.c39
-rw-r--r--src/options.c35
-rw-r--r--src/output.c38
6 files changed, 100 insertions, 27 deletions
diff --git a/include/list_management.h b/include/list_management.h
index a62fe45..9753c13 100644
--- a/include/list_management.h
+++ b/include/list_management.h
@@ -8,27 +8,21 @@
#ifndef LIST_MANAGEMENT_H
#define LIST_MANAGEMENT_H
-#include <time.h>
+#include <sys/stat.h>
/* === DEFINITIONS === */
-/* off_t is defined in different headers, on Linux with glibc,
- * stdio.h, unistd.h and types.h
- * output.h requires this struct definition therefore off_t
- * becomes implicitly defined through stdio.h as every source
- * file includes output.h */
struct list_node {
struct list_node *next;
- off_t fsize;
char fname[256];
- time_t ftime; /* can be creation, access or modification */
+ struct stat ln_stat;
};
struct list_head {
struct list_node *first;
};
-struct list_node *create_node(char *fname, long int fsize, time_t ftime);
+struct list_node *create_node(char *fname, struct stat *ln_stat);
struct list_head *create_list_sort_reversed(struct list_head *list);
void destroy_list(struct list_head *list);
int insert_sorted_by_size(struct list_head *list, struct list_node *node);
diff --git a/include/options.h b/include/options.h
index 7f26f4d..4fb3c82 100644
--- a/include/options.h
+++ b/include/options.h
@@ -30,6 +30,7 @@ extern bool option_sort_reverse_order;
extern enum esort_type option_sort_type;
extern bool option_show_hidden_entries;
extern bool option_timestamp_long;
+extern char option_time_field;
int parse_arguments(int argc, char **argv);
diff --git a/src/dir_monitor.c b/src/dir_monitor.c
index df85f18..722f6d1 100644
--- a/src/dir_monitor.c
+++ b/src/dir_monitor.c
@@ -86,7 +86,7 @@ struct list_head *get_data_from_directory(char *path) {
fullpath, strerror(errno), errno);
continue;
}
- if ((tmp = create_node(de->d_name, stat_res.st_size, stat_res.st_mtime)) == NULL) {
+ if ((tmp = create_node(de->d_name, &stat_res)) == NULL) {
LOGERR("ERROR: Skipping entry %s\n", de->d_name);
continue;
}
diff --git a/src/list_management.c b/src/list_management.c
index 3b02d7f..582eccd 100644
--- a/src/list_management.c
+++ b/src/list_management.c
@@ -11,12 +11,13 @@
#include "output.h"
#include "list_management.h"
+#include "options.h"
/* === IMPLEMENTATION === */
-inline struct list_node *create_node(char *fname, off_t fsize, time_t ftime) {
+inline struct list_node *create_node(char *fname, struct stat *ln_stat) {
struct list_node *node = NULL;
if (fname == NULL || fname[0] == '\0') {
@@ -24,19 +25,23 @@ inline struct list_node *create_node(char *fname, off_t fsize, time_t ftime) {
return NULL;
}
+ if (ln_stat == NULL) {
+ LOGERR("ERROR: No valid file information given\n");
+ return NULL;
+ }
+
if ((node = calloc(1, sizeof(struct list_node))) == NULL) {
LOGERR("ERROR: Failed allocate memory for node: %s\n", strerror(errno));
return NULL;
}
- node->next = NULL;
- node->fsize = fsize;
- node->ftime = ftime;
+ node->next = NULL;
/* With strncpy and strict compiler options it complained. A file name
* can't be longer than 256 bytes, including the string terminating \0
* byte at the end. As the code no longer's in the same file...*/
memcpy(node->fname, fname, 255);
node->fname[255] = '\0';
+ memcpy(&(node->ln_stat), ln_stat, sizeof(struct stat));
return node;
}
@@ -61,12 +66,12 @@ inline void destroy_list(struct list_head *list) {
/* dirty... */
#define INSERT_BY_NUMERIC_FIELD(list, node, field) \
{ struct list_node *ptr = NULL; \
- if (node->field > list->first->field) { \
+ if (node->ln_stat.field > list->first->ln_stat.field) { \
node->next = list->first; list->first = node; return 0; } \
ptr = list->first; \
while (ptr != NULL) { \
if (ptr->next == NULL) { ptr->next = node; return 0; } \
- if (node->field > ptr->next->field) { \
+ if (node->ln_stat.field > ptr->next->ln_stat.field) { \
node->next = ptr->next; ptr->next = node; \
return 0; } \
ptr = ptr->next; \
@@ -74,7 +79,6 @@ inline void destroy_list(struct list_head *list) {
}
-/* TODO: later when, other parameters are actively used move the action to a template */
inline int insert_sorted_by_size(struct list_head *list, struct list_node *node) {
if (list == NULL) { LOGERR("ERROR: No list given.\n"); return -1; }
if (node == NULL) { LOGERR("ERROR: No node given.\n"); return -2; }
@@ -83,7 +87,7 @@ inline int insert_sorted_by_size(struct list_head *list, struct list_node *node)
list->first = node;
return 0;
}
- INSERT_BY_NUMERIC_FIELD(list, node, fsize);
+ INSERT_BY_NUMERIC_FIELD(list, node, st_size);
return -3;
}
@@ -95,7 +99,22 @@ inline int insert_sorted_by_time(struct list_head *list, struct list_node *node)
list->first = node;
return 0;
}
- INSERT_BY_NUMERIC_FIELD(list, node, ftime);
+ switch (option_time_field) {
+ case 'm': /* default setting first */
+ INSERT_BY_NUMERIC_FIELD(list, node, st_mtim.tv_sec);
+ break;
+ case 'a':
+ INSERT_BY_NUMERIC_FIELD(list, node, st_atim.tv_sec);
+ break;
+ case 'c':
+ INSERT_BY_NUMERIC_FIELD(list, node, st_ctim.tv_sec);
+ break;
+ default:
+ LOGERR("WARNING: option_time_field has invalid value %c 0x%02X - going by default m\n",
+ option_time_field, option_time_field);
+ INSERT_BY_NUMERIC_FIELD(list, node, st_mtim.tv_sec);
+ break;
+ };
return -3;
}
@@ -116,7 +135,7 @@ struct list_head *create_list_sort_reversed(struct list_head *list) {
ptr = list->first;
while (ptr != NULL) {
- cpynode = create_node(ptr->fname, ptr->fsize, ptr->ftime);
+ cpynode = create_node(ptr->fname, &(ptr->ln_stat));
if (cpynode == NULL) {
destroy_list(lh);
return NULL;
diff --git a/src/options.c b/src/options.c
index 2136c83..e60d4a2 100644
--- a/src/options.c
+++ b/src/options.c
@@ -8,6 +8,7 @@
#include <string.h>
#include <getopt.h>
#include <stdbool.h>
+#include <ctype.h>
#include "output.h"
#include "options.h"
@@ -16,17 +17,26 @@
/* === GLOBAL VARIABLES === */
struct option long_options[] = {
+ { "long-timestamp", no_argument, 0, 0 },
{ "reverse-sort", no_argument, 0, 0 },
{ "show-hidden-entries", no_argument, 0, 0 },
{ "sort-by", required_argument, 0, 0 },
- { "long-timestamp", no_argument, 0, 0 },
+ { "time-field", required_argument, 0, 0 },
{ 0, 0, 0, 0 }
};
+
bool option_sort_reverse_order = false;
enum esort_type option_sort_type = SORT_BY_SIZE;
bool option_show_hidden_entries = false;
bool option_timestamp_long = false;
+/* There are three fields regarding time, valid values 'a','c', 'm':
+ * st_atime / st_atim.tv_sec - time of the last access
+ * st_ctime / st_ctim.tv_sec - time of the last change to the inode
+ * st_mtime / st_mtim.tv_sec - time of last modification of the content
+ */
+char option_time_field = 'm';
+
/* === IMPLEMENTATION === */
@@ -43,6 +53,8 @@ void usage(char *executable) {
"Show hidden entries in the directory");
fprintf(stderr, " %-25s %2s %10s %s\n", "--sort-by", "", "size|time",
"Sort either by time or size");
+ fprintf(stderr, " %-25s %2s %10s %s\n", "--time-field", "", "a|c|m",
+ "Sort by (a)ccess, (c)hange or (m)odification time. Default: m");
}
@@ -89,6 +101,27 @@ void set_option(const char *option_name, char *option_argument) {
return;
}
+ if (strcmp(option_name, "time-field") == 0) {
+ switch (option_argument[0]) {
+ case 'a':
+ option_time_field = 'a';
+ break;
+ case 'c':
+ option_time_field = 'c';
+ break;
+ case 'm':
+ option_time_field = 'm';
+ break;
+ default:
+ /* Keep in mind: isgraph ignores space, but an explicit call --time-field ' ' is strange */
+ LOGERR("WARNING: --time-field: invalid value %c 0x%02X - falling back to default m\n",
+ ((isgraph(option_argument[0])) ? option_argument[0] : ' '), option_argument[0]);
+ option_time_field = 'm';
+ break;
+ };
+ return;
+ }
+
LOGERR("ERROR: Option '%s' not recognized\n.", option_name);
}
diff --git a/src/output.c b/src/output.c
index be0afb1..64971fa 100644
--- a/src/output.c
+++ b/src/output.c
@@ -11,6 +11,7 @@
#include <sys/ioctl.h>
#include "output.h"
+#include "list_management.h"
#include "options.h"
@@ -49,6 +50,7 @@ void print_list(struct list_head *list) {
struct list_head *lh = list;
struct list_node *ptr;
struct tm *tm = NULL;
+ time_t time_value = 0;
char timestamp[128];
size_t total_size = 0;
@@ -63,10 +65,30 @@ void print_list(struct list_head *list) {
ptr = lh->first;
while (ptr != NULL) {
- printf(" %8ld %2s ", ((ptr->fsize>=1024) ? (ptr->fsize/1024) : ptr->fsize),
- ((ptr->fsize >= 1024) ? "kB" : ""));
+ time_value = 0;
- tm = localtime(&ptr->ftime);
+ switch (option_time_field) {
+ case 'm':
+ time_value = ptr->ln_stat.st_mtim.tv_sec;
+ break;
+ case 'a':
+ time_value = ptr->ln_stat.st_atim.tv_sec;
+ break;
+ case 'c':
+ time_value = ptr->ln_stat.st_ctim.tv_sec;
+ break;
+ default:
+ LOGERR("WARNING: option_time_field has invalid value %c 0x%02X - going by default m\n",
+ option_time_field, option_time_field);
+ option_time_field = 'm';
+ time_value = ptr->ln_stat.st_mtim.tv_sec;
+ break;
+ };
+
+ printf(" %8ld %2s ", ((ptr->ln_stat.st_size>=1024) ? (ptr->ln_stat.st_size/1024) : ptr->ln_stat.st_size),
+ ((ptr->ln_stat.st_size >= 1024) ? "kB" : ""));
+
+ tm = localtime(&time_value);
if (option_timestamp_long) {
strftime(timestamp, sizeof(timestamp), "%Y%m%d %H:%M:%S %Z", tm);
printf(" %20s ", timestamp);
@@ -75,9 +97,13 @@ void print_list(struct list_head *list) {
printf(" %8s ", timestamp);
}
printf(" %s\n", ptr->fname);
- /* Linux: Neither man stat(2) nor stat(3type) declare when struct stat field st_size
- * get's a negative value. */
- total_size += (ptr->fsize>0) ? (unsigned long int)ptr->fsize : 0;
+ /* Linux: Neither man stat(2) nor stat(3type) declare why struct stat field st_size
+ * would get a negative value assigned. The type off_t masks __off_t or __off64_t
+ * which themselves mask bits/types.h __SLONGWORD_TYPE on x86_64 that's long int.
+ * Haven't checked libc/kernel code but regardless why, I assume that a negative
+ * value would imply a corrupt filesystem.
+ */
+ total_size += (ptr->ln_stat.st_size>0) ? (unsigned long int)ptr->ln_stat.st_size : 0;
ptr = ptr->next;
}
fputc_all_cols('=', stdout);