diff --git a/copier.go b/copier.go index 14a9b7f..17c03fb 100644 --- a/copier.go +++ b/copier.go @@ -13,13 +13,11 @@ package copyfile import ( - "fmt" "io" "io/ioutil" "os" "path" "runtime" - "syscall" ) // A Copier performs copying of files with some policies set. @@ -100,22 +98,3 @@ func (c *Copier) Link(src, dest string) error { } return c.Copy(src, dest) } - -// IsSameFile returns true if the two given paths refer to the same file. -func (c *Copier) IsSameFile(file1, file2 string) bool { - i1, err1 := c.getInode(file1) - i2, err2 := c.getInode(file2) - return err1 == nil && err2 == nil && i1 == i2 -} - -func (c *Copier) getInode(filename string) (uint64, error) { - fi, err := os.Lstat(filename) - if err != nil { - return 0, err - } - s, ok := fi.Sys().(*syscall.Stat_t) - if !ok { - return 0, fmt.Errorf("Not a syscall.Stat_t") - } - return uint64(s.Ino), nil -} diff --git a/copier_unix.go b/copier_unix.go new file mode 100644 index 0000000..6827da8 --- /dev/null +++ b/copier_unix.go @@ -0,0 +1,28 @@ +// +build !windows + +package copyfile + +import ( + "fmt" + "os" + "syscall" +) + +// IsSameFile returns true if the two given paths refer to the same file. +func (c *Copier) IsSameFile(file1, file2 string) bool { + i1, err1 := c.getInode(file1) + i2, err2 := c.getInode(file2) + return err1 == nil && err2 == nil && i1 == i2 +} + +func (c *Copier) getInode(filename string) (uint64, error) { + fi, err := os.Lstat(filename) + if err != nil { + return 0, err + } + s, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return 0, fmt.Errorf("Not a syscall.Stat_t") + } + return uint64(s.Ino), nil +} diff --git a/copier_windows.go b/copier_windows.go new file mode 100644 index 0000000..373a8c3 --- /dev/null +++ b/copier_windows.go @@ -0,0 +1,20 @@ +package copyfile + +import ( + "os" +) + +// IsSameFile returns true if the two given paths refer to the same file. +func (c *Copier) IsSameFile(file1, file2 string) bool { + fi1, err := os.Stat(file1) + if err != nil { + return false + } + + fi2, err := os.Stat(file2) + if err != nil { + return false + } + + return os.SameFile(fi1, fi2) +} diff --git a/cow_windows.go b/cow_windows.go new file mode 100644 index 0000000..68d2d20 --- /dev/null +++ b/cow_windows.go @@ -0,0 +1,36 @@ +package copyfile + +import ( + "fmt" + "os" + "syscall" + "unsafe" +) + +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + procCopyFileW = modkernel32.NewProc("CopyFileW") +) + +func (c *Copier) copySpecialised(srcFile *os.File, dest string, mode os.FileMode) error { + var bFailIfExists uint32 = 1 + + lpExistingFileName, err := syscall.UTF16PtrFromString(srcFile.Name()) + if err != nil { + return err + } + lpNewFileName, err := syscall.UTF16PtrFromString(dest) + if err != nil { + return err + } + r1, _, err := syscall.Syscall( + procCopyFileW.Addr(), + 3, + uintptr(unsafe.Pointer(lpExistingFileName)), + uintptr(unsafe.Pointer(lpNewFileName)), + uintptr(bFailIfExists)) + if r1 == 0 { + return fmt.Errorf("failed CopyFileW Win32 call from '%s' to '%s': %s", srcFile.Name(), dest, err) + } + return nil +}