diff --git a/frontend/fe_file.go b/frontend/fe_file.go index b417227..4679589 100644 --- a/frontend/fe_file.go +++ b/frontend/fe_file.go @@ -68,7 +68,7 @@ func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenR func (f *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - fmt.Printf("Read: o=%d l=%d\n", req.Offset, req.Size) + cryptfs.Debug.Printf("Read: o=%d l=%d\n", req.Offset, req.Size) // Read the backing ciphertext in one go iblocks := f.crfs.SplitRange(uint64(req.Offset), uint64(req.Size)) diff --git a/frontend/fe_fs.go b/frontend/fe_fs.go index 4d49194..d1fa5b1 100644 --- a/frontend/fe_fs.go +++ b/frontend/fe_fs.go @@ -27,17 +27,17 @@ type nullTracer struct {} func (nullTracer) Trace(op cluefs.FsOperTracer) {} -func NewFS(key [16]byte, backing string, useOpenssl bool) *FS { - var nt nullTracer - clfs, err := cluefs.NewClueFS(backing, nt) +func NewFS(key [16]byte, backing string, useOpenssl bool) (*FS, error) { + var tracer nullTracer + clfs, err := cluefs.NewClueFS(backing, tracer) if err != nil { - panic(err) + return nil, err } return &FS { CryptFS: cryptfs.NewCryptFS(key, useOpenssl), ClueFS: clfs, backing: backing, - } + }, nil } func (fs *FS) Root() (fusefs.Node, error) { diff --git a/main.go b/main.go index 3ad0fa4..3619bb7 100644 --- a/main.go +++ b/main.go @@ -1,29 +1,46 @@ package main import ( + "path/filepath" + "flag" + "os" + "fmt" + "github.com/rfjakob/gocryptfs/frontend" "bazil.org/fuse" fusefs "bazil.org/fuse/fs" - "fmt" - "github.com/rfjakob/cluefs/lib/cluefs" - "github.com/rfjakob/gocryptfs/frontend" - "os" + ) const ( PROGRAM_NAME = "gocryptfs" USE_OPENSSL = true + + ERREXIT_USAGE = 1 + ERREXIT_NEWFS = 2 + ERREXIT_MOUNT = 3 + ERREXIT_SERVE = 4 + ERREXIT_MOUNT2 = 5 ) func main() { // Parse command line arguments - conf, err := cluefs.ParseArguments() - if err != nil { - os.Exit(1) + flag.Parse() + if flag.NArg() < 2 { + fmt.Printf("NArg=%d\n", flag.NArg()) + fmt.Printf("usage: %s CIPHERDIR MOUNTPOINT\n", PROGRAM_NAME) + os.Exit(ERREXIT_USAGE) } + cipherdir, _ := filepath.Abs(flag.Arg(0)) + mountpoint, err := filepath.Abs(flag.Arg(1)) + // Create the file system object var key [16]byte - cfs := frontend.NewFS(key, conf.GetShadowDir(), USE_OPENSSL) + cfs, err := frontend.NewFS(key, cipherdir, USE_OPENSSL) + if err != nil { + fmt.Println(err) + os.Exit(ERREXIT_NEWFS) + } // Mount the file system mountOpts := []fuse.MountOption{ @@ -33,24 +50,24 @@ func main() { fuse.LocalVolume(), fuse.MaxReadahead(1024*1024), } - conn, err := fuse.Mount(conf.GetMountPoint(), mountOpts...) + conn, err := fuse.Mount(mountpoint, mountOpts...) if err != nil { fmt.Println(err) - os.Exit(1) + os.Exit(ERREXIT_MOUNT) } defer conn.Close() // Start serving requests if err = fusefs.Serve(conn, cfs); err != nil { fmt.Println(err) - os.Exit(1) + os.Exit(ERREXIT_SERVE) } // Check for errors when mounting the file system <-conn.Ready if err = conn.MountError; err != nil { fmt.Println(err) - os.Exit(1) + os.Exit(ERREXIT_MOUNT2) } // We are done diff --git a/main_benchmark.bash b/main_benchmark.bash new file mode 100755 index 0000000..447581a --- /dev/null +++ b/main_benchmark.bash @@ -0,0 +1,6 @@ +#!/bin/bash + +set -eux + +go build +go test -bench=. diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..f17b5f5 --- /dev/null +++ b/main_test.go @@ -0,0 +1,149 @@ +package main + +import ( + "io" + "fmt" + "time" + "testing" + "os" + "os/exec" + "io/ioutil" + "crypto/md5" + "encoding/hex" +) + +const tmpDir = "test_tmp_dir/" +const plainDir = tmpDir + "plain/" +const cipherDir = tmpDir + "cipher/" + +func TestMain(m *testing.M) { + + fu := exec.Command("fusermount", "-u", plainDir) + fu.Stdout = os.Stdout + fu.Stderr = os.Stderr + fu.Run() + os.RemoveAll(tmpDir) + + err := os.MkdirAll(plainDir, 0777) + if err != nil { + panic("Could not create plainDir") + } + + err = os.MkdirAll(cipherDir, 0777) + if err != nil { + panic("Could not create cipherDir") + } + + c := exec.Command("./gocryptfs", cipherDir, plainDir) + c.Stdout = os.Stdout + c.Stderr = os.Stderr + go c.Run() + + time.Sleep(3 * time.Second) + + r := m.Run() + + + fu.Run() + os.Exit(r) +} + +func testWriteN(t *testing.T, fn string, n int, hashWant string) { + file, err := os.Create(plainDir + fn) + if err != nil { + t.FailNow() + } + + d := make([]byte, n) + written, err := file.Write(d) + if err != nil || written != len(d) { + fmt.Printf("err=\"%s\", written=%d\n", err, written) + t.Fail() + } + file.Close() + + buf, err := ioutil.ReadFile(plainDir + fn) + if err != nil { + t.Fail() + } + + rawHash := md5.Sum(buf) + hashActual := hex.EncodeToString(rawHash[:]) + if hashActual != hashWant { + fmt.Printf("hashWant=%s hashActual=%s\n", hashWant, hashActual) + t.Fail() + } +} + +func TestWrite10(t *testing.T) { + testWriteN(t, "10", 10, "a63c90cc3684ad8b0a2176a6a8fe9005") +} + +func TestWrite100(t *testing.T) { + testWriteN(t, "100", 100, "6d0bb00954ceb7fbee436bb55a8397a9") +} + +func TestWrite1M(t *testing.T) { + testWriteN(t, "1M", 1024*1024, "b6d81b360a5672d80c27430f39153e2c") +} + +func TestWrite1Mx100(t *testing.T) { + testWriteN(t, "1Mx100", 1024*1024, "b6d81b360a5672d80c27430f39153e2c") + // Read and check 100 times to catch race conditions + var i int + for i = 0; i < 100; i++ { + buf, err := ioutil.ReadFile(plainDir + "1M") + if err != nil { + t.Fail() + } + rawHash := md5.Sum(buf) + hashActual := hex.EncodeToString(rawHash[:]) + if hashActual != "b6d81b360a5672d80c27430f39153e2c" { + fmt.Printf("Read corruption in loop # %d\n", i) + t.FailNow() + } else { + //fmt.Print(".") + } + } +} + +func BenchmarkStreamWrite(t *testing.B) { + buf := make([]byte, 1024*1024) + t.SetBytes(int64(len(buf))) + + file, err := os.Create(plainDir + "BenchmarkWrite") + if err != nil { + t.FailNow() + } + + t.ResetTimer() + var i int + for i = 0; i < t.N; i++ { + written, err := file.Write(buf) + if err != nil { + fmt.Printf("err=\"%s\", written=%d\n", err.Error(), written) + t.FailNow() + } + } +} + +func BenchmarkStreamRead(t *testing.B) { + buf := make([]byte, 1024*1024) + t.SetBytes(int64(len(buf))) + file, err := os.Open(plainDir + "BenchmarkWrite") + if err != nil { + t.FailNow() + } + t.ResetTimer() + var i int + for i = 0; i < t.N; i++ { + _, err := file.Read(buf) + if err == io.EOF { + fmt.Printf("Test file too small\n") + t.SkipNow() + } else if err != nil { + fmt.Println(err) + t.FailNow() + } + } +}