File: x000a.go

package info (click to toggle)
golang-github-saracen-zipextra 0.0~git20250129.f1aa42d-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 120 kB
  • sloc: makefile: 2
file content (123 lines) | stat: -rw-r--r-- 2,760 bytes parent folder | download | duplicates (2)
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
}