Beispiel #1
0
func (decoderData *decoderData) addHardlink(header *tar.Header,
	parent *filesystem.DirectoryInode, name string) error {
	header.Linkname = normaliseFilename(header.Linkname)
	if inum, ok := decoderData.inodeTable[header.Linkname]; ok {
		var newEntry filesystem.DirectoryEntry
		newEntry.Name = name
		newEntry.InodeNumber = inum
		parent.EntryList = append(parent.EntryList, &newEntry)
	} else {
		return errors.New(fmt.Sprintf("missing hardlink target: %s",
			header.Linkname))
	}
	return nil
}
Beispiel #2
0
func populateHeaderUnix(h *tar.Header, fi os.FileInfo, seen map[uint64]string) {
	st, ok := fi.Sys().(*syscall.Stat_t)
	if !ok {
		return
	}
	h.Uid = int(st.Uid)
	h.Gid = int(st.Gid)
	// If we have already seen this inode, generate a hardlink
	p, ok := seen[uint64(st.Ino)]
	if ok {
		h.Linkname = p
		h.Typeflag = tar.TypeLink
	} else {
		seen[uint64(st.Ino)] = h.Name
	}
}
Beispiel #3
0
// appends as link pointing at a previously written item
func AppendLink(tarfn string, info Info, src string, dst string) (err error) {
	//var (twp *tar.Writer; fh ReadWriteSeekCloser; pos uint64)
	if tw, fh, _, err := OpenForAppend(tarfn); err == nil {
		defer fh.Close()
		defer tw.Close()

		if err := writeInfo(tw, info); err == nil {
			hdr := new(tar.Header)
			hdr.Name = src
			hdr.Typeflag = tar.TypeSymlink
			hdr.Linkname = dst
			if err := tw.WriteHeader(hdr); err == nil {
				err = tw.Flush()
			}
		}
	}
	return
}
Beispiel #4
0
func populateHeaderUnix(h *tar.Header, fi os.FileInfo, seen map[uint64]string) {
	st, ok := fi.Sys().(*syscall.Stat_t)
	if !ok {
		return
	}
	h.Uid = int(st.Uid)
	h.Gid = int(st.Gid)
	if st.Mode&syscall.S_IFMT == syscall.S_IFBLK || st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
		h.Devminor = int64(C.my_minor(C.dev_t(st.Rdev)))
		h.Devmajor = int64(C.my_major(C.dev_t(st.Rdev)))
	}
	// If we have already seen this inode, generate a hardlink
	p, ok := seen[uint64(st.Ino)]
	if ok {
		h.Linkname = p
		h.Typeflag = tar.TypeLink
	} else {
		seen[uint64(st.Ino)] = h.Name
	}
}
Beispiel #5
0
func addPath(writer *tar.Writer, rootPath string, prefixLen int, dereferenceEtc bool) error {
	walkFn := func(source string, info os.FileInfo, err error) error {
		if err != nil {
			return fmt.Errorf("cannot read directory '%s': %v", rootPath, err)
		}
		header := tar.Header{}
		relPath := source[(prefixLen):]
		header.Name = path.Join("rootfs", relPath)
		header.ModTime = info.ModTime()
		header.Mode = int64(info.Mode().Perm())

		if info.Mode().IsRegular() ||
			(dereferenceEtc && info.Mode()&os.ModeSymlink != 0 && strings.HasPrefix(relPath, "etc/")) {
			header.Typeflag = tar.TypeReg
			header.Size = info.Size()
			if err := writer.WriteHeader(&header); err != nil {
				return fmt.Errorf("cannot write aci image entry header '%s': %v", source, err)
			}
			return addFile(writer, source)
		} else {
			if info.Mode()&os.ModeSymlink != 0 {
				target, err := os.Readlink(source)
				if err != nil {
					return fmt.Errorf("cannot read resolve symlink '%s', %v", target, err)
				}
				header.Linkname = target
				header.Typeflag = tar.TypeSymlink
			} else if info.Mode().IsDir() {
				header.Typeflag = tar.TypeDir
			} else {
				return fmt.Errorf("not implemented")
			}
			if err := writer.WriteHeader(&header); err != nil {
				return fmt.Errorf("cannot write aci image entry '%s': %v", source, err)
			}
		}
		return nil
	}
	return filepath.Walk(rootPath, walkFn)
}
Beispiel #6
0
func TestUntarExtractFollowingSymlinks(t *testing.T) {
	StartTest(t)
	defer FinishTest(t)

	// create a buffer and tar.Writer
	buffer := bytes.NewBufferString("")
	archive := tar.NewWriter(buffer)

	writeDirectory := func(name string) {
		header := new(tar.Header)
		header.Name = name + "/"
		header.Typeflag = tar.TypeDir
		header.Mode = 0755
		header.Mode |= c_ISDIR
		header.ModTime = time.Now()
		TestExpectSuccess(t, archive.WriteHeader(header))
	}

	writeFile := func(name, contents string) {
		b := []byte(contents)
		header := new(tar.Header)
		header.Name = name
		header.Typeflag = tar.TypeReg
		header.Mode = 0644
		header.Mode |= c_ISREG
		header.ModTime = time.Now()
		header.Size = int64(len(b))

		TestExpectSuccess(t, archive.WriteHeader(header))
		_, err := archive.Write(b)
		TestExpectSuccess(t, err)
		TestExpectSuccess(t, archive.Flush())
	}

	writeSymlink := func(name, link string) {
		header := new(tar.Header)
		header.Name = name
		header.Linkname = link
		header.Typeflag = tar.TypeSymlink
		header.Mode = 0644
		header.Mode |= c_ISLNK
		header.ModTime = time.Now()
		TestExpectSuccess(t, archive.WriteHeader(header))
	}

	// generate the mock tar
	writeDirectory(".")
	writeFile("./foo", "foo")
	writeDirectory("./usr")
	writeDirectory("./usr/bin")
	writeFile("./usr/bin/bash", "bash")
	writeSymlink("./usr/bin/sh", "bash")

	// now write a symlink that is an absolute path and then a file in it
	writeSymlink("./etc", "/realetc")
	writeFile("./etc/zz", "zz")
	archive.Close()

	// create temp folder to extract to
	tempDir := TempDir(t)
	extractionPath := path.Join(tempDir, "pkg")
	err := os.MkdirAll(extractionPath, 0755)
	TestExpectSuccess(t, err)
	err = os.MkdirAll(path.Join(tempDir, "realetc"), 0755)
	TestExpectSuccess(t, err)

	// extract
	r := bytes.NewReader(buffer.Bytes())
	u := NewUntar(r, extractionPath)
	u.AbsoluteRoot = tempDir
	TestExpectSuccess(t, u.Extract())

	fileExists := func(name string) {
		_, err := os.Stat(path.Join(tempDir, name))
		TestExpectSuccess(t, err)
	}

	fileContents := func(name, contents string) {
		b, err := ioutil.ReadFile(path.Join(tempDir, name))
		TestExpectSuccess(t, err)
		TestEqual(t, string(b), contents)
	}

	fileSymlinks := func(name, link string) {
		l, err := os.Readlink(path.Join(tempDir, name))
		TestExpectSuccess(t, err)
		TestEqual(t, l, link)
	}

	fileExists("./pkg/foo")
	fileContents("./pkg/foo", "foo")
	fileExists("./pkg/usr")
	fileExists("./pkg/usr/bin")
	fileExists("./pkg/usr/bin/bash")
	fileContents("./pkg/usr/bin/bash", "bash")
	fileSymlinks("./pkg/usr/bin/sh", "bash")

	// now validate the symlink and file in the symlinked dir that was outside
	// the symlink should still be absolute to /realetc
	// but the file should be in ./realetc/zz within the tempDir and not the
	// system's root... so Untar follows how it knows it should resolve and not
	// follow the real symlink
	fileSymlinks("./pkg/etc", "/realetc")
	fileExists("./realetc/zz")
	fileContents("./realetc/zz", "zz")
}
Beispiel #7
0
func TestUntarExtractOverwriting(t *testing.T) {
	StartTest(t)
	defer FinishTest(t)

	// create a buffer and tar.Writer
	buffer := bytes.NewBufferString("")
	archive := tar.NewWriter(buffer)

	writeDirectory := func(name string) {
		header := new(tar.Header)
		header.Name = name + "/"
		header.Typeflag = tar.TypeDir
		header.Mode = 0755
		header.Mode |= c_ISDIR
		header.ModTime = time.Now()
		TestExpectSuccess(t, archive.WriteHeader(header))
	}

	writeFile := func(name, contents string) {
		b := []byte(contents)
		header := new(tar.Header)
		header.Name = name
		header.Typeflag = tar.TypeReg
		header.Mode = 0644
		header.Mode |= c_ISREG
		header.ModTime = time.Now()
		header.Size = int64(len(b))

		TestExpectSuccess(t, archive.WriteHeader(header))
		_, err := archive.Write(b)
		TestExpectSuccess(t, err)
		TestExpectSuccess(t, archive.Flush())
	}

	writeSymlink := func(name, link string) {
		header := new(tar.Header)
		header.Name = name
		header.Linkname = link
		header.Typeflag = tar.TypeSymlink
		header.Mode = 0644
		header.Mode |= c_ISLNK
		header.ModTime = time.Now()
		TestExpectSuccess(t, archive.WriteHeader(header))
	}

	// create temp folder to extract to
	tempDir := TempDir(t)

	fileExists := func(name string) {
		_, err := os.Stat(path.Join(tempDir, name))
		TestExpectSuccess(t, err)
	}

	fileContents := func(name, contents string) {
		b, err := ioutil.ReadFile(path.Join(tempDir, name))
		TestExpectSuccess(t, err)
		TestEqual(t, string(b), contents)
	}

	fileSymlinks := func(name, link string) {
		l, err := os.Readlink(path.Join(tempDir, name))
		TestExpectSuccess(t, err)
		TestEqual(t, l, link)
	}

	// generate the mock tar
	writeDirectory(".")
	writeFile("./foo", "foo")
	writeDirectory("./usr")
	writeDirectory("./usr/bin")
	writeFile("./usr/bin/bash", "bash")
	writeSymlink("./usr/bin/sh", "bash")
	writeDirectory("./etc")
	writeFile("./etc/awesome", "awesome")
	writeFile("./var", "vvv")
	archive.Close()

	// extract
	r := bytes.NewReader(buffer.Bytes())
	u := NewUntar(r, tempDir)
	TestExpectSuccess(t, u.Extract())

	// validate the first tar
	fileExists("./foo")
	fileContents("./foo", "foo")
	fileExists("./usr")
	fileExists("./usr/bin")
	fileExists("./usr/bin/bash")
	fileContents("./usr/bin/bash", "bash")
	fileSymlinks("./usr/bin/sh", "bash")
	fileExists("./etc/awesome")
	fileContents("./etc/awesome", "awesome")
	fileExists("./var")
	fileContents("./var", "vvv")

	// create another tar and then extract it
	buffer2 := bytes.NewBufferString("")
	archive = tar.NewWriter(buffer2)

	// write the 2nd tar
	writeDirectory(".")
	writeFile("./foo", "bar")
	writeDirectory("./usr")
	writeDirectory("./usr/bin")
	writeFile("./usr/bin/zsh", "zsh")
	writeSymlink("./usr/bin/sh", "zsh")
	writeFile("./etc", "etc") // replace the directory with a file
	writeDirectory("./var")   // replace the file with a directory
	writeFile("./var/lib", "lll")
	archive.Close()

	// extract the 2nd tar
	r = bytes.NewReader(buffer2.Bytes())
	u = NewUntar(r, tempDir)
	TestExpectSuccess(t, u.Extract())

	// verify the contents were overwritten as expected
	fileContents("./foo", "bar")
	fileContents("./usr/bin/zsh", "zsh")
	fileSymlinks("./usr/bin/sh", "zsh")
	fileContents("./etc", "etc")
	fileContents("./var/lib", "lll")
}
Beispiel #8
0
func createArchive() int {
	archive := tar.NewWriter(output)
	defer archive.Close()
	exit_value := 0

	for _, f := range fileList {
		err := filepath.Walk(f, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			if verbose {
				fmt.Fprintf(os.Stderr, "%s\n", path)
			}

			var hdr tar.Header
			hdr.Name = path
			hdr.Size = info.Size()
			hdr.Mode = int64(info.Mode())
			hdr.ModTime = info.ModTime()

			// this is not portable:
			hdr.Uid = int(info.Sys().(*syscall.Stat_t).Uid)
			hdr.Gid = int(info.Sys().(*syscall.Stat_t).Gid)

			if user, err := user.LookupId(fmt.Sprintf("%d", hdr.Uid)); err == nil {
				hdr.Uname = user.Name
			}
			// TODO: lookup group, too.

			switch info.Mode() & os.ModeType {
			case 0:
				hdr.Typeflag = tar.TypeReg
			case os.ModeDir:
				hdr.Typeflag = tar.TypeDir
			case os.ModeSymlink:
				hdr.Typeflag = tar.TypeSymlink
				linkname, err := os.Readlink(path)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Warning: can't readlink a symlink: %v\n", err)
					return nil
				} else {
					hdr.Linkname = linkname
				}
			case os.ModeNamedPipe:
				hdr.Typeflag = tar.TypeFifo
			case os.ModeSocket:
				fmt.Fprintf(os.Stderr, "Warning: can't tar a socket\n")
				return nil
			case os.ModeDevice:
				fmt.Fprintf(os.Stderr, "Warning: device files are currently unsupported\n")
				return nil
				/*
					if (info.Mode() & os.ModeCharDevice) != 0 {
						os.Typeflag = tar.TypeChar
					} else {
						os.Typeflag = tar.TypeBlock
					}
				*/
			}

			if err := archive.WriteHeader(&hdr); err != nil {
				fmt.Fprintf(os.Stderr, "Writing archive header for %s failed: %v\n", path, err)
				exit_value = 1
				return nil
			}
			defer archive.Flush()

			if hdr.Typeflag == tar.TypeReg {
				if f, err := os.Open(path); err != nil {
					fmt.Fprintf(os.Stderr, "Opening file %s failed: %v\n", path, err)
					exit_value = 1
					return nil
				} else {
					io.Copy(archive, f)
					f.Close()
				}
			}
			return nil
		})
		if err != nil {
			fmt.Fprintf(os.Stderr, "An error occured: %v\n", err)
			exit_value = 1
		}
	}

	return exit_value
}