...
Run Format

Source file src/archive/tar/common.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// Package tar implements access to tar archives.
     6	// It aims to cover most of the variations, including those produced
     7	// by GNU and BSD tars.
     8	//
     9	// References:
    10	//   http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
    11	//   http://www.gnu.org/software/tar/manual/html_node/Standard.html
    12	//   http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
    13	package tar
    14	
    15	import (
    16		"errors"
    17		"fmt"
    18		"os"
    19		"path"
    20		"time"
    21	)
    22	
    23	// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
    24	// architectures. If a large value is encountered when decoding, the result
    25	// stored in Header will be the truncated version.
    26	
    27	// Header type flags.
    28	const (
    29		TypeReg           = '0'    // regular file
    30		TypeRegA          = '\x00' // regular file
    31		TypeLink          = '1'    // hard link
    32		TypeSymlink       = '2'    // symbolic link
    33		TypeChar          = '3'    // character device node
    34		TypeBlock         = '4'    // block device node
    35		TypeDir           = '5'    // directory
    36		TypeFifo          = '6'    // fifo node
    37		TypeCont          = '7'    // reserved
    38		TypeXHeader       = 'x'    // extended header
    39		TypeXGlobalHeader = 'g'    // global extended header
    40		TypeGNULongName   = 'L'    // Next file has a long name
    41		TypeGNULongLink   = 'K'    // Next file symlinks to a file w/ a long name
    42		TypeGNUSparse     = 'S'    // sparse file
    43	)
    44	
    45	// A Header represents a single header in a tar archive.
    46	// Some fields may not be populated.
    47	type Header struct {
    48		Name       string    // name of header file entry
    49		Mode       int64     // permission and mode bits
    50		Uid        int       // user id of owner
    51		Gid        int       // group id of owner
    52		Size       int64     // length in bytes
    53		ModTime    time.Time // modified time
    54		Typeflag   byte      // type of header entry
    55		Linkname   string    // target name of link
    56		Uname      string    // user name of owner
    57		Gname      string    // group name of owner
    58		Devmajor   int64     // major number of character or block device
    59		Devminor   int64     // minor number of character or block device
    60		AccessTime time.Time // access time
    61		ChangeTime time.Time // status change time
    62		Xattrs     map[string]string
    63	}
    64	
    65	// FileInfo returns an os.FileInfo for the Header.
    66	func (h *Header) FileInfo() os.FileInfo {
    67		return headerFileInfo{h}
    68	}
    69	
    70	// headerFileInfo implements os.FileInfo.
    71	type headerFileInfo struct {
    72		h *Header
    73	}
    74	
    75	func (fi headerFileInfo) Size() int64        { return fi.h.Size }
    76	func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
    77	func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
    78	func (fi headerFileInfo) Sys() interface{}   { return fi.h }
    79	
    80	// Name returns the base name of the file.
    81	func (fi headerFileInfo) Name() string {
    82		if fi.IsDir() {
    83			return path.Base(path.Clean(fi.h.Name))
    84		}
    85		return path.Base(fi.h.Name)
    86	}
    87	
    88	// Mode returns the permission and mode bits for the headerFileInfo.
    89	func (fi headerFileInfo) Mode() (mode os.FileMode) {
    90		// Set file permission bits.
    91		mode = os.FileMode(fi.h.Mode).Perm()
    92	
    93		// Set setuid, setgid and sticky bits.
    94		if fi.h.Mode&c_ISUID != 0 {
    95			// setuid
    96			mode |= os.ModeSetuid
    97		}
    98		if fi.h.Mode&c_ISGID != 0 {
    99			// setgid
   100			mode |= os.ModeSetgid
   101		}
   102		if fi.h.Mode&c_ISVTX != 0 {
   103			// sticky
   104			mode |= os.ModeSticky
   105		}
   106	
   107		// Set file mode bits.
   108		// clear perm, setuid, setgid and sticky bits.
   109		m := os.FileMode(fi.h.Mode) &^ 07777
   110		if m == c_ISDIR {
   111			// directory
   112			mode |= os.ModeDir
   113		}
   114		if m == c_ISFIFO {
   115			// named pipe (FIFO)
   116			mode |= os.ModeNamedPipe
   117		}
   118		if m == c_ISLNK {
   119			// symbolic link
   120			mode |= os.ModeSymlink
   121		}
   122		if m == c_ISBLK {
   123			// device file
   124			mode |= os.ModeDevice
   125		}
   126		if m == c_ISCHR {
   127			// Unix character device
   128			mode |= os.ModeDevice
   129			mode |= os.ModeCharDevice
   130		}
   131		if m == c_ISSOCK {
   132			// Unix domain socket
   133			mode |= os.ModeSocket
   134		}
   135	
   136		switch fi.h.Typeflag {
   137		case TypeSymlink:
   138			// symbolic link
   139			mode |= os.ModeSymlink
   140		case TypeChar:
   141			// character device node
   142			mode |= os.ModeDevice
   143			mode |= os.ModeCharDevice
   144		case TypeBlock:
   145			// block device node
   146			mode |= os.ModeDevice
   147		case TypeDir:
   148			// directory
   149			mode |= os.ModeDir
   150		case TypeFifo:
   151			// fifo node
   152			mode |= os.ModeNamedPipe
   153		}
   154	
   155		return mode
   156	}
   157	
   158	// sysStat, if non-nil, populates h from system-dependent fields of fi.
   159	var sysStat func(fi os.FileInfo, h *Header) error
   160	
   161	// Mode constants from the tar spec.
   162	const (
   163		c_ISUID  = 04000   // Set uid
   164		c_ISGID  = 02000   // Set gid
   165		c_ISVTX  = 01000   // Save text (sticky bit)
   166		c_ISDIR  = 040000  // Directory
   167		c_ISFIFO = 010000  // FIFO
   168		c_ISREG  = 0100000 // Regular file
   169		c_ISLNK  = 0120000 // Symbolic link
   170		c_ISBLK  = 060000  // Block special file
   171		c_ISCHR  = 020000  // Character special file
   172		c_ISSOCK = 0140000 // Socket
   173	)
   174	
   175	// Keywords for the PAX Extended Header
   176	const (
   177		paxAtime    = "atime"
   178		paxCharset  = "charset"
   179		paxComment  = "comment"
   180		paxCtime    = "ctime" // please note that ctime is not a valid pax header.
   181		paxGid      = "gid"
   182		paxGname    = "gname"
   183		paxLinkpath = "linkpath"
   184		paxMtime    = "mtime"
   185		paxPath     = "path"
   186		paxSize     = "size"
   187		paxUid      = "uid"
   188		paxUname    = "uname"
   189		paxXattr    = "SCHILY.xattr."
   190		paxNone     = ""
   191	)
   192	
   193	// FileInfoHeader creates a partially-populated Header from fi.
   194	// If fi describes a symlink, FileInfoHeader records link as the link target.
   195	// If fi describes a directory, a slash is appended to the name.
   196	// Because os.FileInfo's Name method returns only the base name of
   197	// the file it describes, it may be necessary to modify the Name field
   198	// of the returned header to provide the full path name of the file.
   199	func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
   200		if fi == nil {
   201			return nil, errors.New("tar: FileInfo is nil")
   202		}
   203		fm := fi.Mode()
   204		h := &Header{
   205			Name:    fi.Name(),
   206			ModTime: fi.ModTime(),
   207			Mode:    int64(fm.Perm()), // or'd with c_IS* constants later
   208		}
   209		switch {
   210		case fm.IsRegular():
   211			h.Mode |= c_ISREG
   212			h.Typeflag = TypeReg
   213			h.Size = fi.Size()
   214		case fi.IsDir():
   215			h.Typeflag = TypeDir
   216			h.Mode |= c_ISDIR
   217			h.Name += "/"
   218		case fm&os.ModeSymlink != 0:
   219			h.Typeflag = TypeSymlink
   220			h.Mode |= c_ISLNK
   221			h.Linkname = link
   222		case fm&os.ModeDevice != 0:
   223			if fm&os.ModeCharDevice != 0 {
   224				h.Mode |= c_ISCHR
   225				h.Typeflag = TypeChar
   226			} else {
   227				h.Mode |= c_ISBLK
   228				h.Typeflag = TypeBlock
   229			}
   230		case fm&os.ModeNamedPipe != 0:
   231			h.Typeflag = TypeFifo
   232			h.Mode |= c_ISFIFO
   233		case fm&os.ModeSocket != 0:
   234			h.Mode |= c_ISSOCK
   235		default:
   236			return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
   237		}
   238		if fm&os.ModeSetuid != 0 {
   239			h.Mode |= c_ISUID
   240		}
   241		if fm&os.ModeSetgid != 0 {
   242			h.Mode |= c_ISGID
   243		}
   244		if fm&os.ModeSticky != 0 {
   245			h.Mode |= c_ISVTX
   246		}
   247		// If possible, populate additional fields from OS-specific
   248		// FileInfo fields.
   249		if sys, ok := fi.Sys().(*Header); ok {
   250			// This FileInfo came from a Header (not the OS). Use the
   251			// original Header to populate all remaining fields.
   252			h.Uid = sys.Uid
   253			h.Gid = sys.Gid
   254			h.Uname = sys.Uname
   255			h.Gname = sys.Gname
   256			h.AccessTime = sys.AccessTime
   257			h.ChangeTime = sys.ChangeTime
   258			if sys.Xattrs != nil {
   259				h.Xattrs = make(map[string]string)
   260				for k, v := range sys.Xattrs {
   261					h.Xattrs[k] = v
   262				}
   263			}
   264			if sys.Typeflag == TypeLink {
   265				// hard link
   266				h.Typeflag = TypeLink
   267				h.Size = 0
   268				h.Linkname = sys.Linkname
   269			}
   270		}
   271		if sysStat != nil {
   272			return h, sysStat(fi, h)
   273		}
   274		return h, nil
   275	}
   276	
   277	// isHeaderOnlyType checks if the given type flag is of the type that has no
   278	// data section even if a size is specified.
   279	func isHeaderOnlyType(flag byte) bool {
   280		switch flag {
   281		case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
   282			return true
   283		default:
   284			return false
   285		}
   286	}
   287	

View as plain text