archive/zip: make zip understand os.FileMode.

Fixes implicit dependency on underlying os file modes.

R=rsc, r, n13m3y3r, gustavo, adg
CC=golang-dev
https://golang.org/cl/5440130
This commit is contained in:
Roger Peppe 2011-12-12 15:22:55 -05:00 committed by Russ Cox
parent 68ec347c16
commit 2cb1aa4681
5 changed files with 153 additions and 23 deletions

View file

@ -12,7 +12,7 @@ This package does not support ZIP64 or disk spanning.
package zip
import (
"errors"
"os"
"time"
)
@ -32,7 +32,11 @@ const (
dataDescriptorLen = 12
// Constants for the first byte in CreatorVersion
creatorUnix = 3
creatorFAT = 0
creatorUnix = 3
creatorNTFS = 11
creatorVFAT = 14
creatorMacOSX = 19
)
type FileHeader struct {
@ -98,17 +102,85 @@ func (h *FileHeader) ModTime() time.Time {
return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
}
// traditional names for Unix constants
const (
s_IFMT = 0xf000
s_IFDIR = 0x4000
s_IFREG = 0x8000
s_ISUID = 0x800
s_ISGID = 0x400
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 uint32, err error) {
if h.CreatorVersion>>8 == creatorUnix {
return h.ExternalAttrs >> 16, nil
func (h *FileHeader) Mode() (mode os.FileMode, err error) {
switch h.CreatorVersion >> 8 {
case creatorUnix, creatorMacOSX:
mode = unixModeToFileMode(h.ExternalAttrs >> 16)
case creatorNTFS, creatorVFAT, creatorFAT:
mode = msdosModeToFileMode(h.ExternalAttrs)
}
return 0, errors.New("file mode not available")
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
mode |= os.ModeDir
}
return mode, nil
}
// SetMode changes the permission and mode bits for the FileHeader.
func (h *FileHeader) SetMode(mode uint32) {
func (h *FileHeader) SetMode(mode os.FileMode) {
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
h.ExternalAttrs = mode << 16
h.ExternalAttrs = fileModeToUnixMode(mode) << 16
// set MSDOS attributes too, as the original zip does.
if mode&os.ModeDir != 0 {
h.ExternalAttrs |= msdosDir
}
if mode&0200 == 0 {
h.ExternalAttrs |= msdosReadOnly
}
}
func msdosModeToFileMode(m uint32) (mode os.FileMode) {
if m&msdosDir != 0 {
mode = os.ModeDir | 0777
} else {
mode = 0666
}
if m&msdosReadOnly != 0 {
mode &^= 0222
}
return mode
}
func fileModeToUnixMode(mode os.FileMode) uint32 {
var m uint32
if mode&os.ModeDir != 0 {
m = s_IFDIR
} else {
m = s_IFREG
}
if mode&os.ModeSetuid != 0 {
m |= s_ISUID
}
if mode&os.ModeSetgid != 0 {
m |= s_ISGID
}
return m | uint32(mode&0777)
}
func unixModeToFileMode(m uint32) os.FileMode {
var mode os.FileMode
if m&s_IFMT == s_IFDIR {
mode |= os.ModeDir
}
if m&s_ISGID != 0 {
mode |= os.ModeSetgid
}
if m&s_ISUID != 0 {
mode |= os.ModeSetuid
}
return mode | os.FileMode(m&0777)
}