github.com/ojongerius/docker@v1.11.2/daemon/graphdriver/overlay/copy.go (about)

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