1
0
mirror of https://github.com/golang/go synced 2024-11-21 14:24:44 -07:00

misc/dist: better archive/tar Headers

This should live in archive/tar later (CL 5796073) but we
can always do that after Go 1 and stick it here for now.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5754096
This commit is contained in:
Brad Fitzpatrick 2012-03-12 21:49:43 -07:00
parent daacba5184
commit c405b58f3f
3 changed files with 134 additions and 16 deletions

86
misc/dist/bindist.go vendored
View File

@ -26,7 +26,6 @@ import (
"path/filepath"
"runtime"
"strings"
"syscall"
)
var (
@ -527,22 +526,16 @@ func makeTar(targ, workdir string) error {
if fi.IsDir() {
return nil
}
var typeFlag byte
switch {
case fi.Mode()&os.ModeType == 0:
typeFlag = tar.TypeReg
default:
log.Fatalf("makeTar: unknown file for file %q", name)
}
hdr := &tar.Header{
Name: name,
Mode: int64(fi.Sys().(*syscall.Stat_t).Mode),
Size: fi.Size(),
ModTime: fi.ModTime(),
Typeflag: typeFlag,
Uname: "root",
Gname: "root",
hdr, err := tarFileInfoHeader(fi, path)
if err != nil {
return err
}
hdr.Name = name
hdr.Uname = "root"
hdr.Gname = "root"
hdr.Uid = 0
hdr.Gid = 0
err = tw.WriteHeader(hdr)
if err != nil {
return fmt.Errorf("Error writing file %q: %v", name, err)
@ -686,3 +679,64 @@ func lookPath(prog string) (absPath string, err error) {
}
return
}
// sysStat, if non-nil, populates h from system-dependent fields of fi.
var sysStat func(fi os.FileInfo, h *tar.Header) error
// Mode constants from the tar spec.
const (
c_ISDIR = 040000
c_ISFIFO = 010000
c_ISREG = 0100000
c_ISLNK = 0120000
c_ISBLK = 060000
c_ISCHR = 020000
c_ISSOCK = 0140000
)
// tarFileInfoHeader creates a partially-populated Header from an os.FileInfo.
// The filename parameter is used only in the case of symlinks, to call os.Readlink.
// If fi is a symlink but filename is empty, an error is returned.
func tarFileInfoHeader(fi os.FileInfo, filename string) (*tar.Header, error) {
h := &tar.Header{
Name: fi.Name(),
ModTime: fi.ModTime(),
Mode: int64(fi.Mode().Perm()), // or'd with c_IS* constants later
}
switch {
case fi.Mode()&os.ModeType == 0:
h.Mode |= c_ISREG
h.Typeflag = tar.TypeReg
h.Size = fi.Size()
case fi.IsDir():
h.Typeflag = tar.TypeDir
h.Mode |= c_ISDIR
case fi.Mode()&os.ModeSymlink != 0:
h.Typeflag = tar.TypeSymlink
h.Mode |= c_ISLNK
if filename == "" {
return h, fmt.Errorf("archive/tar: unable to populate Header.Linkname of symlinks")
}
targ, err := os.Readlink(filename)
if err != nil {
return h, err
}
h.Linkname = targ
case fi.Mode()&os.ModeDevice != 0:
if fi.Mode()&os.ModeCharDevice != 0 {
h.Mode |= c_ISCHR
h.Typeflag = tar.TypeChar
} else {
h.Mode |= c_ISBLK
h.Typeflag = tar.TypeBlock
}
case fi.Mode()&os.ModeSocket != 0:
h.Mode |= c_ISSOCK
default:
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fi.Mode())
}
if sysStat != nil {
return h, sysStat(fi, h)
}
return h, nil
}

32
misc/dist/stat_darwin.go vendored Normal file
View File

@ -0,0 +1,32 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin
package main
import (
"archive/tar"
"os"
"syscall"
"time"
)
func init() {
sysStat = func(fi os.FileInfo, h *tar.Header) error {
sys, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return nil
}
h.Uid = int(sys.Uid)
h.Gid = int(sys.Gid)
// TODO(bradfitz): populate username & group. os/user
// doesn't cache LookupId lookups, and lacks group
// lookup functions.
h.AccessTime = time.Unix(sys.Atimespec.Unix())
h.ChangeTime = time.Unix(sys.Ctimespec.Unix())
// TODO(bradfitz): major/minor device numbers?
return nil
}
}

32
misc/dist/stat_linux.go vendored Normal file
View File

@ -0,0 +1,32 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
package main
import (
"archive/tar"
"os"
"syscall"
"time"
)
func init() {
sysStat = func(fi os.FileInfo, h *tar.Header) error {
sys, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return nil
}
h.Uid = int(sys.Uid)
h.Gid = int(sys.Gid)
// TODO(bradfitz): populate username & group. os/user
// doesn't cache LookupId lookups, and lacks group
// lookup functions.
h.AccessTime = time.Unix(sys.Atim.Unix())
h.ChangeTime = time.Unix(sys.Ctim.Unix())
// TODO(bradfitz): major/minor device numbers?
return nil
}
}