cp: Support the -R flag and add better verbose messages
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
eeb69c923c
commit
f0844c9f69
63
apps/cp.cpp
63
apps/cp.cpp
@ -1,6 +1,7 @@
|
|||||||
#include <luna/PathParser.h>
|
#include <luna/PathParser.h>
|
||||||
#include <luna/String.h>
|
#include <luna/String.h>
|
||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
|
#include <os/Directory.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
#include <os/Prompt.h>
|
#include <os/Prompt.h>
|
||||||
@ -16,10 +17,18 @@ Result<void> copy_file(StringView source, StringView destination, bool verbose,
|
|||||||
TRY(os::FileSystem::stat(source_file->fd(), st, true));
|
TRY(os::FileSystem::stat(source_file->fd(), st, true));
|
||||||
umask(0);
|
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))
|
if (os::FileSystem::is_directory(destination, true))
|
||||||
{
|
{
|
||||||
auto basename = TRY(PathParser::basename(source));
|
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))
|
if (interactive && os::FileSystem::exists(path.view(), false))
|
||||||
{
|
{
|
||||||
@ -31,15 +40,18 @@ Result<void> copy_file(StringView source, StringView destination, bool verbose,
|
|||||||
}
|
}
|
||||||
else
|
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 {};
|
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));
|
auto buf = TRY(Buffer::create_sized(4096));
|
||||||
while (1)
|
while (1)
|
||||||
@ -52,12 +64,45 @@ Result<void> copy_file(StringView source, StringView destination, bool verbose,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> 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<String> 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<int> luna_main(int argc, char** argv)
|
Result<int> luna_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
Vector<StringView> files;
|
Vector<StringView> files;
|
||||||
StringView destination;
|
StringView destination;
|
||||||
bool verbose { false };
|
bool verbose { false };
|
||||||
bool interactive { false };
|
bool interactive { false };
|
||||||
|
bool recursive { false };
|
||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Copy files or directories."_sv);
|
parser.add_description("Copy files or directories."_sv);
|
||||||
@ -66,9 +111,15 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
parser.add_positional_argument(destination, "destination"_sv, true);
|
parser.add_positional_argument(destination, "destination"_sv, true);
|
||||||
parser.add_switch_argument(verbose, 'v', "verbose"_sv, "show more information"_sv);
|
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(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));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user