github.com/freddyisaac/sicortex-golang@v0.0.0-20231019035217-e03519e66f60/src/archive/tar/common.go (about)

     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  }