From 0d786b0b8ce8740abaf3dfa05a79ed085b1f1fab Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sun, 1 Jun 2008 19:50:16 +0200 Subject: [PATCH] Hide the implementation of the uid hash table. The commands should not know anything about the details. So replace the FOR_EACH_USER macro by for_each_admissible_user() which takes a function pointer and calls the given function for each admissible user, passing a pointer to the user_info struct of that user. This allows to un-export uid_hash_table_size and uid_hash_table. --- adu.c | 36 ++++++++++++---- adu.h | 7 +--- select.c | 123 +++++++++++++++++++++++++++++-------------------------- 3 files changed, 93 insertions(+), 73 deletions(-) diff --git a/adu.c b/adu.c index c21df0b..4c1c62c 100644 --- a/adu.c +++ b/adu.c @@ -28,6 +28,9 @@ uint64_t num_bytes = 0; /** The number of different uids found so far. */ uint32_t num_uids = 0; +/** This is always a power of two. It is set in create_hash_table(). */ +static uint32_t uid_hash_table_size; + /** * Contains info for each user that owns at least one regular file. * @@ -35,7 +38,7 @@ uint32_t num_uids = 0; * option occupy a slot in this hash table. This allows to find out * quicky whether a uid is admissible. And yes, this has to be fast. */ -struct user_info *uid_hash_table = NULL; +static struct user_info *uid_hash_table; /** * The table containing the directory names and statistics. @@ -285,10 +288,29 @@ err: return ret; } +int for_each_admissible_user(int (*func)(struct user_info *, void *), + void *data) +{ + struct user_info *ui = uid_hash_table; + + if (!ui) + return -ERRNO_TO_ERROR(EFAULT); + + for (; ui < uid_hash_table + uid_hash_table_size; ui++) { + int ret; + + if (!ui_used(ui) || !ui_admissible(ui)) + continue; + ret = func(ui, data); + if (ret < 0) + return ret; + } + return 1; +} + #define PRIME1 0x811c9dc5 #define PRIME2 0x01000193 -uint32_t uid_hash_table_size; void create_hash_table(unsigned bits) { uid_hash_table_size = 1 << bits; @@ -315,12 +337,10 @@ static void close_dir_table(void) dir_table = NULL; } -static void close_user_table(struct user_info *ui) +static int close_user_table(struct user_info *ui, __a_unused void *data) { int ret; - if (!ui || !ui_used(ui) || !ui_admissible(ui)) - return; ret = osl(osl_close_table(ui->table, OSL_MARK_CLEAN)); if (ret < 0) ERROR_LOG("failed to close user table %u: %s\n", @@ -335,14 +355,12 @@ static void close_user_table(struct user_info *ui) ui->desc = NULL; ui->table = NULL; ui->flags = 0; + return 1; } static void close_user_tables(void) { - struct user_info *ui; - - FOR_EACH_USER(ui) - close_user_table(ui); + for_each_admissible_user(close_user_table, NULL); } void close_all_tables(void) diff --git a/adu.h b/adu.h index 3e06c95..18d9c47 100644 --- a/adu.h +++ b/adu.h @@ -118,9 +118,6 @@ } \ } -#define FOR_EACH_USER(ui) for (ui = uid_hash_table; ui && ui < uid_hash_table \ - + uid_hash_table_size; ui++) - /** The columns of the directory table. */ enum dir_table_columns { /** The name of the directory. */ @@ -178,9 +175,7 @@ enum search_uid_flags { }; extern uint32_t num_uids; -extern uint32_t uid_hash_table_size; extern struct osl_table *dir_table; -extern struct user_info *uid_hash_table; extern uint64_t num_dirs; extern uint64_t num_files; extern uint64_t num_bytes; @@ -195,6 +190,8 @@ char *get_uid_list_name(void); void create_hash_table(unsigned bits); int search_uid(uint32_t uid, enum search_uid_flags flags, struct user_info **ui_ptr); +int for_each_admissible_user(int (*func)(struct user_info *, void *), + void *data); /* select.c */ int com_select(void); diff --git a/select.c b/select.c index e09bce1..efe2c3c 100644 --- a/select.c +++ b/select.c @@ -357,72 +357,73 @@ static void print_global_summary(void) } -static void print_id_stats(void) +static int print_user_summary_line(struct user_info *ui, __a_unused void *data) { - struct user_info *ui; + char formated_dir_count[FORMATED_VALUE_SIZE], + formated_file_count[FORMATED_VALUE_SIZE], + formated_bytes[FORMATED_VALUE_SIZE ]; + + format_count_value(conf.count_unit_arg, ui->dirs, + conf.count_unit_arg == count_unit_arg_h, + formated_dir_count); + format_count_value(conf.count_unit_arg, ui->files, + conf.count_unit_arg == count_unit_arg_h, + formated_file_count); + format_size_value(conf.size_unit_arg, ui->bytes, + conf.size_unit_arg == size_unit_arg_h, + formated_bytes); + printf("\t%s\t%u\t%s\t%s\t%s\n", + ui->pw_name? ui->pw_name : "?", + (unsigned)ui->uid, + formated_dir_count, + formated_file_count, + formated_bytes + ); + return 1; +} +static void print_user_summary(void) +{ printf("User summary " "(pw_name/uid/dirs%s/files%s/size%s):\n", count_unit_buf, count_unit_buf, size_unit_buf); - FOR_EACH_USER(ui) { - char formated_dir_count[FORMATED_VALUE_SIZE], - formated_file_count[FORMATED_VALUE_SIZE], - formated_bytes[FORMATED_VALUE_SIZE ]; - if (!ui_used(ui) || !ui_admissible(ui)) - continue; - format_count_value(conf.count_unit_arg, ui->dirs, - conf.count_unit_arg == count_unit_arg_h, - formated_dir_count); - format_count_value(conf.count_unit_arg, ui->files, - conf.count_unit_arg == count_unit_arg_h, - formated_file_count); - format_size_value(conf.size_unit_arg, ui->bytes, - conf.size_unit_arg == size_unit_arg_h, - formated_bytes); - printf("\t%s\t%u\t%s\t%s\t%s\n", - ui->pw_name? ui->pw_name : "?", - (unsigned)ui->uid, - formated_dir_count, - formated_file_count, - formated_bytes - ); - } + for_each_admissible_user(print_user_summary_line, NULL); } -static int print_user_stats(void) +static int print_user_stat(struct user_info *ui, __a_unused void *data) { - struct user_info *ui; int ret; + struct user_stats_info usi = { + .count = conf.limit_arg, + .ui = ui + }; - FOR_EACH_USER(ui) { - struct user_stats_info usi = { - .count = conf.limit_arg, - .ui = ui - }; - if (!ui_used(ui) || !ui_admissible(ui)) - continue; - usi.flags = USF_PRINT_DIRNAME | USF_PRINT_BYTES | USF_COMPUTE_SUMMARY; - printf("%s (uid %u), by size%s:\n", - ui->pw_name? ui->pw_name : "?", (unsigned)ui->uid, - size_unit_buf); - ret = adu_loop_reverse(ui->table, UT_BYTES, &usi, user_stats_loop_function, - &usi.ret, &usi.osl_errno); - if (ret < 0) - return ret; - printf("\n%s (uid %u), by file count%s:\n", - ui->pw_name? ui->pw_name : "?", (unsigned)ui->uid, - count_unit_buf); - usi.count = conf.limit_arg, - usi.flags = USF_PRINT_DIRNAME | USF_PRINT_FILES; - ret = adu_loop_reverse(ui->table, UT_FILES, &usi, user_stats_loop_function, - &usi.ret, &usi.osl_errno); - if (ret < 0) - return ret; - printf("\n"); - } + usi.flags = USF_PRINT_DIRNAME | USF_PRINT_BYTES | USF_COMPUTE_SUMMARY; + printf("%s (uid %u), by size%s:\n", + ui->pw_name? ui->pw_name : "?", (unsigned)ui->uid, + size_unit_buf); + ret = adu_loop_reverse(ui->table, UT_BYTES, &usi, user_stats_loop_function, + &usi.ret, &usi.osl_errno); + if (ret < 0) + return ret; + printf("\n%s (uid %u), by file count%s:\n", + ui->pw_name? ui->pw_name : "?", (unsigned)ui->uid, + count_unit_buf); + usi.count = conf.limit_arg, + usi.flags = USF_PRINT_DIRNAME | USF_PRINT_FILES; + ret = adu_loop_reverse(ui->table, UT_FILES, &usi, user_stats_loop_function, + &usi.ret, &usi.osl_errno); + if (ret < 0) + return ret; + printf("\n"); return 1; } +static int print_user_stats(void) +{ + return for_each_admissible_user(print_user_stat, NULL); +} + static int print_statistics(void) { int ret; @@ -450,7 +451,7 @@ static int print_statistics(void) printf("\n"); print_global_summary(); print_user_stats(); - print_id_stats(); + print_user_summary(); return 1; } @@ -460,6 +461,7 @@ static int read_uid_file(void) uint32_t n; char *filename = get_uid_list_name(), *map; int ret = mmap_full_file(filename, O_RDONLY, (void **)&map, &size, NULL); + unsigned bits; if (ret < 0) { INFO_LOG("failed to map %s\n", filename); @@ -469,11 +471,14 @@ static int read_uid_file(void) num_uids = size / 4; INFO_LOG("found %u uids in %s\n", (unsigned)num_uids, filename); free(filename); - /* hash table size should be a power of two and larger than the number of uids */ - uid_hash_table_size = 4; - while (uid_hash_table_size < num_uids) - uid_hash_table_size *= 2; - create_hash_table(); + /* + * Compute number of hash table bits. The hash table size must be a + * power of two and larger than the number of uids. + */ + bits = 2; + while (1 << bits < num_uids) + bits++; + create_hash_table(bits); for (n = 0; n < num_uids; n++) { uint32_t uid = read_u32(map + n * sizeof(uid)); ret = search_uid(uid, OPEN_USER_TABLE, NULL); -- 2.39.2