forked from karrick/godirwalk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dirent.go
152 lines (131 loc) · 4.84 KB
/
dirent.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
146
147
148
149
150
151
152
package godirwalk
import (
"os"
"path/filepath"
)
// Dirent stores the name and file system mode type of discovered file system
// entries.
type Dirent struct {
name string // base name of the file system entry.
path string // path name of the file system entry.
modeType os.FileMode // modeType is the type of file system entry.
size int64
mtime int64
}
// NewDirent returns a newly initialized Dirent structure, or an error. This
// function does not follow symbolic links.
//
// This function is rarely used, as Dirent structures are provided by other
// functions in this library that read and walk directories, but is provided,
// however, for the occasion when a program needs to create a Dirent.
func NewDirent(osPathname string) (*Dirent, error) {
modeType, err := modeType(osPathname)
if err != nil {
return nil, err
}
return &Dirent{
name: filepath.Base(osPathname),
path: filepath.Dir(osPathname),
modeType: modeType,
size: -1,
mtime: -1,
}, nil
}
// IsDir returns true if and only if the Dirent represents a file system
// directory. Note that on some operating systems, more than one file mode bit
// may be set for a node. For instance, on Windows, a symbolic link that points
// to a directory will have both the directory and the symbolic link bits set.
func (de Dirent) IsDir() bool { return de.modeType&os.ModeDir != 0 }
// IsDirOrSymlinkToDir returns true if and only if the Dirent represents a file
// system directory, or a symbolic link to a directory. Note that if the Dirent
// is not a directory but is a symbolic link, this method will resolve by
// sending a request to the operating system to follow the symbolic link.
func (de Dirent) IsDirOrSymlinkToDir() (bool, error) {
if de.IsDir() {
return true, nil
}
if !de.IsSymlink() {
return false, nil
}
// Does this symlink point to a directory?
info, err := os.Stat(filepath.Join(de.path, de.name))
if err != nil {
return false, err
}
return info.IsDir(), nil
}
// IsRegular returns true if and only if the Dirent represents a regular file.
// That is, it ensures that no mode type bits are set.
func (de Dirent) IsRegular() bool { return de.modeType&os.ModeType == 0 }
// IsSymlink returns true if and only if the Dirent represents a file system
// symbolic link. Note that on some operating systems, more than one file mode
// bit may be set for a node. For instance, on Windows, a symbolic link that
// points to a directory will have both the directory and the symbolic link bits
// set.
func (de Dirent) IsSymlink() bool { return de.modeType&os.ModeSymlink != 0 }
// IsDevice returns true if and only if the Dirent represents a device file.
func (de Dirent) IsDevice() bool { return de.modeType&os.ModeDevice != 0 }
// ModeType returns the mode bits that specify the file system node type. We
// could make our own enum-like data type for encoding the file type, but Go's
// runtime already gives us architecture independent file modes, as discussed in
// `os/types.go`:
//
// Go's runtime FileMode type has same definition on all systems, so that
// information about files can be moved from one system to another portably.
func (de Dirent) ModeType() os.FileMode { return de.modeType }
// Name returns the base name of the file system entry.
func (de Dirent) Name() string { return de.name }
// Size returns the size of the file system entry.
func (de *Dirent) Size() int64 {
if de.size == -1 {
var fi os.FileInfo
var err error
pathname := de.path + "/" + de.name
fi, err = os.Lstat(pathname)
if err != nil {
return -1
}
de.size = fi.Size()
de.mtime = fi.ModTime().Unix()
if de.mtime <= 0 {
de.mtime = 86401
}
}
return de.size
}
// Time returns the modification time (UNIX) of the file system entry.
func (de *Dirent) Time() int64 {
if de.mtime == -1 {
var fi os.FileInfo
var err error
pathname := de.path + "/" + de.name
fi, err = os.Lstat(pathname)
if err != nil {
return -1
}
de.size = fi.Size()
de.mtime = fi.ModTime().Unix()
if de.mtime <= 0 {
de.mtime = 86401
}
}
return de.mtime
}
// reset releases memory held by entry err and name, and resets mode type to 0.
func (de *Dirent) reset() {
de.name = ""
de.path = ""
de.modeType = 0
de.size = -1
de.mtime = -1
}
// Dirents represents a slice of Dirent pointers, which are sortable by base
// name. This type satisfies the `sort.Interface` interface.
type Dirents []*Dirent
// Len returns the count of Dirent structures in the slice.
func (l Dirents) Len() int { return len(l) }
// Less returns true if and only if the base name of the element specified by
// the first index is lexicographically less than that of the second index.
func (l Dirents) Less(i, j int) bool { return l[i].name < l[j].name }
// Swap exchanges the two Dirent entries specified by the two provided indexes.
func (l Dirents) Swap(i, j int) { l[i], l[j] = l[j], l[i] }