aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2018-04-01 21:23:32 +0200
committerJakob Unterwurzacher2018-04-02 16:38:18 +0200
commitf28d85fad599ffaef9a8e1f353911c81a6605d2f (patch)
tree1acc3514a5dde31e88ad13e8dc48818872e40d0f
parentfb06c65ee90e31d11cf37b3469f7d3336ae51184 (diff)
fsck: add initial implementation
Most corruption cases except xattr should be covered. With test filesystem. The output is still pretty ugly. xattr support will be added in the next commits.
-rw-r--r--fsck.go99
-rw-r--r--internal/exitcodes/exitcodes.go2
-rw-r--r--main.go1
-rw-r--r--tests/cli/cli_test.go18
l---------tests/fsck/broken_fs_v1.4/GUvJFSfy7S1AXUdy4pDRLw1
-rw-r--r--tests/fsck/broken_fs_v1.4/K2m0E6qzIfoLkVZJanoUiQ/mWEr9JLch2FW40qhbnPgpg0
-rw-r--r--tests/fsck/broken_fs_v1.4/OtrNpznB8aMTKPi6bopM2gbin0 -> 63 bytes
-rw-r--r--tests/fsck/broken_fs_v1.4/PnkpLqHimGudw4C3jFY-Yw/_y58usbKXq_YRPMKfC3TNw0
-rw-r--r--tests/fsck/broken_fs_v1.4/PnkpLqHimGudw4C3jFY-Yw/gocryptfs.diriv2
-rw-r--r--tests/fsck/broken_fs_v1.4/gocryptfs.conf20
-rw-r--r--tests/fsck/broken_fs_v1.4/gocryptfs.diriv2
-rw-r--r--tests/fsck/broken_fs_v1.4/invalid_file_name.30
-rw-r--r--tests/fsck/broken_fs_v1.4/invalid_file_name_20
-rw-r--r--tests/fsck/broken_fs_v1.4/invalid_file_name____10
-rw-r--r--tests/fsck/broken_fs_v1.4/qOA8a4yuvgbMFpz7277R8A1
l---------tests/fsck/broken_fs_v1.4/s-P7PcQDUcVkoeMDnC3EYA1
-rw-r--r--tests/fsck/broken_fs_v1.4/vDKs8a7UtM3PmEKk9wlPcAbin0 -> 77 bytes
-rw-r--r--tests/fsck/fsck_test.go26
-rwxr-xr-xtests/fsck/run_fsck.bash2
-rw-r--r--tests/test_helpers/helpers.go12
20 files changed, 170 insertions, 17 deletions
diff --git a/fsck.go b/fsck.go
index 645cf91..7741d19 100644
--- a/fsck.go
+++ b/fsck.go
@@ -1,9 +1,104 @@
package main
import (
- "log"
+ "fmt"
+ "os"
+ "path/filepath"
+ "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
+ }
+ 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) {
- log.Panic("Not yet implemented")
+ 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)
+ }
}
diff --git a/internal/exitcodes/exitcodes.go b/internal/exitcodes/exitcodes.go
index 209656c..36f2aae 100644
--- a/internal/exitcodes/exitcodes.go
+++ b/internal/exitcodes/exitcodes.go
@@ -61,6 +61,8 @@ const (
// Profiler - error occoured when trying to write cpu or memory profile or
// execution trace
Profiler = 25
+ // FsckErrors - the filesystem check found errors
+ FsckErrors = 26
)
// Err wraps an error with an associated numeric exit code
diff --git a/main.go b/main.go
index ff137c4..a69ec9e 100644
--- a/main.go
+++ b/main.go
@@ -287,5 +287,6 @@ func main() {
// "-fsck"
if args.fsck {
fsck(&args)
+ os.Exit(0)
}
}
diff --git a/tests/cli/cli_test.go b/tests/cli/cli_test.go
index 2cdaf37..2f27ec7 100644
--- a/tests/cli/cli_test.go
+++ b/tests/cli/cli_test.go
@@ -18,18 +18,6 @@ import (
var testPw = []byte("test")
-// Extract the exit code from an error value that was returned from
-// exec.Run()
-func extractExitCode(err error) int {
- if err == nil {
- return 0
- }
- // OMG this is convoluted
- err2 := err.(*exec.ExitError)
- code := err2.Sys().(syscall.WaitStatus).ExitStatus()
- return code
-}
-
func TestMain(m *testing.M) {
test_helpers.ResetTmpDir(false)
r := m.Run()
@@ -344,7 +332,7 @@ func TestMountPasswordIncorrect(t *testing.T) {
cDir := test_helpers.InitFS(t) // Create filesystem with password "test"
pDir := cDir + ".mnt"
err := test_helpers.Mount(cDir, pDir, false, "-extpass", "echo WRONG", "-wpanic=false")
- exitCode := extractExitCode(err)
+ exitCode := test_helpers.ExtractCmdExitCode(err)
if exitCode != exitcodes.PasswordIncorrect {
t.Errorf("want=%d, got=%d", exitcodes.PasswordIncorrect, exitCode)
}
@@ -373,7 +361,7 @@ func TestPasswdPasswordIncorrect(t *testing.T) {
t.Fatal(err)
}
err = cmd.Wait()
- exitCode := extractExitCode(err)
+ exitCode := test_helpers.ExtractCmdExitCode(err)
if exitCode != exitcodes.PasswordIncorrect {
t.Errorf("want=%d, got=%d", exitcodes.PasswordIncorrect, exitCode)
}
@@ -444,7 +432,7 @@ func TestMultipleOperationFlags(t *testing.T) {
//t.Logf("testing %v", args)
cmd := exec.Command(test_helpers.GocryptfsBinary, args...)
err := cmd.Run()
- exitCode := extractExitCode(err)
+ exitCode := test_helpers.ExtractCmdExitCode(err)
if exitCode != exitcodes.Usage {
t.Fatalf("this should have failed with code %d, but returned %d",
exitcodes.Usage, exitCode)
diff --git a/tests/fsck/broken_fs_v1.4/GUvJFSfy7S1AXUdy4pDRLw b/tests/fsck/broken_fs_v1.4/GUvJFSfy7S1AXUdy4pDRLw
new file mode 120000
index 0000000..7bbd005
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/GUvJFSfy7S1AXUdy4pDRLw
@@ -0,0 +1 @@
+RFPnVN8r1HjIrFVJ8PffC7ObzAIeBx3DQh8FbgvmbT8Ho8mU \ No newline at end of file
diff --git a/tests/fsck/broken_fs_v1.4/K2m0E6qzIfoLkVZJanoUiQ/mWEr9JLch2FW40qhbnPgpg b/tests/fsck/broken_fs_v1.4/K2m0E6qzIfoLkVZJanoUiQ/mWEr9JLch2FW40qhbnPgpg
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/K2m0E6qzIfoLkVZJanoUiQ/mWEr9JLch2FW40qhbnPgpg
diff --git a/tests/fsck/broken_fs_v1.4/OtrNpznB8aMTKPi6bopM2g b/tests/fsck/broken_fs_v1.4/OtrNpznB8aMTKPi6bopM2g
new file mode 100644
index 0000000..dab7c69
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/OtrNpznB8aMTKPi6bopM2g
Binary files differ
diff --git a/tests/fsck/broken_fs_v1.4/PnkpLqHimGudw4C3jFY-Yw/_y58usbKXq_YRPMKfC3TNw b/tests/fsck/broken_fs_v1.4/PnkpLqHimGudw4C3jFY-Yw/_y58usbKXq_YRPMKfC3TNw
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/PnkpLqHimGudw4C3jFY-Yw/_y58usbKXq_YRPMKfC3TNw
diff --git a/tests/fsck/broken_fs_v1.4/PnkpLqHimGudw4C3jFY-Yw/gocryptfs.diriv b/tests/fsck/broken_fs_v1.4/PnkpLqHimGudw4C3jFY-Yw/gocryptfs.diriv
new file mode 100644
index 0000000..178763a
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/PnkpLqHimGudw4C3jFY-Yw/gocryptfs.diriv
@@ -0,0 +1,2 @@
+f—`Êá
+{g*@w¹6£ \ No newline at end of file
diff --git a/tests/fsck/broken_fs_v1.4/gocryptfs.conf b/tests/fsck/broken_fs_v1.4/gocryptfs.conf
new file mode 100644
index 0000000..cedf571
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/gocryptfs.conf
@@ -0,0 +1,20 @@
+{
+ "Creator": "gocryptfs v1.4.4-13-ga4f3a7d-dirty",
+ "EncryptedKey": "yfnIx9uKv2ZX80KXOlfb4fWws3RNqvcjsx/Ajr0x4pRfg8NLqhWRpEUWGk8NSdVFXKWVDgdhSoYkbfVnFXl07g==",
+ "ScryptObject": {
+ "Salt": "R78m123zJxxO6uU1bg6/0azppry1FoGdH1/Op1xFq+4=",
+ "N": 65536,
+ "R": 8,
+ "P": 1,
+ "KeyLen": 32
+ },
+ "Version": 2,
+ "FeatureFlags": [
+ "GCMIV128",
+ "HKDF",
+ "DirIV",
+ "EMENames",
+ "LongNames",
+ "Raw64"
+ ]
+}
diff --git a/tests/fsck/broken_fs_v1.4/gocryptfs.diriv b/tests/fsck/broken_fs_v1.4/gocryptfs.diriv
new file mode 100644
index 0000000..d7bbcda
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/gocryptfs.diriv
@@ -0,0 +1,2 @@
+å8]ÃjM
+âPg¡çDóç \ No newline at end of file
diff --git a/tests/fsck/broken_fs_v1.4/invalid_file_name.3 b/tests/fsck/broken_fs_v1.4/invalid_file_name.3
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/invalid_file_name.3
diff --git a/tests/fsck/broken_fs_v1.4/invalid_file_name_2 b/tests/fsck/broken_fs_v1.4/invalid_file_name_2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/invalid_file_name_2
diff --git a/tests/fsck/broken_fs_v1.4/invalid_file_name____1 b/tests/fsck/broken_fs_v1.4/invalid_file_name____1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/invalid_file_name____1
diff --git a/tests/fsck/broken_fs_v1.4/qOA8a4yuvgbMFpz7277R8A b/tests/fsck/broken_fs_v1.4/qOA8a4yuvgbMFpz7277R8A
new file mode 100644
index 0000000..8621a03
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/qOA8a4yuvgbMFpz7277R8A
@@ -0,0 +1 @@
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
diff --git a/tests/fsck/broken_fs_v1.4/s-P7PcQDUcVkoeMDnC3EYA b/tests/fsck/broken_fs_v1.4/s-P7PcQDUcVkoeMDnC3EYA
new file mode 120000
index 0000000..158f38a
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/s-P7PcQDUcVkoeMDnC3EYA
@@ -0,0 +1 @@
+Qso5-4WJ2iAxF674mUarvuNbIMTLSJLqfEh3Chq3I_Rm2sY2 \ No newline at end of file
diff --git a/tests/fsck/broken_fs_v1.4/vDKs8a7UtM3PmEKk9wlPcA b/tests/fsck/broken_fs_v1.4/vDKs8a7UtM3PmEKk9wlPcA
new file mode 100644
index 0000000..1dff1a1
--- /dev/null
+++ b/tests/fsck/broken_fs_v1.4/vDKs8a7UtM3PmEKk9wlPcA
Binary files differ
diff --git a/tests/fsck/fsck_test.go b/tests/fsck/fsck_test.go
new file mode 100644
index 0000000..7506636
--- /dev/null
+++ b/tests/fsck/fsck_test.go
@@ -0,0 +1,26 @@
+package fsck
+
+import (
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/rfjakob/gocryptfs/internal/exitcodes"
+ "github.com/rfjakob/gocryptfs/tests/test_helpers"
+)
+
+func TestBrokenFsV14(t *testing.T) {
+ cmd := exec.Command(test_helpers.GocryptfsBinary, "-fsck", "-extpass", "echo test", "broken_fs_v1.4")
+ outBin, err := cmd.CombinedOutput()
+ out := string(outBin)
+ t.Log(out)
+ code := test_helpers.ExtractCmdExitCode(err)
+ if code != exitcodes.FsckErrors {
+ t.Errorf("wrong exit code, have=%d want=%d", code, exitcodes.FsckErrors)
+ }
+ lines := strings.Split(out, "\n")
+ summaryLine := lines[len(lines)-2]
+ if summaryLine != "fsck: found 5 problems" {
+ t.Errorf("wrong summary line: %q", summaryLine)
+ }
+}
diff --git a/tests/fsck/run_fsck.bash b/tests/fsck/run_fsck.bash
new file mode 100755
index 0000000..9637381
--- /dev/null
+++ b/tests/fsck/run_fsck.bash
@@ -0,0 +1,2 @@
+#!/bin/bash
+exec ../../gocryptfs -fsck -extpass "echo test" broken_fs_v1.4
diff --git a/tests/test_helpers/helpers.go b/tests/test_helpers/helpers.go
index 5c0319e..f92fb79 100644
--- a/tests/test_helpers/helpers.go
+++ b/tests/test_helpers/helpers.go
@@ -400,3 +400,15 @@ func QueryCtlSock(t *testing.T, socketPath string, req ctlsock.RequestStruct) (r
json.Unmarshal(buf, &response)
return response
}
+
+// Extract the exit code from an error value that was returned from
+// exec / cmd.Run()
+func ExtractCmdExitCode(err error) int {
+ if err == nil {
+ return 0
+ }
+ // OMG this is convoluted
+ err2 := err.(*exec.ExitError)
+ code := err2.Sys().(syscall.WaitStatus).ExitStatus()
+ return code
+}