Esempio n. 1
0
func (t *TarArchiveProvider) ExtractReader(dst string, src io.Reader) error {
	tr := tar.NewReader(src)

	for {
		var h *tar.Header
		h, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		fp := filepath.Join(dst, h.Name)
		if h.FileInfo().IsDir() {
			os.MkdirAll(fp, 0755)
			continue
		}
		os.MkdirAll(filepath.Dir(fp), 0755)

		f, err := os.Create(fp)
		if err != nil {
			return err
		}
		_, err = io.Copy(f, tr)
		f.Close()
		if err != nil {
			return err
		}
		os.Chmod(fp, os.FileMode(h.Mode))
	}

	return nil
}
Esempio n. 2
0
// Process impl
func (p *ArchiveExtract) Process(hdr *tar.Header, r io.Reader) (*tar.Header, io.Reader, error) {
	// make sure we have our tempdir
	if p.workingDir == "" {
		t, err := ioutil.TempDir(p.tempDir, "tar-")
		if err != nil {
			return hdr, r, err
		}
		p.workingDir = t
	}

	// If a directory make it and continue
	fpath := filepath.Join(p.workingDir, hdr.Name)
	if hdr.FileInfo().IsDir() {
		err := os.MkdirAll(fpath, 0755)
		return hdr, r, err
	}

	// Extract the file!
	file, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE, hdr.FileInfo().Mode())
	if err != nil {
		return hdr, r, err
	}
	defer file.Close()

	_, err = io.Copy(file, r)
	if err != nil {
		return hdr, r, err
	}

	return hdr, r, nil
}
Esempio n. 3
0
File: tar.go Progetto: kcbabo/origin
func extractFile(dir string, header *tar.Header, tarReader io.Reader) error {
	path := filepath.Join(dir, header.Name)
	glog.V(3).Infof("Creating %s", path)

	file, err := os.Create(path)
	// The file times need to be modified after it's been closed thus this function
	// is deferred after the file close (LIFO order for defer)
	defer os.Chtimes(path, time.Now(), header.FileInfo().ModTime())
	defer file.Close()
	if err != nil {
		return err
	}
	glog.V(3).Infof("Extracting/writing %s", path)
	written, err := io.Copy(file, tarReader)
	if err != nil {
		return err
	}
	if written != header.Size {
		return fmt.Errorf("Wrote %d bytes, expected to write %d", written, header.Size)
	}
	if runtime.GOOS != "windows" { // Skip chmod if on windows OS
		return file.Chmod(header.FileInfo().Mode())
	}
	return nil
}
Esempio n. 4
0
func extractTarArchiveFile(header *tar.Header, dest string, input io.Reader) error {
	filePath := filepath.Join(dest, header.Name)
	fileInfo := header.FileInfo()

	if fileInfo.IsDir() {
		err := os.MkdirAll(filePath, fileInfo.Mode())
		if err != nil {
			return err
		}
	} else {
		err := os.MkdirAll(filepath.Dir(filePath), 0755)
		if err != nil {
			return err
		}

		if fileInfo.Mode()&os.ModeSymlink != 0 {
			return os.Symlink(header.Linkname, filePath)
		}

		fileCopy, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileInfo.Mode())
		if err != nil {
			return err
		}
		defer fileCopy.Close()

		_, err = io.Copy(fileCopy, input)
		if err != nil {
			return err
		}
	}

	return nil
}
Esempio n. 5
0
func extractFile(archive *tar.Reader, hdr *tar.Header, path string) error {
	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, hdr.FileInfo().Mode())
	if err != nil {
		return err
	}
	defer file.Close()
	_, err = io.Copy(file, archive)
	return err
}
Esempio n. 6
0
// Process impl
func (p *ArchiveCheckEmpty) Process(hdr *tar.Header, r io.Reader) (*tar.Header, io.Reader, error) {
	if p.hasFiles {
		return hdr, r, nil
	}
	if !hdr.FileInfo().IsDir() {
		p.hasFiles = true
	}
	return hdr, r, nil
}
func (m *SymlinkWebotsManager) extractFile(v WebotsVersion, h *tar.Header, r io.Reader) error {

	dest := strings.TrimPrefix(h.Name, "webots/")
	dest = path.Join(m.workpath, v.String(), dest)
	if dest == path.Join(m.workpath, v.String()) {
		return nil
	}

	switch h.Typeflag {
	case tar.TypeReg, tar.TypeRegA:
		destDir := path.Dir(dest)
		err := os.MkdirAll(destDir, 0775)
		if err != nil {
			return err
		}
		f, err := os.Create(dest)
		if err != nil {
			return err
		}
		_, err = io.Copy(f, r)
		if err != nil {
			return err
		}
	case tar.TypeDir:
		err := os.MkdirAll(dest, 0775)
		if err != nil {
			return err
		}
	case tar.TypeSymlink:
		destDir := path.Dir(dest)
		err := os.MkdirAll(destDir, 0775)
		if err != nil {
			return err
		}
		err = os.Symlink(h.Linkname, dest)
		if err != nil {
			return err
		}
		return nil
	default:
		return fmt.Errorf("Internal error, cannot handle file %s", h.Name)
	}

	err := os.Chtimes(dest, time.Now(), h.FileInfo().ModTime())
	if err != nil {
		return err
	}

	err = os.Chmod(dest, h.FileInfo().Mode())
	if err != nil {
		return err
	}

	return nil
}
Esempio n. 8
0
func untar(tr *tar.Reader, header *tar.Header, dir string) error {
	switch header.Typeflag {
	case tar.TypeDir:
		return os.MkdirAll(filepath.Join(dir, header.Name), 0700)
	case tar.TypeReg, tar.TypeRegA:
		return writeFile(filepath.Join(dir, header.Name), tr, header.FileInfo().Mode())
	case tar.TypeSymlink:
		return writeSymlink(filepath.Join(dir, header.Name), header.Linkname)
	default:
		return fmt.Errorf("%s has unknown type %v", header.Name, header.Typeflag)
	}
}
Esempio n. 9
0
func extractTarArchiveFile(header *tar.Header, dest string, input io.Reader) error {
	home := os.Getenv("HOME")

	// check if dir has a leading hash
	maybeHash := filepath.Dir(header.Name)
	_, err := hex.DecodeString(maybeHash)
	isHash := err == nil

	filePath := filepath.Join(dest, header.Name)
	if isHash {
		filePath = filepath.Join(home, ".dpm", "workspace", header.Name)
	}

	fileInfo := header.FileInfo()

	if fileInfo.IsDir() {
		err := os.MkdirAll(filePath, fileInfo.Mode())
		if err != nil {
			return err
		}
	} else {
		// already exist
		if isHash {
			if _, err := os.Stat(filePath); err == nil {
				return nil
			}
		}

		err := os.MkdirAll(filepath.Dir(filePath), 0755)
		if err != nil {
			return err
		}

		if fileInfo.Mode()&os.ModeSymlink != 0 {
			return os.Symlink(header.Linkname, filePath)
		}

		fileCopy, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileInfo.Mode())
		if err != nil {
			return err
		}
		defer fileCopy.Close()

		_, err = io.Copy(fileCopy, input)
		if err != nil {
			return err
		}
	}

	return nil
}
func (d *dirTarReceiver) OnEntry(tarHeader *tar.Header, tarFileReader io.Reader) error {
	relativePath := tarHeader.Name

	if tarHeader.FileInfo().IsDir() {
		fullDestPath := filepath.Join(d.dir, relativePath)
		defer os.Chtimes(fullDestPath, tarHeader.AccessTime, tarHeader.ModTime)

		return os.MkdirAll(fullDestPath, os.FileMode(tarHeader.Mode))
	} else {
		fullDestPath := filepath.Join(d.dir, relativePath)
		if val, ok := tarHeader.Xattrs["SINGLE_FILE_ONLY"]; ok && val == "1" {
			fullDestPath = d.dir
		}

		parentDir := filepath.Dir(fullDestPath)
		err := os.MkdirAll(parentDir, os.FileMode(tarHeader.Mode))
		if err != nil {
			return fmt.Errorf("Unable to MkDirAll '%s', error: %s", parentDir, err.Error())
		}

		file, err := os.OpenFile(fullDestPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(tarHeader.Mode))
		if err != nil {
			return fmt.Errorf("Unable to open file '%s', error: %s", fullDestPath, err.Error())
		}

		defer func() {
			file.Close()
			os.Chtimes(fullDestPath, tarHeader.AccessTime, tarHeader.ModTime)
		}()

		_, err = io_throttler.CopyThrottled(io_throttler.DefaultIOThrottlingBandwidth, file, tarFileReader)
		if err != nil {
			return fmt.Errorf("Unable to copy stream to file '%s', error: %s", fullDestPath, err.Error())
		}

		return nil
	}
}
Esempio n. 11
0
func openTar(za *ZipAssets, tr *tar.Reader) (err error) {
	var (
		hdr *tar.Header
		fc  filecontent
	)

	for {
		if hdr, err = tr.Next(); err == io.EOF {
			break
		}
		if err != nil {
			return
		}
		if fc.content, err = ioutil.ReadAll(tr); err != nil {
			return
		}
		fc.name = hdr.Name
		fc.lastModified = hdr.ModTime
		fc.isDir = hdr.FileInfo().IsDir()
		za.files[hdr.Name] = &fc
	}

	return
}
Esempio n. 12
0
// WriteHeader changes the mode of files and directories inline as a tarfile is
// being written
func (a ChmodAdapter) WriteHeader(hdr *tar.Header) error {
	if hdr.FileInfo().Mode()&os.ModeSymlink == 0 {
		newMode := hdr.Mode &^ 0777
		if hdr.FileInfo().IsDir() {
			newMode |= a.NewDirMode
		} else if hdr.FileInfo().Mode()&0010 != 0 { // S_IXUSR
			newMode |= a.NewExecFileMode
		} else {
			newMode |= a.NewFileMode
		}
		hdr.Mode = newMode
	}
	return a.Writer.WriteHeader(hdr)
}
Esempio n. 13
0
// extractFile extracts zip.File to file system.
func extractFile(f *tar.Header, tr *tar.Reader, destPath string) error {
	filePath := path.Join(destPath, f.Name)
	os.MkdirAll(path.Dir(filePath), os.ModePerm)

	fw, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer fw.Close()

	if _, err = io.Copy(fw, tr); err != nil {
		return err
	}

	// Skip symbolic links.
	if f.FileInfo().Mode()&os.ModeSymlink != 0 {
		return nil
	}
	// Set back file information.
	if err = os.Chtimes(filePath, f.FileInfo().ModTime(), f.FileInfo().ModTime()); err != nil {
		return err
	}
	return os.Chmod(filePath, f.FileInfo().Mode())
}
Esempio n. 14
0
// extractFile extracts the file described by hdr from the given tarball into
// the target directory.
// If overwrite is true, existing files will be overwritten.
func extractFile(tr *tar.Reader, target string, hdr *tar.Header, overwrite bool, editor FilePermissionsEditor) error {
	p := filepath.Join(target, hdr.Name)
	fi := hdr.FileInfo()
	typ := hdr.Typeflag
	if overwrite {
		info, err := os.Lstat(p)
		switch {
		case os.IsNotExist(err):
		case err == nil:
			// If the old and new paths are both dirs do nothing or
			// RemoveAll will remove all dir's contents
			if !info.IsDir() || typ != tar.TypeDir {
				err := os.RemoveAll(p)
				if err != nil {
					return err
				}
			}
		default:
			return err
		}
	}

	// Create parent dir if it doesn't exist
	if err := os.MkdirAll(filepath.Dir(p), DEFAULT_DIR_MODE); err != nil {
		return err
	}
	switch {
	case typ == tar.TypeReg || typ == tar.TypeRegA:
		f, err := os.OpenFile(p, os.O_CREATE|os.O_RDWR, fi.Mode())
		if err != nil {
			return err
		}
		_, err = io.Copy(f, tr)
		if err != nil {
			f.Close()
			return err
		}
		f.Close()
	case typ == tar.TypeDir:
		if err := os.MkdirAll(p, fi.Mode()); err != nil {
			return err
		}
		dir, err := os.Open(p)
		if err != nil {
			return err
		}
		if err := dir.Chmod(fi.Mode()); err != nil {
			dir.Close()
			return err
		}
		dir.Close()
	case typ == tar.TypeLink:
		dest := filepath.Join(target, hdr.Linkname)
		if err := os.Link(dest, p); err != nil {
			return err
		}
	case typ == tar.TypeSymlink:
		if err := os.Symlink(hdr.Linkname, p); err != nil {
			return err
		}
	case typ == tar.TypeChar:
		dev := device.Makedev(uint(hdr.Devmajor), uint(hdr.Devminor))
		mode := uint32(fi.Mode()) | syscall.S_IFCHR
		if err := syscall.Mknod(p, mode, int(dev)); err != nil {
			return err
		}
	case typ == tar.TypeBlock:
		dev := device.Makedev(uint(hdr.Devmajor), uint(hdr.Devminor))
		mode := uint32(fi.Mode()) | syscall.S_IFBLK
		if err := syscall.Mknod(p, mode, int(dev)); err != nil {
			return err
		}
	case typ == tar.TypeFifo:
		if err := syscall.Mkfifo(p, uint32(fi.Mode())); err != nil {
			return err
		}
	// TODO(jonboulle): implement other modes
	default:
		return fmt.Errorf("unsupported type: %v", typ)
	}

	if editor != nil {
		if err := editor(p, hdr.Uid, hdr.Gid, hdr.Typeflag, fi); err != nil {
			return err
		}
	}

	// Restore entry atime and mtime.
	// Use special function LUtimesNano not available on go's syscall package because we
	// have to restore symlink's times and not the referenced file times.
	ts := HdrToTimespec(hdr)
	if hdr.Typeflag != tar.TypeSymlink {
		if err := syscall.UtimesNano(p, ts); err != nil {
			return err
		}
	} else {
		if err := fileutil.LUtimesNano(p, ts); err != nil && err != ErrNotSupportedPlatform {
			return err
		}
	}

	return nil
}
Esempio n. 15
0
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool) error {
	// hdr.Mode is in linux format, which we can use for sycalls,
	// but for os.Foo() calls we need the mode converted to os.FileMode,
	// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
	hdrInfo := hdr.FileInfo()

	switch hdr.Typeflag {
	case tar.TypeDir:
		// Create directory unless it exists as a directory already.
		// In that case we just want to merge the two
		if fi, err := os.Lstat(path); !(err == nil && fi.IsDir()) {
			if err := os.Mkdir(path, hdrInfo.Mode()); err != nil {
				return err
			}
		}

	case tar.TypeReg, tar.TypeRegA:
		// Source is regular file
		file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode())
		if err != nil {
			return err
		}
		if _, err := io.Copy(file, reader); err != nil {
			file.Close()
			return err
		}
		file.Close()

	case tar.TypeBlock, tar.TypeChar, tar.TypeFifo:
		mode := uint32(hdr.Mode & 07777)
		switch hdr.Typeflag {
		case tar.TypeBlock:
			mode |= syscall.S_IFBLK
		case tar.TypeChar:
			mode |= syscall.S_IFCHR
		case tar.TypeFifo:
			mode |= syscall.S_IFIFO
		}

		if err := system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor))); err != nil {
			return err
		}

	case tar.TypeLink:
		targetPath := filepath.Join(extractDir, hdr.Linkname)
		// check for hardlink breakout
		if !strings.HasPrefix(targetPath, extractDir) {
			return breakoutError(fmt.Errorf("invalid hardlink %q -> %q", targetPath, hdr.Linkname))
		}
		if err := os.Link(targetPath, path); err != nil {
			return err
		}

	case tar.TypeSymlink:
		// 	path 				-> hdr.Linkname = targetPath
		// e.g. /extractDir/path/to/symlink 	-> ../2/file	= /extractDir/path/2/file
		targetPath := filepath.Join(filepath.Dir(path), hdr.Linkname)

		// the reason we don't need to check symlinks in the path (with FollowSymlinkInScope) is because
		// that symlink would first have to be created, which would be caught earlier, at this very check:
		if !strings.HasPrefix(targetPath, extractDir) {
			return breakoutError(fmt.Errorf("invalid symlink %q -> %q", path, hdr.Linkname))
		}
		if err := os.Symlink(hdr.Linkname, path); err != nil {
			return err
		}

	case tar.TypeXGlobalHeader:
		logrus.Debugf("PAX Global Extended Headers found and ignored")
		return nil

	default:
		return fmt.Errorf("Unhandled tar header type %d\n", hdr.Typeflag)
	}

	if err := os.Lchown(path, hdr.Uid, hdr.Gid); err != nil && Lchown {
		return err
	}

	for key, value := range hdr.Xattrs {
		if err := system.Lsetxattr(path, key, []byte(value), 0); err != nil {
			return err
		}
	}

	// There is no LChmod, so ignore mode for symlink. Also, this
	// must happen after chown, as that can modify the file mode
	if hdr.Typeflag == tar.TypeLink {
		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
			if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
				return err
			}
		}
	} else if hdr.Typeflag != tar.TypeSymlink {
		if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
			return err
		}
	}

	ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
	// syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
	if hdr.Typeflag == tar.TypeLink {
		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
			if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
				return err
			}
		}
	} else if hdr.Typeflag != tar.TypeSymlink {
		if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
			return err
		}
	} else {
		if err := system.LUtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
			return err
		}
	}
	return nil
}
Esempio n. 16
0
func unpackFile(
	path string, targetDir string, header *tar.Header,
	reader *bufio.Reader) error {
	info := header.FileInfo()

	switch header.Typeflag {
	case tar.TypeDir:
		// Create dir if it does not exist. Do nothing if it already exists
		// (we want to merge).
		existingInfo, err := os.Lstat(path)
		if err != nil || !existingInfo.IsDir() {
			err = os.Mkdir(path, info.Mode())
			if err != nil {
				return err
			}
		}

	case tar.TypeReg, tar.TypeRegA: // Regular file.
		file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, info.Mode())
		if err != nil {
			return err
		}
		_, err = io.Copy(file, reader)
		if err != nil {
			file.Close()
			return err
		}
		file.Close()

	case tar.TypeBlock, tar.TypeChar, tar.TypeFifo, tar.TypeXGlobalHeader:
		// Not supported. Skip.

	case tar.TypeLink: // Hard link.
		linkPath := filepath.Join(targetDir, header.Linkname)
		if !strings.HasPrefix(linkPath, targetDir) {
			return fmt.Errorf("Invalid hard link pointing outside target dir")
		}
		err := os.Link(linkPath, path)
		if err != nil {
			return err
		}

	case tar.TypeSymlink:
		linkPath := filepath.Join(filepath.Dir(path), header.Linkname)
		if !strings.HasPrefix(linkPath, targetDir) {
			return fmt.Errorf("Invalid sym link pointing outside target dir")
		}
		err := os.Symlink(linkPath, path)
		if err != nil {
			return err
		}

	default:
		return fmt.Errorf("Unhandled tar header type")
	}

	for key, value := range header.Xattrs {
		err := setxattr(path, key, []byte(value), 0)
		if err != nil {
			return err
		}
	}
	return nil
}
Esempio n. 17
0
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *TarChownOptions, inUserns bool) error {
	// hdr.Mode is in linux format, which we can use for sycalls,
	// but for os.Foo() calls we need the mode converted to os.FileMode,
	// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
	hdrInfo := hdr.FileInfo()

	switch hdr.Typeflag {
	case tar.TypeDir:
		// Create directory unless it exists as a directory already.
		// In that case we just want to merge the two
		if fi, err := os.Lstat(path); !(err == nil && fi.IsDir()) {
			if err := os.Mkdir(path, hdrInfo.Mode()); err != nil {
				return err
			}
		}

	case tar.TypeReg, tar.TypeRegA:
		// Source is regular file
		file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode())
		if err != nil {
			return err
		}
		if _, err := io.Copy(file, reader); err != nil {
			file.Close()
			return err
		}
		file.Close()

	case tar.TypeBlock, tar.TypeChar:
		if inUserns { // cannot create devices in a userns
			return nil
		}
		// Handle this is an OS-specific way
		if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
			return err
		}

	case tar.TypeFifo:
		// Handle this is an OS-specific way
		if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
			return err
		}

	case tar.TypeLink:
		targetPath := filepath.Join(extractDir, hdr.Linkname)
		// check for hardlink breakout
		if !strings.HasPrefix(targetPath, extractDir) {
			return breakoutError(fmt.Errorf("invalid hardlink %q -> %q", targetPath, hdr.Linkname))
		}
		if err := os.Link(targetPath, path); err != nil {
			return err
		}

	case tar.TypeSymlink:
		// 	path 				-> hdr.Linkname = targetPath
		// e.g. /extractDir/path/to/symlink 	-> ../2/file	= /extractDir/path/2/file
		targetPath := filepath.Join(filepath.Dir(path), hdr.Linkname)

		// the reason we don't need to check symlinks in the path (with FollowSymlinkInScope) is because
		// that symlink would first have to be created, which would be caught earlier, at this very check:
		if !strings.HasPrefix(targetPath, extractDir) {
			return breakoutError(fmt.Errorf("invalid symlink %q -> %q", path, hdr.Linkname))
		}
		if err := os.Symlink(hdr.Linkname, path); err != nil {
			return err
		}

	case tar.TypeXGlobalHeader:
		logrus.Debug("PAX Global Extended Headers found and ignored")
		return nil

	default:
		return fmt.Errorf("Unhandled tar header type %d\n", hdr.Typeflag)
	}

	// Lchown is not supported on Windows.
	if Lchown && runtime.GOOS != "windows" {
		if chownOpts == nil {
			chownOpts = &TarChownOptions{UID: hdr.Uid, GID: hdr.Gid}
		}
		if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
			return err
		}
	}

	var errors []string
	for key, value := range hdr.Xattrs {
		if err := system.Lsetxattr(path, key, []byte(value), 0); err != nil {
			if err == syscall.ENOTSUP {
				// We ignore errors here because not all graphdrivers support
				// xattrs *cough* old versions of AUFS *cough*. However only
				// ENOTSUP should be emitted in that case, otherwise we still
				// bail.
				errors = append(errors, err.Error())
				continue
			}
			return err
		}

	}

	if len(errors) > 0 {
		logrus.WithFields(logrus.Fields{
			"errors": errors,
		}).Warn("ignored xattrs in archive: underlying filesystem doesn't support them")
	}

	// There is no LChmod, so ignore mode for symlink. Also, this
	// must happen after chown, as that can modify the file mode
	if err := handleLChmod(hdr, path, hdrInfo); err != nil {
		return err
	}

	aTime := hdr.AccessTime
	if aTime.Before(hdr.ModTime) {
		// Last access time should never be before last modified time.
		aTime = hdr.ModTime
	}

	// system.Chtimes doesn't support a NOFOLLOW flag atm
	if hdr.Typeflag == tar.TypeLink {
		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
			if err := system.Chtimes(path, aTime, hdr.ModTime); err != nil {
				return err
			}
		}
	} else if hdr.Typeflag != tar.TypeSymlink {
		if err := system.Chtimes(path, aTime, hdr.ModTime); err != nil {
			return err
		}
	} else {
		ts := []syscall.Timespec{timeToTimespec(aTime), timeToTimespec(hdr.ModTime)}
		if err := system.LUtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
			return err
		}
	}
	return nil
}
Esempio n. 18
0
// Processes a single header/body combination from the tar
// archive being processed in Extract() above.
func (u *Untar) processEntry(header *tar.Header) error {
	// Check the security of the name being given to us by tar.
	// If the name contains any bad things then we force
	// an error in order to protect ourselves.
	if err := checkName(header.Name); err != nil {
		return err
	}

	// Ensure that the file is allowed against the current whitelist, if one is
	// specified.
	if !u.checkEntryAgainstWhitelist(header) {
		return nil
	}

	name := filepath.Join(u.target, header.Name)

	// resolve the destination and then reset the name based on the resolution
	destDir, err := u.resolveDestination(filepath.Dir(name))
	name = filepath.Join(destDir, filepath.Base(name))
	if err != nil {
		return err
	}

	// look at the type to see how we want to remove existing entries
	switch {
	case header.Typeflag == tar.TypeDir:
		// if we are extracting a directory, we want to see if the directory
		// already exists... if it exists but isn't a directory, we need
		// to remove it
		fi, _ := os.Stat(name)
		if fi != nil {
			if !fi.IsDir() {
				os.RemoveAll(name)
			}
		}
	default:
		os.RemoveAll(name)
	}

	// handle individual types
	switch {
	case header.Typeflag == tar.TypeDir:
		// Handle directories
		// don't return error if it already exists
		mode := os.FileMode(0755)
		if u.PreservePermissions {
			mode = header.FileInfo().Mode() | u.IncludedPermissionMask
		}

		// create the directory
		err := os.MkdirAll(name, mode)
		if err != nil {
			return err
		}

		// Perform a chmod after creation to ensure modes are applied directly,
		// regardless of umask.
		if err := os.Chmod(name, mode); err != nil {
			return err
		}

	case header.Typeflag == tar.TypeSymlink:
		// Handle symlinks
		err := checkLinkName(header.Linkname, name, u.target)
		if err != nil {
			return err
		}

		// have seen links to themselves
		if name == header.Linkname {
			break
		}

		// make the link
		if err := os.Symlink(header.Linkname, name); err != nil {
			return err
		}

	case header.Typeflag == tar.TypeLink:
		// handle creation of hard links
		if err := checkLinkName(header.Linkname, name, u.target); err != nil {
			return err
		}

		// find the full path, need to ensure it exists
		link := filepath.Join(u.target, header.Linkname)

		// do the link... no permissions or owners, those carry over
		if err := os.Link(link, name); err != nil {
			return err
		}

	case header.Typeflag == tar.TypeReg || header.Typeflag == tar.TypeRegA:
		flags := os.O_WRONLY | os.O_CREATE | os.O_EXCL
		// determine the mode to use
		mode := os.FileMode(0644)
		if u.PreservePermissions {
			mode = header.FileInfo().Mode() | u.IncludedPermissionMask
		}

		// open the file
		f, err := os.OpenFile(name, flags, mode)
		if err != nil {
			return err
		}
		defer f.Close()

		// Perform a chmod after creation to ensure modes are applied directly,
		// regardless of umask.
		if err := os.Chmod(name, mode); err != nil {
			return err
		}

		// SETUID/SETGID needs to be defered...
		// The standard chown call is after handling the files, since we want to
		// just have it one place, and after the file exists.  However, chown
		// will clear the setuid/setgid bit on a file.
		if header.Mode&c_ISUID != 0 {
			defer lazyChmod(name, os.ModeSetuid)
		}
		if header.Mode&c_ISGID != 0 {
			defer lazyChmod(name, os.ModeSetgid)
		}

		// copy the contents
		n, err := io.Copy(f, u.archive)
		if err != nil {
			return err
		} else if n != header.Size {
			return fmt.Errorf("Short write while copying file %s", name)
		}

	case header.Typeflag == tar.TypeBlock || header.Typeflag == tar.TypeChar || header.Typeflag == tar.TypeFifo:
		// check to see if the flag to skip character/block devices is set, and
		// simply return if it is
		if u.SkipSpecialDevices {
			return nil
		}

		// determine how to OR the mode
		devmode := uint32(0)
		switch header.Typeflag {
		case tar.TypeChar:
			devmode = syscall.S_IFCHR
		case tar.TypeBlock:
			devmode = syscall.S_IFBLK
		case tar.TypeFifo:
			devmode = syscall.S_IFIFO
		}

		// determine the mode to use
		mode := os.FileMode(0644)
		if u.PreservePermissions {
			mode = header.FileInfo().Mode() | u.IncludedPermissionMask
		}

		// syscall to mknod
		dev := makedev(header.Devmajor, header.Devminor)
		if err := osMknod(name, devmode|uint32(mode), dev); err != nil {
			return err
		}

		// Perform a chmod after creation to ensure modes are applied directly,
		// regardless of umask.
		if err := os.Chmod(name, mode|os.FileMode(devmode)); err != nil {
			return err
		}

	default:
		return fmt.Errorf("Unrecognized type: %d", header.Typeflag)
	}

	// process the uid/gid ownership
	uid := u.MappedUserID
	gid := u.MappedGroupID
	if u.PreserveOwners {
		if uid, err = u.OwnerMappingFunc(header.Uid); err != nil {
			return fmt.Errorf("failed to map UID for file: %v", err)
		}
		if gid, err = u.GroupMappingFunc(header.Gid); err != nil {
			return fmt.Errorf("failed to map GID for file: %v", err)
		}
	}

	// apply it
	switch header.Typeflag {
	case tar.TypeSymlink:
		os.Lchown(name, uid, gid)
	case tar.TypeLink:
		// don't chown on hard links or symlinks. doing this also removes setuid
		// from mode and the hard link will already pick up the same owner
	default:
		os.Chown(name, uid, gid)
	}

	return nil
}
Esempio n. 19
0
// ExtractFile extracts the file described by hdr from the given tarball into
// the provided directory.
// If overwrite is true, existing files will be overwritten.
func ExtractFile(tr *tar.Reader, hdr *tar.Header, dir string, overwrite bool) error {
	p := filepath.Join(dir, hdr.Name)
	fi := hdr.FileInfo()
	typ := hdr.Typeflag
	if overwrite {
		info, err := os.Lstat(p)
		switch {
		case os.IsNotExist(err):
		case err == nil:
			// If the old and new paths are both dirs do nothing or
			// RemoveAll will remove all dir's contents
			if !info.IsDir() || typ != tar.TypeDir {
				err := os.RemoveAll(p)
				if err != nil {
					return err
				}
			}
		default:
			return err
		}
	}

	// Create parent dir if it doesn't exist
	if err := os.MkdirAll(filepath.Dir(p), DEFAULT_DIR_MODE); err != nil {
		return err
	}
	switch {
	case typ == tar.TypeReg || typ == tar.TypeRegA:
		f, err := os.OpenFile(p, os.O_CREATE|os.O_RDWR, fi.Mode())
		if err != nil {
			return err
		}
		_, err = io.Copy(f, tr)
		if err != nil {
			f.Close()
			return err
		}
		f.Close()
	case typ == tar.TypeDir:
		if err := os.MkdirAll(p, fi.Mode()); err != nil {
			return err
		}
		dir, err := os.Open(p)
		if err != nil {
			return err
		}
		if err := dir.Chmod(fi.Mode()); err != nil {
			dir.Close()
			return err
		}
		dir.Close()
	case typ == tar.TypeLink:
		dest := filepath.Join(dir, hdr.Linkname)
		if !strings.HasPrefix(dest, dir) {
			return insecureLinkError(fmt.Errorf("insecure link %q -> %q", p, hdr.Linkname))
		}
		if err := os.Link(dest, p); err != nil {
			return err
		}
	case typ == tar.TypeSymlink:
		dest := filepath.Join(filepath.Dir(p), hdr.Linkname)
		if !strings.HasPrefix(dest, dir) {
			return insecureLinkError(fmt.Errorf("insecure symlink %q -> %q", p, hdr.Linkname))
		}
		if err := os.Symlink(hdr.Linkname, p); err != nil {
			return err
		}
	case typ == tar.TypeChar:
		dev := makedev(int(hdr.Devmajor), int(hdr.Devminor))
		mode := uint32(fi.Mode()) | syscall.S_IFCHR
		if err := syscall.Mknod(p, mode, dev); err != nil {
			return err
		}
	case typ == tar.TypeBlock:
		dev := makedev(int(hdr.Devmajor), int(hdr.Devminor))
		mode := uint32(fi.Mode()) | syscall.S_IFBLK
		if err := syscall.Mknod(p, mode, dev); err != nil {
			return err
		}
	case typ == tar.TypeFifo:
		if err := syscall.Mkfifo(p, uint32(fi.Mode())); err != nil {
			return err
		}
	// TODO(jonboulle): implement other modes
	default:
		return fmt.Errorf("unsupported type: %v", typ)
	}

	if err := os.Lchown(p, hdr.Uid, hdr.Gid); err != nil {
		return err
	}

	// lchown(2) says that, depending on the linux kernel version, it
	// can change the file's mode also if executed as root. So call
	// os.Chmod after it.
	if typ != tar.TypeSymlink {
		if err := os.Chmod(p, fi.Mode()); err != nil {
			return err
		}
	}

	// Restore entry atime and mtime.
	// Use special function LUtimesNano not available on go's syscall package because we
	// have to restore symlink's times and not the referenced file times.
	ts := HdrToTimespec(hdr)
	if hdr.Typeflag != tar.TypeSymlink {
		if err := syscall.UtimesNano(p, ts); err != nil {
			return err
		}
	} else {
		if err := LUtimesNano(p, ts); err != nil && err != ErrNotSupportedPlatform {
			return err
		}
	}

	return nil
}
				Expect(outputBuffer).To(test_helpers.Say("Successfully uploaded droplet-name"))
				Expect(fakeDropletRunner.UploadBitsCallCount()).To(Equal(1))
				dropletName, uploadPath := fakeDropletRunner.UploadBitsArgsForCall(0)
				Expect(dropletName).To(Equal("droplet-name"))

				Expect(uploadPath).ToNot(BeNil())
				Expect(uploadPath).To(HaveSuffix(".tar"))

				file, err := os.Open(uploadPath)
				Expect(err).NotTo(HaveOccurred())
				tarReader := tar.NewReader(file)

				var h *tar.Header
				h, err = tarReader.Next()
				Expect(err).NotTo(HaveOccurred())
				Expect(h.FileInfo().Name()).To(Equal("aaa"))
				Expect(h.FileInfo().IsDir()).To(BeFalse())
				Expect(h.FileInfo().Mode()).To(Equal(os.FileMode(0700)))

				h, err = tarReader.Next()
				Expect(err).NotTo(HaveOccurred())
				Expect(h.FileInfo().Name()).To(Equal("bbb"))
				Expect(h.FileInfo().IsDir()).To(BeFalse())
				Expect(h.FileInfo().Mode()).To(Equal(os.FileMode(0750)))

				h, err = tarReader.Next()
				Expect(err).NotTo(HaveOccurred())
				Expect(h.FileInfo().Name()).To(Equal("ccc"))
				Expect(h.FileInfo().IsDir()).To(BeFalse())
				Expect(h.FileInfo().Mode()).To(Equal(os.FileMode(0644)))