// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build unix
+//go:build unix || wasip1
package unix
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build unix && !dragonfly && !freebsd && !netbsd
+//go:build (unix && !dragonfly && !freebsd && !netbsd) || wasip1
package unix
return nil
}
-func Deleteat(dirfd syscall.Handle, name string) error {
+func Deleteat(dirfd syscall.Handle, name string, options uint32) error {
objAttrs := &OBJECT_ATTRIBUTES{}
if err := objAttrs.init(dirfd, name); err != nil {
return err
objAttrs,
&IO_STATUS_BLOCK{},
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
- FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT|options,
)
if err != nil {
return ntCreateFileError(err, 0)
return c == '\\' || c == '/'
}
+// splitPath returns the base name and parent directory.
+func splitPath(path string) (string, string) {
+ dirname, basename := filepathlite.Split(path)
+ volnamelen := filepathlite.VolumeNameLen(dirname)
+ for len(dirname) > volnamelen && IsPathSeparator(dirname[len(dirname)-1]) {
+ dirname = dirname[:len(dirname)-1]
+ }
+ return dirname, basename
+}
+
func dirname(path string) string {
vol := filepathlite.VolumeName(path)
i := len(path) - 1
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build unix
+//go:build unix || wasip1 || windows
package os
import (
- "internal/syscall/unix"
"io"
"syscall"
)
}
func removeAllFrom(parent *File, base string) error {
- parentFd := int(parent.Fd())
+ parentFd := sysfdType(parent.Fd())
+
// Simple case: if Unlink (aka remove) works, we're done.
- err := ignoringEINTR(func() error {
- return unix.Unlinkat(parentFd, base, 0)
- })
+ err := removefileat(parentFd, base)
if err == nil || IsNotExist(err) {
return nil
}
const reqSize = 1024
var respSize int
- // Open the directory to recurse into
+ // Open the directory to recurse into.
file, err := openDirAt(parentFd, base)
if err != nil {
if IsNotExist(err) {
return nil
}
- if err == syscall.ENOTDIR || err == unix.NoFollowErrno {
+ if err == syscall.ENOTDIR || isErrNoFollow(err) {
// Not a directory; return the error from the unix.Unlinkat.
return &PathError{Op: "unlinkat", Path: base, Err: uErr}
}
}
// Remove the directory itself.
- unlinkError := ignoringEINTR(func() error {
- return unix.Unlinkat(parentFd, base, unix.AT_REMOVEDIR)
- })
+ unlinkError := removedirat(parentFd, base)
if unlinkError == nil || IsNotExist(unlinkError) {
return nil
}
// This acts like openFileNolog rather than OpenFile because
// we are going to (try to) remove the file.
// The contents of this file are not relevant for test caching.
-func openDirAt(dirfd int, name string) (*File, error) {
- r, err := ignoringEINTR2(func() (int, error) {
- return unix.Openat(dirfd, name, O_RDONLY|syscall.O_CLOEXEC|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
- })
+func openDirAt(dirfd sysfdType, name string) (*File, error) {
+ fd, err := rootOpenDir(dirfd, name)
if err != nil {
return nil, err
}
-
- if !supportsCloseOnExec {
- syscall.CloseOnExec(r)
- }
-
- // We use kindNoPoll because we know that this is a directory.
- return newFile(r, name, kindNoPoll, false), nil
+ return newDirFile(fd, name)
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build !unix
+//go:build (js && wasm) || plan9
package os
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix || wasip1
+
+package os
+
+import (
+ "internal/syscall/unix"
+)
+
+func isErrNoFollow(err error) bool {
+ return err == unix.NoFollowErrno
+}
+
+func newDirFile(fd int, name string) (*File, error) {
+ // We use kindNoPoll because we know that this is a directory.
+ return newFile(fd, name, kindNoPoll, false), nil
+}
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build windows
+
+package os
+
+import "syscall"
+
+func isErrNoFollow(err error) bool {
+ return err == syscall.ELOOP
+}
+
+func newDirFile(fd syscall.Handle, name string) (*File, error) {
+ return newFile(fd, name, "file"), nil
+}
return e
}
+func removefileat(fd int, name string) error {
+ return ignoringEINTR(func() error {
+ return unix.Unlinkat(fd, name, 0)
+ })
+}
+
+func removedirat(fd int, name string) error {
+ return ignoringEINTR(func() error {
+ return unix.Unlinkat(fd, name, unix.AT_REMOVEDIR)
+ })
+}
+
func renameat(oldfd int, oldname string, newfd int, newname string) error {
return unix.Renameat(oldfd, oldname, newfd, newname)
}
}
func removeat(dirfd syscall.Handle, name string) error {
- return windows.Deleteat(dirfd, name)
+ return windows.Deleteat(dirfd, name, 0)
+}
+
+func removefileat(dirfd syscall.Handle, name string) error {
+ return windows.Deleteat(dirfd, name, windows.FILE_NON_DIRECTORY_FILE)
+}
+
+func removedirat(dirfd syscall.Handle, name string) error {
+ return windows.Deleteat(dirfd, name, windows.FILE_DIRECTORY_FILE)
}
func chtimesat(dirfd syscall.Handle, name string, atime time.Time, mtime time.Time) error {