github.com/tetratelabs/wazero@v1.2.1/internal/sysfs/futimens_windows.go (about) 1 package sysfs 2 3 import ( 4 "syscall" 5 "time" 6 7 "github.com/tetratelabs/wazero/internal/platform" 8 ) 9 10 // Define values even if not used except as sentinels. 11 const ( 12 _UTIME_NOW = -1 13 _UTIME_OMIT = -2 14 SupportsSymlinkNoFollow = false 15 ) 16 17 func utimens(path string, times *[2]syscall.Timespec, symlinkFollow bool) error { 18 return utimensPortable(path, times, symlinkFollow) 19 } 20 21 func futimens(fd uintptr, times *[2]syscall.Timespec) error { 22 // Before Go 1.20, ERROR_INVALID_HANDLE was returned for too many reasons. 23 // Kick out so that callers can use path-based operations instead. 24 if !platform.IsGo120 { 25 return syscall.ENOSYS 26 } 27 28 // Per docs, zero isn't a valid timestamp as it cannot be differentiated 29 // from nil. In both cases, it is a marker like syscall.UTIME_OMIT. 30 // See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfiletime 31 a, w := timespecToFiletime(times) 32 33 if a == nil && w == nil { 34 return nil // both omitted, so nothing to change 35 } 36 37 // Attempt to get the stat by handle, which works for normal files 38 h := syscall.Handle(fd) 39 40 // Note: This returns ERROR_ACCESS_DENIED when the input is a directory. 41 return syscall.SetFileTime(h, nil, a, w) 42 } 43 44 func timespecToFiletime(times *[2]syscall.Timespec) (a, w *syscall.Filetime) { 45 // Handle when both inputs are current system time. 46 if times == nil || times[0].Nsec == UTIME_NOW && times[1].Nsec == UTIME_NOW { 47 now := time.Now().UnixNano() 48 ft := syscall.NsecToFiletime(now) 49 return &ft, &ft 50 } 51 52 // Now, either one of the inputs is current time, or neither. This 53 // means we don't have a risk of re-reading the clock. 54 a = timespecToFileTime(times, 0) 55 w = timespecToFileTime(times, 1) 56 return 57 } 58 59 func timespecToFileTime(times *[2]syscall.Timespec, i int) *syscall.Filetime { 60 if times[i].Nsec == UTIME_OMIT { 61 return nil 62 } 63 64 var nsec int64 65 if times[i].Nsec == UTIME_NOW { 66 nsec = time.Now().UnixNano() 67 } else { 68 nsec = syscall.TimespecToNsec(times[i]) 69 } 70 ft := syscall.NsecToFiletime(nsec) 71 return &ft 72 }