From f0a7098470adc92499e379c698b3f4adcf682e5a Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 2 Jul 2023 16:38:24 +0200 Subject: [PATCH] apps: Add cp --- apps/CMakeLists.txt | 1 + apps/cp.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 apps/cp.cpp diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 5d6ef751..fbb2935d 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -32,3 +32,4 @@ luna_app(ln.cpp ln) luna_app(mktemp.cpp mktemp) luna_app(sysfuzz.cpp sysfuzz) luna_app(pivot_root.cpp pivot_root) +luna_app(cp.cpp cp) diff --git a/apps/cp.cpp b/apps/cp.cpp new file mode 100644 index 00000000..fa5065a5 --- /dev/null +++ b/apps/cp.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +using os::File; + +Result luna_main(int argc, char** argv) +{ + StringView source; + StringView destination; + bool verbose { false }; + + os::ArgumentParser parser; + parser.add_description("Copy files or directories."_sv); + parser.add_system_program_info("cp"_sv); + parser.add_positional_argument(source, "source"_sv, true); + parser.add_positional_argument(destination, "destination"_sv, true); + parser.add_switch_argument(verbose, 'v', "verbose"_sv, "show more information"_sv); + parser.parse(argc, argv); + + SharedPtr source_file = TRY(os::File::open(source, File::ReadOnly)); + SharedPtr destination_file; + + struct stat st; + TRY(os::FileSystem::stat(source_file->fd(), st, true)); + umask(0); + + if (os::FileSystem::is_directory(destination, true)) + { + auto basename = TRY(PathParser::basename(source)); + auto path = TRY(PathParser::join_paths(destination, basename.view())); + + destination_file = TRY(File::open_or_create(path.view(), File::ReadWrite, st.st_mode & ~S_IFMT)); + } + else + destination_file = TRY(File::open_or_create(destination, File::ReadWrite, st.st_mode & ~S_IFMT)); + + if (verbose) os::eprintln("copying %s to %s", source.chars(), destination.chars()); + + auto buf = TRY(Buffer::create_sized(4096)); + while (1) + { + TRY(source_file->read(buf, 4096)); + if (buf.is_empty()) break; + destination_file->write(buf); + } + + return 0; +}