From: Andre Noll Date: Sun, 1 Jun 2008 17:52:17 +0000 (+0200) Subject: Add create.c. X-Git-Tag: v0.0.2~8 X-Git-Url: http://git.tuebingen.mpg.de/?p=adu.git;a=commitdiff_plain;h=b542a1e3c66b7b01cd2dc91749c5154e25cbff1e Add create.c. Oops, forgot to check it in.. --- diff --git a/create.c b/create.c new file mode 100644 index 0000000..1ce2e54 --- /dev/null +++ b/create.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2008 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/** \file create.c The create mode of adu. */ + +#include /* readdir() */ +#include "adu.h" +#include "gcc-compat.h" +#include "cmdline.h" +#include "fd.h" +#include "string.h" +#include "error.h" +#include "portable_io.h" + +/* Id of the device containing the base dir. */ +static dev_t device_id; + +static int write_uid(struct user_info *ui, void *data) +{ + char **p = data; + + write_u32(*p, ui->uid); + *p += sizeof(uint32_t); + return 1; +} + +static int write_uid_list(void) +{ + char *buf, *p, *filename; + uint32_t count = 0; + struct user_info *ui; + size_t size = num_uids * sizeof(uint32_t); + int ret; + + if (!num_uids) + return 0; + buf = p = adu_malloc(size); + ret = for_each_admissible_user(write_uid, &p); + if (ret < 0) + goto out; + filename = get_uid_list_name(); + ret = adu_write_file(filename, buf, size); + free(filename); +out: + free(buf); + return ret; +} + +static int add_directory(char *dirname, uint64_t *dir_num, uint64_t *parent_dir_num, + uint64_t *dir_size, uint64_t *dir_files) +{ + struct osl_object dir_objects[NUM_DT_COLUMNS]; + + INFO_LOG("adding #%llu: %s\n", (long long unsigned)*dir_num, dirname); + dir_objects[DT_NAME].data = dirname; + dir_objects[DT_NAME].size = strlen(dirname) + 1; + dir_objects[DT_NUM].data = dir_num; + dir_objects[DT_NUM].size = sizeof(*dir_num); + dir_objects[DT_PARENT_NUM].data = parent_dir_num; + dir_objects[DT_PARENT_NUM].size = sizeof(*parent_dir_num); + dir_objects[DT_BYTES].data = dir_size; + dir_objects[DT_BYTES].size = sizeof(*dir_size); + dir_objects[DT_FILES].data = dir_files; + dir_objects[DT_FILES].size = sizeof(*dir_files); + return osl(osl_add_row(dir_table, dir_objects)); +} + +static int update_user_row(struct osl_table *t, uint64_t dir_num, + uint64_t *add) +{ + struct osl_row *row; + struct osl_object obj = {.data = &dir_num, .size = sizeof(dir_num)}; + + int ret = osl(osl_get_row(t, UT_DIR_NUM, &obj, &row)); + + if (ret == -E_OSL && osl_errno != E_OSL_RB_KEY_NOT_FOUND) + return ret; + if (ret < 0) { /* this is the first file we add */ + struct osl_object objects[NUM_UT_COLUMNS]; + uint64_t num_files = 1; + + objects[UT_DIR_NUM].data = &dir_num; + objects[UT_DIR_NUM].size = sizeof(dir_num); + objects[UT_BYTES].data = add; + objects[UT_BYTES].size = sizeof(*add); + objects[UT_FILES].data = &num_files; + objects[UT_FILES].size = sizeof(num_files); + INFO_LOG("######################### ret: %d\n", ret); + ret = osl(osl_add_row(t, objects)); + INFO_LOG("######################### ret: %d\n", ret); + return ret; + } else { /* add size and increment file count */ + uint64_t num; + struct osl_object obj1, obj2 = {.data = &num, .size = sizeof(num)}; + + ret = osl(osl_get_object(t, row, UT_BYTES, &obj1)); + if (ret < 0) + return ret; + num = *(uint64_t *)obj1.data + *add; + ret = osl(osl_update_object(t, row, UT_BYTES, &obj2)); + if (ret < 0) + return ret; + ret = osl(osl_get_object(t, row, UT_FILES, &obj1)); + if (ret < 0) + return ret; + num = *(uint64_t *)obj1.data + 1; + return osl(osl_update_object(t, row, UT_FILES, &obj2)); + } +} + +static int scan_dir(char *dirname, uint64_t *parent_dir_num) +{ + DIR *dir; + struct dirent *entry; + int ret, cwd_fd, ret2; + uint64_t dir_size = 0, dir_files = 0; + uint64_t this_dir_num = ++num_dirs; + + check_signals(); + DEBUG_LOG("----------------- %llu: %s\n", (long long unsigned)num_dirs, dirname); + ret = adu_opendir(dirname, &dir, &cwd_fd); + if (ret < 0) { + if (ret != -ERRNO_TO_ERROR(EACCES)) + return ret; + WARNING_LOG("permission denied for %s\n", dirname); + return 1; + } + while ((entry = readdir(dir))) { + mode_t m; + struct stat s; + uint32_t uid; + uint64_t size; + struct user_info *ui; + + if (!strcmp(entry->d_name, ".")) + continue; + if (!strcmp(entry->d_name, "..")) + continue; + if (lstat(entry->d_name, &s) == -1) { + WARNING_LOG("lstat error for %s/%s\n", dirname, + entry->d_name); + continue; + } + m = s.st_mode; + if (!S_ISREG(m) && !S_ISDIR(m)) + continue; + if (S_ISDIR(m)) { + if (conf.one_file_system_given && s.st_dev != device_id) + continue; + ret = scan_dir(entry->d_name, &this_dir_num); + if (ret < 0) + goto out; + continue; + } + /* regular file */ + size = s.st_size; + dir_size += size; + num_bytes += size; + dir_files++; + num_files++; + uid = s.st_uid; + ret = search_uid(uid, CREATE_USER_TABLE | OPEN_USER_TABLE, &ui); + if (ret < 0) + goto out; + ui->bytes += size; + ui->files++; + ret = update_user_row(ui->table, this_dir_num, &size); + if (ret < 0) + goto out; + } + ret = add_directory(dirname, &this_dir_num, parent_dir_num, + &dir_size, &dir_files); +out: + closedir(dir); + ret2 = adu_fchdir(cwd_fd); + if (ret2 < 0 && ret >= 0) + ret = ret2; + close(cwd_fd); + return ret; +} + +int com_create() +{ + uint64_t zero = 0ULL; + int ret; + struct stat statbuf; + + if (lstat(conf.base_dir_arg, &statbuf) == -1) + return -ERRNO_TO_ERROR(errno); + if (!S_ISDIR(statbuf.st_mode)) + return -ERRNO_TO_ERROR(ENOTDIR); + device_id = statbuf.st_dev; + create_hash_table(conf.hash_table_bits_arg); + ret = open_dir_table(1); + if (ret < 0) + return ret; + check_signals(); + ret = scan_dir(conf.base_dir_arg, &zero); + if (ret < 0) + goto out; + ret = write_uid_list(); +out: + close_all_tables(); + return ret; +}