summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Boric <jblbeurope@gmail.com>2021-08-15 12:24:00 +0200
committerAndreas Kling <kling@serenityos.org>2021-08-18 20:30:46 +0200
commit8cc8d72619e408be8b792499c33b3c9cbc1dbe23 (patch)
tree8e9ab2d4ea0595d0875c5fe18579841aed7f3bc7
parent91bcff29944c98ed1ee69f5d024942175c7a6af2 (diff)
downloadserenity-8cc8d72619e408be8b792499c33b3c9cbc1dbe23.zip
LibCore: Implement preserve flag for file/directory copy
-rw-r--r--Userland/Libraries/LibCore/File.cpp45
-rw-r--r--Userland/Libraries/LibCore/File.h11
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);