예제 #1
0
파일: deb.go 프로젝트: pombredanne/snappy-1
// tarCreate creates a tarfile for a clickdeb, all files in the archive
// belong to root (same as dpkg-deb)
func tarCreate(tarname string, sourceDir string, fn tarExcludeFunc) error {
	w, err := os.Create(tarname)
	if err != nil {
		return err
	}
	defer w.Close()

	var compressor io.WriteCloser
	switch {
	case strings.HasSuffix(tarname, ".gz"):
		compressor, err = gzip.NewWriterLevel(w, 9)
	case strings.HasSuffix(tarname, ".xz"):
		compressor = newXZPipeWriter(w)
	default:
		return fmt.Errorf("unknown compression extension %s", tarname)
	}
	if err != nil {
		return err
	}
	defer compressor.Close()

	tarWriter := tar.NewWriter(compressor)
	defer tarWriter.Close()

	err = filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
		st, err := os.Lstat(path)
		if err != nil {
			return err
		}

		// check if we support this type
		if !st.Mode().IsRegular() && !helpers.IsSymlink(st.Mode()) && !st.Mode().IsDir() && !helpers.IsDevice(st.Mode()) {
			return fmt.Errorf("unsupported file type for %s", path)
		}

		// check our exclude function
		if fn != nil {
			if !fn(path) {
				return nil
			}
		}

		// huh? golang, come on! the symlink stuff is a bit complicated
		target, _ := os.Readlink(path)
		hdr, err := tar.FileInfoHeader(info, target)
		if err != nil {
			return err
		}

		// tar.FileInfoHeader does include the fact that its a
		// char/block device, but does not set major/minor :/
		if helpers.IsDevice(st.Mode()) {
			major, minor, err := helpers.MajorMinor(st)
			if err != nil {
				return err
			}
			hdr.Devmajor = int64(major)
			hdr.Devminor = int64(minor)
		}

		// exclude "."
		relativePath := "." + path[len(sourceDir):]
		if relativePath == "." {
			return nil
		}

		// add header, note that all files belong to root
		hdr.Name = relativePath
		hdr.Uid = 0
		hdr.Gid = 0
		hdr.Uname = "root"
		hdr.Gname = "root"

		if err := tarWriter.WriteHeader(hdr); err != nil {
			return err
		}

		// add content
		if st.Mode().IsRegular() {
			f, err := os.Open(path)
			if err != nil {
				return err
			}
			defer f.Close()
			_, err = io.Copy(tarWriter, f)
			if err != nil {
				return err
			}
		}

		return nil
	})

	return err
}
예제 #2
0
func copyToBuildDir(sourceDir, buildDir string) error {
	sourceDir, err := filepath.Abs(sourceDir)
	if err != nil {
		return err
	}

	err = os.Remove(buildDir)
	if err != nil && !os.IsNotExist(err) {
		// this shouldn't happen, but.
		return err
	}

	// no umask here so that we get the permissions correct
	oldUmask := syscall.Umask(0)
	defer syscall.Umask(oldUmask)

	return filepath.Walk(sourceDir, func(path string, info os.FileInfo, errin error) (err error) {
		if errin != nil {
			return errin
		}

		relpath := path[len(sourceDir):]
		if relpath == "/DEBIAN" || shouldExclude(sourceDir, filepath.Base(path)) {
			if info.IsDir() {
				return filepath.SkipDir
			}
			return nil
		}

		dest := filepath.Join(buildDir, relpath)

		// handle dirs
		if info.IsDir() {
			return os.Mkdir(dest, info.Mode())
		}

		// handle char/block devices
		if helpers.IsDevice(info.Mode()) {
			return helpers.CopySpecialFile(path, dest)
		}

		if (info.Mode() & os.ModeSymlink) != 0 {
			target, err := os.Readlink(path)
			if err != nil {
				return err
			}
			return os.Symlink(target, dest)
		}

		// fail if its unsupported
		if !info.Mode().IsRegular() {
			return fmt.Errorf("can not handle type of file %s", path)
		}

		// it's a file. Maybe we can link it?
		if os.Link(path, dest) == nil {
			// whee
			return nil
		}
		// sigh. ok, copy it is.
		return helpers.CopyFile(path, dest, helpers.CopyFlagDefault)
	})
}