struct user_summary_info {
struct user_info *ui;
+ /** Total number of files owned by this user. */
+ uint64_t files;
+ /** Total number of bytes owned by this user. */
+ uint64_t bytes;
+ /** Total number of directories that contain at least one file */
+ uint64_t dirs;
int ret;
int osl_errno;
regex_t *preg;
int inverse_matching;
};
-struct user_summary_line_info {
+struct user_summary_loop_data {
+ unsigned num_admissible_users;
+ struct user_summary_info *usis;
+ struct user_summary_info *current;
struct format_info *fi;
- uint32_t count;
};
static FILE *output_file;
ret = get_num_user_files(row, usi->ui, &num);
if (ret < 0)
goto err;
- usi->ui->files += num;
+ usi->files += num;
ret = get_num_user_bytes(row, usi->ui, &num);
if (ret < 0)
goto err;
- usi->ui->bytes += num;
- usi->ui->dirs++;
+ usi->bytes += num;
+ usi->dirs++;
return 1;
err:
usi->ret = ret;
return ret;
}
-static int compute_user_summary(struct user_info *ui, __a_unused void *data)
+static int compute_user_summary(struct user_info *ui, void *data)
{
- struct user_summary_info usi = {.ui = ui};
- int ret = compile_regex(&usi.preg, &usi.inverse_matching);
+ struct user_summary_loop_data *usld = data;
+ struct user_summary_info *usi = usld->current++;
+ int ret = compile_regex(&usi->preg, &usi->inverse_matching);
if (ret < 0)
return ret;
- ret = adu_loop_reverse(ui->table, UT_BYTES, &usi, user_summary_loop_function,
- &usi.ret, &usi.osl_errno);
- free_regex(usi.preg);
+ usi->ui = ui;
+ ret = adu_loop_reverse(ui->table, UT_BYTES, usi, user_summary_loop_function,
+ &usi->ret, &usi->osl_errno);
+ free_regex(usi->preg);
return ret;
}
-static int print_user_summary_line(struct user_info *ui, void *data)
+static int print_user_summary_line(struct user_summary_info *usi,
+ struct format_info *fi)
{
- struct user_summary_line_info *usli = data;
+ struct user_info *ui = usi->ui;
union atom_value values[] = {
[usa_pw_name] = {.string_value = ui->pw_name?
ui->pw_name : "?"},
[usa_uid] = {.num_value = (long long unsigned)ui->uid},
- [usa_dirs] = {.num_value = (long long unsigned)ui->dirs},
- [usa_files] = {.num_value = (long long unsigned)ui->files},
- [usa_size] = {.num_value = (long long unsigned)ui->bytes}
+ [usa_dirs] = {.num_value = (long long unsigned)usi->dirs},
+ [usa_files] = {.num_value = (long long unsigned)usi->files},
+ [usa_size] = {.num_value = (long long unsigned)usi->bytes}
};
- char *buf;
- int ret = -E_LOOP_COMPLETE;
+ char *buf = format_items(fi, values);
+ int ret = output("%s", buf);
- if (!usli->count)
- return ret;
-
- buf = format_items(usli->fi, values);
- ret = output("%s", buf);
free(buf);
- usli->count--;
return ret;
}
-static int name_comp(struct user_info *a, struct user_info *b)
+static int name_comp(const void *a, const void *b)
{
- char *x = a->pw_name;
- char *y = b->pw_name;
+ const struct user_summary_info *x = a, *y = b;
+ char *n1 = x->ui->pw_name;
+ char *n2 = y->ui->pw_name;
- if (!x)
+ if (!n1)
return 1;
- if (!y)
+ if (!n2)
return -1;
- return strcmp(x, y);
+ return strcmp(n1, n2);
}
-static int uid_comp(struct user_info *a, struct user_info *b)
+static int uid_comp(const void *a, const void *b)
{
- return -NUM_COMPARE(a->uid, b->uid);
+ const struct user_summary_info *x = a, *y = b;
+ return -NUM_COMPARE(x->ui->uid, y->ui->uid);
}
-static int dir_count_comp(struct user_info *a, struct user_info *b)
+static int dir_count_comp(const void *a, const void *b)
{
- return NUM_COMPARE(a->dirs, b->dirs);
+ const struct user_summary_info *x = a, *y = b;
+ return NUM_COMPARE(x->dirs, y->dirs);
}
-static int file_count_comp(struct user_info *a, struct user_info *b)
+static int file_count_comp(const void *a, const void *b)
{
- return NUM_COMPARE(a->files, b->files);
+ const struct user_summary_info *x = a, *y = b;
+ return NUM_COMPARE(x->files, y->files);
}
-static int size_comp(struct user_info *a, struct user_info *b)
+static int size_comp(const void *a, const void *b)
{
- return NUM_COMPARE(a->bytes, b->bytes);
+ const struct user_summary_info *x = a, *y = b;
+ return NUM_COMPARE(x->bytes, y->bytes);
+}
+
+static int count_admissible_users(__a_unused struct user_info *ui, void *data)
+{
+ struct user_summary_loop_data *usld = data;
+ usld->num_admissible_users++;
+ return 1;
}
static int print_user_summary(struct format_info *fi)
{
- int ret;
- int (*comp)(struct user_info *a, struct user_info *b);
- struct user_summary_line_info usli = {
- .fi = fi,
- .count = select_conf.limit_arg
- };
+ int i, ret;
+ int (*comp)(const void *a, const void *b);
+ struct user_summary_loop_data usld = { .fi = fi};
char *header = select_conf.header_given? select_conf.header_arg :
"User summary\n";
ret = output("%s", header);
if (ret < 0)
return ret;
- ret = for_each_admissible_user(compute_user_summary, NULL);
+ ret = for_each_admissible_user(count_admissible_users, &usld);
if (ret < 0)
return ret;
+ if (usld.num_admissible_users == 0)
+ return 1;
+ usld.usis = adu_calloc(usld.num_admissible_users
+ * sizeof(struct user_summary_info));
+ usld.current = usld.usis;
+ ret = for_each_admissible_user(compute_user_summary, &usld);
+ if (ret < 0)
+ goto out;
switch (select_conf.user_summary_sort_arg) {
case user_summary_sort_arg_name:
comp = name_comp;
comp = size_comp;
break;
}
- sort_hash_table(comp);
- ret = for_each_admissible_user(print_user_summary_line, &usli);
- if (ret == -E_LOOP_COMPLETE)
- ret = 1;
+ qsort(usld.usis, usld.num_admissible_users,
+ sizeof(struct user_summary_info), comp);
+ for (i = 0; i < usld.num_admissible_users; i++) {
+ if (select_conf.limit_arg >= 0 && i > select_conf.limit_arg)
+ break;
+ print_user_summary_line(usld.usis + i, usld.fi);
+ }
+out:
+ free(usld.usis);
return ret;
}
/** This is always a power of two. It is set in create_hash_table(). */
static uint32_t uid_hash_table_size;
-/* Array of indices to the entries of \a uid_hash_table. */
-static int *uid_hash_table_sort_idx;
-
/** The number of used slots in the hash table. */
static uint32_t num_uids;
assert(uid_hash_table);
for (i = 0; i < uid_hash_table_size; i++) {
int ret;
- struct user_info *ui = uid_hash_table +
- uid_hash_table_sort_idx[i];
+ struct user_info *ui = uid_hash_table + i;
if (!ui_used(ui) || !ui_admissible(ui))
continue;
*/
void create_hash_table(unsigned bits)
{
- int i;
-
uid_hash_table_size = 1 << bits;
uid_hash_table = adu_calloc(uid_hash_table_size *
sizeof(struct user_info));
- uid_hash_table_sort_idx = adu_malloc(uid_hash_table_size * sizeof(int));
- for (i = 0; i < uid_hash_table_size; i++)
- uid_hash_table_sort_idx[i] = i;
}
/**
}
free(uid_hash_table);
uid_hash_table = NULL;
- free(uid_hash_table_sort_idx);
- uid_hash_table_sort_idx = NULL;
}
/*
{
return make_message("%s/uid_list", conf.database_dir_arg);
}
-
-static int (*hash_table_comparator)(struct user_info *a, struct user_info *b);
-
-static int comp_wrapper(const void *a, const void *b)
-{
- struct user_info *x = uid_hash_table + *(unsigned *)a;
- struct user_info *y = uid_hash_table + *(unsigned *)b;
- return hash_table_comparator(x, y);
-}
-
-/**
- * Sort the hash table according to a given comparator.
- *
- * \param comp The comparator.
- *
- * The comparator is a user-defined function which must return 1, 0, or -1.
- *
- * \sa qsort(3).
- */
-void sort_hash_table(int (*comp)(struct user_info *, struct user_info *))
-{
- hash_table_comparator = comp;
- qsort(uid_hash_table_sort_idx, uid_hash_table_size,
- sizeof(*uid_hash_table_sort_idx), comp_wrapper);
-}
-
/**
* Open the osl tables for all admissible uids.
*