// We have a dummy version of this call in posix.go. // Windows does not implement the syscall.Stat_t type we // need, but the *nixes do. We use this in util.AddToArchive // to set owner/group on files being added to a tar archive. func GetOwnerAndGroup(finfo os.FileInfo, header *tar.Header) { systat := finfo.Sys().(*syscall.Stat_t) if systat != nil { header.Uid = int(systat.Uid) header.Gid = int(systat.Gid) } }
func writeTarEntry(tw *tar.Writer, name string, data []byte) error { h := new(tar.Header) h.Name = name h.Uid = 1000 h.Gid = 1000 h.Mode = 0755 h.Size = int64(len(data)) if err := tw.WriteHeader(h); err != nil { return err } if _, err := tw.Write(data); err != nil { return err } return nil }
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 } }
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 } }
// fills tar.Header missing information (uid/gid, username/groupname, times ...) func FillHeader(hdr *tar.Header) { var cuname string cuid := os.Getuid() if curr, err := user.LookupId(fmt.Sprintf("%d", cuid)); err == nil { cuname = curr.Username } if hdr.Uid == 0 { if hdr.Uname == "" { hdr.Uid = cuid hdr.Uname = cuname } else { if usr, err := user.Lookup(hdr.Uname); err == nil { if i, err := fmt.Sscanf("%d", usr.Uid); err == nil { hdr.Uid = i hdr.Uname = usr.Username } } } } if hdr.Gid == 0 { if hdr.Gname == "" { if hdr.Uid != 0 { if usr, err := user.LookupId(fmt.Sprintf("%d", hdr.Uid)); err == nil { if i, err := fmt.Sscanf("%d", usr.Gid); err == nil { hdr.Gid = i } } } } } if hdr.ModTime.IsZero() { hdr.ModTime = time.Now() } if hdr.AccessTime.IsZero() { hdr.AccessTime = hdr.ModTime } if hdr.ChangeTime.IsZero() { hdr.ChangeTime = hdr.ModTime } }
func fakeTar() (io.Reader, error) { uid := os.Getuid() gid := os.Getgid() content := []byte("Hello world!\n") buf := new(bytes.Buffer) tw := tar.NewWriter(buf) for _, name := range []string{"/etc/postgres/postgres.conf", "/etc/passwd", "/var/log/postgres/postgres.conf"} { hdr := new(tar.Header) // Leaving these fields blank requires root privileges hdr.Uid = uid hdr.Gid = gid hdr.Size = int64(len(content)) hdr.Name = name if err := tw.WriteHeader(hdr); err != nil { return nil, err } tw.Write([]byte(content)) } tw.Close() return buf, nil }
func TestUntarIDMappings(t *testing.T) { StartTest(t) defer FinishTest(t) // create a buffer and tar.Writer buffer := bytes.NewBufferString("") archive := tar.NewWriter(buffer) writeDirectoryWithOwners := func(name string, uid, gid int) { header := new(tar.Header) header.Name = name + "/" header.Typeflag = tar.TypeDir header.Mode = 0755 header.Mode |= c_ISDIR header.ModTime = time.Now() header.Uid = uid header.Gid = gid TestExpectSuccess(t, archive.WriteHeader(header)) } writeFileWithOwners := func(name, contents string, uid, gid int) { 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)) header.Uid = uid header.Gid = gid TestExpectSuccess(t, archive.WriteHeader(header)) _, err := archive.Write(b) TestExpectSuccess(t, err) TestExpectSuccess(t, archive.Flush()) } writeDirectoryWithOwners(".", 0, 0) writeFileWithOwners("./foo", "foo", 0, 0) archive.Close() // setup our mapping func usr, err := user.Current() TestExpectSuccess(t, err) myUid, err := strconv.Atoi(usr.Uid) TestExpectSuccess(t, err) myGid, err := strconv.Atoi(usr.Gid) TestExpectSuccess(t, err) uidFuncCalled := false gidFuncCalled := false uidMappingFunc := func(uid int) (int, error) { uidFuncCalled = true TestEqual(t, uid, 0) return myUid, nil } gidMappingFunc := func(gid int) (int, error) { gidFuncCalled = true TestEqual(t, gid, 0) return myGid, nil } // extract tempDir := TempDir(t) r := bytes.NewReader(buffer.Bytes()) u := NewUntar(r, tempDir) u.PreserveOwners = true u.OwnerMappingFunc = uidMappingFunc u.GroupMappingFunc = gidMappingFunc TestExpectSuccess(t, u.Extract()) // verify it was called TestEqual(t, uidFuncCalled, true) TestEqual(t, gidFuncCalled, true) // verify the file stat, err := os.Stat(path.Join(tempDir, "foo")) TestExpectSuccess(t, err) sys := stat.Sys().(*syscall.Stat_t) TestEqual(t, sys.Uid, uint32(myUid)) TestEqual(t, sys.Gid, uint32(myGid)) }
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 }