2 * Copyright (C) 2008 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file create.c The create mode of adu. */
9 #include <dirent.h> /* readdir() */
12 #include "gcc-compat.h"
17 #include "portable_io.h"
19 /* Id of the device containing the base dir. */
20 static dev_t device_id;
22 static int write_uid(struct user_info *ui, void *data)
26 write_u32(*p, ui->uid);
27 *p += sizeof(uint32_t);
31 static int write_uid_list(void)
33 char *buf, *p, *filename;
34 size_t size = num_uids * sizeof(uint32_t);
39 buf = p = adu_malloc(size);
40 ret = for_each_admissible_user(write_uid, &p);
43 filename = get_uid_list_name();
44 ret = adu_write_file(filename, buf, size);
51 static int add_directory(char *dirname, uint64_t *dir_num, uint64_t *parent_dir_num,
52 uint64_t *dir_size, uint64_t *dir_files)
54 struct osl_object dir_objects[NUM_DT_COLUMNS];
56 INFO_LOG("adding #%llu: %s\n", (long long unsigned)*dir_num, dirname);
57 dir_objects[DT_NAME].data = dirname;
58 dir_objects[DT_NAME].size = strlen(dirname) + 1;
59 dir_objects[DT_NUM].data = dir_num;
60 dir_objects[DT_NUM].size = sizeof(*dir_num);
61 dir_objects[DT_PARENT_NUM].data = parent_dir_num;
62 dir_objects[DT_PARENT_NUM].size = sizeof(*parent_dir_num);
63 dir_objects[DT_BYTES].data = dir_size;
64 dir_objects[DT_BYTES].size = sizeof(*dir_size);
65 dir_objects[DT_FILES].data = dir_files;
66 dir_objects[DT_FILES].size = sizeof(*dir_files);
67 return osl(osl_add_row(dir_table, dir_objects));
70 static int update_user_row(struct osl_table *t, uint64_t dir_num,
74 struct osl_object obj = {.data = &dir_num, .size = sizeof(dir_num)};
76 int ret = osl(osl_get_row(t, UT_DIR_NUM, &obj, &row));
78 if (ret == -E_OSL && osl_errno != E_OSL_RB_KEY_NOT_FOUND)
80 if (ret < 0) { /* this is the first file we add */
81 struct osl_object objects[NUM_UT_COLUMNS];
82 uint64_t num_files = 1;
84 objects[UT_DIR_NUM].data = &dir_num;
85 objects[UT_DIR_NUM].size = sizeof(dir_num);
86 objects[UT_BYTES].data = add;
87 objects[UT_BYTES].size = sizeof(*add);
88 objects[UT_FILES].data = &num_files;
89 objects[UT_FILES].size = sizeof(num_files);
90 INFO_LOG("######################### ret: %d\n", ret);
91 ret = osl(osl_add_row(t, objects));
92 INFO_LOG("######################### ret: %d\n", ret);
94 } else { /* add size and increment file count */
96 struct osl_object obj1, obj2 = {.data = &num, .size = sizeof(num)};
98 ret = osl(osl_get_object(t, row, UT_BYTES, &obj1));
101 num = *(uint64_t *)obj1.data + *add;
102 ret = osl(osl_update_object(t, row, UT_BYTES, &obj2));
105 ret = osl(osl_get_object(t, row, UT_FILES, &obj1));
108 num = *(uint64_t *)obj1.data + 1;
109 return osl(osl_update_object(t, row, UT_FILES, &obj2));
113 static int scan_dir(char *dirname, uint64_t *parent_dir_num)
116 struct dirent *entry;
117 int ret, cwd_fd, ret2;
118 uint64_t dir_size = 0, dir_files = 0;
120 static uint64_t current_dir_num;
122 uint64_t this_dir_num = ++current_dir_num;
125 DEBUG_LOG("----------------- %llu: %s\n", (long long unsigned)current_dir_num, dirname);
126 ret = adu_opendir(dirname, &dir, &cwd_fd);
128 if (ret != -ERRNO_TO_ERROR(EACCES))
130 WARNING_LOG("permission denied for %s\n", dirname);
133 while ((entry = readdir(dir))) {
138 struct user_info *ui;
140 if (!strcmp(entry->d_name, "."))
142 if (!strcmp(entry->d_name, ".."))
144 if (lstat64(entry->d_name, &s) == -1) {
145 WARNING_LOG("lstat64 error for %s/%s (%s)\n",
146 dirname, entry->d_name, strerror(errno));
150 if (!S_ISREG(m) && !S_ISDIR(m))
153 if (conf.one_file_system_given && s.st_dev != device_id)
155 ret = scan_dir(entry->d_name, &this_dir_num);
165 ret = search_uid(uid, NULL, CREATE_USER_TABLE | OPEN_USER_TABLE, &ui);
170 ret = update_user_row(ui->table, this_dir_num, &size);
174 ret = add_directory(dirname, &this_dir_num, parent_dir_num,
175 &dir_size, &dir_files);
178 ret2 = adu_fchdir(cwd_fd);
179 if (ret2 < 0 && ret >= 0)
187 uint64_t zero = 0ULL;
191 if (lstat(conf.base_dir_arg, &statbuf) == -1)
192 return -ERRNO_TO_ERROR(errno);
193 if (!S_ISDIR(statbuf.st_mode))
194 return -ERRNO_TO_ERROR(ENOTDIR);
195 device_id = statbuf.st_dev;
196 create_hash_table(conf.hash_table_bits_arg);
197 ret = open_dir_table(1);
201 ret = scan_dir(conf.base_dir_arg, &zero);
204 ret = write_uid_list();