copy_unix.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // +build solaris darwin freebsd
  2. package fs
  3. import (
  4. "io"
  5. "os"
  6. "syscall"
  7. "github.com/containerd/continuity/sysx"
  8. "github.com/pkg/errors"
  9. "golang.org/x/sys/unix"
  10. )
  11. func copyFileInfo(fi os.FileInfo, name string) error {
  12. st := fi.Sys().(*syscall.Stat_t)
  13. if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
  14. if os.IsPermission(err) {
  15. // Normally if uid/gid are the same this would be a no-op, but some
  16. // filesystems may still return EPERM... for instance NFS does this.
  17. // In such a case, this is not an error.
  18. if dstStat, err2 := os.Lstat(name); err2 == nil {
  19. st2 := dstStat.Sys().(*syscall.Stat_t)
  20. if st.Uid == st2.Uid && st.Gid == st2.Gid {
  21. err = nil
  22. }
  23. }
  24. }
  25. if err != nil {
  26. return errors.Wrapf(err, "failed to chown %s", name)
  27. }
  28. }
  29. if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
  30. if err := os.Chmod(name, fi.Mode()); err != nil {
  31. return errors.Wrapf(err, "failed to chmod %s", name)
  32. }
  33. }
  34. timespec := []syscall.Timespec{StatAtime(st), StatMtime(st)}
  35. if err := syscall.UtimesNano(name, timespec); err != nil {
  36. return errors.Wrapf(err, "failed to utime %s", name)
  37. }
  38. return nil
  39. }
  40. func copyFileContent(dst, src *os.File) error {
  41. buf := bufferPool.Get().(*[]byte)
  42. _, err := io.CopyBuffer(dst, src, *buf)
  43. bufferPool.Put(buf)
  44. return err
  45. }
  46. func copyXAttrs(dst, src string) error {
  47. xattrKeys, err := sysx.LListxattr(src)
  48. if err != nil {
  49. return errors.Wrapf(err, "failed to list xattrs on %s", src)
  50. }
  51. for _, xattr := range xattrKeys {
  52. data, err := sysx.LGetxattr(src, xattr)
  53. if err != nil {
  54. return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
  55. }
  56. if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
  57. return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
  58. }
  59. }
  60. return nil
  61. }
  62. func copyDevice(dst string, fi os.FileInfo) error {
  63. st, ok := fi.Sys().(*syscall.Stat_t)
  64. if !ok {
  65. return errors.New("unsupported stat type")
  66. }
  67. return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
  68. }