-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathStat.swift
377 lines (312 loc) · 8.9 KB
/
Stat.swift
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
//
// Stat.swift
// SwiftRuby
//
// Created by John Holdsworth on 26/09/2015.
// Copyright © 2015 John Holdsworth. All rights reserved.
//
// $Id: //depot/SwiftRuby/Stat.swift#10 $
//
// Repo: https://github.com/RubyNative/SwiftRuby
//
// See: http://ruby-doc.org/core-2.2.3/File/Stat.html
//
import Darwin
// from <sys/stat.h> (not in Foundation)
/* File mode */
/* Read, write, execute/search by owner */
public let S_IRWXU: Int = 0o000700 /* [XSI] RWX mask for owner */
public let S_IRUSR: Int = 0o000400 /* [XSI] R for owner */
public let S_IWUSR: Int = 0o000200 /* [XSI] W for owner */
public let S_IXUSR: Int = 0o000100 /* [XSI] X for owner */
/* Read, write, execute/search by group */
public let S_IRWXG: Int = 0o000070 /* [XSI] RWX mask for group */
public let S_IRGRP: Int = 0o000040 /* [XSI] R for group */
public let S_IWGRP: Int = 0o000020 /* [XSI] W for group */
public let S_IXGRP: Int = 0o000010 /* [XSI] X for group */
/* Read, write, execute/search by others */
public let S_IRWXO: Int = 0o000007 /* [XSI] RWX mask for other */
public let S_IROTH: Int = 0o000004 /* [XSI] R for other */
public let S_IWOTH: Int = 0o000002 /* [XSI] W for other */
public let S_IXOTH: Int = 0o000001 /* [XSI] X for other */
public let S_ISUID: Int = 0o004000 /* [XSI] set user id on execution */
public let S_ISGID: Int = 0o002000 /* [XSI] set group id on execution */
public let S_ISVTX: Int = 0o001000 /* [XSI] directory restrcted delete */
public let S_IFMT : Int = 0o170000 /* [XSI] type of file mask */
public let S_IFIFO: Int = 0o010000 /* [XSI] named pipe (fifo) */
public let S_IFCHR: Int = 0o020000 /* [XSI] character special */
public let S_IFDIR: Int = 0o040000 /* [XSI] directory */
public let S_IFBLK: Int = 0o060000 /* [XSI] block special */
public let S_IFREG: Int = 0o100000 /* [XSI] regular */
public let S_IFLNK: Int = 0o120000 /* [XSI] symbolic link */
public let S_IFSOCK:Int = 0o140000 /* [XSI] socket */
/* Linux only? */
public let S_IRUGO = (S_IRUSR|S_IRGRP|S_IROTH)
public let S_IWUGO = (S_IWUSR|S_IWGRP|S_IWOTH)
public let S_IXUGO = (S_IXUSR|S_IXGRP|S_IXOTH)
public func S_ISBLK(_ m: Int) -> Bool {
return (((m) & S_IFMT) == S_IFBLK) /* block special */
}
public func S_ISCHR(_ m: Int) -> Bool {
return (((m) & S_IFMT) == S_IFCHR) /* char special */
}
public func S_ISDIR(_ m: Int) -> Bool {
return (((m) & S_IFMT) == S_IFDIR) /* directory */
}
public func S_ISFIFO(_ m: Int) -> Bool {
return (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */
}
public func S_ISREG(_ m: Int) -> Bool {
return (((m) & S_IFMT) == S_IFREG) /* regular file */
}
public func S_ISLNK(_ m: Int) -> Bool {
return (((m) & S_IFMT) == S_IFLNK) /* symbolic link */
}
public func S_ISSOCK(_ m: Int) -> Bool {
return (((m) & S_IFMT) == S_IFSOCK) /* socket */
}
public func ==(lhs: Stat, rhs: Stat) -> Bool {
return lhs.dev == rhs.dev && lhs.ino == rhs.ino
}
open class Stat : RubyObject {
open var info = stat()
open class func new(_ filename: string_like, statLink: Bool = false, file: StaticString = #file, line: UInt = #line) -> Stat? {
return Stat(filename, statLink: statLink, file: file, line: line)
}
public convenience init?(fd: Int, file: StaticString, line: UInt) {
self.init()
if !unixOK("Stat.fstat #\(fd)", fstat(Int32(fd), &info), file: file, line: line) || info.st_dev == 0 {
return nil
}
}
public convenience init?(_ filepath: string_like, statLink: Bool = false, file: StaticString?, line: UInt = 0) {
self.init()
if statLink {
if !unixOK("Stat.lstat \(filepath.to_s)", lstat(filepath.to_s, &info), file: file, line: line) {
return nil
}
}
else {
if !unixOK("Stat.stat \(filepath.to_s)", stat(filepath.to_s, &info), file: file, line: line) {
return nil
}
}
}
// MARK: Instance methods
open var atime: Time {
return Time(spec: info.st_atimespec)
}
open var birthtime: Time {
return Time(spec: info.st_ctimespec)
}
open var blksize: Int {
return Int(info.st_blksize)
}
open var blockdev: Bool {
return S_ISBLK(mode)
}
open var blocks: Int {
return Int(info.st_blocks)
}
open var chardev: Bool {
return S_ISCHR(mode)
}
open var ctime: Time {
return Time(spec: info.st_ctimespec)
}
open var dev: Int {
return Int(info.st_dev)
}
open var directory: Bool {
return S_ISDIR(mode)
}
open var executable: Bool {
if geteuid() == 0 {
return true
}
if owned {
return mode & S_IXUSR != 0
}
if grpowned {
return mode & S_IXGRP != 0
}
if mode & S_IXOTH == 0 {
return false
}
return true
}
open var executable_real: Bool {
if getuid() == 0 {
return true
}
if rowned {
return mode & S_IXUSR != 0
}
if rgrpowned {
return mode & S_IXGRP != 0
}
if mode & S_IXOTH == 0 {
return false
}
return true
}
open var file: Bool {
return S_ISREG(mode)
}
open var ftype: String {
return
S_ISREG(mode) ? "file" :
S_ISDIR(mode) ? "directory" :
S_ISCHR(mode) ? "characterSpecial" :
S_ISBLK(mode) ? "blockSpecial" :
S_ISFIFO(mode) ? "fifo" :
S_ISLNK(mode) ? "link" :
S_ISSOCK(mode) ? "socket" :
"unknown"
}
open var gid: Int {
return Int(info.st_gid)
}
open var grpowned: Bool {
let egid = gid_t(getegid())
var groups = [gid_t](repeating: 0, count: 1000)
let gcount = getgroups(Int32(groups.count), &groups)
for g in 0..<Int(gcount) {
if groups[g] == egid {
return true
}
}
return false
}
open var ino: Int {
return Int(info.st_ino)
}
open var mode: Int {
return Int(info.st_mode)
}
open var mtime: Time {
return Time(spec: info.st_mtimespec)
}
open var nlink: Int {
return Int(info.st_nlink)
}
open var owned: Bool {
return geteuid() == info.st_uid
}
open var pipe: Bool {
return S_ISFIFO(mode)
}
open var rdev: Int {
return Int(info.st_rdev)
}
open var rdev_major: Int? {
return nil
}
open var rdev_minor: Int? {
return nil
}
open var readable: Bool {
if geteuid() == 0 {
return true
}
if owned {
return mode & S_IRUSR != 0
}
if grpowned {
return mode & S_IRGRP != 0
}
if mode & S_IROTH == 0 {
return false
}
return true
}
open var readable_real: Bool {
if getuid() == 0 {
return true
}
if rowned {
return mode & S_IRUSR != 0
}
if rgrpowned {
return mode & S_IRGRP != 0
}
if mode & S_IROTH == 0 {
return false
}
return true
}
open var rowned: Bool {
return getuid() == info.st_uid
}
open var rgrpowned: Bool {
let egid = gid_t(getgid())
var groups = [gid_t](repeating: 0, count: 1000)
let gcount = getgroups(Int32(groups.count), &groups)
for g in 0..<Int(gcount) {
if groups[g] == egid {
return true
}
}
return false
}
open var setgid: Bool {
return (mode & S_ISGID) != 0
}
open var setuid: Bool {
return (mode & S_ISUID) != 0
}
open var size: Int {
return Int(info.st_size)
}
open var socket: Bool {
return S_ISSOCK(mode)
}
open var sticky: Bool {
return mode & S_ISVTX != 0
}
open var symlink: Bool {
return S_ISLNK(mode)
}
open var uid: Int {
return Int(info.st_uid)
}
open var world_readable: Bool {
return mode & S_IROTH != 0
}
open var world_writable: Bool {
return mode & S_IWOTH != 0
}
open var writable: Bool {
if geteuid() == 0 {
return true
}
if owned {
return mode & S_IWUSR != 0
}
if grpowned {
return mode & S_IWGRP != 0
}
if mode & S_IWOTH == 0 {
return false
}
return true
}
open var writable_real: Bool {
if getuid() == 0 {
return true
}
if rowned {
return mode & S_IWUSR != 0
}
if rgrpowned {
return mode & S_IWGRP != 0
}
if mode & S_IWOTH == 0 {
return false
}
return true
}
open var zero: Bool {
return info.st_size == 0
}
}