mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:57:45 +00:00
LibCore: Remove recursive copy API from DeprecatedFile
This commit is contained in:
parent
9f820fa2c5
commit
33026bcefe
2 changed files with 0 additions and 232 deletions
|
@ -24,11 +24,6 @@
|
||||||
# include <serenity.h>
|
# include <serenity.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// On Linux distros that use glibc `basename` is defined as a macro that expands to `__xpg_basename`, so we undefine it
|
|
||||||
#if defined(AK_OS_LINUX) && defined(basename)
|
|
||||||
# undef basename
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<DeprecatedFile>> DeprecatedFile::open(DeprecatedString filename, OpenMode mode, mode_t permissions)
|
ErrorOr<NonnullRefPtr<DeprecatedFile>> DeprecatedFile::open(DeprecatedString filename, OpenMode mode, mode_t permissions)
|
||||||
|
@ -181,196 +176,6 @@ DeprecatedString DeprecatedFile::absolute_path(DeprecatedString const& path)
|
||||||
return LexicalPath::canonicalized_path(full_path.string());
|
return LexicalPath::canonicalized_path(full_path.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
static DeprecatedString get_duplicate_name(DeprecatedString const& path, int duplicate_count)
|
|
||||||
{
|
|
||||||
if (duplicate_count == 0) {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
LexicalPath lexical_path(path);
|
|
||||||
StringBuilder duplicated_name;
|
|
||||||
duplicated_name.append('/');
|
|
||||||
auto& parts = lexical_path.parts_view();
|
|
||||||
for (size_t i = 0; i < parts.size() - 1; ++i) {
|
|
||||||
duplicated_name.appendff("{}/", parts[i]);
|
|
||||||
}
|
|
||||||
auto prev_duplicate_tag = DeprecatedString::formatted("({})", duplicate_count);
|
|
||||||
auto title = lexical_path.title();
|
|
||||||
if (title.ends_with(prev_duplicate_tag)) {
|
|
||||||
// remove the previous duplicate tag "(n)" so we can add a new tag.
|
|
||||||
title = title.substring_view(0, title.length() - prev_duplicate_tag.length());
|
|
||||||
}
|
|
||||||
duplicated_name.appendff("{} ({})", title, duplicate_count);
|
|
||||||
if (!lexical_path.extension().is_empty()) {
|
|
||||||
duplicated_name.appendff(".{}", lexical_path.extension());
|
|
||||||
}
|
|
||||||
return duplicated_name.to_deprecated_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void, DeprecatedFile::CopyError> DeprecatedFile::copy_file_or_directory(DeprecatedString const& dst_path, DeprecatedString 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;
|
|
||||||
while (access(get_duplicate_name(dst_path, duplicate_count).characters(), F_OK) == 0) {
|
|
||||||
++duplicate_count;
|
|
||||||
}
|
|
||||||
if (duplicate_count != 0) {
|
|
||||||
return copy_file_or_directory(get_duplicate_name(dst_path, duplicate_count), src_path, RecursionMode::Allowed, LinkMode::Disallowed, AddDuplicateFileMarker::Yes, preserve_mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto source_or_error = DeprecatedFile::open(src_path, OpenMode::ReadOnly);
|
|
||||||
if (source_or_error.is_error())
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
auto& source = *source_or_error.value();
|
|
||||||
|
|
||||||
struct stat src_stat;
|
|
||||||
if (fstat(source.fd(), &src_stat) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
if (source.is_directory()) {
|
|
||||||
if (recursion_mode == RecursionMode::Disallowed)
|
|
||||||
return CopyError { errno, true };
|
|
||||||
return copy_directory(dst_path, src_path, src_stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link_mode == LinkMode::Allowed) {
|
|
||||||
if (link(src_path.characters(), dst_path.characters()) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return copy_file(dst_path, src_stat, source, preserve_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void, DeprecatedFile::CopyError> DeprecatedFile::copy_file(DeprecatedString const& dst_path, struct stat const& src_stat, DeprecatedFile& source, PreserveMode preserve_mode)
|
|
||||||
{
|
|
||||||
int dst_fd = creat(dst_path.characters(), 0666);
|
|
||||||
if (dst_fd < 0) {
|
|
||||||
if (errno != EISDIR)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
auto dst_dir_path = DeprecatedString::formatted("{}/{}", dst_path, LexicalPath::basename(source.filename()));
|
|
||||||
dst_fd = creat(dst_dir_path.characters(), 0666);
|
|
||||||
if (dst_fd < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopeGuard close_fd_guard([dst_fd]() { ::close(dst_fd); });
|
|
||||||
|
|
||||||
if (src_stat.st_size > 0) {
|
|
||||||
if (ftruncate(dst_fd, src_stat.st_size) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
char buffer[32768];
|
|
||||||
ssize_t nread = ::read(source.fd(), buffer, sizeof(buffer));
|
|
||||||
if (nread < 0) {
|
|
||||||
return CopyError { errno, false };
|
|
||||||
}
|
|
||||||
if (nread == 0)
|
|
||||||
break;
|
|
||||||
ssize_t remaining_to_write = nread;
|
|
||||||
char* bufptr = buffer;
|
|
||||||
while (remaining_to_write) {
|
|
||||||
ssize_t nwritten = ::write(dst_fd, bufptr, remaining_to_write);
|
|
||||||
if (nwritten < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
VERIFY(nwritten > 0);
|
|
||||||
remaining_to_write -= nwritten;
|
|
||||||
bufptr += nwritten;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto my_umask = umask(0);
|
|
||||||
umask(my_umask);
|
|
||||||
// NOTE: We don't copy the set-uid and set-gid bits unless requested.
|
|
||||||
if (!has_flag(preserve_mode, PreserveMode::Permissions))
|
|
||||||
my_umask |= 06000;
|
|
||||||
|
|
||||||
if (fchmod(dst_fd, src_stat.st_mode & ~my_umask) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
if (has_flag(preserve_mode, PreserveMode::Ownership)) {
|
|
||||||
if (fchown(dst_fd, src_stat.st_uid, src_stat.st_gid) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
|
|
||||||
struct timespec times[2] = {
|
|
||||||
#ifdef AK_OS_MACOS
|
|
||||||
src_stat.st_atimespec,
|
|
||||||
src_stat.st_mtimespec,
|
|
||||||
#else
|
|
||||||
src_stat.st_atim,
|
|
||||||
src_stat.st_mtim,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
if (utimensat(AT_FDCWD, dst_path.characters(), times, 0) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void, DeprecatedFile::CopyError> DeprecatedFile::copy_directory(DeprecatedString const& dst_path, DeprecatedString const& src_path, struct stat const& src_stat, LinkMode link, PreserveMode preserve_mode)
|
|
||||||
{
|
|
||||||
if (mkdir(dst_path.characters(), 0755) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
DeprecatedString src_rp = DeprecatedFile::real_path_for(src_path);
|
|
||||||
src_rp = DeprecatedString::formatted("{}/", src_rp);
|
|
||||||
DeprecatedString dst_rp = DeprecatedFile::real_path_for(dst_path);
|
|
||||||
dst_rp = DeprecatedString::formatted("{}/", dst_rp);
|
|
||||||
|
|
||||||
if (!dst_rp.is_empty() && dst_rp.starts_with(src_rp))
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
DirIterator di(src_path, DirIterator::SkipParentAndBaseDir);
|
|
||||||
if (di.has_error())
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
while (di.has_next()) {
|
|
||||||
DeprecatedString filename = di.next_path();
|
|
||||||
auto result = copy_file_or_directory(
|
|
||||||
DeprecatedString::formatted("{}/{}", dst_path, filename),
|
|
||||||
DeprecatedString::formatted("{}/{}", src_path, filename),
|
|
||||||
RecursionMode::Allowed, link, AddDuplicateFileMarker::Yes, preserve_mode);
|
|
||||||
if (result.is_error())
|
|
||||||
return result.release_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto my_umask = umask(0);
|
|
||||||
umask(my_umask);
|
|
||||||
|
|
||||||
if (chmod(dst_path.characters(), src_stat.st_mode & ~my_umask) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
|
|
||||||
if (has_flag(preserve_mode, PreserveMode::Ownership)) {
|
|
||||||
if (chown(dst_path.characters(), src_stat.st_uid, src_stat.st_gid) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
|
|
||||||
struct timespec times[2] = {
|
|
||||||
#ifdef AK_OS_MACOS
|
|
||||||
src_stat.st_atimespec,
|
|
||||||
src_stat.st_mtimespec,
|
|
||||||
#else
|
|
||||||
src_stat.st_atim,
|
|
||||||
src_stat.st_mtim,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
if (utimensat(AT_FDCWD, dst_path.characters(), times, 0) < 0)
|
|
||||||
return CopyError { errno, false };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<DeprecatedString> DeprecatedFile::resolve_executable_from_environment(StringView filename)
|
Optional<DeprecatedString> DeprecatedFile::resolve_executable_from_environment(StringView filename)
|
||||||
{
|
{
|
||||||
if (filename.is_empty())
|
if (filename.is_empty())
|
||||||
|
|
|
@ -35,41 +35,6 @@ public:
|
||||||
static DeprecatedString current_working_directory();
|
static DeprecatedString current_working_directory();
|
||||||
static DeprecatedString absolute_path(DeprecatedString const& path);
|
static DeprecatedString absolute_path(DeprecatedString const& path);
|
||||||
|
|
||||||
enum class RecursionMode {
|
|
||||||
Allowed,
|
|
||||||
Disallowed
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class LinkMode {
|
|
||||||
Allowed,
|
|
||||||
Disallowed
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class AddDuplicateFileMarker {
|
|
||||||
Yes,
|
|
||||||
No,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class PreserveMode {
|
|
||||||
Nothing = 0,
|
|
||||||
Permissions = (1 << 0),
|
|
||||||
Ownership = (1 << 1),
|
|
||||||
Timestamps = (1 << 2),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CopyError : public Error {
|
|
||||||
CopyError(int error_code, bool t)
|
|
||||||
: Error(error_code)
|
|
||||||
, tried_recursing(t)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
bool tried_recursing;
|
|
||||||
};
|
|
||||||
|
|
||||||
static ErrorOr<void, CopyError> copy_file(DeprecatedString const& dst_path, struct stat const& src_stat, DeprecatedFile& source, PreserveMode = PreserveMode::Nothing);
|
|
||||||
static ErrorOr<void, CopyError> copy_directory(DeprecatedString const& dst_path, DeprecatedString const& src_path, struct stat const& src_stat, LinkMode = LinkMode::Disallowed, PreserveMode = PreserveMode::Nothing);
|
|
||||||
static ErrorOr<void, CopyError> copy_file_or_directory(DeprecatedString const& dst_path, DeprecatedString const& src_path, RecursionMode = RecursionMode::Allowed, LinkMode = LinkMode::Disallowed, AddDuplicateFileMarker = AddDuplicateFileMarker::Yes, PreserveMode = PreserveMode::Nothing);
|
|
||||||
|
|
||||||
static DeprecatedString real_path_for(DeprecatedString const& filename);
|
static DeprecatedString real_path_for(DeprecatedString const& filename);
|
||||||
|
|
||||||
virtual bool open(OpenMode) override;
|
virtual bool open(OpenMode) override;
|
||||||
|
@ -96,6 +61,4 @@ private:
|
||||||
ShouldCloseFileDescriptor m_should_close_file_descriptor { ShouldCloseFileDescriptor::Yes };
|
ShouldCloseFileDescriptor m_should_close_file_descriptor { ShouldCloseFileDescriptor::Yes };
|
||||||
};
|
};
|
||||||
|
|
||||||
AK_ENUM_BITWISE_OPERATORS(DeprecatedFile::PreserveMode);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue