From 49997ac30b46c42a0366423cb2048f8257774805 Mon Sep 17 00:00:00 2001 From: Thorsten Töpper Date: Fri, 20 Jun 2025 01:45:13 +0200 Subject: Store everything from lstat() --- src/dir_monitor.c | 2 +- src/list_management.c | 39 +++++++++++++++++++++++++++++---------- src/options.c | 35 ++++++++++++++++++++++++++++++++++- src/output.c | 40 +++++++++++++++++++++++++++++++++------- 4 files changed, 97 insertions(+), 19 deletions(-) (limited to 'src') 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 #include #include +#include #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 #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" : "")); - - tm = localtime(&ptr->ftime); + time_value = 0; + + 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); -- cgit v1.2.3-70-g09d2