forked from zach-klippenstein/adbfs
/
util.go
127 lines (111 loc) · 3.29 KB
/
util.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
package adbfs
import (
"bytes"
"fmt"
"os"
"sync/atomic"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/zach-klippenstein/goadb"
)
type AtomicBool int32
func (b *AtomicBool) Value() bool {
return atomic.LoadInt32((*int32)(b)) != 0
}
// CompareAndSwap sets the value to newVal iff the current value is oldVal.
// If the comparison was successful, returns true.
func (b *AtomicBool) CompareAndSwap(oldVal, newVal bool) (swapped bool) {
var oldIntVal int32 = 0
if oldVal {
oldIntVal = 1
}
var newIntVal int32 = 0
if newVal {
newIntVal = 1
}
return atomic.CompareAndSwapInt32((*int32)(b), oldIntVal, newIntVal)
}
// asFuseDirEntries reads directory entries from a goadb DirEntries and returns them as a
// list of fuse DirEntry objects.
func asFuseDirEntries(entries []*goadb.DirEntry) (result []fuse.DirEntry) {
result = make([]fuse.DirEntry, len(entries))
for i, entry := range entries {
result[i] = fuse.DirEntry{
Name: entry.Name,
Mode: osFileModeToFuseFileMode(entry.Mode),
}
}
return
}
// asFuseAttr creates a fuse Attr struct that contains the information from a goadb DirEntry.
func asFuseAttr(entry *goadb.DirEntry, attr *fuse.Attr) {
*attr = fuse.Attr{
Mode: osFileModeToFuseFileMode(entry.Mode),
Size: uint64(entry.Size),
Mtime: uint64(entry.ModifiedAt.Unix()),
}
}
// osFileModeToFuseFileMode converts a standard os.FileMode to the bit array used
// by the fuse package. Permissions, regular/dir modes, symlinks, and named pipes
// are the only bits that are converted.
func osFileModeToFuseFileMode(inMode os.FileMode) (outMode uint32) {
if inMode.IsRegular() {
outMode |= fuse.S_IFREG
}
if inMode.IsDir() {
outMode |= fuse.S_IFDIR
}
if inMode&os.ModeSymlink == os.ModeSymlink {
outMode |= fuse.S_IFLNK
}
if inMode&os.ModeNamedPipe == os.ModeNamedPipe {
outMode |= fuse.S_IFIFO
}
outMode |= uint32(inMode.Perm())
return
}
// newLoggingFile returns a file object that logs all operations performed on it.
func newLoggingFile(file nodefs.File, path string) nodefs.File {
return &WrappingFile{
File: file,
BeforeCall: func(f *WrappingFile, method string, args ...interface{}) interface{} {
return StartFileOperation(method, path, formatArgsListForLog(args...))
},
AfterCall: func(f *WrappingFile, call interface{}, status *fuse.Status, results ...interface{}) {
logEntry := call.(*LogEntry)
if status != nil {
logEntry.Status(fuseStatusToErrno(*status))
}
logEntry.Result(formatArgsListForLog(results...))
logEntry.FinishOperation()
},
}
}
func formatArgsListForLog(args ...interface{}) string {
if len(args) == 0 {
return ""
}
summarizeForLog(args)
var buffer bytes.Buffer
buffer.WriteRune('[')
for i, item := range args {
fmt.Fprintf(&buffer, "%#v", item)
if i < len(args)-1 {
buffer.WriteString(", ")
}
}
buffer.WriteRune(']')
return buffer.String()
}
// summarizeByteSlices replaces all elements of the passed slice that are of type []byte with
// their length and type, so for logging they neither show sensitive data nor flood the log.
func summarizeForLog(vals []interface{}) {
for i, val := range vals {
switch val := val.(type) {
case []byte:
vals[i] = fmt.Sprintf("[]byte(%d)", len(val))
case fuse.ReadResult:
vals[i] = fmt.Sprintf("fuse.ReadResult(%d)", val.Size())
}
}
}