| 1 | //go:build windows |
| 2 | |
| 3 | package fileops |
| 4 | |
| 5 | import ( |
| 6 | "fmt" |
| 7 | "os" |
| 8 | "unsafe" |
| 9 | |
| 10 | "golang.org/x/sys/windows" |
| 11 | ) |
| 12 | |
| 13 | type windowsFileBasicInfo struct { |
| 14 | CreationTime int64 |
| 15 | LastAccessTime int64 |
| 16 | LastWriteTime int64 |
| 17 | ChangeTime int64 |
| 18 | Attributes uint32 |
| 19 | Reserved uint32 |
| 20 | } |
| 21 | |
| 22 | func diskNativeSnapshot(path string) (string, []string) { |
| 23 | name, err := windows.UTF16PtrFromString(path) |
| 24 | if err != nil { |
| 25 | return "", nil |
| 26 | } |
| 27 | h, err := windows.CreateFile(name, windows.FILE_READ_ATTRIBUTES, |
| 28 | windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, |
| 29 | nil, windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0) |
| 30 | if err != nil { |
| 31 | return "", nil |
| 32 | } |
| 33 | defer windows.CloseHandle(h) |
| 34 | return windowsSnapshot(h) |
| 35 | } |
| 36 | |
| 37 | func diskNativeHandleSnapshot(file *os.File) (string, []string) { |
| 38 | if file == nil { |
| 39 | return "", nil |
| 40 | } |
| 41 | return windowsSnapshot(windows.Handle(file.Fd())) |
| 42 | } |
| 43 | |
| 44 | func windowsSnapshot(h windows.Handle) (string, []string) { |
| 45 | var byHandle windows.ByHandleFileInformation |
| 46 | if err := windows.GetFileInformationByHandle(h, &byHandle); err != nil { |
| 47 | return "", nil |
| 48 | } |
| 49 | identity := fmt.Sprintf("volume=%d,fileindex=%08x%08x", byHandle.VolumeSerialNumber, byHandle.FileIndexHigh, byHandle.FileIndexLow) |
| 50 | meta := []string{ |
| 51 | fmt.Sprintf("win.volume=%d", byHandle.VolumeSerialNumber), |
| 52 | fmt.Sprintf("win.fileindex=%08x%08x", byHandle.FileIndexHigh, byHandle.FileIndexLow), |
| 53 | fmt.Sprintf("win.links=%d", byHandle.NumberOfLinks), |
| 54 | fmt.Sprintf("win.attributes=%d", byHandle.FileAttributes), |
| 55 | } |
| 56 | var basic windowsFileBasicInfo |
| 57 | if err := windows.GetFileInformationByHandleEx(h, windows.FileBasicInfo, (*byte)(unsafe.Pointer(&basic)), uint32(unsafe.Sizeof(basic))); err == nil { |
| 58 | meta = append(meta, |
| 59 | fmt.Sprintf("win.creation=%d", basic.CreationTime), |
| 60 | fmt.Sprintf("win.lastwrite=%d", basic.LastWriteTime), |
| 61 | fmt.Sprintf("win.change=%d", basic.ChangeTime), |
| 62 | fmt.Sprintf("win.basic_attributes=%d", basic.Attributes), |
| 63 | ) |
| 64 | } |
| 65 | return identity, meta |
| 66 | } |
| 67 |