diff --git a/programs/disks/CommandCopy.cpp b/programs/disks/CommandCopy.cpp index 4ba8a9ecbc2..0938e88a7f5 100644 --- a/programs/disks/CommandCopy.cpp +++ b/programs/disks/CommandCopy.cpp @@ -1,4 +1,5 @@ #include +#include "Common/Exception.h" #include #include "DisksClient.h" #include "ICommand.h" @@ -17,7 +18,8 @@ public: "disk-from", po::value(), "disk from which we copy is executed (default value is a current disk)")( "disk-to", po::value(), "disk to which copy is executed (default value is a current disk)")( "path-from", po::value(), "path from which copy is executed (mandatory, positional)")( - "path-to", po::value(), "path to which copy is executed (mandatory, positional)"); + "path-to", po::value(), "path to which copy is executed (mandatory, positional)")( + "recursive", "recursively copy the directory"); positional_options_description.add("path-from", 1); positional_options_description.add("path-to", 1); } @@ -28,9 +30,55 @@ public: auto disk_to = getDiskWithPath(client, options, "disk-to"); String path_from = disk_from.getRelativeFromRoot(getValueFromCommandLineOptionsThrow(options, "path-from")); String path_to = disk_to.getRelativeFromRoot(getValueFromCommandLineOptionsThrow(options, "path-to")); + bool recursive = options.count("recursive"); - disk_from.getDisk()->copyDirectoryContent( - path_from, disk_to.getDisk(), path_to, /* read_settings= */ {}, /* write_settings= */ {}, /* cancellation_hook= */ {}); + if (!disk_from.getDisk()->exists(path_from)) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "cannot stat '{}': No such file or directory", path_from); + } + else if (disk_from.getDisk()->isFile(path_from)) + { + auto target_location = getTargetLocation(path_from, disk_to, path_to); + if (!disk_to.getDisk()->exists(target_location) || disk_to.getDisk()->isFile(target_location)) + { + disk_from.getDisk()->copyFile( + path_from, + *disk_to.getDisk(), + target_location, + /* read_settings= */ {}, + /* write_settings= */ {}, + /* cancellation_hook= */ {}); + } + else + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, "cannot overwrite directory {} with non-directory {}", target_location, path_from); + } + } + else if (disk_from.getDisk()->isDirectory(path_from)) + { + if (!recursive) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "--recursive not specified; omitting directory {}", path_from); + } + auto target_location = getTargetLocation(path_from, disk_to, path_to); + + if (disk_to.getDisk()->isFile(target_location)) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "cannot overwrite non-directory {} with directory {}", path_to, target_location); + } + else if (!disk_to.getDisk()->exists(target_location)) + { + disk_to.getDisk()->createDirectory(target_location); + } + disk_from.getDisk()->copyDirectoryContent( + path_from, + disk_to.getDisk(), + target_location, + /* read_settings= */ {}, + /* write_settings= */ {}, + /* cancellation_hook= */ {}); + } } }; diff --git a/programs/disks/CommandMkDir.cpp b/programs/disks/CommandMkDir.cpp index 3ea6df5622d..535936480d9 100644 --- a/programs/disks/CommandMkDir.cpp +++ b/programs/disks/CommandMkDir.cpp @@ -13,14 +13,14 @@ public: { command_name = "mkdir"; description = "Creates a directory"; - options_description.add_options()("recursive", "recursively create directories")( - "path", po::value(), "the path of listing (mandatory, positional)"); + options_description.add_options()("parents", "recursively create directories")( + "path", po::value(), "the path on which directory should be created (mandatory, positional)"); positional_options_description.add("path", 1); } void executeImpl(const CommandLineOptions & options, DisksClient & client) override { - bool recursive = options.count("recursive"); + bool recursive = options.count("parents"); auto disk = client.getCurrentDiskWithPath(); String path = disk.getRelativeFromRoot(getValueFromCommandLineOptionsThrow(options, "path")); diff --git a/programs/disks/CommandMove.cpp b/programs/disks/CommandMove.cpp index 23144df3d35..6080fcf6811 100644 --- a/programs/disks/CommandMove.cpp +++ b/programs/disks/CommandMove.cpp @@ -25,9 +25,38 @@ public: String path_to = disk.getRelativeFromRoot(getValueFromCommandLineOptionsThrow(options, "path-to")); if (disk.getDisk()->isFile(path_from)) + { disk.getDisk()->moveFile(path_from, path_to); - else - disk.getDisk()->moveDirectory(path_from, path_to); + } + else if (disk.getDisk()->isDirectory(path_from)) + { + auto target_location = getTargetLocation(path_from, disk, path_to); + if (!disk.getDisk()->exists(target_location)) + { + disk.getDisk()->createDirectory(target_location); + disk.getDisk()->moveDirectory(path_from, target_location); + } + else + { + if (disk.getDisk()->isFile(target_location)) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, "cannot overwrite non-directory '{}' with directory '{}'", target_location, path_from); + } + if (!disk.getDisk()->isDirectoryEmpty(target_location)) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "cannot move '{}' to '{}': Directory not empty", path_from, target_location); + } + else + { + disk.getDisk()->moveDirectory(path_from, target_location); + } + } + } + else if (!disk.getDisk()->exists(path_from)) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "cannot stat '{}': No such file or directory", path_from); + } } }; diff --git a/programs/disks/CommandRemove.cpp b/programs/disks/CommandRemove.cpp index b322fb2701f..d508645fc65 100644 --- a/programs/disks/CommandRemove.cpp +++ b/programs/disks/CommandRemove.cpp @@ -1,4 +1,5 @@ #include +#include "Common/Exception.h" #include "ICommand.h" namespace DB @@ -10,8 +11,9 @@ public: CommandRemove() { command_name = "remove"; - description = "Remove file or directory with all children. Throws exception if file doesn't exists"; - options_description.add_options()("path", po::value(), "path from which we copy (mandatory, positional)"); + description = "Remove file or directory. Throws exception if file doesn't exists"; + options_description.add_options()("path", po::value(), "path from which we copy (mandatory, positional)")( + "recursive", "recursively removes the directory (required to remove a directory)"); positional_options_description.add("path", 1); } @@ -19,7 +21,26 @@ public: { auto disk = client.getCurrentDiskWithPath(); const String & path = disk.getRelativeFromRoot(getValueFromCommandLineOptionsThrow(options, "path")); - disk.getDisk()->removeRecursive(path); + bool recursive = options.count("recursive"); + if (!disk.getDisk()->exists(path)) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Path {} on disk {} doesn't exist", path, disk.getDisk()->getName()); + } + else if (disk.getDisk()->isDirectory(path)) + { + if (!recursive) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "cannot remove '{}': Is a directory", path); + } + else + { + disk.getDisk()->removeRecursive(path); + } + } + else + { + disk.getDisk()->removeFileIfExists(path); + } } }; diff --git a/programs/disks/DisksClient.cpp b/programs/disks/DisksClient.cpp index 379c87e4f2f..7e36c7911ab 100644 --- a/programs/disks/DisksClient.cpp +++ b/programs/disks/DisksClient.cpp @@ -20,7 +20,7 @@ DiskWithPath::DiskWithPath(DiskPtr disk_, std::optional path_) : disk(di { if (!fs::path{path_.value()}.is_absolute()) { - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Initializing path {} is not absolute", path_.value()); + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Initializing path {} is not absolute", path_.value()); } path = path_.value(); } diff --git a/programs/disks/ICommand.h b/programs/disks/ICommand.h index 4b0ec731966..6faf90e2b52 100644 --- a/programs/disks/ICommand.h +++ b/programs/disks/ICommand.h @@ -100,6 +100,22 @@ protected: DiskWithPath & getDiskWithPath(DisksClient & client, const CommandLineOptions & options, const String & name); + String getTargetLocation(const String & path_from, DiskWithPath & disk_to, const String & path_to) + { + if (!disk_to.getDisk()->isDirectory(path_to)) + { + return path_to; + } + String copied_path_from = path_from; + if (copied_path_from.ends_with('/')) + { + copied_path_from.pop_back(); + } + String plain_filename = fs::path(copied_path_from).filename(); + + return fs::path{path_to} / plain_filename; + } + public: String command_name;