// Copy copies/extracts a source FileInfo to a destination path inside a container // specified by a container object. // TODO: make sure callers don't unnecessarily convert destPath with filepath.FromSlash (Copy does it already). // Copy should take in abstract paths (with slashes) and the implementation should convert it to OS-specific paths. func (d Docker) Copy(c *daemon.Container, destPath string, src builder.FileInfo, decompress bool) error { srcPath := src.Path() destExists := true rootUID, rootGID := d.Daemon.GetRemappedUIDGID() // Work in daemon-local OS specific file paths destPath = filepath.FromSlash(destPath) /* dest, err := c.GetResourcePath(destPath) if err != nil { return err } */ // Preserve the trailing slash // TODO: why are we appending another path separator if there was already one? if strings.HasSuffix(destPath, string(os.PathSeparator)) || destPath == "." { destPath += string(os.PathSeparator) } destStat, err := os.Stat(destPath) if err != nil { if !os.IsNotExist(err) { logrus.Errorf("Error performing os.Stat on %s. %s", destPath, err) return err } destExists = false } if src.IsDir() { // copy as directory if err := d.Archiver.CopyWithTar(srcPath, destPath); err != nil { return err } return fixPermissions(srcPath, destPath, rootUID, rootGID, destExists) } if decompress { // Only try to untar if it is a file and that we've been told to decompress (when ADD-ing a remote file) // First try to unpack the source as an archive // to support the untar feature we need to clean up the path a little bit // because tar is very forgiving. First we need to strip off the archive's // filename from the path but this is only added if it does not end in slash tarDest := destPath if strings.HasSuffix(tarDest, string(os.PathSeparator)) { tarDest = filepath.Dir(destPath) } // try to successfully untar the orig if err := d.Archiver.UntarPath(srcPath, tarDest); err == nil { return nil } else if err != io.EOF { logrus.Debugf("Couldn't untar to %s: %v", tarDest, err) } } // only needed for fixPermissions, but might as well put it before CopyFileWithTar if destExists && destStat.IsDir() { destPath = filepath.Join(destPath, src.Name()) } if err := idtools.MkdirAllNewAs(filepath.Dir(destPath), 0755, rootUID, rootGID); err != nil { return err } if err := d.Archiver.CopyFileWithTar(srcPath, destPath); err != nil { return err } return fixPermissions(srcPath, destPath, rootUID, rootGID, destExists) }