summaryrefslogtreecommitdiff
path: root/Userland/Services/FileOperation/main.cpp
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@gmail.com>2021-06-22 15:45:55 +0100
committerAndreas Kling <kling@serenityos.org>2021-07-22 12:48:44 +0200
commit967314023c0af9e900a58dfb1ce0b1362a29c445 (patch)
treecf8919e6aedc2c6985335fc2308cb70829834e0d /Userland/Services/FileOperation/main.cpp
parente99200cc23c8ddf45ac93fd6236a5dd137921b1c (diff)
downloadserenity-967314023c0af9e900a58dfb1ce0b1362a29c445.zip
FileOperation: Implement 'Delete' operation
Diffstat (limited to 'Userland/Services/FileOperation/main.cpp')
-rw-r--r--Userland/Services/FileOperation/main.cpp71
1 files changed, 70 insertions, 1 deletions
diff --git a/Userland/Services/FileOperation/main.cpp b/Userland/Services/FileOperation/main.cpp
index 22b7a36b8c..829ad6803d 100644
--- a/Userland/Services/FileOperation/main.cpp
+++ b/Userland/Services/FileOperation/main.cpp
@@ -20,6 +20,7 @@ struct WorkItem {
DeleteDirectory,
CopyFile,
MoveFile,
+ DeleteFile,
};
Type type;
String source;
@@ -29,6 +30,7 @@ struct WorkItem {
static int perform_copy(Vector<String> const& sources, String const& destination);
static int perform_move(Vector<String> const& sources, String const& destination);
+static int perform_delete(Vector<String> const& sources);
static int execute_work_items(Vector<WorkItem> const& items);
static void report_error(String message);
static void report_warning(String message);
@@ -39,10 +41,13 @@ int main(int argc, char** argv)
Vector<String> paths;
Core::ArgsParser args_parser;
- args_parser.add_positional_argument(operation, "Operation: either 'Copy' or 'Move'", "operation", Core::ArgsParser::Required::Yes);
+ args_parser.add_positional_argument(operation, "Operation: either 'Copy', 'Move' or 'Delete'", "operation", Core::ArgsParser::Required::Yes);
args_parser.add_positional_argument(paths, "Source paths, followed by a destination if applicable", "paths", Core::ArgsParser::Required::Yes);
args_parser.parse(argc, argv);
+ if (operation == "Delete")
+ return perform_delete(paths);
+
String destination = paths.take_last();
if (paths.is_empty()) {
report_warning("At least one source and destination are required");
@@ -183,6 +188,56 @@ int perform_move(Vector<String> const& sources, String const& destination)
return execute_work_items(items);
}
+static bool collect_delete_work_items(String const& source, Vector<WorkItem>& items)
+{
+ struct stat st = {};
+ if (stat(source.characters(), &st) < 0) {
+ auto original_errno = errno;
+ report_error(String::formatted("stat: {}", strerror(original_errno)));
+ return false;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ // It's a file.
+ items.append(WorkItem {
+ .type = WorkItem::Type::DeleteFile,
+ .source = source,
+ .destination = {},
+ .size = st.st_size,
+ });
+ return true;
+ }
+
+ // It's a directory.
+ Core::DirIterator dt(source, Core::DirIterator::SkipParentAndBaseDir);
+ while (dt.has_next()) {
+ auto name = dt.next_path();
+ if (!collect_delete_work_items(String::formatted("{}/{}", source, name), items))
+ return false;
+ }
+
+ items.append(WorkItem {
+ .type = WorkItem::Type::DeleteDirectory,
+ .source = source,
+ .destination = {},
+ .size = 0,
+ });
+
+ return true;
+}
+
+int perform_delete(Vector<String> const& sources)
+{
+ Vector<WorkItem> items;
+
+ for (auto& source : sources) {
+ if (!collect_delete_work_items(source, items))
+ return 1;
+ }
+
+ return execute_work_items(items);
+}
+
int execute_work_items(Vector<WorkItem> const& items)
{
off_t total_work_bytes = 0;
@@ -288,6 +343,20 @@ int execute_work_items(Vector<WorkItem> const& items)
break;
}
+ case WorkItem::Type::DeleteFile: {
+ if (unlink(item.source.characters()) < 0) {
+ auto original_errno = errno;
+ report_error(String::formatted("unlink: {}", strerror(original_errno)));
+ return 1;
+ }
+
+ item_done += item.size;
+ executed_work_bytes += item.size;
+ print_progress();
+
+ break;
+ }
+
default:
VERIFY_NOT_REACHED();
}