}
+func TestOpenFileCreateExclDanglingSymlink(t *testing.T) {
+ testMaybeRooted(t, func(t *testing.T, r *Root) {
+ const link = "link"
+ if err := Symlink("does_not_exist", link); err != nil {
+ t.Fatal(err)
+ }
+ var f *File
+ var err error
+ if r == nil {
+ f, err = OpenFile(link, O_WRONLY|O_CREATE|O_EXCL, 0o444)
+ } else {
+ f, err = r.OpenFile(link, O_WRONLY|O_CREATE|O_EXCL, 0o444)
+ }
+ if err == nil {
+ f.Close()
+ }
+ if !errors.Is(err, ErrExist) {
+ t.Errorf("OpenFile of a dangling symlink with O_CREATE|O_EXCL = %v, want ErrExist", err)
+ }
+ if _, err := Stat(link); err == nil {
+ t.Errorf("OpenFile of a dangling symlink with O_CREATE|O_EXCL created a file")
+ }
+ })
+}
+
// TestFileRDWRFlags tests the O_RDONLY, O_WRONLY, and O_RDWR flags.
func TestFileRDWRFlags(t *testing.T) {
for _, test := range []struct {
if flag&O_CLOEXEC == 0 {
sa = makeInheritSa()
}
- // We don't use CREATE_ALWAYS, because when opening a file with
- // FILE_ATTRIBUTE_READONLY these will replace an existing file
- // with a new, read-only one. See https://go.dev/issue/38225.
- //
- // Instead, we ftruncate the file after opening when O_TRUNC is set.
- var createmode uint32
- switch {
- case flag&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
- createmode = CREATE_NEW
- case flag&O_CREAT == O_CREAT:
- createmode = OPEN_ALWAYS
- default:
- createmode = OPEN_EXISTING
- }
var attrs uint32 = FILE_ATTRIBUTE_NORMAL
if perm&S_IWRITE == 0 {
attrs = FILE_ATTRIBUTE_READONLY
const _FILE_FLAG_WRITE_THROUGH = 0x80000000
attrs |= _FILE_FLAG_WRITE_THROUGH
}
+ // We don't use CREATE_ALWAYS, because when opening a file with
+ // FILE_ATTRIBUTE_READONLY these will replace an existing file
+ // with a new, read-only one. See https://go.dev/issue/38225.
+ //
+ // Instead, we ftruncate the file after opening when O_TRUNC is set.
+ var createmode uint32
+ switch {
+ case flag&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
+ createmode = CREATE_NEW
+ attrs |= FILE_FLAG_OPEN_REPARSE_POINT // don't follow symlinks
+ case flag&O_CREAT == O_CREAT:
+ createmode = OPEN_ALWAYS
+ default:
+ createmode = OPEN_EXISTING
+ }
h, err := createFile(namep, access, sharemode, sa, createmode, attrs, 0)
if h == InvalidHandle {
if err == ERROR_ACCESS_DENIED && (flag&O_WRONLY != 0 || flag&O_RDWR != 0) {