From 75173e48eecd6755d1c9f4921a497860c5ff2def Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Tue, 14 Nov 2023 18:18:55 -0500 Subject: [PATCH] implementing inode equivalent on windows Signed-off-by: Juan Bustamante --- pkg/archive/archive.go | 2 +- pkg/archive/archive_unix.go | 2 +- pkg/archive/archive_windows.go | 64 ++++++++++++++++++++-------------- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/pkg/archive/archive.go b/pkg/archive/archive.go index b5528a5b93..3fd0944290 100644 --- a/pkg/archive/archive.go +++ b/pkg/archive/archive.go @@ -220,7 +220,7 @@ func WriteDirToTar(tw TarWriter, srcDir, basePath string, uid, gid int, mode int header.Name = getHeaderNameFromBaseAndRelPath(basePath, relPath) if hasHardlinks(fi, file) { - inode, err := getInodeFromStat(fi.Sys()) + inode, err := getInodeFromStat(fi.Sys(), file) if err != nil { return err } diff --git a/pkg/archive/archive_unix.go b/pkg/archive/archive_unix.go index 6100308f74..719d2566e3 100644 --- a/pkg/archive/archive_unix.go +++ b/pkg/archive/archive_unix.go @@ -11,7 +11,7 @@ func hasHardlinks(fi os.FileInfo, path string) bool { return fi.Sys().(*syscall.Stat_t).Nlink > 1 } -func getInodeFromStat(stat interface{}) (inode uint64, err error) { +func getInodeFromStat(stat interface{}, path string) (inode uint64, err error) { s, ok := stat.(*syscall.Stat_t) if ok { inode = s.Ino diff --git a/pkg/archive/archive_windows.go b/pkg/archive/archive_windows.go index e9196074ea..68ee1c286a 100644 --- a/pkg/archive/archive_windows.go +++ b/pkg/archive/archive_windows.go @@ -14,40 +14,50 @@ func hasHardlinks(fi os.FileInfo, path string) bool { case *syscall.ByHandleFileInformation: numberOfLinks = v.NumberOfLinks default: - // We need to open the file and create an instance of a ByHandleFileInformation - fPath, err := syscall.UTF16PtrFromString(path) - if err != nil { - return false - } - - handle, err := syscall.CreateFile( - fPath, - windows.FILE_READ_ATTRIBUTES, - syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, - nil, - syscall.OPEN_EXISTING, - syscall.FILE_FLAG_BACKUP_SEMANTICS, - 0) - if err != nil { - return false + if info, err := open(path); err == nil { + numberOfLinks = info.NumberOfLinks } - defer syscall.CloseHandle(handle) - - // Get the number of links - var info syscall.ByHandleFileInformation - err = syscall.GetFileInformationByHandle(handle, &info) - if err != nil { - return false - } - numberOfLinks = info.NumberOfLinks } return numberOfLinks > 1 } -func getInodeFromStat(stat interface{}) (inode uint64, err error) { +func getInodeFromStat(stat interface{}, path string) (inode uint64, err error) { s, ok := stat.(*syscall.ByHandleFileInformation) if ok { - inode = uint64(s.VolumeSerialNumber) + inode = (uint64(s.FileIndexHigh) << 32) | uint64(s.FileIndexLow) + } else { + s, err = open(path) + if err != nil { + inode = (uint64(s.FileIndexHigh) << 32) | uint64(s.FileIndexLow) + } } return } + +func open(path string) (*syscall.ByHandleFileInformation, error) { + // We need to open the file and create an instance of a ByHandleFileInformation + fPath, err := syscall.UTF16PtrFromString(path) + if err != nil { + return nil, err + } + + handle, err := syscall.CreateFile( + fPath, + windows.FILE_READ_ATTRIBUTES, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + nil, + syscall.OPEN_EXISTING, + syscall.FILE_FLAG_BACKUP_SEMANTICS, + 0) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(handle) + + var info syscall.ByHandleFileInformation + err = syscall.GetFileInformationByHandle(handle, &info) + if err != nil { + return nil, err + } + return &info, nil +}