-
Notifications
You must be signed in to change notification settings - Fork 44
/
filesystem.go
145 lines (125 loc) · 3.07 KB
/
filesystem.go
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
package desync
import (
"io"
"os"
"syscall"
"time"
)
func isDevice(m os.FileMode) bool {
return m&os.ModeDevice != 0
}
// FilesystemWriter is a filesystem implementation that supports untar'ing
// a catar archive to.
type FilesystemWriter interface {
CreateDir(n NodeDirectory) error
CreateFile(n NodeFile) error
CreateSymlink(n NodeSymlink) error
CreateDevice(n NodeDevice) error
}
// FilesystemReader is an interface for source filesystem to be used during
// tar operations. Next() is expected to return files and directories in a
// consistent and stable order and return io.EOF when no further files are available.
type FilesystemReader interface {
Next() (*File, error)
}
// File represents a filesystem object such as directory, file, symlink or device.
// It's used when creating archives from a source filesystem which can be a real
// OS filesystem, or another archive stream such as tar.
type File struct {
Name string
Path string
Mode os.FileMode
Size uint64
// Link target for symlinks
LinkTarget string
// Modification time
ModTime time.Time
// User/group IDs
Uid int
Gid int
// Major/Minor for character or block devices
DevMajor uint64
DevMinor uint64
// Extended attributes
Xattrs map[string]string
// File content. Nil for non-regular files.
Data io.ReadCloser
}
func (f *File) IsDir() bool {
return f.Mode.IsDir()
}
func (f *File) IsRegular() bool {
return f.Mode.IsRegular()
}
func (f *File) IsSymlink() bool {
return f.Mode&os.ModeSymlink != 0
}
func (f *File) IsDevice() bool {
return f.Mode&os.ModeDevice != 0
}
// Close closes the file data reader if any. It's safe to call
// for non-regular files as well.
func (f *File) Close() error {
if f.Data != nil {
return f.Data.Close()
}
return nil
}
// StatModeToFilemode converts syscall mode to Go's os.Filemode value.
func StatModeToFilemode(mode uint32) os.FileMode {
fm := os.FileMode(mode & 0777)
switch mode & syscall.S_IFMT {
case syscall.S_IFBLK:
fm |= os.ModeDevice
case syscall.S_IFCHR:
fm |= os.ModeDevice | os.ModeCharDevice
case syscall.S_IFDIR:
fm |= os.ModeDir
case syscall.S_IFIFO:
fm |= os.ModeNamedPipe
case syscall.S_IFLNK:
fm |= os.ModeSymlink
case syscall.S_IFSOCK:
fm |= os.ModeSocket
}
if mode&syscall.S_ISGID != 0 {
fm |= os.ModeSetgid
}
if mode&syscall.S_ISUID != 0 {
fm |= os.ModeSetuid
}
if mode&syscall.S_ISVTX != 0 {
fm |= os.ModeSticky
}
return fm
}
// FilemodeToStatMode converts Go's os.Filemode value into the syscall equivalent.
func FilemodeToStatMode(mode os.FileMode) uint32 {
o := uint32(mode.Perm())
switch m := mode & os.ModeType; m {
case os.ModeDevice:
o |= syscall.S_IFBLK
case os.ModeDevice | os.ModeCharDevice:
o |= syscall.S_IFCHR
case os.ModeDir:
o |= syscall.S_IFDIR
case os.ModeNamedPipe:
o |= syscall.S_IFIFO
case os.ModeSymlink:
o |= syscall.S_IFLNK
case os.ModeSocket:
o |= syscall.S_IFSOCK
default:
o |= syscall.S_IFREG
}
if mode&os.ModeSetuid != 0 {
o |= syscall.S_ISUID
}
if mode&os.ModeSetgid != 0 {
o |= syscall.S_ISGID
}
if mode&os.ModeSticky != 0 {
o |= syscall.S_ISVTX
}
return o
}