v2api: make fsck compile again
Horribly broken, but it compiles. .../tests/fsck$ ./run_fsck.bash Reading password from extpass program "echo", arguments: ["test"] Decrypting master key OpenDir ".": invalid entry "invalid_file_name.3": illegal base64 data at input byte 17 OpenDir ".": invalid entry "invalid_file_name_2": bad message fsck: corrupt entry in dir "": "invalid_file_name.3" fsck: corrupt entry in dir "": "invalid_file_name_2" OpenDir ".": invalid entry "invalid_file_name____1": bad message fsck: corrupt entry in dir "": "invalid_file_name____1" fsck: error stating file ".go-fuse.5577006791947779410/deleted": no such file or directory fsck: error listing xattrs on ".go-fuse.13260572831089785859/deleted": no such file or directory fsck: error opening dir "i10488239 (dir): ": no such file or directory fsck: error reading symlink ".go-fuse.10667007354186551956/deleted": no such file or directory fsck: error listing xattrs on ".go-fuse.11998794077335055257/deleted": no such file or directory [...]
This commit is contained in:
parent
6b7ff09373
commit
751f237993
127
fsck.go
127
fsck.go
@ -1,6 +1,3 @@
|
|||||||
// +build ignore
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -8,13 +5,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
"github.com/hanwen/go-fuse/v2/fuse"
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
"github.com/hanwen/go-fuse/v2/fuse/nodefs"
|
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/exitcodes"
|
"github.com/rfjakob/gocryptfs/internal/exitcodes"
|
||||||
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
||||||
@ -22,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type fsckObj struct {
|
type fsckObj struct {
|
||||||
fs *fusefrontend.FS
|
rootNode *fusefrontend.RootNode
|
||||||
// List of corrupt files
|
// List of corrupt files
|
||||||
corruptList []string
|
corruptList []string
|
||||||
// List of skipped files
|
// List of skipped files
|
||||||
@ -55,7 +51,7 @@ func (ck *fsckObj) markSkipped(path string) {
|
|||||||
func (ck *fsckObj) watchMitigatedCorruptionsOpenDir(path string) {
|
func (ck *fsckObj) watchMitigatedCorruptionsOpenDir(path string) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case item := <-ck.fs.MitigatedCorruptions:
|
case item := <-ck.rootNode.MitigatedCorruptions:
|
||||||
fmt.Printf("fsck: corrupt entry in dir %q: %q\n", path, item)
|
fmt.Printf("fsck: corrupt entry in dir %q: %q\n", path, item)
|
||||||
ck.markCorrupt(filepath.Join(path, item))
|
ck.markCorrupt(filepath.Join(path, item))
|
||||||
case <-ck.watchDone:
|
case <-ck.watchDone:
|
||||||
@ -65,30 +61,39 @@ func (ck *fsckObj) watchMitigatedCorruptionsOpenDir(path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recursively check dir for corruption
|
// Recursively check dir for corruption
|
||||||
func (ck *fsckObj) dir(path string) {
|
func (ck *fsckObj) dir(n *fusefrontend.Node) {
|
||||||
tlog.Debug.Printf("ck.dir %q\n", path)
|
path := n.Path()
|
||||||
ck.xattrs(path)
|
tlog.Debug.Printf("ck.dir %q\n")
|
||||||
|
ck.xattrs(n)
|
||||||
// Run OpenDir and catch transparently mitigated corruptions
|
// Run OpenDir and catch transparently mitigated corruptions
|
||||||
go ck.watchMitigatedCorruptionsOpenDir(path)
|
go ck.watchMitigatedCorruptionsOpenDir(path)
|
||||||
entries, status := ck.fs.OpenDir(path, nil)
|
entries, errno := n.Readdir(nil)
|
||||||
ck.watchDone <- struct{}{}
|
ck.watchDone <- struct{}{}
|
||||||
// Also catch non-mitigated corruptions
|
// Also catch non-mitigated corruptions
|
||||||
if !status.Ok() {
|
if errno != 0 {
|
||||||
fmt.Printf("fsck: error opening dir %q: %v\n", path, status)
|
fmt.Printf("fsck: error opening dir %q: %v\n", n, errno)
|
||||||
if status == fuse.EACCES && !runsAsRoot() {
|
if errno == syscall.EACCES && !runsAsRoot() {
|
||||||
ck.markSkipped(path)
|
ck.markSkipped(path)
|
||||||
} else {
|
} else {
|
||||||
ck.markCorrupt(path)
|
ck.markCorrupt(path)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Sort alphabetically
|
for entries.HasNext() {
|
||||||
sort.Sort(sortableDirEntries(entries))
|
entry, errno := entries.Next()
|
||||||
for _, entry := range entries {
|
if errno != 0 {
|
||||||
|
fmt.Printf("fsck: dirstream error: %v\n", errno)
|
||||||
|
break
|
||||||
|
}
|
||||||
if entry.Name == "." || entry.Name == ".." {
|
if entry.Name == "." || entry.Name == ".." {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nextPath := filepath.Join(path, entry.Name)
|
tmp, errno := n.Lookup(nil, entry.Name, &fuse.EntryOut{})
|
||||||
|
if errno != 0 {
|
||||||
|
ck.markCorrupt(filepath.Join(path, entry.Name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
nextPath := tmp.Operations().(*fusefrontend.Node)
|
||||||
filetype := entry.Mode & syscall.S_IFMT
|
filetype := entry.Mode & syscall.S_IFMT
|
||||||
//fmt.Printf(" %q %x\n", entry.Name, entry.Mode)
|
//fmt.Printf(" %q %x\n", entry.Name, entry.Mode)
|
||||||
switch filetype {
|
switch filetype {
|
||||||
@ -106,11 +111,12 @@ func (ck *fsckObj) dir(path string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ck *fsckObj) symlink(path string) {
|
func (ck *fsckObj) symlink(n *fusefrontend.Node) {
|
||||||
_, status := ck.fs.Readlink(path, nil)
|
_, errno := n.Readlink(nil)
|
||||||
if !status.Ok() {
|
if errno != 0 {
|
||||||
|
path := n.Path()
|
||||||
ck.markCorrupt(path)
|
ck.markCorrupt(path)
|
||||||
fmt.Printf("fsck: error reading symlink %q: %v\n", path, status)
|
fmt.Printf("fsck: error reading symlink %q: %v\n", path, errno)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +124,7 @@ func (ck *fsckObj) symlink(path string) {
|
|||||||
func (ck *fsckObj) watchMitigatedCorruptionsRead(path string) {
|
func (ck *fsckObj) watchMitigatedCorruptionsRead(path string) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case item := <-ck.fs.MitigatedCorruptions:
|
case item := <-ck.rootNode.MitigatedCorruptions:
|
||||||
fmt.Printf("fsck: corrupt file %q (inode %s)\n", path, item)
|
fmt.Printf("fsck: corrupt file %q (inode %s)\n", path, item)
|
||||||
ck.markCorrupt(path)
|
ck.markCorrupt(path)
|
||||||
case <-ck.watchDone:
|
case <-ck.watchDone:
|
||||||
@ -128,12 +134,14 @@ func (ck *fsckObj) watchMitigatedCorruptionsRead(path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check file for corruption
|
// Check file for corruption
|
||||||
func (ck *fsckObj) file(path string) {
|
func (ck *fsckObj) file(n *fusefrontend.Node) {
|
||||||
|
path := n.Path()
|
||||||
tlog.Debug.Printf("ck.file %q\n", path)
|
tlog.Debug.Printf("ck.file %q\n", path)
|
||||||
attr, status := ck.fs.GetAttr(path, nil)
|
var attr fuse.AttrOut
|
||||||
if !status.Ok() {
|
errno := n.Getattr(nil, nil, &attr)
|
||||||
|
if errno != 0 {
|
||||||
ck.markCorrupt(path)
|
ck.markCorrupt(path)
|
||||||
fmt.Printf("fsck: error stating file %q: %v\n", path, status)
|
fmt.Printf("fsck: error stating file %q: %v\n", path, errno)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if attr.Nlink > 1 {
|
if attr.Nlink > 1 {
|
||||||
@ -144,18 +152,19 @@ func (ck *fsckObj) file(path string) {
|
|||||||
}
|
}
|
||||||
ck.seenInodes[attr.Ino] = struct{}{}
|
ck.seenInodes[attr.Ino] = struct{}{}
|
||||||
}
|
}
|
||||||
ck.xattrs(path)
|
ck.xattrs(n)
|
||||||
f, status := ck.fs.Open(path, syscall.O_RDONLY, nil)
|
tmp, _, errno := n.Open(nil, syscall.O_RDONLY)
|
||||||
if !status.Ok() {
|
if errno != 0 {
|
||||||
fmt.Printf("fsck: error opening file %q: %v\n", path, status)
|
fmt.Printf("fsck: error opening file %q: %v\n", path, errno)
|
||||||
if status == fuse.EACCES && !runsAsRoot() {
|
if errno == syscall.EACCES && !runsAsRoot() {
|
||||||
ck.markSkipped(path)
|
ck.markSkipped(path)
|
||||||
} else {
|
} else {
|
||||||
ck.markCorrupt(path)
|
ck.markCorrupt(path)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Release()
|
f := tmp.(*fusefrontend.File2)
|
||||||
|
defer f.Release(nil)
|
||||||
// 128 kiB of zeros
|
// 128 kiB of zeros
|
||||||
allZero := make([]byte, fuse.MAX_KERNEL_WRITE)
|
allZero := make([]byte, fuse.MAX_KERNEL_WRITE)
|
||||||
buf := make([]byte, fuse.MAX_KERNEL_WRITE)
|
buf := make([]byte, fuse.MAX_KERNEL_WRITE)
|
||||||
@ -165,10 +174,10 @@ func (ck *fsckObj) file(path string) {
|
|||||||
defer func() { ck.watchDone <- struct{}{} }()
|
defer func() { ck.watchDone <- struct{}{} }()
|
||||||
for {
|
for {
|
||||||
tlog.Debug.Printf("ck.file: read %d bytes from offset %d\n", len(buf), off)
|
tlog.Debug.Printf("ck.file: read %d bytes from offset %d\n", len(buf), off)
|
||||||
result, status := f.Read(buf, off)
|
result, errno := f.Read(nil, buf, off)
|
||||||
if !status.Ok() {
|
if errno != 0 {
|
||||||
ck.markCorrupt(path)
|
ck.markCorrupt(path)
|
||||||
fmt.Printf("fsck: error reading file %q (inum %d): %v\n", path, inum(f), status)
|
fmt.Printf("fsck: error reading file %q (inum %d): %v\n", path, inum(f), errno)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n := result.Size()
|
n := result.Size()
|
||||||
@ -182,8 +191,7 @@ func (ck *fsckObj) file(path string) {
|
|||||||
data := buf[:n]
|
data := buf[:n]
|
||||||
if bytes.Equal(data, allZero) {
|
if bytes.Equal(data, allZero) {
|
||||||
tlog.Debug.Printf("ck.file: trying to skip file hole\n")
|
tlog.Debug.Printf("ck.file: trying to skip file hole\n")
|
||||||
f2 := f.(*fusefrontend.File)
|
nextOff, err := f.SeekData(off)
|
||||||
nextOff, err := f2.SeekData(off)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
off = nextOff
|
off = nextOff
|
||||||
}
|
}
|
||||||
@ -195,7 +203,7 @@ func (ck *fsckObj) file(path string) {
|
|||||||
func (ck *fsckObj) watchMitigatedCorruptionsListXAttr(path string) {
|
func (ck *fsckObj) watchMitigatedCorruptionsListXAttr(path string) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case item := <-ck.fs.MitigatedCorruptions:
|
case item := <-ck.rootNode.MitigatedCorruptions:
|
||||||
fmt.Printf("fsck: corrupt xattr name on file %q: %q\n", path, item)
|
fmt.Printf("fsck: corrupt xattr name on file %q: %q\n", path, item)
|
||||||
ck.markCorrupt(path + " xattr:" + item)
|
ck.markCorrupt(path + " xattr:" + item)
|
||||||
case <-ck.watchDone:
|
case <-ck.watchDone:
|
||||||
@ -205,22 +213,32 @@ func (ck *fsckObj) watchMitigatedCorruptionsListXAttr(path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check xattrs on file/dir at path
|
// Check xattrs on file/dir at path
|
||||||
func (ck *fsckObj) xattrs(path string) {
|
func (ck *fsckObj) xattrs(n *fusefrontend.Node) {
|
||||||
// Run ListXAttr() and catch transparently mitigated corruptions
|
// Run ListXAttr() and catch transparently mitigated corruptions
|
||||||
|
path := n.Path()
|
||||||
go ck.watchMitigatedCorruptionsListXAttr(path)
|
go ck.watchMitigatedCorruptionsListXAttr(path)
|
||||||
attrs, status := ck.fs.ListXAttr(path, nil)
|
listBuf := make([]byte, 1024*1024)
|
||||||
|
cnt, errno := n.Listxattr(nil, listBuf)
|
||||||
ck.watchDone <- struct{}{}
|
ck.watchDone <- struct{}{}
|
||||||
// Also catch non-mitigated corruptions
|
// Also catch non-mitigated corruptions
|
||||||
if !status.Ok() {
|
if errno != 0 {
|
||||||
fmt.Printf("fsck: error listing xattrs on %q: %v\n", path, status)
|
fmt.Printf("fsck: error listing xattrs on %q: %v\n", path, errno)
|
||||||
ck.markCorrupt(path)
|
ck.markCorrupt(path)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if cnt == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Drop final trailing NULL byte
|
||||||
|
cnt--
|
||||||
|
listBuf = listBuf[:cnt]
|
||||||
|
attrs := bytes.Split(listBuf, []byte{0})
|
||||||
for _, a := range attrs {
|
for _, a := range attrs {
|
||||||
_, status := ck.fs.GetXAttr(path, a, nil)
|
getBuf := make([]byte, 1024*1024)
|
||||||
if !status.Ok() {
|
_, errno := n.Getxattr(nil, string(a), getBuf)
|
||||||
fmt.Printf("fsck: error reading xattr %q from %q: %v\n", a, path, status)
|
if errno != 0 {
|
||||||
if status == fuse.EACCES && !runsAsRoot() {
|
fmt.Printf("fsck: error reading xattr %q from %q: %v\n", a, path, errno)
|
||||||
|
if errno == syscall.EACCES && !runsAsRoot() {
|
||||||
ck.markSkipped(path)
|
ck.markSkipped(path)
|
||||||
} else {
|
} else {
|
||||||
ck.markCorrupt(path)
|
ck.markCorrupt(path)
|
||||||
@ -236,14 +254,15 @@ func fsck(args *argContainer) {
|
|||||||
}
|
}
|
||||||
args.allow_other = false
|
args.allow_other = false
|
||||||
pfs, wipeKeys := initFuseFrontend(args)
|
pfs, wipeKeys := initFuseFrontend(args)
|
||||||
fs := pfs.(*fusefrontend.FS)
|
fs.NewNodeFS(pfs, &fs.Options{})
|
||||||
fs.MitigatedCorruptions = make(chan string)
|
rn := pfs.(*fusefrontend.RootNode)
|
||||||
|
rn.MitigatedCorruptions = make(chan string)
|
||||||
ck := fsckObj{
|
ck := fsckObj{
|
||||||
fs: fs,
|
rootNode: rn,
|
||||||
watchDone: make(chan struct{}),
|
watchDone: make(chan struct{}),
|
||||||
seenInodes: make(map[uint64]struct{}),
|
seenInodes: make(map[uint64]struct{}),
|
||||||
}
|
}
|
||||||
ck.dir("")
|
ck.dir(&rn.Node)
|
||||||
wipeKeys()
|
wipeKeys()
|
||||||
if len(ck.corruptList) == 0 && len(ck.skippedList) == 0 {
|
if len(ck.corruptList) == 0 && len(ck.skippedList) == 0 {
|
||||||
tlog.Info.Printf("fsck summary: no problems found\n")
|
tlog.Info.Printf("fsck summary: no problems found\n")
|
||||||
@ -270,8 +289,8 @@ func (s sortableDirEntries) Less(i, j int) bool {
|
|||||||
return strings.Compare(s[i].Name, s[j].Name) < 0
|
return strings.Compare(s[i].Name, s[j].Name) < 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func inum(f nodefs.File) uint64 {
|
func inum(f *fusefrontend.File2) uint64 {
|
||||||
var a fuse.Attr
|
var a fuse.AttrOut
|
||||||
f.GetAttr(&a)
|
f.Getattr(nil, &a)
|
||||||
return a.Ino
|
return a.Ino
|
||||||
}
|
}
|
||||||
|
3
main.go
3
main.go
@ -313,8 +313,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
// "-fsck"
|
// "-fsck"
|
||||||
if args.fsck {
|
if args.fsck {
|
||||||
// TODO
|
fsck(&args)
|
||||||
//fsck(&args)
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
mount.go
1
mount.go
@ -316,7 +316,6 @@ func initFuseFrontend(args *argContainer) (rootNode fs.InodeEmbedder, wipeKeys f
|
|||||||
log.Panic("reverse mode must use AES-SIV, everything else is insecure")
|
log.Panic("reverse mode must use AES-SIV, everything else is insecure")
|
||||||
}
|
}
|
||||||
rootNode = fusefrontend_reverse.NewRootNode(frontendArgs, cEnc, nameTransform)
|
rootNode = fusefrontend_reverse.NewRootNode(frontendArgs, cEnc, nameTransform)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
rootNode = fusefrontend.NewRootNode(frontendArgs, cEnc, nameTransform)
|
rootNode = fusefrontend.NewRootNode(frontendArgs, cEnc, nameTransform)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user