From f0844c9f692ccf0d8d55f4d29c4af1b65b59e641 Mon Sep 17 00:00:00 2001 From: apio Date: Mon, 25 Sep 2023 21:31:14 +0200 Subject: [PATCH] cp: Support the -R flag and add better verbose messages --- apps/cp.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/apps/cp.cpp b/apps/cp.cpp index a1692bb0..de858bac 100644 --- a/apps/cp.cpp +++ b/apps/cp.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -16,10 +17,18 @@ Result copy_file(StringView source, StringView destination, bool verbose, TRY(os::FileSystem::stat(source_file->fd(), st, true)); umask(0); + if (st.st_mode & S_IFDIR) + { + os::eprintln("cp: warning: -R not specified, skipping directory %s", source.chars()); + return {}; + } + + String path; + if (os::FileSystem::is_directory(destination, true)) { auto basename = TRY(PathParser::basename(source)); - auto path = TRY(PathParser::join_paths(destination, basename.view())); + path = TRY(PathParser::join_paths(destination, basename.view())); if (interactive && os::FileSystem::exists(path.view(), false)) { @@ -31,15 +40,18 @@ Result copy_file(StringView source, StringView destination, bool verbose, } else { - if (interactive && os::FileSystem::exists(destination, false)) + path = TRY(String::from_string_view(destination)); + + if (interactive && os::FileSystem::exists(path.view(), false)) { - auto prompt = TRY(String::format("cp: Overwrite %s with %s?"_sv, destination.chars(), source.chars())); + auto prompt = TRY(String::format("cp: Overwrite %s with %s?"_sv, path.chars(), source.chars())); if (!os::conditional_prompt(prompt.view(), os::DefaultNo)) return {}; } - destination_file = TRY(File::open_or_create(destination, File::ReadWrite, st.st_mode & ~S_IFMT)); + + destination_file = TRY(File::open_or_create(path.view(), File::ReadWrite, st.st_mode & ~S_IFMT)); } - if (verbose) os::eprintln("copying %s to %s", source.chars(), destination.chars()); + if (verbose) os::eprintln("copying %s to %s", source.chars(), path.chars()); auto buf = TRY(Buffer::create_sized(4096)); while (1) @@ -52,12 +64,45 @@ Result copy_file(StringView source, StringView destination, bool verbose, return {}; } +Result copy_tree(StringView source, StringView destination, bool verbose, bool interactive) +{ + String path; + + if (!os::FileSystem::is_directory(source, true)) return copy_file(source, destination, verbose, interactive); + + if (os::FileSystem::is_directory(destination, true)) + { + auto basename = TRY(PathParser::basename(source)); + path = TRY(PathParser::join_paths(destination, basename.view())); + + if (!os::FileSystem::exists(path.view(), false)) TRY(os::FileSystem::create_directory(path.view(), 0755)); + } + else + { + path = TRY(String::from_string_view(destination)); + if (!os::FileSystem::exists(path.view(), false)) TRY(os::FileSystem::create_directory(path.view(), 0755)); + } + + auto dir = TRY(os::Directory::open(source)); + + Vector entries = TRY(dir->list_names(os::Directory::Filter::ParentAndBase)); + + for (const auto& entry : entries) + { + auto subpath = TRY(PathParser::join_paths(source, entry.view())); + TRY(copy_tree(subpath.view(), path.view(), verbose, interactive)); + } + + return {}; +} + Result luna_main(int argc, char** argv) { Vector files; StringView destination; bool verbose { false }; bool interactive { false }; + bool recursive { false }; os::ArgumentParser parser; parser.add_description("Copy files or directories."_sv); @@ -66,9 +111,15 @@ Result luna_main(int argc, char** argv) parser.add_positional_argument(destination, "destination"_sv, true); parser.add_switch_argument(verbose, 'v', "verbose"_sv, "show more information"_sv); parser.add_switch_argument(interactive, 'i', "interactive"_sv, "prompt before overwriting existing files"_sv); + parser.add_switch_argument(recursive, 'R', "recursive"_sv, "copy directories recursively"_sv); TRY(parser.parse(argc, argv)); - for (const auto& file : files) { TRY(copy_file(file, destination, verbose, interactive)); } + for (const auto& file : files) + { + if (recursive) TRY(copy_tree(file, destination, verbose, interactive)); + else + TRY(copy_file(file, destination, verbose, interactive)); + } return 0; }