diff options
author | Jakob Unterwurzacher | 2018-04-01 21:23:32 +0200 |
---|---|---|
committer | Jakob Unterwurzacher | 2018-04-02 16:38:18 +0200 |
commit | f28d85fad599ffaef9a8e1f353911c81a6605d2f (patch) | |
tree | 1acc3514a5dde31e88ad13e8dc48818872e40d0f | |
parent | fb06c65ee90e31d11cf37b3469f7d3336ae51184 (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.
20 files changed, 170 insertions, 17 deletions
@@ -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 @@ -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 Binary files differnew file mode 100644 index 0000000..dab7c69 --- /dev/null +++ b/tests/fsck/broken_fs_v1.4/OtrNpznB8aMTKPi6bopM2g 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 Binary files differnew file mode 100644 index 0000000..1dff1a1 --- /dev/null +++ b/tests/fsck/broken_fs_v1.4/vDKs8a7UtM3PmEKk9wlPcA 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 +} |