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
|
package main
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"syscall"
"github.com/hanwen/go-fuse/fuse"
"github.com/rfjakob/gocryptfs/internal/exitcodes"
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
"github.com/rfjakob/gocryptfs/internal/tlog"
)
type fsckObj struct {
fs *fusefrontend.FS
errorCount int
}
// Recursively check dir for corruption
func (ck *fsckObj) dir(path string) {
//fmt.Printf("ck.dir %q\n", path)
entries, status := ck.fs.OpenDir(path, nil)
if !status.Ok() {
fmt.Printf("fsck: error opening dir %q: %v\n", path, status)
ck.errorCount++
return
}
// Sort alphabetically
sort.Sort(sortableDirEntries(entries))
for _, entry := range entries {
if entry.Name == "." || entry.Name == ".." {
continue
}
nextPath := filepath.Join(path, entry.Name)
filetype := entry.Mode & syscall.S_IFMT
//fmt.Printf(" %q %x\n", entry.Name, entry.Mode)
switch filetype {
case syscall.S_IFDIR:
ck.dir(nextPath)
case syscall.S_IFREG:
ck.file(nextPath)
case syscall.S_IFLNK:
ck.symlink(nextPath)
case syscall.S_IFIFO, syscall.S_IFSOCK, syscall.S_IFBLK, syscall.S_IFCHR:
// nothing to check
default:
fmt.Printf("fsck: unhandle file type %x\n", filetype)
}
}
}
func (ck *fsckObj) symlink(path string) {
_, status := ck.fs.Readlink(path, nil)
if !status.Ok() {
fmt.Printf("fsck: error reading symlink %q: %v\n", path, status)
ck.errorCount++
}
}
// check file for corruption
func (ck *fsckObj) file(path string) {
//fmt.Printf("ck.file %q\n", path)
f, status := ck.fs.Open(path, syscall.O_RDONLY, nil)
if !status.Ok() {
fmt.Printf("fsck: error opening file %q: %v\n", path, status)
ck.errorCount++
return
}
defer f.Release()
buf := make([]byte, fuse.MAX_KERNEL_WRITE)
var off int64
for {
result, status := f.Read(buf, off)
if !status.Ok() {
fmt.Printf("fsck: error reading file %q at offset %d: %v\n", path, off, status)
ck.errorCount++
return
}
// EOF
if result.Size() == 0 {
return
}
off += int64(result.Size())
}
}
func fsck(args *argContainer) {
if args.reverse {
tlog.Fatal.Printf("Running -fsck with -reverse is not supported")
os.Exit(exitcodes.Usage)
}
args.allow_other = false
pfs, wipeKeys := initFuseFrontend(args)
defer wipeKeys()
fs := pfs.(*fusefrontend.FS)
ck := fsckObj{
fs: fs,
}
ck.dir("")
fmt.Printf("fsck: found %d problems\n", ck.errorCount)
if ck.errorCount != 0 {
os.Exit(exitcodes.FsckErrors)
}
}
type sortableDirEntries []fuse.DirEntry
func (s sortableDirEntries) Len() int {
return len(s)
}
func (s sortableDirEntries) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s sortableDirEntries) Less(i, j int) bool {
return strings.Compare(s[i].Name, s[j].Name) < 0
}
|