OSDN Git Service

libgo: Update to weekly.2012-03-13.
[pf3gnuchains/gcc-fork.git] / libgo / go / archive / zip / struct.go
index 34a87fa..55f3dcf 100644 (file)
@@ -12,6 +12,7 @@ This package does not support ZIP64 or disk spanning.
 package zip
 
 import (
+       "errors"
        "os"
        "time"
 )
@@ -26,10 +27,11 @@ const (
        fileHeaderSignature      = 0x04034b50
        directoryHeaderSignature = 0x02014b50
        directoryEndSignature    = 0x06054b50
-       fileHeaderLen            = 30 // + filename + extra
-       directoryHeaderLen       = 46 // + filename + extra + comment
-       directoryEndLen          = 22 // + comment
-       dataDescriptorLen        = 12
+       dataDescriptorSignature  = 0x08074b50 // de-facto standard; required by OS X Finder
+       fileHeaderLen            = 30         // + filename + extra
+       directoryHeaderLen       = 46         // + filename + extra + comment
+       directoryEndLen          = 22         // + comment
+       dataDescriptorLen        = 16         // four uint32: descriptor signature, crc32, compressed size, size
 
        // Constants for the first byte in CreatorVersion
        creatorFAT    = 0
@@ -55,6 +57,39 @@ type FileHeader struct {
        Comment          string
 }
 
+// FileInfo returns an os.FileInfo for the FileHeader.
+func (h *FileHeader) FileInfo() os.FileInfo {
+       return headerFileInfo{h}
+}
+
+// headerFileInfo implements os.FileInfo.
+type headerFileInfo struct {
+       fh *FileHeader
+}
+
+func (fi headerFileInfo) Name() string       { return fi.fh.Name }
+func (fi headerFileInfo) Size() int64        { return int64(fi.fh.UncompressedSize) }
+func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
+func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
+func (fi headerFileInfo) Mode() os.FileMode  { return fi.fh.Mode() }
+func (fi headerFileInfo) Sys() interface{}   { return fi.fh }
+
+// FileInfoHeader creates a partially-populated FileHeader from an
+// os.FileInfo.
+func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
+       size := fi.Size()
+       if size > (1<<32 - 1) {
+               return nil, errors.New("zip: file over 4GB")
+       }
+       fh := &FileHeader{
+               Name:             fi.Name(),
+               UncompressedSize: uint32(size),
+       }
+       fh.SetModTime(fi.ModTime())
+       fh.SetMode(fi.Mode())
+       return fh, nil
+}
+
 type directoryEnd struct {
        diskNbr            uint16 // unused
        dirDiskNbr         uint16 // unused
@@ -66,16 +101,6 @@ type directoryEnd struct {
        comment            string
 }
 
-func recoverError(errp *error) {
-       if e := recover(); e != nil {
-               if err, ok := e.(error); ok {
-                       *errp = err
-                       return
-               }
-               panic(e)
-       }
-}
-
 // msDosTimeToTime converts an MS-DOS date and time into a time.Time.
 // The resolution is 2s.
 // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
@@ -118,21 +143,27 @@ func (h *FileHeader) SetModTime(t time.Time) {
        h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
 }
 
-// traditional names for Unix constants
 const (
-       s_IFMT  = 0xf000
-       s_IFDIR = 0x4000
-       s_IFREG = 0x8000
-       s_ISUID = 0x800
-       s_ISGID = 0x400
+       // Unix constants. The specification doesn't mention them,
+       // but these seem to be the values agreed on by tools.
+       s_IFMT   = 0xf000
+       s_IFSOCK = 0xc000
+       s_IFLNK  = 0xa000
+       s_IFREG  = 0x8000
+       s_IFBLK  = 0x6000
+       s_IFDIR  = 0x4000
+       s_IFCHR  = 0x2000
+       s_IFIFO  = 0x1000
+       s_ISUID  = 0x800
+       s_ISGID  = 0x400
+       s_ISVTX  = 0x200
 
        msdosDir      = 0x10
        msdosReadOnly = 0x01
 )
 
 // Mode returns the permission and mode bits for the FileHeader.
-// An error is returned in case the information is not available.
-func (h *FileHeader) Mode() (mode os.FileMode, err error) {
+func (h *FileHeader) Mode() (mode os.FileMode) {
        switch h.CreatorVersion >> 8 {
        case creatorUnix, creatorMacOSX:
                mode = unixModeToFileMode(h.ExternalAttrs >> 16)
@@ -142,7 +173,7 @@ func (h *FileHeader) Mode() (mode os.FileMode, err error) {
        if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
                mode |= os.ModeDir
        }
-       return mode, nil
+       return mode
 }
 
 // SetMode changes the permission and mode bits for the FileHeader.
@@ -173,10 +204,23 @@ func msdosModeToFileMode(m uint32) (mode os.FileMode) {
 
 func fileModeToUnixMode(mode os.FileMode) uint32 {
        var m uint32
-       if mode&os.ModeDir != 0 {
-               m = s_IFDIR
-       } else {
+       switch mode & os.ModeType {
+       default:
                m = s_IFREG
+       case os.ModeDir:
+               m = s_IFDIR
+       case os.ModeSymlink:
+               m = s_IFLNK
+       case os.ModeNamedPipe:
+               m = s_IFIFO
+       case os.ModeSocket:
+               m = s_IFSOCK
+       case os.ModeDevice:
+               if mode&os.ModeCharDevice != 0 {
+                       m = s_IFCHR
+               } else {
+                       m = s_IFBLK
+               }
        }
        if mode&os.ModeSetuid != 0 {
                m |= s_ISUID
@@ -184,13 +228,29 @@ func fileModeToUnixMode(mode os.FileMode) uint32 {
        if mode&os.ModeSetgid != 0 {
                m |= s_ISGID
        }
+       if mode&os.ModeSticky != 0 {
+               m |= s_ISVTX
+       }
        return m | uint32(mode&0777)
 }
 
 func unixModeToFileMode(m uint32) os.FileMode {
-       var mode os.FileMode
-       if m&s_IFMT == s_IFDIR {
+       mode := os.FileMode(m & 0777)
+       switch m & s_IFMT {
+       case s_IFBLK:
+               mode |= os.ModeDevice
+       case s_IFCHR:
+               mode |= os.ModeDevice | os.ModeCharDevice
+       case s_IFDIR:
                mode |= os.ModeDir
+       case s_IFIFO:
+               mode |= os.ModeNamedPipe
+       case s_IFLNK:
+               mode |= os.ModeSymlink
+       case s_IFREG:
+               // nothing to do
+       case s_IFSOCK:
+               mode |= os.ModeSocket
        }
        if m&s_ISGID != 0 {
                mode |= os.ModeSetgid
@@ -198,5 +258,8 @@ func unixModeToFileMode(m uint32) os.FileMode {
        if m&s_ISUID != 0 {
                mode |= os.ModeSetuid
        }
-       return mode | os.FileMode(m&0777)
+       if m&s_ISVTX != 0 {
+               mode |= os.ModeSticky
+       }
+       return mode
 }