github.com/pritambaral/docker@v1.4.2-0.20150120174542-b2fe1b3dd952/daemon/graphdriver/overlay/copy.go (about) 1 // +build linux 2 3 package overlay 4 5 import ( 6 "fmt" 7 "io" 8 "os" 9 "path/filepath" 10 "syscall" 11 12 "github.com/docker/docker/pkg/system" 13 ) 14 15 type CopyFlags int 16 17 const ( 18 CopyHardlink CopyFlags = 1 << iota 19 ) 20 21 func copyRegular(srcPath, dstPath string, mode os.FileMode) error { 22 srcFile, err := os.Open(srcPath) 23 if err != nil { 24 return err 25 } 26 defer srcFile.Close() 27 28 dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE, mode) 29 if err != nil { 30 return err 31 } 32 defer dstFile.Close() 33 34 _, err = io.Copy(dstFile, srcFile) 35 36 return err 37 } 38 39 func copyXattr(srcPath, dstPath, attr string) error { 40 data, err := system.Lgetxattr(srcPath, attr) 41 if err != nil { 42 return err 43 } 44 if data != nil { 45 if err := system.Lsetxattr(dstPath, attr, data, 0); err != nil { 46 return err 47 } 48 } 49 return nil 50 } 51 52 func copyDir(srcDir, dstDir string, flags CopyFlags) error { 53 err := filepath.Walk(srcDir, func(srcPath string, f os.FileInfo, err error) error { 54 if err != nil { 55 return err 56 } 57 58 // Rebase path 59 relPath, err := filepath.Rel(srcDir, srcPath) 60 if err != nil { 61 return err 62 } 63 64 dstPath := filepath.Join(dstDir, relPath) 65 if err != nil { 66 return err 67 } 68 69 stat, ok := f.Sys().(*syscall.Stat_t) 70 if !ok { 71 return fmt.Errorf("Unable to get raw syscall.Stat_t data for %s", srcPath) 72 } 73 74 switch f.Mode() & os.ModeType { 75 case 0: // Regular file 76 if flags&CopyHardlink != 0 { 77 if err := os.Link(srcPath, dstPath); err != nil { 78 return err 79 } 80 } else { 81 if err := copyRegular(srcPath, dstPath, f.Mode()); err != nil { 82 return err 83 } 84 } 85 86 case os.ModeDir: 87 if err := os.Mkdir(dstPath, f.Mode()); err != nil && !os.IsExist(err) { 88 return err 89 } 90 91 case os.ModeSymlink: 92 link, err := os.Readlink(srcPath) 93 if err != nil { 94 return err 95 } 96 97 if err := os.Symlink(link, dstPath); err != nil { 98 return err 99 } 100 101 case os.ModeNamedPipe: 102 fallthrough 103 case os.ModeSocket: 104 if err := syscall.Mkfifo(dstPath, stat.Mode); err != nil { 105 return err 106 } 107 108 case os.ModeDevice: 109 if err := syscall.Mknod(dstPath, stat.Mode, int(stat.Rdev)); err != nil { 110 return err 111 } 112 113 default: 114 return fmt.Errorf("Unknown file type for %s\n", srcPath) 115 } 116 117 if err := os.Lchown(dstPath, int(stat.Uid), int(stat.Gid)); err != nil { 118 return err 119 } 120 121 if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil { 122 return err 123 } 124 125 // We need to copy this attribute if it appears in an overlay upper layer, as 126 // this function is used to copy those. It is set by overlay if a directory 127 // is removed and then re-created and should not inherit anything from the 128 // same dir in the lower dir. 129 if err := copyXattr(srcPath, dstPath, "trusted.overlay.opaque"); err != nil { 130 return err 131 } 132 133 isSymlink := f.Mode()&os.ModeSymlink != 0 134 135 // There is no LChmod, so ignore mode for symlink. Also, this 136 // must happen after chown, as that can modify the file mode 137 if !isSymlink { 138 if err := os.Chmod(dstPath, f.Mode()); err != nil { 139 return err 140 } 141 } 142 143 ts := []syscall.Timespec{stat.Atim, stat.Mtim} 144 // syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and 145 if !isSymlink { 146 if err := system.UtimesNano(dstPath, ts); err != nil { 147 return err 148 } 149 } else { 150 if err := system.LUtimesNano(dstPath, ts); err != nil { 151 return err 152 } 153 } 154 return nil 155 }) 156 return err 157 }