1package filexfer
2
3// FileMode represents a file’s mode and permission bits.
4// The bits are defined according to POSIX standards,
5// and may not apply to the OS being built for.
6type FileMode uint32
7
8// Permission flags, defined here to avoid potential inconsistencies in individual OS implementations.
9const (
10	ModePerm       FileMode = 0o0777 // S_IRWXU | S_IRWXG | S_IRWXO
11	ModeUserRead   FileMode = 0o0400 // S_IRUSR
12	ModeUserWrite  FileMode = 0o0200 // S_IWUSR
13	ModeUserExec   FileMode = 0o0100 // S_IXUSR
14	ModeGroupRead  FileMode = 0o0040 // S_IRGRP
15	ModeGroupWrite FileMode = 0o0020 // S_IWGRP
16	ModeGroupExec  FileMode = 0o0010 // S_IXGRP
17	ModeOtherRead  FileMode = 0o0004 // S_IROTH
18	ModeOtherWrite FileMode = 0o0002 // S_IWOTH
19	ModeOtherExec  FileMode = 0o0001 // S_IXOTH
20
21	ModeSetUID FileMode = 0o4000 // S_ISUID
22	ModeSetGID FileMode = 0o2000 // S_ISGID
23	ModeSticky FileMode = 0o1000 // S_ISVTX
24
25	ModeType       FileMode = 0xF000 // S_IFMT
26	ModeNamedPipe  FileMode = 0x1000 // S_IFIFO
27	ModeCharDevice FileMode = 0x2000 // S_IFCHR
28	ModeDir        FileMode = 0x4000 // S_IFDIR
29	ModeDevice     FileMode = 0x6000 // S_IFBLK
30	ModeRegular    FileMode = 0x8000 // S_IFREG
31	ModeSymlink    FileMode = 0xA000 // S_IFLNK
32	ModeSocket     FileMode = 0xC000 // S_IFSOCK
33)
34
35// IsDir reports whether m describes a directory.
36// That is, it tests for m.Type() == ModeDir.
37func (m FileMode) IsDir() bool {
38	return (m & ModeType) == ModeDir
39}
40
41// IsRegular reports whether m describes a regular file.
42// That is, it tests for m.Type() == ModeRegular
43func (m FileMode) IsRegular() bool {
44	return (m & ModeType) == ModeRegular
45}
46
47// Perm returns the POSIX permission bits in m (m & ModePerm).
48func (m FileMode) Perm() FileMode {
49	return (m & ModePerm)
50}
51
52// Type returns the type bits in m (m & ModeType).
53func (m FileMode) Type() FileMode {
54	return (m & ModeType)
55}
56
57// String returns a `-rwxrwxrwx` style string representing the `ls -l` POSIX permissions string.
58func (m FileMode) String() string {
59	var buf [10]byte
60
61	switch m.Type() {
62	case ModeRegular:
63		buf[0] = '-'
64	case ModeDir:
65		buf[0] = 'd'
66	case ModeSymlink:
67		buf[0] = 'l'
68	case ModeDevice:
69		buf[0] = 'b'
70	case ModeCharDevice:
71		buf[0] = 'c'
72	case ModeNamedPipe:
73		buf[0] = 'p'
74	case ModeSocket:
75		buf[0] = 's'
76	default:
77		buf[0] = '?'
78	}
79
80	const rwx = "rwxrwxrwx"
81	for i, c := range rwx {
82		if m&(1<<uint(9-1-i)) != 0 {
83			buf[i+1] = byte(c)
84		} else {
85			buf[i+1] = '-'
86		}
87	}
88
89	if m&ModeSetUID != 0 {
90		if buf[3] == 'x' {
91			buf[3] = 's'
92		} else {
93			buf[3] = 'S'
94		}
95	}
96
97	if m&ModeSetGID != 0 {
98		if buf[6] == 'x' {
99			buf[6] = 's'
100		} else {
101			buf[6] = 'S'
102		}
103	}
104
105	if m&ModeSticky != 0 {
106		if buf[9] == 'x' {
107			buf[9] = 't'
108		} else {
109			buf[9] = 'T'
110		}
111	}
112
113	return string(buf[:])
114}
115