1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
package zipextra
import (
"time"
)
// NTFS Extra Field identifier
const ExtraFieldNTFS uint16 = 0x000a
// NTFS is the NTFS Extra Field structure for holding NTFS attributes.
type NTFS struct {
Attributes []NTFSAttribute
}
// NTFSAttribute is an NTFS attribute interface. Each attribute consists of a
// tag and data. The tag is an identifier for the type of data.
type NTFSAttribute interface {
Tag() uint16
Data() []byte
}
// NTFSRawAttribute represents an unrecognized NTFS attribute.
type NTFSRawAttribute struct {
RawTag uint16
RawData []byte
}
// Tag returns the unrecognized NTFS attribute's tag.
func (a NTFSRawAttribute) Tag() uint16 {
return a.RawTag
}
// Tag returns the unrecognized NTFS attribute's data.
func (a NTFSRawAttribute) Data() []byte {
return a.RawData
}
// NTFSTimeAttribute is an NTFS attribute for storing modified, access and
// creation file times.
type NTFSTimeAttribute struct {
MTime time.Time
ATime time.Time
CTime time.Time
}
// Tag returns the NTFS Time attribute's tag. It is always 1.
func (a NTFSTimeAttribute) Tag() uint16 {
return 1
}
// Data returns the NTFS Time attribute's encoded data.
func (a NTFSTimeAttribute) Data() []byte {
buf := NewBuffer(make([]byte, 0, 8*3))
for _, t := range []time.Time{a.MTime, a.ATime, a.CTime} {
l, h := timeToFiletime(t)
buf.Write32(l)
buf.Write32(h)
}
return buf.Bytes()
}
// NewNTFS returns a new NTFS extra field structure.
func NewNTFS(attributes ...NTFSAttribute) NTFS {
return NTFS{
Attributes: attributes,
}
}
// Encode encodes the NTFS extra field.
func (field NTFS) Encode() []byte {
buf := NewBuffer([]byte{})
defer buf.WriteHeader(ExtraFieldNTFS)()
buf.Write32(0) // reserved
for _, attribute := range field.Attributes {
buf.Write16(attribute.Tag())
buf.Write16(uint16(len(attribute.Data())))
buf.WriteBytes(attribute.Data())
}
return buf.Bytes()
}
// NTFS returns the decoded NTFS extra field.
func (ef ExtraField) NTFS() (field NTFS, err error) {
buf := NewBuffer(ef)
if buf.Available() < 4 {
return field, ErrInvalidExtraFieldFormat
}
buf.Read32() // reserved
for buf.Available() >= 2 {
tag := buf.Read16()
size := buf.Read16()
if buf.Available() < int(size) {
return field, ErrInvalidExtraFieldFormat
}
switch tag {
case 1:
if size < 24 {
return field, ErrInvalidExtraFieldFormat
}
field.Attributes = append(field.Attributes, NTFSTimeAttribute{
MTime: filetimeToTime(buf.Read32(), buf.Read32()),
ATime: filetimeToTime(buf.Read32(), buf.Read32()),
CTime: filetimeToTime(buf.Read32(), buf.Read32()),
})
default:
field.Attributes = append(field.Attributes, NTFSRawAttribute{
RawTag: tag,
RawData: buf.ReadBytes(int(size)),
})
}
}
return
}
|