LibFileSystem: Port to Windows

This commit is contained in:
stasoid 2024-11-15 18:26:27 +05:00 committed by Andrew Kaster
parent d87144fde2
commit 33e7d6121b
Notes: github-actions[bot] 2024-11-19 22:18:12 +00:00
2 changed files with 65 additions and 38 deletions

View file

@ -10,6 +10,7 @@
#include <LibCore/DirIterator.h>
#include <LibCore/System.h>
#include <LibFileSystem/FileSystem.h>
#include <dirent.h>
#include <limits.h>
#if !defined(AK_OS_IOS) && defined(AK_OS_BSD_GENERIC)
@ -32,16 +33,19 @@ ErrorOr<ByteString> current_working_directory()
ErrorOr<ByteString> absolute_path(StringView path)
{
#ifndef AK_OS_WINDOWS
if (exists(path))
return real_path(path);
#endif
if (path.starts_with("/"sv))
if (LexicalPath::is_absolute_path(path))
return LexicalPath::canonicalized_path(path);
auto working_directory = TRY(current_working_directory());
return LexicalPath::absolute_path(working_directory, path);
}
#ifndef AK_OS_WINDOWS
ErrorOr<ByteString> real_path(StringView path)
{
if (path.is_null())
@ -56,6 +60,13 @@ ErrorOr<ByteString> real_path(StringView path)
return ByteString { real_path, strlen(real_path) };
}
#else
// NOTE: real_path on Windows does not resolve symlinks
ErrorOr<ByteString> real_path(StringView path)
{
return absolute_path(path);
}
#endif
bool exists(StringView path)
{
@ -103,6 +114,16 @@ bool is_directory(int fd)
return S_ISDIR(st.st_mode);
}
#ifdef AK_OS_WINDOWS
bool is_link(StringView path)
{
ByteString string_path = path;
auto attr = GetFileAttributes(string_path.characters());
if (attr == INVALID_FILE_ATTRIBUTES)
return false;
return attr & FILE_ATTRIBUTE_REPARSE_POINT;
}
#else
bool is_link(StringView path)
{
auto st_or_error = Core::System::lstat(path);
@ -178,13 +199,13 @@ ErrorOr<void> copy_file(StringView destination_path, StringView source_path, str
if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
struct timespec times[2] = {
#if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
# if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
source_stat.st_atimespec,
source_stat.st_mtimespec,
#else
# else
source_stat.st_atim,
source_stat.st_mtim,
#endif
# endif
};
TRY(Core::System::utimensat(AT_FDCWD, destination_path, times, 0));
}
@ -226,13 +247,13 @@ ErrorOr<void> copy_directory(StringView destination_path, StringView source_path
if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
struct timespec times[2] = {
#if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
# if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
source_stat.st_atimespec,
source_stat.st_mtimespec,
#else
# else
source_stat.st_atim,
source_stat.st_mtim,
#endif
# endif
};
TRY(Core::System::utimensat(AT_FDCWD, destination_path, times, 0));
}
@ -284,6 +305,34 @@ ErrorOr<void> move_file(StringView destination_path, StringView source_path, Pre
return Core::System::unlink(source_path);
}
bool can_delete_or_move(StringView path)
{
VERIFY(!path.is_empty());
auto directory = LexicalPath::dirname(path);
auto directory_has_write_access = !Core::System::access(directory, W_OK).is_error();
if (!directory_has_write_access)
return false;
auto stat_or_empty = [](StringView path) {
auto stat_or_error = Core::System::stat(path);
if (stat_or_error.is_error()) {
struct stat stat { };
return stat;
}
return stat_or_error.release_value();
};
auto directory_stat = stat_or_empty(directory);
bool is_directory_sticky = (directory_stat.st_mode & S_ISVTX) != 0;
if (!is_directory_sticky)
return true;
// Directory is sticky, only the file owner, directory owner, and root can modify (rename, remove) it.
auto user_id = geteuid();
return user_id == 0 || directory_stat.st_uid == user_id || stat_or_empty(path).st_uid == user_id;
}
#endif // !AK_OS_WINDOWS
ErrorOr<void> remove(StringView path, RecursionMode mode)
{
if (is_directory(path) && mode == RecursionMode::Allowed) {
@ -314,31 +363,4 @@ ErrorOr<off_t> size_from_fstat(int fd)
return st.st_size;
}
bool can_delete_or_move(StringView path)
{
VERIFY(!path.is_empty());
auto directory = LexicalPath::dirname(path);
auto directory_has_write_access = !Core::System::access(directory, W_OK).is_error();
if (!directory_has_write_access)
return false;
auto stat_or_empty = [](StringView path) {
auto stat_or_error = Core::System::stat(path);
if (stat_or_error.is_error()) {
struct stat stat { };
return stat;
}
return stat_or_error.release_value();
};
auto directory_stat = stat_or_empty(directory);
bool is_directory_sticky = (directory_stat.st_mode & S_ISVTX) != 0;
if (!is_directory_sticky)
return true;
// Directory is sticky, only the file owner, directory owner, and root can modify (rename, remove) it.
auto user_id = geteuid();
return user_id == 0 || directory_stat.st_uid == user_id || stat_or_empty(path).st_uid == user_id;
}
}