forked from cavaliergopher/cpio
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathheader.go
More file actions
152 lines (132 loc) · 3.83 KB
/
header.go
File metadata and controls
152 lines (132 loc) · 3.83 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package cpio
import (
"errors"
"fmt"
"os"
"time"
)
const (
// TypeReg indicates a regular file
TypeReg = 0100000
// The following are header-only flags and may not have a data body.
TypeSocket = 0140000 // Socket
TypeSymlink = 0120000 // Symbolic link
TypeBlock = 060000 // Block device node
TypeDir = 040000 // Directory
TypeChar = 020000 // Character device node
TypeFifo = 010000 // FIFO node
)
const (
ModeSetuid = 04000 // Set uid
ModeSetgid = 02000 // Set gid
ModeSticky = 01000 // Save text (sticky bit)
ModeType = 0170000 // Mask for the type bits
ModePerm = 0777 // Unix permission bits
)
const (
// headerEOF is the value of the filename of the last header in a CPIO archive.
headerEOF = "TRAILER!!!"
)
// ErrHeader indicates there was an error decoding a CPIO header entry.
var ErrHeader = errors.New("cpio: invalid cpio header")
// A FileMode represents a file's mode and permission bits.
type FileMode uint32
func (m FileMode) String() string {
return fmt.Sprintf("%#o", m)
}
// IsDir reports whether m describes a directory. That is, it tests for the
// TypeDir bit being set in m.
func (m FileMode) IsDir() bool {
return m&TypeDir != 0
}
// IsRegular reports whether m describes a regular file. That is, it tests for
// the TypeReg bit being set in m.
func (m FileMode) IsRegular() bool {
return m&^ModePerm == TypeReg
}
// Perm returns the Unix permission bits in m.
func (m FileMode) Perm() FileMode {
return m & ModePerm
}
// A Header represents a single header in a CPIO archive. Some fields may not be
// populated.
//
// For forward compatibility, users that retrieve a Header from Reader.Next,
// mutate it in some ways, and then pass it back to Writer.WriteHeader should do
// so by creating a new Header and copying the fields that they are interested
// in preserving.
type Header struct {
Name string // Name of the file entry
Links int // Number of inbound links
Size int64 // Size in bytes
Mode FileMode // Permission and mode bits
Uid int // User id of the owner
Guid int // Group id of the owner
ModTime time.Time // Modification time
Checksum uint32 // Computed checksum
DeviceID int
Inode int64 // Inode number
pad int64 // bytes to pad before next header
}
// FileInfo returns an fs.FileInfo for the Header.
func (h *Header) FileInfo() os.FileInfo {
return fileInfo{h}
}
// FileInfoHeader creates a partially-populated Header from fi. If fi describes
// a symlink, FileInfoHeader records link as the link target. If fi describes a
// directory, a slash is appended to the name.
//
// Since fs.FileInfo's Name method returns only the base name of the file it
// describes, it may be necessary to modify Header.Name to provide the full path
// name of the file.
func FileInfoHeader(fi os.FileInfo) (*Header, error) {
if fi == nil {
return nil, errors.New("cpio: FileInfo is nil")
}
if sys, ok := fi.Sys().(*Header); ok {
// This FileInfo came from a Header (not the OS). Return a copy of the
// original Header.
h := &Header{}
*h = *sys
return h, nil
}
fm := fi.Mode()
h := &Header{
Name: fi.Name(),
Mode: FileMode(fi.Mode().Perm()), // or'd with Mode* constants later
ModTime: fi.ModTime(),
Size: fi.Size(),
}
switch {
case fm.IsRegular():
h.Mode |= TypeReg
case fi.IsDir():
h.Mode |= TypeDir
h.Name += "/"
h.Size = 0
case fm&os.ModeSymlink != 0:
h.Mode |= TypeSymlink
case fm&os.ModeDevice != 0:
if fm&os.ModeCharDevice != 0 {
h.Mode |= TypeChar
} else {
h.Mode |= TypeBlock
}
case fm&os.ModeNamedPipe != 0:
h.Mode |= TypeFifo
case fm&os.ModeSocket != 0:
h.Mode |= TypeSocket
default:
return nil, fmt.Errorf("cpio: unknown file mode %v", fm)
}
if fm&os.ModeSetuid != 0 {
h.Mode |= ModeSetuid
}
if fm&os.ModeSetgid != 0 {
h.Mode |= ModeSetgid
}
if fm&os.ModeSticky != 0 {
h.Mode |= ModeSticky
}
return h, nil
}