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  }