From fad87b294be540ac469c92a487a16c9fd2103c03 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 30 Jun 2025 21:19:15 +0200 Subject: [PATCH] mkdir/rmdir would not work properly with substring paths on non-windows platforms. --- lib/std/io/io.c3 | 1 + lib/std/io/os/chdir.c3 | 40 ++++++++++++++++++------------------ lib/std/io/os/ls.c3 | 6 +++++- lib/std/io/os/mkdir.c3 | 12 ++++++----- lib/std/io/os/rmdir.c3 | 36 ++++++++++++++++----------------- lib/std/io/os/rmtree.c3 | 45 ++++++++++++++++++++++------------------- lib/std/io/path.c3 | 2 +- releasenotes.md | 1 + 8 files changed, 77 insertions(+), 66 deletions(-) diff --git a/lib/std/io/io.c3 b/lib/std/io/io.c3 index 8023b89e3..f58d413ac 100644 --- a/lib/std/io/io.c3 +++ b/lib/std/io/io.c3 @@ -16,6 +16,7 @@ faultdef BUSY, CANNOT_READ_DIR, DIR_NOT_EMPTY, + PARENT_DIR_MISSING, EOF, FILE_CANNOT_DELETE, FILE_IS_DIR, diff --git a/lib/std/io/os/chdir.c3 b/lib/std/io/os/chdir.c3 index d64252539..731d4438e 100644 --- a/lib/std/io/os/chdir.c3 +++ b/lib/std/io/os/chdir.c3 @@ -3,28 +3,28 @@ import std::io::path, libc, std::os; macro void? native_chdir(Path path) { - $switch: - $case env::POSIX: - if (posix::chdir(path.as_zstr())) - { - switch (libc::errno()) + @pool() + { + $switch: + $case env::POSIX: + if (posix::chdir(path.str_view().zstr_tcopy())) { - case errno::EACCES: return io::NO_PERMISSION?; - case errno::ENAMETOOLONG: return io::NAME_TOO_LONG?; - case errno::ENOTDIR: return io::FILE_NOT_DIR?; - case errno::ENOENT: return io::FILE_NOT_FOUND?; - case errno::ELOOP: return io::SYMLINK_FAILED?; - default: return io::GENERAL_ERROR?; + switch (libc::errno()) + { + case errno::EACCES: return io::NO_PERMISSION?; + case errno::ENAMETOOLONG: return io::NAME_TOO_LONG?; + case errno::ENOTDIR: return io::FILE_NOT_DIR?; + case errno::ENOENT: return io::FILE_NOT_FOUND?; + case errno::ELOOP: return io::SYMLINK_FAILED?; + default: return io::GENERAL_ERROR?; + } } - } - $case env::WIN32: - @pool() - { + $case env::WIN32: // TODO improve with better error handling. if (win32::setCurrentDirectoryW(path.str_view().to_temp_utf16()!!)) return; - }; - return io::GENERAL_ERROR?; - $default: - return io::UNSUPPORTED_OPERATION?; - $endswitch + return io::GENERAL_ERROR?; + $default: + return io::UNSUPPORTED_OPERATION?; + $endswitch + }; } diff --git a/lib/std/io/os/ls.c3 b/lib/std/io/os/ls.c3 index c1569d3f7..0d8c9d1a5 100644 --- a/lib/std/io/os/ls.c3 +++ b/lib/std/io/os/ls.c3 @@ -5,7 +5,11 @@ fn PathList? native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al { PathList list; list.init(allocator); - DIRPtr directory = posix::opendir(dir.str_view() ? dir.as_zstr() : (ZString)"."); + DIRPtr directory @noinit; + @pool() + { + directory = posix::opendir(dir.str_view() ? dir.str_view().zstr_tcopy() : (ZString)"."); + }; defer if (directory) posix::closedir(directory); if (!directory) return (path::is_dir(dir) ? io::CANNOT_READ_DIR : io::FILE_NOT_DIR)?; Posix_dirent* entry; diff --git a/lib/std/io/os/mkdir.c3 b/lib/std/io/os/mkdir.c3 index 717d065bd..32cd82548 100644 --- a/lib/std/io/os/mkdir.c3 +++ b/lib/std/io/os/mkdir.c3 @@ -7,9 +7,11 @@ import std::os::posix; macro bool? native_mkdir(Path path, MkdirPermissions permissions) { + @pool() + { $switch: $case env::POSIX: - if (!posix::mkdir(path.as_zstr(), permissions == NORMAL ? 0o777 : 0o700)) return true; + if (!posix::mkdir(path.str_view().zstr_tcopy(), permissions == NORMAL ? 0o777 : 0o700)) return true; switch (libc::errno()) { case errno::EACCES: @@ -23,11 +25,11 @@ macro bool? native_mkdir(Path path, MkdirPermissions permissions) case errno::EEXIST: return false; case errno::ELOOP: return io::SYMLINK_FAILED?; case errno::ENOTDIR: return io::FILE_NOT_FOUND?; - default: return io::GENERAL_ERROR?; + case errno::ENOENT: return io::PARENT_DIR_MISSING?; + default: + return io::GENERAL_ERROR?; } $case env::WIN32: - @pool() - { // TODO security attributes if (win32::createDirectoryW(path.str_view().to_temp_utf16()!!, null)) return true; switch (win32::getLastError()) @@ -43,8 +45,8 @@ macro bool? native_mkdir(Path path, MkdirPermissions permissions) default: return io::GENERAL_ERROR?; } - }; $default: return io::UNSUPPORTED_OPERATION?; $endswitch + }; } \ No newline at end of file diff --git a/lib/std/io/os/rmdir.c3 b/lib/std/io/os/rmdir.c3 index cf367bf75..e117fa160 100644 --- a/lib/std/io/os/rmdir.c3 +++ b/lib/std/io/os/rmdir.c3 @@ -6,9 +6,11 @@ import std::os::posix; macro bool? native_rmdir(Path path) { + @pool() + { $switch: $case env::POSIX: - if (!posix::rmdir(path.as_zstr())) return true; + if (!posix::rmdir(path.str_view().zstr_tcopy())) return true; switch (libc::errno()) { case errno::EBUSY: return io::BUSY?; @@ -24,25 +26,23 @@ macro bool? native_rmdir(Path path) default: return io::GENERAL_ERROR?; } $case env::WIN32: - @pool() + if (win32::removeDirectoryW(path.str_view().to_temp_utf16()!!)) return true; + switch (win32::getLastError()) { - if (win32::removeDirectoryW(path.str_view().to_temp_utf16()!!)) return true; - switch (win32::getLastError()) - { - case win32::ERROR_ACCESS_DENIED: - return io::NO_PERMISSION?; - case win32::ERROR_CURRENT_DIRECTORY: - return io::BUSY?; - case win32::ERROR_DIR_NOT_EMPTY: - return io::DIR_NOT_EMPTY?; - case win32::ERROR_DIRECTORY: - case win32::ERROR_PATH_NOT_FOUND: - return false; - default: - return io::GENERAL_ERROR?; - } - }; + case win32::ERROR_ACCESS_DENIED: + return io::NO_PERMISSION?; + case win32::ERROR_CURRENT_DIRECTORY: + return io::BUSY?; + case win32::ERROR_DIR_NOT_EMPTY: + return io::DIR_NOT_EMPTY?; + case win32::ERROR_DIRECTORY: + case win32::ERROR_PATH_NOT_FOUND: + return false; + default: + return io::GENERAL_ERROR?; + } $default: return io::UNSUPPORTED_OPERATION?; $endswitch + }; } diff --git a/lib/std/io/os/rmtree.c3 b/lib/std/io/os/rmtree.c3 index fac177f0f..6514baca1 100644 --- a/lib/std/io/os/rmtree.c3 +++ b/lib/std/io/os/rmtree.c3 @@ -6,30 +6,33 @@ import std::io, std::os, libc; *> fn void? native_rmtree(Path dir) { - DIRPtr directory = posix::opendir(dir.as_zstr()); - defer if (directory) posix::closedir(directory); - if (!directory) return path::is_dir(dir) ? io::CANNOT_READ_DIR? : io::FILE_NOT_DIR?; - Posix_dirent* entry; - while ((entry = posix::readdir(directory))) + @pool() { - @pool() + DIRPtr directory = posix::opendir(dir.str_view().zstr_tcopy()); + defer if (directory) posix::closedir(directory); + if (!directory) return path::is_dir(dir) ? io::CANNOT_READ_DIR? : io::FILE_NOT_DIR?; + Posix_dirent* entry; + while ((entry = posix::readdir(directory))) { - String name = ((ZString)&entry.name).str_view(); - if (!name || name == "." || name == "..") continue; - Path new_path = dir.tappend(name)!; - if (entry.d_type == posix::DT_DIR) + @pool() { - native_rmtree(new_path)!; - continue; - } - if (libc::remove(new_path.as_zstr())) - { - // TODO improve - return io::GENERAL_ERROR?; - } - }; - } - os::native_rmdir(dir)!; + String name = ((ZString)&entry.name).str_view(); + if (!name || name == "." || name == "..") continue; + Path new_path = dir.tappend(name)!; + if (entry.d_type == posix::DT_DIR) + { + native_rmtree(new_path)!; + continue; + } + if (libc::remove(new_path.str_view().zstr_tcopy())) + { + // TODO improve + return io::GENERAL_ERROR?; + } + }; + } + os::native_rmdir(dir)!; + }; } module std::io::os @if(env::WIN32); diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index d98854c55..b26372a7a 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -527,7 +527,7 @@ fn String? normalize(String path_str, PathEnv path_env = DEFAULT_ENV) return path_str[:len]; } -fn ZString Path.as_zstr(self) => (ZString)self.path_string.ptr; +fn ZString Path.as_zstr(self) @deprecated => (ZString)self.path_string.ptr; fn String Path.root_directory(self) { diff --git a/releasenotes.md b/releasenotes.md index 46ea7d8a3..f37d4462a 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -8,6 +8,7 @@ - Inline associated enum values are deprecated, use `--use-old-enums` to re-enable them. ### Fixes +- mkdir/rmdir would not work properly with substring paths on non-windows platforms. ### Stdlib changes