Skip to content

Commit

Permalink
Support SymlinkNoFollow on Windows
Browse files Browse the repository at this point in the history
Fixes #41
  • Loading branch information
Tim van der Molen committed Feb 8, 2024
1 parent 710511a commit 1466b65
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 17 deletions.
17 changes: 0 additions & 17 deletions at/at_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,6 @@ func (d Dir) stat(path string, flag int) (fs.FileInfo, error) {
return os.Stat(d.join(path))
}

func (d Dir) utimes(path string, atime, mtime time.Time, flag int) error {
if flag == SymlinkNoFollow {
return &Error{Op: "utimes", Err: ErrUnsupportedFlag}
}
return chtimes(d.join(path), atime, mtime)
}

func futimes(f *os.File, atime, mtime time.Time) error {
return os.Chtimes(f.Name(), atime, mtime)
}
Expand All @@ -123,13 +116,3 @@ func (d Dir) join(path string) string {
}
return filepath.Join(d.path, path)
}

func chtimes(path string, atime, mtime time.Time) error {
if mtime == UtimeOmit {
return &Error{Op: "chtimes", Err: ErrMtimeOmitted}
}
if atime == UtimeOmit {
atime = time.Now()
}
return os.Chtimes(path, atime, mtime)
}
35 changes: 35 additions & 0 deletions at/utimes_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2023 Tim van der Molen <[email protected]>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

//go:build !(unix || aix || android || darwin || dragonfly || freebsd || hurd || illumos || ios || linux || netbsd || openbsd || solaris || windows)

package at

import (
"os"
"time"
)

func (d Dir) utimes(path string, atime, mtime time.Time, flag int) error {
if flag == SymlinkNoFollow {
return &Error{Op: "utimes", Err: ErrUnsupportedFlag}
}
if mtime == UtimeOmit {
return &Error{Op: "utimes", Err: ErrMtimeOmitted}
}
if atime == UtimeOmit {
atime = time.Now()
}
return os.Chtimes(d.join(path), atime, mtime)
}
59 changes: 59 additions & 0 deletions at/utimes_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) 2024 Tim van der Molen <[email protected]>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

package at

import (
"os"
"time"

"golang.org/x/sys/windows"
)

func (d Dir) utimes(path string, atime, mtime time.Time, flag int) error {
upath, err := windows.UTF16PtrFromString(path)
if err != nil {
return &os.PathError{Op: "utimes", Path: path, Err: err}
}

var fileFlags uint32 = windows.FILE_FLAG_BACKUP_SEMANTICS
if flag == SymlinkNoFollow {
fileFlags |= windows.FILE_FLAG_OPEN_REPARSE_POINT
}

h, err := windows.CreateFile(upath, windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, fileFlags, 0)
if err != nil {
return &os.PathError{Op: "utimes", Path: path, Err: err}
}

aft := timeToFiletime(atime)
mft := timeToFiletime(mtime)
if err := windows.SetFileTime(h, nil, &aft, &mft); err != nil {
windows.CloseHandle(h)
return &os.PathError{Op: "utimes", Path: path, Err: err}
}

if err := windows.CloseHandle(h); err != nil {
return &os.PathError{Op: "utimes", Path: path, Err: err}
}

return nil
}

func timeToFiletime(t time.Time) windows.Filetime {
if t == UtimeOmit {
return windows.Filetime{LowDateTime: 0, HighDateTime: 0}
}
return windows.NsecToFiletime(t.UnixNano())
}

0 comments on commit 1466b65

Please sign in to comment.