Replace syscall.Rmdir with golang.org/x/sys for cross-platform directory removal#1885
Replace syscall.Rmdir with golang.org/x/sys for cross-platform directory removal#1885rumpl wants to merge 1 commit intodocker:mainfrom
Conversation
…ory removal Use platform-specific files with golang.org/x/sys/unix and golang.org/x/sys/windows instead of the frozen syscall package. Both unix.Rmdir and windows.RemoveDirectory are atomic, directory-only syscalls, avoiding the TOCTOU race that an os.Lstat + os.Remove sequence would introduce. Fixes docker#1884 Assisted-By: cagent
There was a problem hiding this comment.
Review Summary
This PR successfully modernizes the directory removal implementation by replacing the frozen syscall package with platform-specific implementations from golang.org/x/sys. The changes are well-structured with proper build tags and maintain atomicity guarantees.
However, there is one notable behavioral change in error handling that should be considered.
| if errors.Is(err, syscall.ENOTDIR) { | ||
| return tools.ResultError(fmt.Sprintf("Error: %s is not a directory", path)), nil | ||
| } | ||
| if err := rmdir(resolvedPath); err != nil { |
There was a problem hiding this comment.
Loss of type-safe ENOTDIR error handling
The old implementation explicitly checked for syscall.ENOTDIR using errors.Is() to distinguish "not a directory" errors from other failure types (permission denied, path not found, etc.). The new implementation removes this check and now relies on error message strings.
While the underlying system calls (unix.Rmdir and windows.RemoveDirectory) do return appropriate error types/messages, callers that previously depended on type-safe error detection would now need to parse error strings. This is more fragile and platform-dependent.
Impact: Moderate - the functionality still works and the test passes, but error handling becomes less robust and harder to reason about programmatically.
Consider: If maintaining the explicit ENOTDIR check is important for API consumers, you could wrap the platform-specific errors and check for the appropriate error types (unix.ENOTDIR on Unix, windows.ERROR_DIRECTORY on Windows) before returning the generic error message.
Summary
Replace
syscall.Rmdirwith platform-specific implementations usinggolang.org/x/sys, the supported successor to the frozensyscallpackage.Changes
rmdir_unix.go— usesunix.Rmdiron aix/darwin/dragonfly/freebsd/linux/netbsd/openbsd/solarisrmdir_windows.go— useswindows.RemoveDirectoryfilesystem.go— calls the newrmdir()helper, removessyscallanderrorsimportsfilesystem_test.go— relaxes assertion to match OS-level error string ("not a directory"vs"is not a directory")Both
unix.Rmdirandwindows.RemoveDirectoryare atomic, directory-only syscalls — they will not accidentally delete regular files and avoid the TOCTOU race that anos.Lstat+os.Removesequence would introduce.golang.org/x/sysis already a dependency of this project.Fixes #1884