/** Command line and config file options. */
struct gengetopt_args_info conf;
-/** Global dir count. */
-uint64_t num_dirs = 0;
-/** Global files count. */
-uint64_t num_files = 0;
-/** Global bytes count. */
-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.
*
* 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;
+
+static inline int ui_used(struct user_info *ui)
+{
+ return ui->flags & UI_FL_SLOT_USED;
+}
+
+static inline int ui_admissible(struct user_info *ui)
+{
+ return ui->flags & UI_FL_ADMISSIBLE;
+}
/**
* The table containing the directory names and statistics.
*/
struct uid_range *admissible_uids;
-/** Evaluates to 1 if x < y, to -1 if x > y and to 0 if x == y. */
-#define NUM_COMPARE(x, y) ((int)((x) < (y)) - (int)((x) > (y)))
/**
* Compare the size of two directories
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;
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",
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)
return make_message("%s/uid_list", conf.database_dir_arg);
}
+void sort_hash_table(int (*comp)(const void *, const void *))
+{
+ qsort(uid_hash_table, uid_hash_table_size, sizeof(struct user_info),
+ comp);
+}
+
int open_dir_table(int create)
{
dir_table_desc.dir = adu_strdup(conf.database_dir_arg);