diff --git a/Libraries/LibFileSystem/CMakeLists.txt b/Libraries/LibFileSystem/CMakeLists.txt index edd0d59cfdc..e782d40baab 100644 --- a/Libraries/LibFileSystem/CMakeLists.txt +++ b/Libraries/LibFileSystem/CMakeLists.txt @@ -1,7 +1,12 @@ -set(SOURCES - FileSystem.cpp - TempFile.cpp -) +set (SOURCES FileSystem.cpp) +if (NOT WIN32) + list(APPEND SOURCES TempFile.cpp) +endif() serenity_lib(LibFileSystem filesystem) 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() diff --git a/Libraries/LibFileSystem/FileSystem.cpp b/Libraries/LibFileSystem/FileSystem.cpp index 3270dbc68f8..ec24a4d0e11 100644 --- a/Libraries/LibFileSystem/FileSystem.cpp +++ b/Libraries/LibFileSystem/FileSystem.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #if !defined(AK_OS_IOS) && defined(AK_OS_BSD_GENERIC) @@ -32,16 +33,19 @@ ErrorOr current_working_directory() ErrorOr 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 real_path(StringView path) { if (path.is_null()) @@ -56,6 +60,13 @@ ErrorOr real_path(StringView path) return ByteString { real_path, strlen(real_path) }; } +#else +// NOTE: real_path on Windows does not resolve symlinks +ErrorOr 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 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 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 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 remove(StringView path, RecursionMode mode) { if (is_directory(path) && mode == RecursionMode::Allowed) { @@ -314,31 +363,4 @@ ErrorOr 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; -} - }