LibFileSystem: Port to Windows

This commit is contained in:
stasoid 2024-11-15 18:26:27 +05:00 committed by Andrew Kaster
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

@ -1,7 +1,12 @@
set(SOURCES set (SOURCES FileSystem.cpp)
FileSystem.cpp if (NOT WIN32)
TempFile.cpp list(APPEND SOURCES TempFile.cpp)
) endif()
serenity_lib(LibFileSystem filesystem) serenity_lib(LibFileSystem filesystem)
target_link_libraries(LibFileSystem PRIVATE LibCoreMinimal) target_link_libraries(LibFileSystem PRIVATE LibCoreMinimal)
if (WIN32)
find_path(DIRENT_INCLUDE_DIR dirent.h REQUIRED)
target_include_directories(LibFileSystem PRIVATE ${DIRENT_INCLUDE_DIR})
endif()

View file

@ -10,6 +10,7 @@
#include <LibCore/DirIterator.h> #include <LibCore/DirIterator.h>
#include <LibCore/System.h> #include <LibCore/System.h>
#include <LibFileSystem/FileSystem.h> #include <LibFileSystem/FileSystem.h>
#include <dirent.h>
#include <limits.h> #include <limits.h>
#if !defined(AK_OS_IOS) && defined(AK_OS_BSD_GENERIC) #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) ErrorOr<ByteString> absolute_path(StringView path)
{ {
#ifndef AK_OS_WINDOWS
if (exists(path)) if (exists(path))
return real_path(path); return real_path(path);
#endif
if (path.starts_with("/"sv)) if (LexicalPath::is_absolute_path(path))
return LexicalPath::canonicalized_path(path); return LexicalPath::canonicalized_path(path);
auto working_directory = TRY(current_working_directory()); auto working_directory = TRY(current_working_directory());
return LexicalPath::absolute_path(working_directory, path); return LexicalPath::absolute_path(working_directory, path);
} }
#ifndef AK_OS_WINDOWS
ErrorOr<ByteString> real_path(StringView path) ErrorOr<ByteString> real_path(StringView path)
{ {
if (path.is_null()) if (path.is_null())
@ -56,6 +60,13 @@ ErrorOr<ByteString> real_path(StringView path)
return ByteString { real_path, strlen(real_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) bool exists(StringView path)
{ {
@ -103,6 +114,16 @@ bool is_directory(int fd)
return S_ISDIR(st.st_mode); 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) bool is_link(StringView path)
{ {
auto st_or_error = Core::System::lstat(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)) { if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
struct timespec times[2] = { 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_atimespec,
source_stat.st_mtimespec, source_stat.st_mtimespec,
#else # else
source_stat.st_atim, source_stat.st_atim,
source_stat.st_mtim, source_stat.st_mtim,
#endif # endif
}; };
TRY(Core::System::utimensat(AT_FDCWD, destination_path, times, 0)); 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)) { if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
struct timespec times[2] = { 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_atimespec,
source_stat.st_mtimespec, source_stat.st_mtimespec,
#else # else
source_stat.st_atim, source_stat.st_atim,
source_stat.st_mtim, source_stat.st_mtim,
#endif # endif
}; };
TRY(Core::System::utimensat(AT_FDCWD, destination_path, times, 0)); 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); 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) ErrorOr<void> remove(StringView path, RecursionMode mode)
{ {
if (is_directory(path) && mode == RecursionMode::Allowed) { if (is_directory(path) && mode == RecursionMode::Allowed) {
@ -314,31 +363,4 @@ ErrorOr<off_t> size_from_fstat(int fd)
return st.st_size; 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;
}
} }