aboutsummaryrefslogtreecommitdiff
path: root/src/internal/syscall
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2024-11-12 17:16:10 +0100
committerDamien Neil <dneil@google.com>2024-11-20 23:21:14 +0000
commit49d24d469eb4ecbbf5a77d905ca2bd1da0e18bbd (patch)
tree620dfeb866b8bdc9174da763bd19e9cbd0e53b28 /src/internal/syscall
parent43d90c6a14e7b3fd1b3b8085b8071a09231c4b62 (diff)
downloadgo-49d24d469eb4ecbbf5a77d905ca2bd1da0e18bbd.tar.xz
os: add Root.Remove
For #67002 Change-Id: Ibbf44c0bf62f53695a7399ba0dae5b84d5efd374 Reviewed-on: https://go-review.googlesource.com/c/go/+/627076 Reviewed-by: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/internal/syscall')
-rw-r--r--src/internal/syscall/unix/at_wasip1.go26
-rw-r--r--src/internal/syscall/windows/at_windows.go70
-rw-r--r--src/internal/syscall/windows/syscall_windows.go4
-rw-r--r--src/internal/syscall/windows/types_windows.go20
-rw-r--r--src/internal/syscall/windows/zsyscall_windows.go18
5 files changed, 138 insertions, 0 deletions
diff --git a/src/internal/syscall/unix/at_wasip1.go b/src/internal/syscall/unix/at_wasip1.go
index 45ae22afcc..2be7ef3630 100644
--- a/src/internal/syscall/unix/at_wasip1.go
+++ b/src/internal/syscall/unix/at_wasip1.go
@@ -17,8 +17,34 @@ const (
// to avoid changing AccessTime or ModifiedTime.
// Its value must match syscall/fs_wasip1.go
UTIME_OMIT = -0x2
+
+ AT_REMOVEDIR = 0x200
)
+func Unlinkat(dirfd int, path string, flags int) error {
+ if flags&AT_REMOVEDIR == 0 {
+ return errnoErr(path_unlink_file(
+ int32(dirfd),
+ unsafe.StringData(path),
+ size(len(path)),
+ ))
+ } else {
+ return errnoErr(path_remove_directory(
+ int32(dirfd),
+ unsafe.StringData(path),
+ size(len(path)),
+ ))
+ }
+}
+
+//go:wasmimport wasi_snapshot_preview1 path_unlink_file
+//go:noescape
+func path_unlink_file(fd int32, path *byte, pathLen size) syscall.Errno
+
+//go:wasmimport wasi_snapshot_preview1 path_remove_directory
+//go:noescape
+func path_remove_directory(fd int32, path *byte, pathLen size) syscall.Errno
+
func Openat(dirfd int, path string, flags int, perm uint32) (int, error) {
return syscall.Openat(dirfd, path, flags, perm)
}
diff --git a/src/internal/syscall/windows/at_windows.go b/src/internal/syscall/windows/at_windows.go
index af8167dd06..72780139a0 100644
--- a/src/internal/syscall/windows/at_windows.go
+++ b/src/internal/syscall/windows/at_windows.go
@@ -6,6 +6,7 @@ package windows
import (
"syscall"
+ "unsafe"
)
// Openat flags not supported by syscall.Open.
@@ -171,3 +172,72 @@ func Mkdirat(dirfd syscall.Handle, name string, mode uint32) error {
syscall.CloseHandle(h)
return nil
}
+
+func Deleteat(dirfd syscall.Handle, name string) error {
+ objAttrs := &OBJECT_ATTRIBUTES{}
+ if err := objAttrs.init(dirfd, name); err != nil {
+ return err
+ }
+ var h syscall.Handle
+ err := NtOpenFile(
+ &h,
+ DELETE,
+ objAttrs,
+ &IO_STATUS_BLOCK{},
+ FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT,
+ )
+ if err != nil {
+ return ntCreateFileError(err, 0)
+ }
+ defer syscall.CloseHandle(h)
+
+ const (
+ FileDispositionInformation = 13
+ FileDispositionInformationEx = 64
+ )
+
+ // First, attempt to delete the file using POSIX semantics
+ // (which permit a file to be deleted while it is still open).
+ // This matches the behavior of DeleteFileW.
+ err = NtSetInformationFile(
+ h,
+ &IO_STATUS_BLOCK{},
+ uintptr(unsafe.Pointer(&FILE_DISPOSITION_INFORMATION_EX{
+ Flags: FILE_DISPOSITION_DELETE |
+ FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK |
+ FILE_DISPOSITION_POSIX_SEMANTICS |
+ // This differs from DeleteFileW, but matches os.Remove's
+ // behavior on Unix platforms of permitting deletion of
+ // read-only files.
+ FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE,
+ })),
+ uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION_EX{})),
+ FileDispositionInformationEx,
+ )
+ switch err {
+ case nil:
+ return nil
+ case STATUS_CANNOT_DELETE, STATUS_DIRECTORY_NOT_EMPTY:
+ return err.(NTStatus).Errno()
+ }
+
+ // If the prior deletion failed, the filesystem either doesn't support
+ // POSIX semantics (for example, FAT), or hasn't implemented
+ // FILE_DISPOSITION_INFORMATION_EX.
+ //
+ // Try again.
+ err = NtSetInformationFile(
+ h,
+ &IO_STATUS_BLOCK{},
+ uintptr(unsafe.Pointer(&FILE_DISPOSITION_INFORMATION{
+ DeleteFile: true,
+ })),
+ uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION{})),
+ FileDispositionInformation,
+ )
+ if st, ok := err.(NTStatus); ok {
+ return st.Errno()
+ }
+ return err
+}
diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
index 924f4951e7..f6fbf199bf 100644
--- a/src/internal/syscall/windows/syscall_windows.go
+++ b/src/internal/syscall/windows/syscall_windows.go
@@ -523,10 +523,14 @@ func (s NTStatus) Error() string {
// If this list starts getting long, we should consider generating the full set.
const (
STATUS_FILE_IS_A_DIRECTORY NTStatus = 0xC00000BA
+ STATUS_DIRECTORY_NOT_EMPTY NTStatus = 0xC0000101
STATUS_NOT_A_DIRECTORY NTStatus = 0xC0000103
+ STATUS_CANNOT_DELETE NTStatus = 0xC0000121
STATUS_REPARSE_POINT_ENCOUNTERED NTStatus = 0xC000050B
)
// NT Native APIs
//sys NtCreateFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, allocationSize *int64, attributes uint32, share uint32, disposition uint32, options uint32, eabuffer uintptr, ealength uint32) (ntstatus error) = ntdll.NtCreateFile
+//sys NtOpenFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, options uint32) (ntstatus error) = ntdll.NtOpenFile
//sys rtlNtStatusToDosErrorNoTeb(ntstatus NTStatus) (ret syscall.Errno) = ntdll.RtlNtStatusToDosErrorNoTeb
+//sys NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer uintptr, inBufferLen uint32, class uint32) (ntstatus error) = ntdll.NtSetInformationFile
diff --git a/src/internal/syscall/windows/types_windows.go b/src/internal/syscall/windows/types_windows.go
index 514feafae4..6ae37afff8 100644
--- a/src/internal/syscall/windows/types_windows.go
+++ b/src/internal/syscall/windows/types_windows.go
@@ -196,3 +196,23 @@ const (
FILE_OPEN_NO_RECALL = 0x00400000
FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000
)
+
+// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information
+type FILE_DISPOSITION_INFORMATION struct {
+ DeleteFile bool
+}
+
+// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex
+type FILE_DISPOSITION_INFORMATION_EX struct {
+ Flags uint32
+}
+
+// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex
+const (
+ FILE_DISPOSITION_DO_NOT_DELETE = 0x00000000
+ FILE_DISPOSITION_DELETE = 0x00000001
+ FILE_DISPOSITION_POSIX_SEMANTICS = 0x00000002
+ FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK = 0x00000004
+ FILE_DISPOSITION_ON_CLOSE = 0x00000008
+ FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE = 0x00000010
+)
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
index c81bc399ff..6a6ea7bdc0 100644
--- a/src/internal/syscall/windows/zsyscall_windows.go
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -93,6 +93,8 @@ var (
procNetUserDel = modnetapi32.NewProc("NetUserDel")
procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups")
procNtCreateFile = modntdll.NewProc("NtCreateFile")
+ procNtOpenFile = modntdll.NewProc("NtOpenFile")
+ procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile")
procRtlGetVersion = modntdll.NewProc("RtlGetVersion")
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
@@ -477,6 +479,22 @@ func NtCreateFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES,
return
}
+func NtOpenFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, options uint32) (ntstatus error) {
+ r0, _, _ := syscall.Syscall6(procNtOpenFile.Addr(), 6, uintptr(unsafe.Pointer(handle)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(options))
+ if r0 != 0 {
+ ntstatus = NTStatus(r0)
+ }
+ return
+}
+
+func NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer uintptr, inBufferLen uint32, class uint32) (ntstatus error) {
+ r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(inBuffer), uintptr(inBufferLen), uintptr(class), 0)
+ if r0 != 0 {
+ ntstatus = NTStatus(r0)
+ }
+ return
+}
+
func rtlGetVersion(info *_OSVERSIONINFOW) {
syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0)
return