Mercurial > dovecot > core-2.2
view src/doveadm/doveadm-fs.c @ 17130:add8c00fb3cc
Updated copyright notices to include year 2014.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 04 Feb 2014 16:23:22 -0500 |
parents | 436117bbac78 |
children | 304d545927d2 |
line wrap: on
line source
/* Copyright (c) 2013-2014 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "istream.h" #include "ostream.h" #include "iostream-ssl.h" #include "fs-api.h" #include "doveadm.h" #include <stdio.h> #include <unistd.h> static void fs_cmd_help(doveadm_command_t *cmd); static void cmd_fs_delete(int argc, char *argv[]); static struct fs * cmd_fs_init(int *argc, char **argv[], int own_arg_count, doveadm_command_t *cmd) { struct ssl_iostream_settings ssl_set; struct fs_settings fs_set; struct fs *fs; const char *error; if (*argc != 3 + own_arg_count) fs_cmd_help(cmd); memset(&ssl_set, 0, sizeof(ssl_set)); ssl_set.ca_dir = doveadm_settings->ssl_client_ca_dir; ssl_set.ca_file = doveadm_settings->ssl_client_ca_file; ssl_set.verbose = doveadm_debug; memset(&fs_set, 0, sizeof(fs_set)); fs_set.ssl_client_set = &ssl_set; fs_set.temp_dir = "/tmp"; fs_set.base_dir = doveadm_settings->base_dir; fs_set.debug = doveadm_debug; if (fs_init((*argv)[1], (*argv)[2], &fs_set, &fs, &error) < 0) i_fatal("fs_init() failed: %s", error); *argc += 3; *argv += 3; return fs; } static void cmd_fs_get(int argc, char *argv[]) { struct fs *fs; struct fs_file *file; struct istream *input; const unsigned char *data; size_t size; ssize_t ret; fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_get); file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY); input = fs_read_stream(file, IO_BLOCK_SIZE); while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) { fwrite(data, 1, size, stdout); i_stream_skip(input, size); } i_assert(ret == -1); if (input->stream_errno == ENOENT) { i_error("%s doesn't exist", fs_file_path(file)); doveadm_exit_code = DOVEADM_EX_NOTFOUND; } else if (input->stream_errno != 0) { i_error("read(%s) failed: %m", fs_file_path(file)); doveadm_exit_code = EX_TEMPFAIL; } i_stream_unref(&input); fs_file_deinit(&file); fs_deinit(&fs); } static void cmd_fs_put(int argc, char *argv[]) { struct fs *fs; const char *src_path, *dest_path; struct fs_file *file; struct istream *input; struct ostream *output; off_t ret; fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_put); src_path = argv[0]; dest_path = argv[1]; file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE); output = fs_write_stream(file); input = i_stream_create_file(src_path, IO_BLOCK_SIZE); if ((ret = o_stream_send_istream(output, input)) < 0) { if (output->stream_errno != 0) i_error("write(%s) failed: %m", dest_path); else i_error("read(%s) failed: %m", src_path); doveadm_exit_code = EX_TEMPFAIL; } i_stream_destroy(&input); if (fs_write_stream_finish(file, &output) < 0) { i_error("fs_write_stream_finish() failed: %s", fs_file_last_error(file)); doveadm_exit_code = EX_TEMPFAIL; } fs_file_deinit(&file); fs_deinit(&fs); } static void cmd_fs_copy(int argc, char *argv[]) { struct fs *fs; struct fs_file *src_file, *dest_file; const char *src_path, *dest_path; fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_copy); src_path = argv[0]; dest_path = argv[1]; src_file = fs_file_init(fs, src_path, FS_OPEN_MODE_READONLY); dest_file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE); if (fs_copy(src_file, dest_file) == 0) ; else if (errno == ENOENT) { i_error("%s doesn't exist", src_path); doveadm_exit_code = DOVEADM_EX_NOTFOUND; } else { i_error("fs_copy(%s, %s) failed: %s", src_path, dest_path, fs_last_error(fs)); doveadm_exit_code = EX_TEMPFAIL; } fs_file_deinit(&src_file); fs_file_deinit(&dest_file); fs_deinit(&fs); } static void cmd_fs_stat(int argc, char *argv[]) { struct fs *fs; struct fs_file *file; struct stat st; fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_stat); file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY); if (fs_stat(file, &st) == 0) { printf("%s size=%lld\n", fs_file_path(file), (long long)st.st_size); } else if (errno == ENOENT) { i_error("%s doesn't exist", fs_file_path(file)); doveadm_exit_code = DOVEADM_EX_NOTFOUND; } else { i_error("fs_stat(%s) failed: %s", fs_file_path(file), fs_file_last_error(file)); doveadm_exit_code = EX_TEMPFAIL; } fs_file_deinit(&file); fs_deinit(&fs); } static void cmd_fs_metadata(int argc, char *argv[]) { struct fs *fs; struct fs_file *file; const struct fs_metadata *m; const ARRAY_TYPE(fs_metadata) *metadata; fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_metadata); file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY); if (fs_get_metadata(file, &metadata) == 0) { array_foreach(metadata, m) printf("%s=%s\n", m->key, m->value); } else if (errno == ENOENT) { i_error("%s doesn't exist", fs_file_path(file)); doveadm_exit_code = DOVEADM_EX_NOTFOUND; } else { i_error("fs_stat(%s) failed: %s", fs_file_path(file), fs_file_last_error(file)); doveadm_exit_code = EX_TEMPFAIL; } fs_file_deinit(&file); fs_deinit(&fs); } struct fs_delete_ctx { unsigned int files_count; struct fs_file **files; }; static bool cmd_fs_delete_ctx_run(struct fs_delete_ctx *ctx) { unsigned int i; bool ret = FALSE; for (i = 0; i < ctx->files_count; i++) { if (ctx->files[i] == NULL) ; else if (fs_delete(ctx->files[i]) == 0) fs_file_deinit(&ctx->files[i]); else if (errno == EAGAIN) ret = TRUE; else { i_error("fs_delete(%s) failed: %s", fs_file_path(ctx->files[i]), fs_file_last_error(ctx->files[i])); doveadm_exit_code = EX_TEMPFAIL; } } return ret; } static void cmd_fs_delete_dir_recursive(struct fs *fs, unsigned int async_count, const char *path) { struct fs_iter *iter; ARRAY_TYPE(const_string) fnames; struct fs_delete_ctx ctx; const char *fname, *const *fnamep; unsigned int i; memset(&ctx, 0, sizeof(ctx)); ctx.files_count = I_MAX(async_count, 1); ctx.files = t_new(struct fs_file *, ctx.files_count); /* delete subdirs first. all fs backends can't handle recursive lookups, so save the list first. */ t_array_init(&fnames, 8); iter = fs_iter_init(fs, path, FS_ITER_FLAG_DIRS); while ((fname = fs_iter_next(iter)) != NULL) { fname = t_strdup(fname); array_append(&fnames, &fname, 1); } if (fs_iter_deinit(&iter) < 0) { i_error("fs_iter_deinit(%s) failed: %s", path, fs_last_error(fs)); doveadm_exit_code = EX_TEMPFAIL; } array_foreach(&fnames, fnamep) T_BEGIN { cmd_fs_delete_dir_recursive(fs, async_count, t_strdup_printf("%s/%s", path, *fnamep)); } T_END; /* delete files. again because we're doing this asynchronously finish the iteration first. */ array_clear(&fnames); iter = fs_iter_init(fs, path, 0); while ((fname = fs_iter_next(iter)) != NULL) { fname = t_strdup(fname); array_append(&fnames, &fname, 1); } if (fs_iter_deinit(&iter) < 0) { i_error("fs_iter_deinit(%s) failed: %s", path, fs_last_error(fs)); doveadm_exit_code = EX_TEMPFAIL; } array_foreach(&fnames, fnamep) T_BEGIN { fname = *fnamep; retry: for (i = 0; i < ctx.files_count; i++) { if (ctx.files[i] != NULL) continue; ctx.files[i] = fs_file_init(fs, t_strdup_printf("%s/%s", path, fname), FS_OPEN_MODE_READONLY | FS_OPEN_FLAG_ASYNC | FS_OPEN_FLAG_ASYNC_NOQUEUE); fname = NULL; break; } cmd_fs_delete_ctx_run(&ctx); if (fname != NULL) { if (fs_wait_async(fs) < 0) { i_error("fs_wait_async() failed: %s", fs_last_error(fs)); doveadm_exit_code = EX_TEMPFAIL; break; } goto retry; } } T_END; while (doveadm_exit_code == 0 && cmd_fs_delete_ctx_run(&ctx)) { if (fs_wait_async(fs) < 0) { i_error("fs_wait_async() failed: %s", fs_last_error(fs)); doveadm_exit_code = EX_TEMPFAIL; break; } } for (i = 0; i < ctx.files_count; i++) { if (ctx.files[i] != NULL) fs_file_deinit(&ctx.files[i]); } } static void cmd_fs_delete_recursive(int argc, char *argv[], unsigned int async_count) { struct fs *fs; fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete); cmd_fs_delete_dir_recursive(fs, async_count, argv[0]); fs_deinit(&fs); } static void cmd_fs_delete(int argc, char *argv[]) { struct fs *fs; struct fs_file *file; bool recursive = FALSE; unsigned int async_count = 0; int c; while ((c = getopt(argc, argv, "Rn:")) > 0) { switch (c) { case 'R': recursive = TRUE; break; case 'n': if (str_to_uint(optarg, &async_count) < 0) i_fatal("Invalid -n parameter: %s", optarg); break; default: fs_cmd_help(cmd_fs_delete); } } argc -= optind-1; argv += optind-1; if (recursive) { cmd_fs_delete_recursive(argc, argv, async_count); return; } fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete); file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY); if (fs_delete(file) == 0) ; else if (errno == ENOENT) { i_error("%s doesn't exist", fs_file_path(file)); doveadm_exit_code = DOVEADM_EX_NOTFOUND; } else { i_error("fs_delete(%s) failed: %s", fs_file_path(file), fs_file_last_error(file)); doveadm_exit_code = EX_TEMPFAIL; } fs_file_deinit(&file); fs_deinit(&fs); } static void cmd_fs_iter_full(int argc, char *argv[], enum fs_iter_flags flags, doveadm_command_t *cmd) { struct fs *fs; struct fs_iter *iter; const char *fname; fs = cmd_fs_init(&argc, &argv, 1, cmd); iter = fs_iter_init(fs, argv[0], flags); while ((fname = fs_iter_next(iter)) != NULL) printf("%s\n", fname); if (fs_iter_deinit(&iter) < 0) { i_error("fs_iter_deinit(%s) failed: %s", argv[0], fs_last_error(fs)); doveadm_exit_code = EX_TEMPFAIL; } fs_deinit(&fs); } static void cmd_fs_iter(int argc, char *argv[]) { cmd_fs_iter_full(argc, argv, 0, cmd_fs_iter); } static void cmd_fs_iter_dirs(int argc, char *argv[]) { cmd_fs_iter_full(argc, argv, FS_ITER_FLAG_DIRS, cmd_fs_iter_dirs); } struct doveadm_cmd doveadm_cmd_fs[] = { { cmd_fs_get, "fs get", "<fs-driver> <fs-args> <path>" }, { cmd_fs_put, "fs put", "<fs-driver> <fs-args> <input path> <path>" }, { cmd_fs_copy, "fs copy", "<fs-driver> <fs-args> <source path> <dest path>" }, { cmd_fs_stat, "fs stat", "<fs-driver> <fs-args> <path>" }, { cmd_fs_metadata, "fs metadata", "<fs-driver> <fs-args> <path>" }, { cmd_fs_delete, "fs delete", "[-R] <fs-driver> <fs-args> <path>" }, { cmd_fs_iter, "fs iter", "<fs-driver> <fs-args> <path>" }, { cmd_fs_iter_dirs, "fs iter-dirs", "<fs-driver> <fs-args> <path>" }, }; static void fs_cmd_help(doveadm_command_t *cmd) { unsigned int i; for (i = 0; i < N_ELEMENTS(doveadm_cmd_fs); i++) { if (doveadm_cmd_fs[i].cmd == cmd) help(&doveadm_cmd_fs[i]); } i_unreached(); } void doveadm_register_fs_commands(void) { unsigned int i; for (i = 0; i < N_ELEMENTS(doveadm_cmd_fs); i++) doveadm_register_cmd(&doveadm_cmd_fs[i]); }