diff options
author | Jean-Baptiste Boric <jblbeurope@gmail.com> | 2021-08-15 12:24:00 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-18 20:30:46 +0200 |
commit | 8cc8d72619e408be8b792499c33b3c9cbc1dbe23 (patch) | |
tree | 8e9ab2d4ea0595d0875c5fe18579841aed7f3bc7 | |
parent | 91bcff29944c98ed1ee69f5d024942175c7a6af2 (diff) | |
download | serenity-8cc8d72619e408be8b792499c33b3c9cbc1dbe23.zip |
LibCore: Implement preserve flag for file/directory copy
-rw-r--r-- | Userland/Libraries/LibCore/File.cpp | 45 | ||||
-rw-r--r-- | Userland/Libraries/LibCore/File.h | 11 |
2 files changed, 45 insertions, 11 deletions
diff --git a/Userland/Libraries/LibCore/File.cpp b/Userland/Libraries/LibCore/File.cpp index 7e8c4210f4..dc2fbdf816 100644 --- a/Userland/Libraries/LibCore/File.cpp +++ b/Userland/Libraries/LibCore/File.cpp @@ -18,6 +18,7 @@ #include <string.h> #include <sys/stat.h> #include <unistd.h> +#include <utime.h> // On Linux distros that use glibc `basename` is defined as a macro that expands to `__xpg_basename`, so we undefine it #if defined(__linux__) && defined(basename) @@ -338,7 +339,7 @@ static String get_duplicate_name(String const& path, int duplicate_count) return duplicated_name.build(); } -Result<void, File::CopyError> File::copy_file_or_directory(String const& dst_path, String const& src_path, RecursionMode recursion_mode, LinkMode link_mode, AddDuplicateFileMarker add_duplicate_file_marker) +Result<void, File::CopyError> File::copy_file_or_directory(String const& dst_path, String const& src_path, RecursionMode recursion_mode, LinkMode link_mode, AddDuplicateFileMarker add_duplicate_file_marker, PreserveMode preserve_mode) { if (add_duplicate_file_marker == AddDuplicateFileMarker::Yes) { int duplicate_count = 0; @@ -346,7 +347,7 @@ Result<void, File::CopyError> File::copy_file_or_directory(String const& dst_pat ++duplicate_count; } if (duplicate_count != 0) { - return copy_file_or_directory(get_duplicate_name(dst_path, duplicate_count), src_path); + return copy_file_or_directory(get_duplicate_name(dst_path, duplicate_count), src_path, RecursionMode::Allowed, LinkMode::Disallowed, AddDuplicateFileMarker::Yes, preserve_mode); } } @@ -373,10 +374,10 @@ Result<void, File::CopyError> File::copy_file_or_directory(String const& dst_pat return {}; } - return copy_file(dst_path, src_stat, source); + return copy_file(dst_path, src_stat, source, preserve_mode); } -Result<void, File::CopyError> File::copy_file(String const& dst_path, struct stat const& src_stat, File& source) +Result<void, File::CopyError> File::copy_file(String const& dst_path, struct stat const& src_stat, File& source, PreserveMode preserve_mode) { int dst_fd = creat(dst_path.characters(), 0666); if (dst_fd < 0) { @@ -417,16 +418,31 @@ Result<void, File::CopyError> File::copy_file(String const& dst_path, struct sta } } - // NOTE: We don't copy the set-uid and set-gid bits. auto my_umask = umask(0); umask(my_umask); - if (fchmod(dst_fd, (src_stat.st_mode & ~my_umask) & ~06000) < 0) + // NOTE: We don't copy the set-uid and set-gid bits unless requested. + if (preserve_mode != PreserveMode::PermissionsOwnershipTimestamps) + my_umask |= 06000; + + if (fchmod(dst_fd, src_stat.st_mode & ~my_umask) < 0) return CopyError { OSError(errno), false }; + if (preserve_mode == PreserveMode::PermissionsOwnershipTimestamps) { + if (fchown(dst_fd, src_stat.st_uid, src_stat.st_gid) < 0) + return CopyError { OSError(errno), false }; + + // FIXME: Implement utimens() and use it here. + struct utimbuf timbuf; + timbuf.actime = src_stat.st_atime; + timbuf.modtime = src_stat.st_mtime; + if (utime(dst_path.characters(), &timbuf) < 0) + return CopyError { OSError(errno), false }; + } + return {}; } -Result<void, File::CopyError> File::copy_directory(String const& dst_path, String const& src_path, struct stat const& src_stat, LinkMode link) +Result<void, File::CopyError> File::copy_directory(String const& dst_path, String const& src_path, struct stat const& src_stat, LinkMode link, PreserveMode preserve_mode) { if (mkdir(dst_path.characters(), 0755) < 0) return CopyError { OSError(errno), false }; @@ -448,16 +464,29 @@ Result<void, File::CopyError> File::copy_directory(String const& dst_path, Strin auto result = copy_file_or_directory( String::formatted("{}/{}", dst_path, filename), String::formatted("{}/{}", src_path, filename), - RecursionMode::Allowed, link); + RecursionMode::Allowed, link, AddDuplicateFileMarker::Yes, preserve_mode); if (result.is_error()) return result.error(); } auto my_umask = umask(0); umask(my_umask); + if (chmod(dst_path.characters(), src_stat.st_mode & ~my_umask) < 0) return CopyError { OSError(errno), false }; + if (preserve_mode == PreserveMode::PermissionsOwnershipTimestamps) { + if (chown(dst_path.characters(), src_stat.st_uid, src_stat.st_gid) < 0) + return CopyError { OSError(errno), false }; + + // FIXME: Implement utimens() and use it here. + struct utimbuf timbuf; + timbuf.actime = src_stat.st_atim.tv_sec; + timbuf.modtime = src_stat.st_atim.tv_sec; + if (utime(dst_path.characters(), &timbuf) < 0) + return CopyError { OSError(errno), false }; + } + return {}; } diff --git a/Userland/Libraries/LibCore/File.h b/Userland/Libraries/LibCore/File.h index a8649a20b0..c430d1eade 100644 --- a/Userland/Libraries/LibCore/File.h +++ b/Userland/Libraries/LibCore/File.h @@ -53,14 +53,19 @@ public: No, }; + enum class PreserveMode { + Nothing, + PermissionsOwnershipTimestamps, + }; + struct CopyError { OSError error_code; bool tried_recursing; }; - static Result<void, CopyError> copy_file(String const& dst_path, struct stat const& src_stat, File& source); - static Result<void, CopyError> copy_directory(String const& dst_path, String const& src_path, struct stat const& src_stat, LinkMode = LinkMode::Disallowed); - static Result<void, CopyError> copy_file_or_directory(String const& dst_path, String const& src_path, RecursionMode = RecursionMode::Allowed, LinkMode = LinkMode::Disallowed, AddDuplicateFileMarker = AddDuplicateFileMarker::Yes); + static Result<void, CopyError> copy_file(String const& dst_path, struct stat const& src_stat, File& source, PreserveMode = PreserveMode::Nothing); + static Result<void, CopyError> copy_directory(String const& dst_path, String const& src_path, struct stat const& src_stat, LinkMode = LinkMode::Disallowed, PreserveMode = PreserveMode::Nothing); + static Result<void, CopyError> copy_file_or_directory(String const& dst_path, String const& src_path, RecursionMode = RecursionMode::Allowed, LinkMode = LinkMode::Disallowed, AddDuplicateFileMarker = AddDuplicateFileMarker::Yes, PreserveMode = PreserveMode::Nothing); static String real_path_for(String const& filename); static String read_link(String const& link_path); |