github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/archive/archive_windows.go (about) 1 //go:build windows 2 3 package archive 4 5 import ( 6 "os" 7 "syscall" 8 9 "golang.org/x/sys/windows" 10 ) 11 12 // hasHardlinks returns true if the given file has hard-links associated with it 13 func hasHardlinks(fi os.FileInfo, path string) (bool, error) { 14 var numberOfLinks uint32 15 switch v := fi.Sys().(type) { 16 case *syscall.ByHandleFileInformation: 17 numberOfLinks = v.NumberOfLinks 18 default: 19 // We need an instance of a ByHandleFileInformation to read NumberOfLinks 20 info, err := open(path) 21 if err != nil { 22 return false, err 23 } 24 numberOfLinks = info.NumberOfLinks 25 } 26 return numberOfLinks > 1, nil 27 } 28 29 // getInodeFromStat returns an equivalent representation of unix inode on windows based on FileIndexHigh and FileIndexLow values 30 func getInodeFromStat(stat interface{}, path string) (inode uint64, err error) { 31 s, ok := stat.(*syscall.ByHandleFileInformation) 32 if ok { 33 inode = (uint64(s.FileIndexHigh) << 32) | uint64(s.FileIndexLow) 34 } else { 35 s, err = open(path) 36 if err == nil { 37 inode = (uint64(s.FileIndexHigh) << 32) | uint64(s.FileIndexLow) 38 } 39 } 40 return 41 } 42 43 // open returns a ByHandleFileInformation object representation of the given file 44 func open(path string) (*syscall.ByHandleFileInformation, error) { 45 fPath, err := syscall.UTF16PtrFromString(path) 46 if err != nil { 47 return nil, err 48 } 49 50 handle, err := syscall.CreateFile( 51 fPath, 52 windows.FILE_READ_ATTRIBUTES, 53 syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, 54 nil, 55 syscall.OPEN_EXISTING, 56 syscall.FILE_FLAG_BACKUP_SEMANTICS, 57 0) 58 if err != nil { 59 return nil, err 60 } 61 defer syscall.CloseHandle(handle) 62 63 var info syscall.ByHandleFileInformation 64 if err = syscall.GetFileInformationByHandle(handle, &info); err != nil { 65 return nil, err 66 } 67 return &info, nil 68 }