diff options
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/OtrNpznB8aMTKPi6bopM2gBinary files differ new 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/vDKs8a7UtM3PmEKk9wlPcABinary files differ new 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 +} | 
