From 4bfe060336b96926dfd72bc3b0ef0b7ffdf5e168 Mon Sep 17 00:00:00 2001 From: Tetsui Ohkubo Date: Wed, 15 Sep 2021 00:03:24 +0900 Subject: [PATCH] FileOperation: Deduplicate file names on move For file copying, when there is a file with the same name in the destination directory, the file will be automatically renamed to "file-2.txt", for example. This change expands that special-case handling to file moving. --- Userland/Services/FileOperation/main.cpp | 49 ++++++++++++++---------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/Userland/Services/FileOperation/main.cpp b/Userland/Services/FileOperation/main.cpp index a4da956002..188d472b1f 100644 --- a/Userland/Services/FileOperation/main.cpp +++ b/Userland/Services/FileOperation/main.cpp @@ -321,27 +321,36 @@ int execute_work_items(Vector const& items) } case WorkItem::Type::MoveFile: { - if (rename(item.source.characters(), item.destination.characters()) == 0) { - item_done += item.size; - executed_work_bytes += item.size; - print_progress(); - continue; - } - - auto original_errno = errno; - if (original_errno != EXDEV) { - report_warning(String::formatted("Failed to move {}: {}", item.source, strerror(original_errno))); - return 1; - } - - // EXDEV means we have to copy the file data and then remove the original - if (!copy_file(item.source, item.destination)) - return 1; - - if (unlink(item.source.characters()) < 0) { + String destination = item.destination; + while (true) { + if (rename(item.source.characters(), destination.characters()) == 0) { + item_done += item.size; + executed_work_bytes += item.size; + print_progress(); + break; + } auto original_errno = errno; - report_error(String::formatted("unlink: {}", strerror(original_errno))); - return 1; + + if (original_errno == EEXIST) { + destination = deduplicate_destination_file_name(destination); + continue; + } + + if (original_errno != EXDEV) { + report_warning(String::formatted("Failed to move {}: {}", item.source, strerror(original_errno))); + return 1; + } + + // EXDEV means we have to copy the file data and then remove the original + if (!copy_file(item.source, item.destination)) + return 1; + + if (unlink(item.source.characters()) < 0) { + auto original_errno = errno; + report_error(String::formatted("unlink: {}", strerror(original_errno))); + return 1; + } + break; } break;