doveadm-fs.c revision 4d981bcd01bd1dd5248095b0e59957949332657e
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2013-2014 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
35316602eabbae7dcb86dd74c71e04cce45ba7c7Timo Sirainen#include "array.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "md5.h"
26e5bdf37d7d0deed1e2e8483366c83631b9d251Aki Tuomi#include "sha2.h"
27bc15088a485a8047fca9b0d24d2904c6dda919Timo Sirainen#include "hash-method.h"
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainen#include "hex-binary.h"
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen#include "istream.h"
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "iostream-ssl.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "fs-api.h"
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomi#include "doveadm.h"
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi#include <stdio.h>
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomi#include <unistd.h>
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomistatic void fs_cmd_help(doveadm_command_t *cmd);
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomistatic void cmd_fs_delete(int argc, char *argv[]);
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomistatic struct fs *
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomicmd_fs_init(int *argc, char **argv[], int own_arg_count, doveadm_command_t *cmd)
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomi{
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi struct ssl_iostream_settings ssl_set;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi struct fs_settings fs_set;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi struct fs *fs;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi const char *error;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi if (*argc != 3 + own_arg_count)
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomi fs_cmd_help(cmd);
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi memset(&ssl_set, 0, sizeof(ssl_set));
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi ssl_set.ca_dir = doveadm_settings->ssl_client_ca_dir;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi ssl_set.ca_file = doveadm_settings->ssl_client_ca_file;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi ssl_set.verbose = doveadm_debug;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi memset(&fs_set, 0, sizeof(fs_set));
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi fs_set.ssl_client_set = &ssl_set;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi fs_set.temp_dir = "/tmp";
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi fs_set.base_dir = doveadm_settings->base_dir;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi fs_set.debug = doveadm_debug;
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fs_init((*argv)[1], (*argv)[2], &fs_set, &fs, &error) < 0)
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen i_fatal("fs_init() failed: %s", error);
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainen
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen *argc += 3;
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen *argv += 3;
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen return fs;
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen}
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainenstatic void cmd_fs_get(int argc, char *argv[])
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen{
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen struct fs *fs;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen struct fs_file *file;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen struct istream *input;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen const unsigned char *data;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen size_t size;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen ssize_t ret;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_get);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen input = fs_read_stream(file, IO_BLOCK_SIZE);
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen fwrite(data, 1, size, stdout);
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen i_stream_skip(input, size);
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen }
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen i_assert(ret == -1);
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen if (input->stream_errno == ENOENT) {
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen i_error("%s doesn't exist", fs_file_path(file));
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen } else if (input->stream_errno != 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_error("read(%s) failed: %m", fs_file_path(file));
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen i_stream_unref(&input);
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen fs_file_deinit(&file);
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen fs_deinit(&fs);
741d705983e10046f07ef372b760bcdd169b068aTimo Sirainen}
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainenstatic void cmd_fs_put(int argc, char *argv[])
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen{
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen struct fs *fs;
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen enum fs_properties props;
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen const char *src_path, *dest_path;
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen struct fs_file *file;
b346610430690398b8c840006004a2df4aa8ce92Timo Sirainen struct istream *input;
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen struct ostream *output;
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen buffer_t *hash = NULL;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen off_t ret;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen int c;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen while ((c = getopt(argc, argv, "h:")) > 0) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen switch (c) {
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen case 'h':
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen hash = buffer_create_dynamic(pool_datastack_create(), 32);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (hex_to_binary(optarg, hash) < 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_fatal("Invalid -h parameter: Hash not in hex");
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen break;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen default:
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen fs_cmd_help(cmd_fs_put);
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen }
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen }
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen argc -= optind-1; argv += optind-1;
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_put);
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen src_path = argv[0];
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen dest_path = argv[1];
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen props = fs_get_properties(fs);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (hash == NULL)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen ;
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen else if (hash->used == hash_method_md5.digest_size) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if ((props & FS_PROPERTY_WRITE_HASH_MD5) == 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_fatal("fs backend doesn't support MD5 hashes");
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen fs_write_set_hash(file,
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen hash_method_lookup(hash_method_md5.name), hash->data);
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen } else if (hash->used == hash_method_sha256.digest_size) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if ((props & FS_PROPERTY_WRITE_HASH_SHA256) == 0)
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen i_fatal("fs backend doesn't support SHA256 hashes");
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen fs_write_set_hash(file,
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen hash_method_lookup(hash_method_sha256.name), hash->data);
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen }
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen output = fs_write_stream(file);
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen input = i_stream_create_file(src_path, IO_BLOCK_SIZE);
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen if ((ret = o_stream_send_istream(output, input)) < 0) {
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen if (output->stream_errno != 0)
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen i_error("write(%s) failed: %m", dest_path);
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen else
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen i_error("read(%s) failed: %m", src_path);
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen }
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen i_stream_destroy(&input);
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen if (fs_write_stream_finish(file, &output) < 0) {
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen i_error("fs_write_stream_finish() failed: %s",
93d08c32afb545ba32e9a1d973b34756c4b01983Timo Sirainen fs_file_last_error(file));
93d08c32afb545ba32e9a1d973b34756c4b01983Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen }
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen fs_file_deinit(&file);
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen fs_deinit(&fs);
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic void cmd_fs_copy(int argc, char *argv[])
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen{
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen struct fs *fs;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct fs_file *src_file, *dest_file;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen const char *src_path, *dest_path;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen fs = cmd_fs_init(&argc, &argv, 2, cmd_fs_copy);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen src_path = argv[0];
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen dest_path = argv[1];
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen src_file = fs_file_init(fs, src_path, FS_OPEN_MODE_READONLY);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen dest_file = fs_file_init(fs, dest_path, FS_OPEN_MODE_REPLACE);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (fs_copy(src_file, dest_file) == 0) ;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen else if (errno == ENOENT) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_error("%s doesn't exist", src_path);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen } else {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_error("fs_copy(%s, %s) failed: %s",
659fe5d24825b160cae512538088020d97a60239Timo Sirainen src_path, dest_path, fs_last_error(fs));
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen }
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen fs_file_deinit(&src_file);
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen fs_file_deinit(&dest_file);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen fs_deinit(&fs);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
e6f0cbdb1eb604f21a65cd45072febe678187054Timo Sirainenstatic void cmd_fs_stat(int argc, char *argv[])
e6f0cbdb1eb604f21a65cd45072febe678187054Timo Sirainen{
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct fs *fs;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct fs_file *file;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct stat st;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_stat);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (fs_stat(file, &st) == 0) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen printf("%s size=%lld\n", fs_file_path(file),
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen (long long)st.st_size);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen } else if (errno == ENOENT) {
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen i_error("%s doesn't exist", fs_file_path(file));
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen } else {
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen i_error("fs_stat(%s) failed: %s",
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen fs_file_path(file), fs_file_last_error(file));
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen }
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen fs_file_deinit(&file);
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen fs_deinit(&fs);
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen}
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainenstatic void cmd_fs_metadata(int argc, char *argv[])
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen{
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen struct fs *fs;
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen struct fs_file *file;
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen const struct fs_metadata *m;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen const ARRAY_TYPE(fs_metadata) *metadata;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_metadata);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen file = fs_file_init(fs, argv[0], FS_OPEN_MODE_READONLY);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (fs_get_metadata(file, &metadata) == 0) {
406393bc328f056c49df0804f894ac2070aa5846Timo Sirainen array_foreach(metadata, m)
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen printf("%s=%s\n", m->key, m->value);
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen } else if (errno == ENOENT) {
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen i_error("%s doesn't exist", fs_file_path(file));
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen doveadm_exit_code = DOVEADM_EX_NOTFOUND;
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen } else {
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen i_error("fs_stat(%s) failed: %s",
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen fs_file_path(file), fs_file_last_error(file));
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen doveadm_exit_code = EX_TEMPFAIL;
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen }
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen fs_file_deinit(&file);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen fs_deinit(&fs);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen}
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstruct fs_delete_ctx {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int files_count;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen struct fs_file **files;
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen};
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainenstatic bool cmd_fs_delete_ctx_run(struct fs_delete_ctx *ctx)
5ada3f57a970f226eb29956d30f66afc3537200dTimo Sirainen{
5ada3f57a970f226eb29956d30f66afc3537200dTimo Sirainen unsigned int i;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen bool ret = FALSE;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < ctx->files_count; i++) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (ctx->files[i] == NULL)
61ddcdc28f50d9cb9994fcc4ad63f9dff0e80628Timo Sirainen ;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (fs_delete(ctx->files[i]) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fs_file_deinit(&ctx->files[i]);
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen else if (errno == EAGAIN)
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen ret = TRUE;
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen else {
61ddcdc28f50d9cb9994fcc4ad63f9dff0e80628Timo Sirainen i_error("fs_delete(%s) failed: %s",
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen fs_file_path(ctx->files[i]),
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen fs_file_last_error(ctx->files[i]));
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
61ddcdc28f50d9cb9994fcc4ad63f9dff0e80628Timo Sirainen return ret;
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen}
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainenstatic void
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainencmd_fs_delete_dir_recursive(struct fs *fs, unsigned int async_count,
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen const char *path)
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen{
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen struct fs_iter *iter;
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen ARRAY_TYPE(const_string) fnames;
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainen struct fs_delete_ctx ctx;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen const char *fname, *const *fnamep;
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen unsigned int i;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
1f68b6db9b8d02b0f4116e42ac82c4aac5579574Timo Sirainen memset(&ctx, 0, sizeof(ctx));
1f68b6db9b8d02b0f4116e42ac82c4aac5579574Timo Sirainen ctx.files_count = I_MAX(async_count, 1);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen ctx.files = t_new(struct fs_file *, ctx.files_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* delete subdirs first. all fs backends can't handle recursive
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lookups, so save the list first. */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen t_array_init(&fnames, 8);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iter = fs_iter_init(fs, path, FS_ITER_FLAG_DIRS);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen while ((fname = fs_iter_next(iter)) != NULL) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen fname = t_strdup(fname);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen array_append(&fnames, &fname, 1);
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen }
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen if (fs_iter_deinit(&iter) < 0) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen i_error("fs_iter_deinit(%s) failed: %s",
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen path, fs_last_error(fs));
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen }
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen array_foreach(&fnames, fnamep) T_BEGIN {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen cmd_fs_delete_dir_recursive(fs, async_count,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen t_strdup_printf("%s/%s", path, *fnamep));
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen } T_END;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen /* delete files. again because we're doing this asynchronously finish
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen the iteration first. */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if ((fs_get_properties(fs) & FS_PROPERTY_DIRECTORIES) != 0) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* we need to explicitly delete also the directories */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen } else {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen array_clear(&fnames);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
491178793199e62320f7bc6292e7b8fd843ae5bcTimo Sirainen iter = fs_iter_init(fs, path, 0);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen while ((fname = fs_iter_next(iter)) != NULL) {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen fname = t_strdup(fname);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen array_append(&fnames, &fname, 1);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen }
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen if (fs_iter_deinit(&iter) < 0) {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen i_error("fs_iter_deinit(%s) failed: %s",
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen path, fs_last_error(fs));
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch array_foreach(&fnames, fnamep) T_BEGIN {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen fname = *fnamep;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen retry:
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen for (i = 0; i < ctx.files_count; i++) {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen if (ctx.files[i] != NULL)
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen continue;
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen ctx.files[i] = fs_file_init(fs,
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen t_strdup_printf("%s/%s", path, fname),
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen FS_OPEN_MODE_READONLY | FS_OPEN_FLAG_ASYNC |
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen FS_OPEN_FLAG_ASYNC_NOQUEUE);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen fname = NULL;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen break;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen cmd_fs_delete_ctx_run(&ctx);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (fname != NULL) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (fs_wait_async(fs) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fs_wait_async() failed: %s", fs_last_error(fs));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainen break;
5e40ed3f0a2c2acddc9b8eab59670c7a850114c5Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen goto retry;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen } T_END;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen while (doveadm_exit_code == 0 && cmd_fs_delete_ctx_run(&ctx)) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (fs_wait_async(fs) < 0) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen i_error("fs_wait_async() failed: %s", fs_last_error(fs));
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen doveadm_exit_code = EX_TEMPFAIL;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen break;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen for (i = 0; i < ctx.files_count; i++) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (ctx.files[i] != NULL)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen fs_file_deinit(&ctx.files[i]);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen}
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenstatic void
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainencmd_fs_delete_recursive(int argc, char *argv[], unsigned int async_count)
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen{
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen struct fs *fs;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen cmd_fs_delete_dir_recursive(fs, async_count, argv[0]);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen fs_deinit(&fs);
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen}
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen
439942f89a77180719644e7af3752a8329259eb9Timo Sirainenstatic void cmd_fs_delete(int argc, char *argv[])
439942f89a77180719644e7af3752a8329259eb9Timo Sirainen{
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen struct fs *fs;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen struct fs_file *file;
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen bool recursive = FALSE;
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen unsigned int async_count = 0;
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainen int c;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi while ((c = getopt(argc, argv, "Rn:")) > 0) {
26e5bdf37d7d0deed1e2e8483366c83631b9d251Aki Tuomi switch (c) {
26e5bdf37d7d0deed1e2e8483366c83631b9d251Aki Tuomi case 'R':
a102d189881a35d72ac3106a9e7e00577ae69310Aki Tuomi recursive = TRUE;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi break;
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi case 'n':
26e5bdf37d7d0deed1e2e8483366c83631b9d251Aki Tuomi if (str_to_uint(optarg, &async_count) < 0)
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi i_fatal("Invalid -n parameter: %s", optarg);
26e5bdf37d7d0deed1e2e8483366c83631b9d251Aki Tuomi break;
26e5bdf37d7d0deed1e2e8483366c83631b9d251Aki Tuomi default:
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi fs_cmd_help(cmd_fs_delete);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen }
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", "[-h <hash>] <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] [-n <count>] <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]);
}