diff --git a/gocryptfs-xray/paths_ctlsock.go b/gocryptfs-xray/paths_ctlsock.go index 3c69ec3..c489f0e 100644 --- a/gocryptfs-xray/paths_ctlsock.go +++ b/gocryptfs-xray/paths_ctlsock.go @@ -8,36 +8,55 @@ import ( "github.com/rfjakob/gocryptfs/ctlsock" ) -func decryptPaths(socketPath string) { +func decryptPaths(socketPath string, sep0 bool) { var req ctlsock.RequestStruct - transformPaths(socketPath, &req, &req.DecryptPath) + transformPaths(socketPath, &req, &req.DecryptPath, sep0) } -func encryptPaths(socketPath string) { +func encryptPaths(socketPath string, sep0 bool) { var req ctlsock.RequestStruct - transformPaths(socketPath, &req, &req.EncryptPath) + transformPaths(socketPath, &req, &req.EncryptPath, sep0) } -func transformPaths(socketPath string, req *ctlsock.RequestStruct, in *string) { +func transformPaths(socketPath string, req *ctlsock.RequestStruct, in *string, sep0 bool) { + errorCount := 0 c, err := ctlsock.New(socketPath) if err != nil { fmt.Printf("fatal: %v\n", err) os.Exit(1) } - line := 0 - scanner := bufio.NewScanner(os.Stdin) - for scanner.Scan() { - line++ - *in = scanner.Text() + line := 1 + var separator byte = '\n' + if sep0 { + separator = '\000' + } + r := bufio.NewReader(os.Stdin) + for eof := false; eof == false; line++ { + val, err := r.ReadBytes(separator) + if len(val) == 0 { + break + } + if err != nil { + // break the loop after we have processed the last val + eof = true + } else { + // drop trailing separator + val = val[:len(val)-1] + } + *in = string(val) resp, err := c.Query(req) if err != nil { fmt.Fprintf(os.Stderr, "error at input line %d %q: %v\n", line, *in, err) + errorCount++ continue } if resp.WarnText != "" { fmt.Fprintf(os.Stderr, "warning at input line %d %q: %v\n", line, *in, resp.WarnText) } - fmt.Println(resp.Result) + fmt.Printf("%s%c", resp.Result, separator) } - os.Exit(0) + if errorCount == 0 { + os.Exit(0) + } + os.Exit(1) } diff --git a/gocryptfs-xray/xray_main.go b/gocryptfs-xray/xray_main.go index 0777524..8dcaf8d 100644 --- a/gocryptfs-xray/xray_main.go +++ b/gocryptfs-xray/xray_main.go @@ -65,10 +65,12 @@ func main() { decryptPaths *bool encryptPaths *bool aessiv *bool + sep0 *bool } args.dumpmasterkey = flag.Bool("dumpmasterkey", false, "Decrypt and dump the master key") args.decryptPaths = flag.Bool("decrypt-paths", false, "Decrypt file paths using gocryptfs control socket") args.encryptPaths = flag.Bool("encrypt-paths", false, "Encrypt file paths using gocryptfs control socket") + args.sep0 = flag.Bool("0", false, "Use \\0 instead of \\n as separator") args.aessiv = flag.Bool("aessiv", false, "Assume AES-SIV mode instead of AES-GCM") flag.Usage = usage flag.Parse() @@ -83,10 +85,10 @@ func main() { } fn := flag.Arg(0) if *args.decryptPaths { - decryptPaths(fn) + decryptPaths(fn, *args.sep0) } if *args.encryptPaths { - encryptPaths(fn) + encryptPaths(fn, *args.sep0) } fd, err := os.Open(fn) if err != nil { diff --git a/gocryptfs-xray/xray_tests/xray_test.go b/gocryptfs-xray/xray_tests/xray_test.go index dfd21e6..790d2db 100644 --- a/gocryptfs-xray/xray_tests/xray_test.go +++ b/gocryptfs-xray/xray_tests/xray_test.go @@ -6,6 +6,8 @@ import ( "io/ioutil" "os/exec" "testing" + + "github.com/rfjakob/gocryptfs/tests/test_helpers" ) func TestAesgcmXray(t *testing.T) { @@ -58,3 +60,51 @@ func TestDumpmasterkey(t *testing.T) { fmt.Printf("have: %s\n", out) } } + +func TestEncryptPaths(t *testing.T) { + cDir := test_helpers.InitFS(t) + pDir := cDir + ".mnt" + sock := cDir + ".sock" + test_helpers.MountOrFatal(t, cDir, pDir, "-ctlsock="+sock, "-extpass", "echo test") + defer test_helpers.UnmountPanic(pDir) + + testCases := []struct { + in []string + sep0 bool + }{ + { + []string{ + "test1", + "test1\n", + "test1\ntest2", + "test1\ntest2\n", + }, + false, + }, + { + []string{ + "test1", + "test1\000", + "test1\000test2", + "test1\000test2\000", + }, + true, + }, + } + + for _, tc := range testCases { + for _, in := range tc.in { + sepArg := "-0=false" + if tc.sep0 { + sepArg = "-0=true" + } + cmd := exec.Command("../gocryptfs-xray", "-encrypt-paths", sepArg, sock) + cmd.Stdin = bytes.NewBuffer([]byte(in)) + out, err := cmd.CombinedOutput() + t.Logf("%q", string(out)) + if err != nil { + t.Fatal(err) + } + } + } +} diff --git a/tests/test_helpers/helpers.go b/tests/test_helpers/helpers.go index b612de0..2d23586 100644 --- a/tests/test_helpers/helpers.go +++ b/tests/test_helpers/helpers.go @@ -26,7 +26,7 @@ var testParentDir = "" const GocryptfsBinary = "../../gocryptfs" // UnmountScript is the fusermount/umount compatibility wrapper script -const UnmountScript = "../fuse-unmount.bash" +const UnmountScript = "../../tests/fuse-unmount.bash" // X255 contains 255 uppercase "X". This can be used as a maximum-length filename. var X255 string