doveadm-fs.c revision e3734a6606e292b6673a506dfcd7e0964b7ba451
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2013-2014 Dovecot authors, see the included COPYING file */
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "lib.h"
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen#include "array.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "istream.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "ostream.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "iostream-ssl.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "fs-api.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "doveadm.h"
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen#include <stdio.h>
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include <unistd.h>
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic void fs_cmd_help(doveadm_command_t *cmd);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic void cmd_fs_delete(int argc, char *argv[]);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic struct fs *
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainencmd_fs_init(int *argc, char **argv[], int own_arg_count, doveadm_command_t *cmd)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct ssl_iostream_settings ssl_set;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct fs_settings fs_set;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct fs *fs;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen const char *error;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen if (*argc != 3 + own_arg_count)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen fs_cmd_help(cmd);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen memset(&ssl_set, 0, sizeof(ssl_set));
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen ssl_set.ca_dir = doveadm_settings->ssl_client_ca_dir;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen ssl_set.ca_file = doveadm_settings->ssl_client_ca_file;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen ssl_set.verbose = doveadm_debug;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen memset(&fs_set, 0, sizeof(fs_set));
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen fs_set.ssl_client_set = &ssl_set;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen fs_set.temp_dir = "/tmp";
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen fs_set.base_dir = doveadm_settings->base_dir;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen fs_set.debug = doveadm_debug;
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen if (fs_init((*argv)[1], (*argv)[2], &fs_set, &fs, &error) < 0)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen i_fatal("fs_init() failed: %s", error);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen *argc += 3;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen *argv += 3;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen return fs;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic void cmd_fs_get(int argc, char *argv[])
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct fs *fs;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct fs_file *file;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct istream *input;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen const unsigned char *data;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen size_t size;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen ssize_t ret;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_get);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen input = fs_read_stream(file, IO_BLOCK_SIZE);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fwrite(data, 1, size, stdout);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen i_stream_skip(input, size);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen i_assert(ret == -1);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (input->stream_errno == ENOENT) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen i_error("%s doesn't exist", fs_file_path(file));
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen } else if (input->stream_errno != 0) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen i_error("read(%s) failed: %m", fs_file_path(file));
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen i_stream_unref(&input);
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen fs_file_deinit(&file);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_deinit(&fs);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainenstatic void cmd_fs_put(int argc, char *argv[])
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen{
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen struct fs *fs;
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen const char *src_path, *dest_path;
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen struct fs_file *file;
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen struct istream *input;
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen struct ostream *output;
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen off_t ret;
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_put);
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen src_path = argv[0];
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen dest_path = argv[1];
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE);
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen output = fs_write_stream(file);
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen input = i_stream_create_file(src_path, IO_BLOCK_SIZE);
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen if ((ret = o_stream_send_istream(output, input)) < 0) {
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen if (output->stream_errno != 0)
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen i_error("write(%s) failed: %m", dest_path);
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen else
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen i_error("read(%s) failed: %m", src_path);
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen i_stream_destroy(&input);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (fs_write_stream_finish(file, &output) < 0) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen i_error("fs_write_stream_finish() failed: %s",
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_file_last_error(file));
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_file_deinit(&file);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_deinit(&fs);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic void cmd_fs_copy(int argc, char *argv[])
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen{
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct fs *fs;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct fs_file *src_file, *dest_file;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen const char *src_path, *dest_path;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_copy);
992118a50af940482b6cf884a89be56d7015580aTimo Sirainen src_path = argv[0];
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen dest_path = argv[1];
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen src_file = fs_file_init(fs, src_path, FS_OPEN_MODE_READONLY);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen dest_file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (fs_copy(src_file, dest_file) == 0) ;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen else if (errno == ENOENT) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen i_error("%s doesn't exist", src_path);
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen } else {
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen i_error("fs_copy(%s, %s) failed: %s",
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen src_path, dest_path, fs_last_error(fs));
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_file_deinit(&src_file);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_file_deinit(&dest_file);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_deinit(&fs);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic void cmd_fs_stat(int argc, char *argv[])
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen struct fs *fs;
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen struct fs_file *file;
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen struct stat st;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_stat);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (fs_stat(file, &st) == 0) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen printf("%s size=%lld\n", fs_file_path(file),
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen (long long)st.st_size);
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen } else if (errno == ENOENT) {
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen i_error("%s doesn't exist", fs_file_path(file));
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen } else {
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen i_error("fs_stat(%s) failed: %s",
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen fs_file_path(file), fs_file_last_error(file));
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen }
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen fs_file_deinit(&file);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_deinit(&fs);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic void cmd_fs_metadata(int argc, char *argv[])
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
992118a50af940482b6cf884a89be56d7015580aTimo Sirainen struct fs *fs;
992118a50af940482b6cf884a89be56d7015580aTimo Sirainen struct fs_file *file;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen const struct fs_metadata *m;
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen const ARRAY_TYPE(fs_metadata) *metadata;
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_metadata);
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen if (fs_get_metadata(file, &metadata) == 0) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen array_foreach(metadata, m)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen printf("%s=%s\n", m->key, m->value);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen } else if (errno == ENOENT) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_error("%s doesn't exist", fs_file_path(file));
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen } else {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_error("fs_stat(%s) failed: %s",
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen fs_file_path(file), fs_file_last_error(file));
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen fs_file_deinit(&file);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs_deinit(&fs);
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen}
e22b857e838fe118de3f78513aad6a3c6f4306b3Timo Sirainen
e22b857e838fe118de3f78513aad6a3c6f4306b3Timo Sirainenstruct fs_delete_ctx {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen unsigned int files_count;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fs_file **files;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen};
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic bool cmd_fs_delete_ctx_run(struct fs_delete_ctx *ctx)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen unsigned int i;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen bool ret = FALSE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen for (i = 0; i < ctx->files_count; i++) {
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen if (ctx->files[i] == NULL)
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen ;
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen else if (fs_delete(ctx->files[i]) == 0)
1176124297af5c56e932c0863c6637ff21d8a0efTimo Sirainen fs_file_deinit(&ctx->files[i]);
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen else if (errno == EAGAIN)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen ret = TRUE;
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen else {
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen i_error("fs_delete(%s) failed: %s",
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen fs_file_path(ctx->files[i]),
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen fs_file_last_error(ctx->files[i]));
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen }
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return ret;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen}
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenstatic void
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainencmd_fs_delete_dir_recursive(struct fs *fs, unsigned int async_count,
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen const char *path)
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen{
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen struct fs_iter *iter;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen ARRAY_TYPE(const_string) fnames;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fs_delete_ctx ctx;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen const char *fname, *const *fnamep;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen unsigned int i;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen memset(&ctx, 0, sizeof(ctx));
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ctx.files_count = I_MAX(async_count, 1);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ctx.files = t_new(struct fs_file *, ctx.files_count);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* delete subdirs first. all fs backends can't handle recursive
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen lookups, so save the list first. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen t_array_init(&fnames, 8);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen iter = fs_iter_init(fs, path, FS_ITER_FLAG_DIRS);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen while ((fname = fs_iter_next(iter)) != NULL) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fname = t_strdup(fname);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen array_append(&fnames, &fname, 1);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fs_iter_deinit(&iter) < 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_error("fs_iter_deinit(%s) failed: %s",
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen path, fs_last_error(fs));
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen array_foreach(&fnames, fnamep) T_BEGIN {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen cmd_fs_delete_dir_recursive(fs, async_count,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen t_strdup_printf("%s/%s", path, *fnamep));
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen } T_END;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* delete files. again because we're doing this asynchronously finish
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen the iteration first. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if ((fs_get_properties(fs) & FS_PROPERTY_DIRECTORIES) != 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* we need to explicitly delete also the directories */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen } else {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen array_clear(&fnames);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen iter = fs_iter_init(fs, path, 0);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen while ((fname = fs_iter_next(iter)) != NULL) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fname = t_strdup(fname);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen array_append(&fnames, &fname, 1);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fs_iter_deinit(&iter) < 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_error("fs_iter_deinit(%s) failed: %s",
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen path, fs_last_error(fs));
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen array_foreach(&fnames, fnamep) T_BEGIN {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fname = *fnamep;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen retry:
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen for (i = 0; i < ctx.files_count; i++) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (ctx.files[i] != NULL)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen continue;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ctx.files[i] = fs_file_init(fs,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen t_strdup_printf("%s/%s", path, fname),
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen FS_OPEN_MODE_READONLY | FS_OPEN_FLAG_ASYNC |
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen FS_OPEN_FLAG_ASYNC_NOQUEUE);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fname = NULL;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen break;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen cmd_fs_delete_ctx_run(&ctx);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fname != NULL) {
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen if (fs_wait_async(fs) < 0) {
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen i_error("fs_wait_async() failed: %s", fs_last_error(fs));
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen break;
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen }
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen goto retry;
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen }
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen } T_END;
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen while (doveadm_exit_code == 0 && cmd_fs_delete_ctx_run(&ctx)) {
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen if (fs_wait_async(fs) < 0) {
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen i_error("fs_wait_async() failed: %s", fs_last_error(fs));
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen break;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen for (i = 0; i < ctx.files_count; i++) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (ctx.files[i] != NULL)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs_file_deinit(&ctx.files[i]);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainencmd_fs_delete_recursive(int argc, char *argv[], unsigned int async_count)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fs *fs;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen cmd_fs_delete_dir_recursive(fs, async_count, argv[0]);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs_deinit(&fs);
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen}
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void cmd_fs_delete(int argc, char *argv[])
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fs *fs;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fs_file *file;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen bool recursive = FALSE;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen unsigned int async_count = 0;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen int c;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen while ((c = getopt(argc, argv, "Rn:")) > 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen switch (c) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen case 'R':
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen recursive = TRUE;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen break;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen case 'n':
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (str_to_uint(optarg, &async_count) < 0)
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen i_fatal("Invalid -n parameter: %s", optarg);
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen break;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen default:
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs_cmd_help(cmd_fs_delete);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen argc -= optind-1; argv += optind-1;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (recursive) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen cmd_fs_delete_recursive(argc, argv, async_count);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fs_delete(file) == 0)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen else if (errno == ENOENT) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_error("%s doesn't exist", fs_file_path(file));
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen } else {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_error("fs_delete(%s) failed: %s",
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs_file_path(file), fs_file_last_error(file));
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs_file_deinit(&file);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs_deinit(&fs);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void cmd_fs_iter_full(int argc, char *argv[], enum fs_iter_flags flags,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen doveadm_command_t *cmd)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fs *fs;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fs_iter *iter;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen const char *fname;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen iter = fs_iter_init(fs, argv[0], flags);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen while ((fname = fs_iter_next(iter)) != NULL)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen printf("%s\n", fname);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fs_iter_deinit(&iter) < 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_error("fs_iter_deinit(%s) failed: %s",
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen argv[0], fs_last_error(fs));
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fs_deinit(&fs);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void cmd_fs_iter(int argc, char *argv[])
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen cmd_fs_iter_full(argc, argv, 0, cmd_fs_iter);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void cmd_fs_iter_dirs(int argc, char *argv[])
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen cmd_fs_iter_full(argc, argv, FS_ITER_FLAG_DIRS, cmd_fs_iter_dirs);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstruct doveadm_cmd doveadm_cmd_fs[] = {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen { cmd_fs_get, "fs get", "<fs-driver> <fs-args> <path>" },
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen { cmd_fs_put, "fs put", "<fs-driver> <fs-args> <input path> <path>" },
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen { cmd_fs_copy, "fs copy", "<fs-driver> <fs-args> <source path> <dest path>" },
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen { cmd_fs_stat, "fs stat", "<fs-driver> <fs-args> <path>" },
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen { cmd_fs_metadata, "fs metadata", "<fs-driver> <fs-args> <path>" },
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen { cmd_fs_delete, "fs delete", "[-R] [-n <count>] <fs-driver> <fs-args> <path>" },
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen { cmd_fs_iter, "fs iter", "<fs-driver> <fs-args> <path>" },
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen { cmd_fs_iter_dirs, "fs iter-dirs", "<fs-driver> <fs-args> <path>" },
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen};
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void fs_cmd_help(doveadm_command_t *cmd)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen unsigned int i;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_fs); i++) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (doveadm_cmd_fs[i].cmd == cmd)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen help(&doveadm_cmd_fs[i]);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen i_unreached();
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen}
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainenvoid doveadm_register_fs_commands(void)
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen{
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen unsigned int i;
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen for (i = 0; i < N_ELEMENTS(doveadm_cmd_fs); i++)
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen doveadm_register_cmd(&doveadm_cmd_fs[i]);
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen}
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen