Skip to content

Commit

Permalink
os: add Root
Browse files Browse the repository at this point in the history
Add os.Root, a type which represents a directory and permits performing
file operations within that directory.

For #67002

Change-Id: I863f4f1bc320a89b1125ae4237761f3e9320a901
Reviewed-on: https://go-review.googlesource.com/c/go/+/612136
Reviewed-by: Ian Lance Taylor <[email protected]>
Reviewed-by: Quim Muntal <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
  • Loading branch information
neild committed Nov 20, 2024
1 parent 558f537 commit 43d90c6
Show file tree
Hide file tree
Showing 17 changed files with 2,243 additions and 70 deletions.
9 changes: 9 additions & 0 deletions api/next/67002.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pkg os, func OpenRoot(string) (*Root, error) #67002
pkg os, method (*Root) Close() error #67002
pkg os, method (*Root) Create(string) (*File, error) #67002
pkg os, method (*Root) Mkdir(string, fs.FileMode) error #67002
pkg os, method (*Root) Name() string #67002
pkg os, method (*Root) Open(string) (*File, error) #67002
pkg os, method (*Root) OpenFile(string, int, fs.FileMode) (*File, error) #67002
pkg os, method (*Root) OpenRoot(string) (*Root, error) #67002
pkg os, type Root struct #67002
16 changes: 16 additions & 0 deletions doc/next/6-stdlib/1-os-root.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### Directory-limited filesystem access

<!-- go.dev/issue/67002 -->
The new [os.Root] type provides the ability to perform filesystem
operations within a specific directory.

The [os.OpenRoot] function opens a directory and returns an [os.Root].
Methods on [os.Root] operate within the directory and do not permit
paths that refer to locations outside the directory, including
ones that follow symbolic links out of the directory.

- [os.Root.Open] opens a file for reading.
- [os.Root.Create] creates a file.
- [os.Root.OpenFile] is the generalized open call.
- [os.Root.Mkdir] creates a directory.

1 change: 1 addition & 0 deletions doc/next/6-stdlib/99-minor/os/67002.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- os.Root -->
4 changes: 2 additions & 2 deletions src/internal/syscall/windows/at_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func Openat(dirfd syscall.Handle, name string, flag int, perm uint32) (_ syscall
}
if flag&syscall.O_APPEND != 0 {
access |= FILE_APPEND_DATA
// Remove GENERIC_WRITE access unless O_TRUNC is set,
// Remove FILE_WRITE_DATA access unless O_TRUNC is set,
// in which case we need it to truncate the file.
if flag&syscall.O_TRUNC == 0 {
access &^= FILE_WRITE_DATA
Expand Down Expand Up @@ -99,7 +99,7 @@ func Openat(dirfd syscall.Handle, name string, flag int, perm uint32) (_ syscall
fileAttrs,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
disposition,
FILE_SYNCHRONOUS_IO_NONALERT|options,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT|options,
0,
0,
)
Expand Down
2 changes: 2 additions & 0 deletions src/os/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
return f, nil
}

var errPathEscapes = errors.New("path escapes from parent")

// openDir opens a file which is assumed to be a directory. As such, it skips
// the syscalls that make the file descriptor non-blocking as these take time
// and will fail on file descriptors for directories.
Expand Down
5 changes: 4 additions & 1 deletion src/os/file_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,10 +415,13 @@ func readReparseLink(path string) (string, error) {
return "", err
}
defer syscall.CloseHandle(h)
return readReparseLinkHandle(h)
}

func readReparseLinkHandle(h syscall.Handle) (string, error) {
rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
var bytesReturned uint32
err = syscall.DeviceIoControl(h, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
err := syscall.DeviceIoControl(h, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
if err != nil {
return "", err
}
Expand Down
Loading

0 comments on commit 43d90c6

Please sign in to comment.