Convert logging to standard Go log.Logger

This is in preparation of logging to syslog.
This commit is contained in:
Jakob Unterwurzacher 2016-01-20 20:55:56 +01:00
parent b9dd9e9a1c
commit 17f0eb1339
12 changed files with 109 additions and 140 deletions

View File

@ -75,17 +75,17 @@ func LoadConfFile(filename string, password string) ([]byte, *ConfFile, error) {
// Unmarshal // Unmarshal
err = json.Unmarshal(js, &cf) err = json.Unmarshal(js, &cf)
if err != nil { if err != nil {
Warn.Printf("Failed to unmarshal config file\n") Warn.Printf("Failed to unmarshal config file")
return nil, nil, err return nil, nil, err
} }
if cf.Version != HEADER_CURRENT_VERSION { if cf.Version != HEADER_CURRENT_VERSION {
return nil, nil, fmt.Errorf("Unsupported on-disk format %d\n", cf.Version) return nil, nil, fmt.Errorf("Unsupported on-disk format %d", cf.Version)
} }
for _, flag := range cf.FeatureFlags { for _, flag := range cf.FeatureFlags {
if cf.isFeatureFlagKnown(flag) == false { if cf.isFeatureFlagKnown(flag) == false {
return nil, nil, fmt.Errorf("Unsupported feature flag %s\n", flag) return nil, nil, fmt.Errorf("Unsupported feature flag %s", flag)
} }
} }
@ -98,8 +98,8 @@ func LoadConfFile(filename string, password string) ([]byte, *ConfFile, error) {
cfs := NewCryptFS(scryptHash, false, false, false) cfs := NewCryptFS(scryptHash, false, false, false)
key, err := cfs.DecryptBlock(cf.EncryptedKey, 0, nil) key, err := cfs.DecryptBlock(cf.EncryptedKey, 0, nil)
if err != nil { if err != nil {
Warn.Printf("failed to unlock master key: %s\n", err.Error()) Warn.Printf("failed to unlock master key: %s", err.Error())
Warn.Printf("Password incorrect.\n") Warn.Printf("Password incorrect.")
return nil, nil, err return nil, nil, err
} }

View File

@ -2,6 +2,8 @@ package cryptfs
import ( import (
"fmt" "fmt"
"io/ioutil"
"os"
"testing" "testing"
"time" "time"
) )
@ -33,10 +35,10 @@ func TestLoadV2(t *testing.T) {
func TestLoadV2PwdError(t *testing.T) { func TestLoadV2PwdError(t *testing.T) {
if !testing.Verbose() { if !testing.Verbose() {
Warn.Disable() Warn.SetOutput(ioutil.Discard)
} }
_, _, err := LoadConfFile("config_test/v2.conf", "wrongpassword") _, _, err := LoadConfFile("config_test/v2.conf", "wrongpassword")
Warn.Enable() Warn.SetOutput(os.Stderr)
if err == nil { if err == nil {
t.Errorf("Loading with wrong password must fail but it didn't") t.Errorf("Loading with wrong password must fail but it didn't")
} }

View File

@ -55,12 +55,12 @@ func (be *CryptFS) DecryptBlock(ciphertext []byte, blockNo uint64, fileId []byte
// All-zero block? // All-zero block?
if bytes.Equal(ciphertext, be.allZeroBlock) { if bytes.Equal(ciphertext, be.allZeroBlock) {
Debug.Printf("DecryptBlock: file hole encountered\n") Debug.Printf("DecryptBlock: file hole encountered")
return make([]byte, be.plainBS), nil return make([]byte, be.plainBS), nil
} }
if len(ciphertext) < be.gcmIVLen { if len(ciphertext) < be.gcmIVLen {
Warn.Printf("DecryptBlock: Block is too short: %d bytes\n", len(ciphertext)) Warn.Printf("DecryptBlock: Block is too short: %d bytes", len(ciphertext))
return nil, errors.New("Block is too short") return nil, errors.New("Block is too short")
} }
@ -77,7 +77,7 @@ func (be *CryptFS) DecryptBlock(ciphertext []byte, blockNo uint64, fileId []byte
plaintext, err := be.gcm.Open(plaintext, nonce, ciphertext, aData) plaintext, err := be.gcm.Open(plaintext, nonce, ciphertext, aData)
if err != nil { if err != nil {
Warn.Printf("DecryptBlock: %s, len=%d, md5=%s\n", err.Error(), len(ciphertextOrig), Warn.Md5sum(ciphertextOrig)) Warn.Printf("DecryptBlock: %s, len=%d, md5=%s", err.Error(), len(ciphertextOrig), md5sum(ciphertextOrig))
Debug.Println(hex.Dump(ciphertextOrig)) Debug.Println(hex.Dump(ciphertextOrig))
return nil, err return nil, err
} }

View File

@ -13,8 +13,8 @@ import (
// compiled on 1.4. // compiled on 1.4.
func goGCMWrapper(bc cipher.Block, nonceSize int) (cipher.AEAD, error) { func goGCMWrapper(bc cipher.Block, nonceSize int) (cipher.AEAD, error) {
if nonceSize != 12 { if nonceSize != 12 {
Warn.Printf("128 bit GCM IVs are not supported by Go 1.4 and lower.\n") Warn.Printf("128 bit GCM IVs are not supported by Go 1.4 and lower.")
Warn.Printf("Please use openssl crypto or recompile using a newer Go runtime.\n") Warn.Printf("Please use openssl crypto or recompile using a newer Go runtime.")
return nil, fmt.Errorf("128 bit GCM IVs are not supported by Go 1.4 and lower") return nil, fmt.Errorf("128 bit GCM IVs are not supported by Go 1.4 and lower")
} }
return cipher.NewGCM(bc) return cipher.NewGCM(bc)

View File

@ -28,7 +28,7 @@ func NewScryptKdf(logN int) scryptKdf {
s.N = 1 << SCRYPT_DEFAULT_LOGN s.N = 1 << SCRYPT_DEFAULT_LOGN
} else { } else {
if logN < 10 { if logN < 10 {
fmt.Printf("Error: scryptn below 10 is too low to make sense. Aborting.\n") fmt.Println("Error: scryptn below 10 is too low to make sense. Aborting.")
os.Exit(1) os.Exit(1)
} }
s.N = 1 << uint32(logN) s.N = 1 << uint32(logN)

View File

@ -2,67 +2,33 @@ package cryptfs
import ( import (
"encoding/json" "encoding/json"
"fmt" "io/ioutil"
"strings" "log"
"os"
) )
type logChannel struct { func JSONDump(obj interface{}) string {
enabled bool
}
func (l *logChannel) Printf(format string, args ...interface{}) {
if l.enabled == true {
fmt.Printf(format, args...)
}
}
func (l *logChannel) Println(s string) {
if l.enabled == true {
fmt.Println(s)
}
}
func (l *logChannel) Dump(d []byte) {
s := string(d)
fmt.Println(strings.Replace(s, "\000", "\\0", -1))
}
func (l *logChannel) JSONDump(obj interface{}) {
if !l.enabled {
return
}
b, err := json.MarshalIndent(obj, "", "\t") b, err := json.MarshalIndent(obj, "", "\t")
if err != nil { if err != nil {
fmt.Println(err) return err.Error()
} else { } else {
fmt.Println(string(b)) return string(b)
} }
} }
func (l *logChannel) Enable() {
l.enabled = true
}
func (l *logChannel) Disable() {
l.enabled = false
}
// Only actually calculate the md5sum if the log channel is enabled to save
// CPU cycles
func (l *logChannel) Md5sum(buf []byte) string {
if l.enabled == false {
return "disabled"
}
return md5sum(buf)
}
// As defined by http://elinux.org/Debugging_by_printing#Log_Levels // As defined by http://elinux.org/Debugging_by_printing#Log_Levels
// Debug messages // Debug messages
var Debug = logChannel{false} var Debug *log.Logger
// Informational message e.g. startup information // Informational message e.g. startup information
var Info = logChannel{true} var Info *log.Logger
// A warning, meaning nothing serious by itself but might indicate problems // A warning, meaning nothing serious by itself but might indicate problems
var Warn = logChannel{true} var Warn *log.Logger
func init() {
Debug = log.New(ioutil.Discard, "", 0)
Info = log.New(os.Stdout, "", 0)
Warn = log.New(os.Stderr, "", 0)
}

View File

@ -24,7 +24,7 @@ func TestMain(m *testing.M) {
flag.Parse() flag.Parse()
if testing.Verbose() { if testing.Verbose() {
fmt.Printf("***** Testing with OpenSSL\n") fmt.Println("***** Testing with OpenSSL")
} }
resetTmpDir() // <- this also create gocryptfs.diriv resetTmpDir() // <- this also create gocryptfs.diriv
mount(defaultCipherDir, defaultPlainDir, "--zerokey") mount(defaultCipherDir, defaultPlainDir, "--zerokey")
@ -40,7 +40,7 @@ func TestMain(m *testing.M) {
} }
if testing.Verbose() { if testing.Verbose() {
fmt.Printf("***** Testing with native Go crypto\n") fmt.Println("***** Testing with native Go crypto")
} }
resetTmpDir() resetTmpDir()
mount(defaultCipherDir, defaultPlainDir, "--zerokey", "--openssl=false") mount(defaultCipherDir, defaultPlainDir, "--zerokey", "--openssl=false")
@ -52,7 +52,7 @@ func TestMain(m *testing.M) {
} }
if testing.Verbose() { if testing.Verbose() {
fmt.Printf("***** Testing \"--plaintextnames\"\n") fmt.Println("***** Testing \"--plaintextnames\"")
} }
resetTmpDir() resetTmpDir()
mount(defaultCipherDir, defaultPlainDir, "--zerokey", "--plaintextnames") mount(defaultCipherDir, defaultPlainDir, "--zerokey", "--plaintextnames")
@ -77,7 +77,7 @@ func testWriteN(t *testing.T, fn string, n int) string {
d := make([]byte, n) d := make([]byte, n)
written, err := file.Write(d) written, err := file.Write(d)
if err != nil || written != len(d) { if err != nil || written != len(d) {
t.Errorf("err=\"%s\", written=%d\n", err, written) t.Errorf("err=\"%s\", written=%d", err, written)
} }
err = file.Close() err = file.Close()
if err != nil { if err != nil {
@ -92,7 +92,7 @@ func testWriteN(t *testing.T, fn string, n int) string {
hashActual := md5fn(defaultPlainDir + fn) hashActual := md5fn(defaultPlainDir + fn)
if hashActual != hashWant { if hashActual != hashWant {
t.Errorf("Wrong content, hashWant=%s hashActual=%s\n", hashWant, hashActual) t.Errorf("Wrong content, hashWant=%s hashActual=%s", hashWant, hashActual)
} }
return hashActual return hashActual

View File

@ -58,7 +58,6 @@ func BenchmarkStreamRead(t *testing.B) {
} }
} }
f2.Close() f2.Close()
//fmt.Printf("done\n")
} }
file, err := os.Open(fn) file, err := os.Open(fn)
@ -70,7 +69,7 @@ func BenchmarkStreamRead(t *testing.B) {
for i = 0; i < t.N; i++ { for i = 0; i < t.N; i++ {
_, err := file.Read(buf) _, err := file.Read(buf)
if err == io.EOF { if err == io.EOF {
fmt.Printf("Test file too small\n") fmt.Println("Test file too small")
t.SkipNow() t.SkipNow()
} else if err != nil { } else if err != nil {
fmt.Println(err) fmt.Println(err)

46
main.go
View File

@ -1,8 +1,10 @@
package main package main
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@ -55,7 +57,7 @@ func initDir(args *argContainer) {
} }
// Create gocryptfs.conf // Create gocryptfs.conf
cryptfs.Info.Printf("Choose a password for protecting your files.\n") cryptfs.Info.Printf("Choose a password for protecting your files.")
password := readPasswordTwice(args.extpass) password := readPasswordTwice(args.extpass)
err = cryptfs.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn) err = cryptfs.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn)
if err != nil { if err != nil {
@ -72,8 +74,8 @@ func initDir(args *argContainer) {
} }
} }
cryptfs.Info.Printf(colorGreen+"The filesystem has been created successfully.\n"+colorReset) cryptfs.Info.Printf(colorGreen + "The filesystem has been created successfully." + colorReset)
cryptfs.Info.Printf(colorGrey+"You can now mount it using: %s %s MOUNTPOINT\n"+colorReset, cryptfs.Info.Printf(colorGrey+"You can now mount it using: %s %s MOUNTPOINT"+colorReset,
PROGRAM_NAME, args.cipherdir) PROGRAM_NAME, args.cipherdir)
os.Exit(0) os.Exit(0)
} }
@ -98,15 +100,15 @@ func loadConfig(args *argContainer) (masterkey []byte, confFile *cryptfs.ConfFil
fmt.Printf("Password: ") fmt.Printf("Password: ")
pw := readPassword(args.extpass) pw := readPassword(args.extpass)
cryptfs.Info.Printf("Decrypting master key... ") cryptfs.Info.Printf("Decrypting master key... ")
cryptfs.Warn.Disable() // Silence DecryptBlock() error messages on incorrect password cryptfs.Warn.SetOutput(ioutil.Discard) // Silence DecryptBlock() error messages on incorrect password
masterkey, confFile, err = cryptfs.LoadConfFile(args.config, pw) masterkey, confFile, err = cryptfs.LoadConfFile(args.config, pw)
cryptfs.Warn.Enable() cryptfs.Warn.SetOutput(os.Stderr)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
fmt.Println(colorRed + "Wrong password." + colorReset) fmt.Println(colorRed + "Wrong password." + colorReset)
os.Exit(ERREXIT_LOADCONF) os.Exit(ERREXIT_LOADCONF)
} }
cryptfs.Info.Printf("done.\n") cryptfs.Info.Printf("done.")
return masterkey, confFile return masterkey, confFile
} }
@ -114,7 +116,7 @@ func loadConfig(args *argContainer) (masterkey []byte, confFile *cryptfs.ConfFil
// changePassword - change the password of config file "filename" // changePassword - change the password of config file "filename"
func changePassword(args *argContainer) { func changePassword(args *argContainer) {
masterkey, confFile := loadConfig(args) masterkey, confFile := loadConfig(args)
fmt.Printf("Please enter your new password.\n") fmt.Println("Please enter your new password.")
newPw := readPasswordTwice(args.extpass) newPw := readPasswordTwice(args.extpass)
confFile.EncryptKey(masterkey, newPw, confFile.ScryptObject.LogN()) confFile.EncryptKey(masterkey, newPw, confFile.ScryptObject.LogN())
err := confFile.WriteFile() err := confFile.WriteFile()
@ -122,7 +124,7 @@ func changePassword(args *argContainer) {
fmt.Println(err) fmt.Println(err)
os.Exit(ERREXIT_INIT) os.Exit(ERREXIT_INIT)
} }
cryptfs.Info.Printf("Password changed.\n") cryptfs.Info.Printf("Password changed.")
os.Exit(0) os.Exit(0)
} }
@ -175,8 +177,8 @@ func main() {
os.Exit(0) os.Exit(0)
} }
if args.debug { if args.debug {
cryptfs.Debug.Enable() cryptfs.Debug.SetOutput(os.Stdout)
cryptfs.Debug.Printf("Debug output enabled\n") cryptfs.Debug.Printf("Debug output enabled")
} }
// Every operation below requires CIPHERDIR. Check that we have it. // Every operation below requires CIPHERDIR. Check that we have it.
if flagSet.NArg() >= 1 { if flagSet.NArg() >= 1 {
@ -192,7 +194,7 @@ func main() {
} }
// "-q" // "-q"
if args.quiet { if args.quiet {
cryptfs.Info.Disable() cryptfs.Info.SetOutput(ioutil.Discard)
} }
// "-config" // "-config"
if args.config != "" { if args.config != "" {
@ -200,7 +202,7 @@ func main() {
if err != nil { if err != nil {
fmt.Printf(colorRed+"Invalid \"-config\" setting: %v\n"+colorReset, err) fmt.Printf(colorRed+"Invalid \"-config\" setting: %v\n"+colorReset, err)
} }
cryptfs.Info.Printf("Using config file at custom location %s\n", args.config) cryptfs.Info.Printf("Using config file at custom location %s", args.config)
} else { } else {
args.config = filepath.Join(args.cipherdir, cryptfs.ConfDefaultName) args.config = filepath.Join(args.cipherdir, cryptfs.ConfDefaultName)
} }
@ -211,13 +213,13 @@ func main() {
fmt.Println(err) fmt.Println(err)
os.Exit(ERREXIT_INIT) os.Exit(ERREXIT_INIT)
} }
cryptfs.Info.Printf("Writing CPU profile to %s\n", args.cpuprofile) cryptfs.Info.Printf("Writing CPU profile to %s", args.cpuprofile)
pprof.StartCPUProfile(f) pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile() defer pprof.StopCPUProfile()
} }
// "-openssl" // "-openssl"
if args.openssl == false { if args.openssl == false {
cryptfs.Info.Printf("Openssl disabled\n") cryptfs.Info.Printf("Openssl disabled")
} }
// Operation flags: init, passwd or mount // Operation flags: init, passwd or mount
// "-init" // "-init"
@ -257,13 +259,13 @@ func main() {
var confFile *cryptfs.ConfFile var confFile *cryptfs.ConfFile
if args.masterkey != "" { if args.masterkey != "" {
// "-masterkey" // "-masterkey"
cryptfs.Info.Printf("Using explicit master key.\n") cryptfs.Info.Printf("Using explicit master key.")
masterkey = parseMasterKey(args.masterkey) masterkey = parseMasterKey(args.masterkey)
cryptfs.Info.Printf("THE MASTER KEY IS VISIBLE VIA \"ps -auxwww\", ONLY USE THIS MODE FOR EMERGENCIES.\n") cryptfs.Info.Printf("THE MASTER KEY IS VISIBLE VIA \"ps -auxwww\", ONLY USE THIS MODE FOR EMERGENCIES.")
} else if args.zerokey { } else if args.zerokey {
// "-zerokey" // "-zerokey"
cryptfs.Info.Printf("Using all-zero dummy master key.\n") cryptfs.Info.Printf("Using all-zero dummy master key.")
cryptfs.Info.Printf("ZEROKEY MODE PROVIDES NO SECURITY AT ALL AND SHOULD ONLY BE USED FOR TESTING.\n") cryptfs.Info.Printf("ZEROKEY MODE PROVIDES NO SECURITY AT ALL AND SHOULD ONLY BE USED FOR TESTING.")
masterkey = make([]byte, cryptfs.KEY_LEN) masterkey = make([]byte, cryptfs.KEY_LEN)
} else { } else {
// Load master key from config file // Load master key from config file
@ -271,7 +273,7 @@ func main() {
printMasterKey(masterkey) printMasterKey(masterkey)
} }
// Initialize FUSE server // Initialize FUSE server
cryptfs.Debug.Printf("cli args: %v\n", args) cryptfs.Debug.Printf("cli args: %v", args)
srv := pathfsFrontend(masterkey, args, confFile) srv := pathfsFrontend(masterkey, args, confFile)
cryptfs.Info.Println(colorGreen + "Filesystem mounted and ready." + colorReset) cryptfs.Info.Println(colorGreen + "Filesystem mounted and ready." + colorReset)
// We are ready - send USR1 signal to our parent // We are ready - send USR1 signal to our parent
@ -318,8 +320,8 @@ func pathfsFrontend(key []byte, args argContainer, confFile *cryptfs.ConfFile) *
frontendArgs.DirIV = false frontendArgs.DirIV = false
frontendArgs.EMENames = false frontendArgs.EMENames = false
} }
cryptfs.Debug.Printf("frontendArgs: ") jsonBytes, _ := json.MarshalIndent(frontendArgs, "", "\t")
cryptfs.Debug.JSONDump(frontendArgs) cryptfs.Debug.Printf("frontendArgs: %s", string(jsonBytes))
finalFs := pathfs_frontend.NewFS(frontendArgs) finalFs := pathfs_frontend.NewFS(frontendArgs)
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true} pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
@ -364,7 +366,7 @@ func handleSigint(srv *fuse.Server, mountpoint string) {
err := srv.Unmount() err := srv.Unmount()
if err != nil { if err != nil {
fmt.Print(err) fmt.Print(err)
cryptfs.Info.Printf("Trying lazy unmount\n") cryptfs.Info.Printf("Trying lazy unmount")
cmd := exec.Command("fusermount", "-u", "-z", mountpoint) cmd := exec.Command("fusermount", "-u", "-z", mountpoint)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr

View File

@ -144,20 +144,20 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
blocks := f.cfs.ExplodePlainRange(off, length) blocks := f.cfs.ExplodePlainRange(off, length)
alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks) alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks)
skip := blocks[0].Skip skip := blocks[0].Skip
cryptfs.Debug.Printf("JointCiphertextRange(%d, %d) -> %d, %d, %d\n", off, length, alignedOffset, alignedLength, skip) cryptfs.Debug.Printf("JointCiphertextRange(%d, %d) -> %d, %d, %d", off, length, alignedOffset, alignedLength, skip)
ciphertext := make([]byte, int(alignedLength)) ciphertext := make([]byte, int(alignedLength))
f.fdLock.Lock() f.fdLock.Lock()
n, err := f.fd.ReadAt(ciphertext, int64(alignedOffset)) n, err := f.fd.ReadAt(ciphertext, int64(alignedOffset))
f.fdLock.Unlock() f.fdLock.Unlock()
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
cryptfs.Warn.Printf("read: ReadAt: %s\n", err.Error()) cryptfs.Warn.Printf("read: ReadAt: %s", err.Error())
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
} }
// Truncate ciphertext buffer down to actually read bytes // Truncate ciphertext buffer down to actually read bytes
ciphertext = ciphertext[0:n] ciphertext = ciphertext[0:n]
firstBlockNo := blocks[0].BlockNo firstBlockNo := blocks[0].BlockNo
cryptfs.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d\n", alignedOffset, firstBlockNo, alignedLength, n) cryptfs.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d", alignedOffset, firstBlockNo, alignedLength, n)
// Decrypt it // Decrypt it
plaintext, err := f.cfs.DecryptBlocks(ciphertext, firstBlockNo, f.header.Id) plaintext, err := f.cfs.DecryptBlocks(ciphertext, firstBlockNo, f.header.Id)
@ -165,7 +165,7 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
curruptBlockNo := firstBlockNo + f.cfs.PlainOffToBlockNo(uint64(len(plaintext))) curruptBlockNo := firstBlockNo + f.cfs.PlainOffToBlockNo(uint64(len(plaintext)))
cipherOff := f.cfs.BlockNoToCipherOff(curruptBlockNo) cipherOff := f.cfs.BlockNoToCipherOff(curruptBlockNo)
plainOff := f.cfs.BlockNoToPlainOff(curruptBlockNo) plainOff := f.cfs.BlockNoToPlainOff(curruptBlockNo)
cryptfs.Warn.Printf("ino%d: doRead: corrupt block #%d (plainOff=%d, cipherOff=%d)\n", cryptfs.Warn.Printf("ino%d: doRead: corrupt block #%d (plainOff=%d, cipherOff=%d)",
f.ino, curruptBlockNo, plainOff, cipherOff) f.ino, curruptBlockNo, plainOff, cipherOff)
return nil, fuse.EIO return nil, fuse.EIO
} }
@ -187,23 +187,23 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
// Read - FUSE call // Read - FUSE call
func (f *file) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fuse.Status) { func (f *file) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fuse.Status) {
cryptfs.Debug.Printf("ino%d: FUSE Read: offset=%d length=%d\n", f.ino, len(buf), off) cryptfs.Debug.Printf("ino%d: FUSE Read: offset=%d length=%d", f.ino, len(buf), off)
if f.writeOnly { if f.writeOnly {
cryptfs.Warn.Printf("ino%d: Tried to read from write-only file\n", f.ino) cryptfs.Warn.Printf("ino%d: Tried to read from write-only file", f.ino)
return nil, fuse.EBADF return nil, fuse.EBADF
} }
out, status := f.doRead(uint64(off), uint64(len(buf))) out, status := f.doRead(uint64(off), uint64(len(buf)))
if status == fuse.EIO { if status == fuse.EIO {
cryptfs.Warn.Printf("ino%d: Read failed with EIO, offset=%d, length=%d\n", f.ino, len(buf), off) cryptfs.Warn.Printf("ino%d: Read failed with EIO, offset=%d, length=%d", f.ino, len(buf), off)
} }
if status != fuse.OK { if status != fuse.OK {
return nil, status return nil, status
} }
cryptfs.Debug.Printf("ino%d: Read: status %v, returning %d bytes\n", f.ino, status, len(out)) cryptfs.Debug.Printf("ino%d: Read: status %v, returning %d bytes", f.ino, status, len(out))
return fuse.ReadResultData(out), status return fuse.ReadResultData(out), status
} }
@ -244,25 +244,25 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
o, _ := b.PlaintextRange() o, _ := b.PlaintextRange()
oldData, status := f.doRead(o, f.cfs.PlainBS()) oldData, status := f.doRead(o, f.cfs.PlainBS())
if status != fuse.OK { if status != fuse.OK {
cryptfs.Warn.Printf("RMW read failed: %s\n", status.String()) cryptfs.Warn.Printf("RMW read failed: %s", status.String())
return written, status return written, status
} }
// Modify // Modify
blockData = f.cfs.MergeBlocks(oldData, blockData, int(b.Skip)) blockData = f.cfs.MergeBlocks(oldData, blockData, int(b.Skip))
cryptfs.Debug.Printf("len(oldData)=%d len(blockData)=%d\n", len(oldData), len(blockData)) cryptfs.Debug.Printf("len(oldData)=%d len(blockData)=%d", len(oldData), len(blockData))
} }
blockOffset, blockLen := b.CiphertextRange() blockOffset, blockLen := b.CiphertextRange()
blockData = f.cfs.EncryptBlock(blockData, b.BlockNo, f.header.Id) blockData = f.cfs.EncryptBlock(blockData, b.BlockNo, f.header.Id)
cryptfs.Debug.Printf("ino%d: Writing %d bytes to block #%d, md5=%s\n", cryptfs.Debug.Printf("ino%d: Writing %d bytes to block #%d",
f.ino, uint64(len(blockData))-f.cfs.BlockOverhead(), b.BlockNo, cryptfs.Debug.Md5sum(blockData)) f.ino, uint64(len(blockData))-f.cfs.BlockOverhead(), b.BlockNo)
// Prevent partially written (=corrupt) blocks by preallocating the space beforehand // Prevent partially written (=corrupt) blocks by preallocating the space beforehand
f.fdLock.Lock() f.fdLock.Lock()
err := prealloc(int(f.fd.Fd()), int64(blockOffset), int64(blockLen)) err := prealloc(int(f.fd.Fd()), int64(blockOffset), int64(blockLen))
f.fdLock.Unlock() f.fdLock.Unlock()
if err != nil { if err != nil {
cryptfs.Warn.Printf("doWrite: fallocateRetry failed: %s\n", err.Error()) cryptfs.Warn.Printf("doWrite: fallocateRetry failed: %s", err.Error())
status = fuse.ToStatus(err) status = fuse.ToStatus(err)
break break
} }
@ -272,7 +272,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
_, err = f.fd.WriteAt(blockData, int64(blockOffset)) _, err = f.fd.WriteAt(blockData, int64(blockOffset))
f.fdLock.Unlock() f.fdLock.Unlock()
if err != nil { if err != nil {
cryptfs.Warn.Printf("doWrite: Write failed: %s\n", err.Error()) cryptfs.Warn.Printf("doWrite: Write failed: %s", err.Error())
status = fuse.ToStatus(err) status = fuse.ToStatus(err)
break break
} }
@ -283,18 +283,18 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
// Write - FUSE call // Write - FUSE call
func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) { func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {
cryptfs.Debug.Printf("ino%d: FUSE Write: offset=%d length=%d\n", f.ino, off, len(data)) cryptfs.Debug.Printf("ino%d: FUSE Write: offset=%d length=%d", f.ino, off, len(data))
fi, err := f.fd.Stat() fi, err := f.fd.Stat()
if err != nil { if err != nil {
cryptfs.Warn.Printf("Write: Fstat failed: %v\n", err) cryptfs.Warn.Printf("Write: Fstat failed: %v", err)
return 0, fuse.ToStatus(err) return 0, fuse.ToStatus(err)
} }
plainSize := f.cfs.CipherSizeToPlainSize(uint64(fi.Size())) plainSize := f.cfs.CipherSizeToPlainSize(uint64(fi.Size()))
if f.createsHole(plainSize, off) { if f.createsHole(plainSize, off) {
status := f.zeroPad(plainSize) status := f.zeroPad(plainSize)
if status != fuse.OK { if status != fuse.OK {
cryptfs.Warn.Printf("zeroPad returned error %v\n", status) cryptfs.Warn.Printf("zeroPad returned error %v", status)
return 0, status return 0, status
} }
} }
@ -352,14 +352,14 @@ func (f *file) Truncate(newSize uint64) fuse.Status {
// the file // the file
fi, err := f.fd.Stat() fi, err := f.fd.Stat()
if err != nil { if err != nil {
cryptfs.Warn.Printf("Truncate: Fstat failed: %v\n", err) cryptfs.Warn.Printf("Truncate: Fstat failed: %v", err)
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
oldSize := f.cfs.CipherSizeToPlainSize(uint64(fi.Size())) oldSize := f.cfs.CipherSizeToPlainSize(uint64(fi.Size()))
{ {
oldB := float32(oldSize) / float32(f.cfs.PlainBS()) oldB := float32(oldSize) / float32(f.cfs.PlainBS())
newB := float32(newSize) / float32(f.cfs.PlainBS()) newB := float32(newSize) / float32(f.cfs.PlainBS())
cryptfs.Debug.Printf("ino%d: FUSE Truncate from %.2f to %.2f blocks (%d to %d bytes)\n", f.ino, oldB, newB, oldSize, newSize) cryptfs.Debug.Printf("ino%d: FUSE Truncate from %.2f to %.2f blocks (%d to %d bytes)", f.ino, oldB, newB, oldSize, newSize)
} }
// File grows // File grows
@ -444,7 +444,7 @@ func (f *file) Chown(uid uint32, gid uint32) fuse.Status {
} }
func (f *file) GetAttr(a *fuse.Attr) fuse.Status { func (f *file) GetAttr(a *fuse.Attr) fuse.Status {
cryptfs.Debug.Printf("file.GetAttr()\n") cryptfs.Debug.Printf("file.GetAttr()")
st := syscall.Stat_t{} st := syscall.Stat_t{}
f.fdLock.Lock() f.fdLock.Lock()
err := syscall.Fstat(int(f.fd.Fd()), &st) err := syscall.Fstat(int(f.fd.Fd()), &st)
@ -460,7 +460,7 @@ func (f *file) GetAttr(a *fuse.Attr) fuse.Status {
// Allocate - FUSE call, fallocate(2) // Allocate - FUSE call, fallocate(2)
func (f *file) Allocate(off uint64, sz uint64, mode uint32) fuse.Status { func (f *file) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
cryptfs.Warn.Printf("Fallocate is not supported, returning ENOSYS - see https://github.com/rfjakob/gocryptfs/issues/1\n") cryptfs.Warn.Printf("Fallocate is not supported, returning ENOSYS - see https://github.com/rfjakob/gocryptfs/issues/1")
return fuse.ENOSYS return fuse.ENOSYS
} }

View File

@ -43,12 +43,12 @@ func (fs *FS) getBackingPath(relPath string) (string, error) {
return "", err return "", err
} }
cAbsPath := filepath.Join(fs.args.Cipherdir, cPath) cAbsPath := filepath.Join(fs.args.Cipherdir, cPath)
cryptfs.Debug.Printf("getBackingPath: %s + %s -> %s\n", fs.args.Cipherdir, relPath, cAbsPath) cryptfs.Debug.Printf("getBackingPath: %s + %s -> %s", fs.args.Cipherdir, relPath, cAbsPath)
return cAbsPath, nil return cAbsPath, nil
} }
func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
cryptfs.Debug.Printf("FS.GetAttr('%s')\n", name) cryptfs.Debug.Printf("FS.GetAttr('%s')", name)
if fs.isFiltered(name) { if fs.isFiltered(name) {
return nil, fuse.EPERM return nil, fuse.EPERM
} }
@ -58,7 +58,7 @@ func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Stat
} }
a, status := fs.FileSystem.GetAttr(cName, context) a, status := fs.FileSystem.GetAttr(cName, context)
if a == nil { if a == nil {
cryptfs.Debug.Printf("FS.GetAttr failed: %s\n", status.String()) cryptfs.Debug.Printf("FS.GetAttr failed: %s", status.String())
return a, status return a, status
} }
if a.IsRegular() { if a.IsRegular() {
@ -71,7 +71,7 @@ func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Stat
} }
func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) { func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
cryptfs.Debug.Printf("OpenDir(%s)\n", dirName) cryptfs.Debug.Printf("OpenDir(%s)", dirName)
cDirName, err := fs.encryptPath(dirName) cDirName, err := fs.encryptPath(dirName)
if err != nil { if err != nil {
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
@ -107,7 +107,7 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f
if !fs.args.PlaintextNames { if !fs.args.PlaintextNames {
name, err = fs.CryptFS.DecryptName(cName, cachedIV, fs.args.EMENames) name, err = fs.CryptFS.DecryptName(cName, cachedIV, fs.args.EMENames)
if err != nil { if err != nil {
cryptfs.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s\n", cName, dirName, err) cryptfs.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s", cName, dirName, err)
continue continue
} }
} }
@ -137,10 +137,10 @@ func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile n
iflags, writeOnly := fs.mangleOpenFlags(flags) iflags, writeOnly := fs.mangleOpenFlags(flags)
cPath, err := fs.getBackingPath(path) cPath, err := fs.getBackingPath(path)
if err != nil { if err != nil {
cryptfs.Debug.Printf("Open: getBackingPath: %v\n", err) cryptfs.Debug.Printf("Open: getBackingPath: %v", err)
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
} }
cryptfs.Debug.Printf("Open: %s\n", cPath) cryptfs.Debug.Printf("Open: %s", cPath)
f, err := os.OpenFile(cPath, iflags, 0666) f, err := os.OpenFile(cPath, iflags, 0666)
if err != nil { if err != nil {
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
@ -199,7 +199,7 @@ func (fs *FS) Mknod(path string, mode uint32, dev uint32, context *fuse.Context)
} }
func (fs *FS) Truncate(path string, offset uint64, context *fuse.Context) (code fuse.Status) { func (fs *FS) Truncate(path string, offset uint64, context *fuse.Context) (code fuse.Status) {
cryptfs.Warn.Printf("Truncate of a closed file is not supported, returning ENOSYS\n") cryptfs.Warn.Printf("Truncate of a closed file is not supported, returning ENOSYS")
return fuse.ENOSYS return fuse.ENOSYS
} }
@ -235,12 +235,12 @@ func (fs *FS) Readlink(path string, context *fuse.Context) (out string, status f
// Since gocryptfs v0.5 symlinks are encrypted like file contents (GCM) // Since gocryptfs v0.5 symlinks are encrypted like file contents (GCM)
cBinTarget, err := base64.URLEncoding.DecodeString(cTarget) cBinTarget, err := base64.URLEncoding.DecodeString(cTarget)
if err != nil { if err != nil {
cryptfs.Warn.Printf("Readlink: %v\n", err) cryptfs.Warn.Printf("Readlink: %v", err)
return "", fuse.EIO return "", fuse.EIO
} }
target, err := fs.CryptFS.DecryptBlock([]byte(cBinTarget), 0, nil) target, err := fs.CryptFS.DecryptBlock([]byte(cBinTarget), 0, nil)
if err != nil { if err != nil {
cryptfs.Warn.Printf("Readlink: %v\n", err) cryptfs.Warn.Printf("Readlink: %v", err)
return "", fuse.EIO return "", fuse.EIO
} }
return string(target), fuse.OK return string(target), fuse.OK
@ -258,7 +258,7 @@ func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) {
} }
func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (code fuse.Status) { func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (code fuse.Status) {
cryptfs.Debug.Printf("Symlink(\"%s\", \"%s\")\n", target, linkName) cryptfs.Debug.Printf("Symlink(\"%s\", \"%s\")", target, linkName)
if fs.isFiltered(linkName) { if fs.isFiltered(linkName) {
return fuse.EPERM return fuse.EPERM
} }
@ -270,7 +270,7 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co
if !fs.args.DirIV { if !fs.args.DirIV {
cTarget, err := fs.encryptPath(target) cTarget, err := fs.encryptPath(target)
if err != nil { if err != nil {
cryptfs.Warn.Printf("Symlink: BUG: we should not get an error here: %v\n", err) cryptfs.Warn.Printf("Symlink: BUG: we should not get an error here: %v", err)
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
err = os.Symlink(cTarget, cPath) err = os.Symlink(cTarget, cPath)
@ -281,7 +281,7 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co
cTarget := base64.URLEncoding.EncodeToString(cBinTarget) cTarget := base64.URLEncoding.EncodeToString(cBinTarget)
err = os.Symlink(cTarget, cPath) err = os.Symlink(cTarget, cPath)
cryptfs.Debug.Printf("Symlink: os.Symlink(%s, %s) = %v\n", cTarget, cPath, err) cryptfs.Debug.Printf("Symlink: os.Symlink(%s, %s) = %v", cTarget, cPath, err)
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
@ -307,7 +307,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
// If an empty directory is overwritten we will always get // If an empty directory is overwritten we will always get
// ENOTEMPTY as the "empty" directory will still contain gocryptfs.diriv. // ENOTEMPTY as the "empty" directory will still contain gocryptfs.diriv.
// Handle that case by removing the target directory and trying again. // Handle that case by removing the target directory and trying again.
cryptfs.Debug.Printf("Rename: Handling ENOTEMPTY\n") cryptfs.Debug.Printf("Rename: Handling ENOTEMPTY")
if fs.Rmdir(newPath, context) == fuse.OK { if fs.Rmdir(newPath, context) == fuse.OK {
err = os.Rename(cOldPath, cNewPath) err = os.Rename(cOldPath, cNewPath)
} }

View File

@ -41,10 +41,10 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu
err = cryptfs.WriteDirIV(encPath) err = cryptfs.WriteDirIV(encPath)
if err != nil { if err != nil {
// This should not happen // This should not happen
cryptfs.Warn.Printf("Mkdir: WriteDirIV failed: %v\n", err) cryptfs.Warn.Printf("Mkdir: WriteDirIV failed: %v", err)
err2 := syscall.Rmdir(encPath) err2 := syscall.Rmdir(encPath)
if err2 != nil { if err2 != nil {
cryptfs.Warn.Printf("Mkdir: Rmdir rollback failed: %v\n", err2) cryptfs.Warn.Printf("Mkdir: Rmdir rollback failed: %v", err2)
} }
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
@ -53,7 +53,7 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu
if origMode != mode { if origMode != mode {
err = os.Chmod(encPath, os.FileMode(origMode)) err = os.Chmod(encPath, os.FileMode(origMode))
if err != nil { if err != nil {
cryptfs.Warn.Printf("Mkdir: Chmod failed: %v\n", err) cryptfs.Warn.Printf("Mkdir: Chmod failed: %v", err)
} }
} }
@ -74,17 +74,17 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
fd, err := os.Open(encPath) fd, err := os.Open(encPath)
if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.EACCES { if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.EACCES {
// We need permission to read and modify the directory // We need permission to read and modify the directory
cryptfs.Debug.Printf("Rmdir: handling EACCESS\n") cryptfs.Debug.Printf("Rmdir: handling EACCESS")
fi, err2 := os.Stat(encPath) fi, err2 := os.Stat(encPath)
if err2 != nil { if err2 != nil {
cryptfs.Debug.Printf("Rmdir: Stat: %v\n", err2) cryptfs.Debug.Printf("Rmdir: Stat: %v", err2)
return fuse.ToStatus(err2) return fuse.ToStatus(err2)
} }
origMode := fi.Mode() origMode := fi.Mode()
newMode := origMode | 0700 newMode := origMode | 0700
err2 = os.Chmod(encPath, newMode) err2 = os.Chmod(encPath, newMode)
if err2 != nil { if err2 != nil {
cryptfs.Debug.Printf("Rmdir: Chmod failed: %v\n", err2) cryptfs.Debug.Printf("Rmdir: Chmod failed: %v", err2)
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
defer func() { defer func() {
@ -92,7 +92,7 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
// Undo the chmod if removing the directory failed // Undo the chmod if removing the directory failed
err3 := os.Chmod(encPath, origMode) err3 := os.Chmod(encPath, origMode)
if err3 != nil { if err3 != nil {
cryptfs.Warn.Printf("Rmdir: Chmod rollback failed: %v\n", err2) cryptfs.Warn.Printf("Rmdir: Chmod rollback failed: %v", err2)
} }
} }
}() }()
@ -100,19 +100,19 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
fd, err = os.Open(encPath) fd, err = os.Open(encPath)
} }
if err != nil { if err != nil {
cryptfs.Debug.Printf("Rmdir: Open: %v\n", err) cryptfs.Debug.Printf("Rmdir: Open: %v", err)
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
list, err := fd.Readdirnames(10) list, err := fd.Readdirnames(10)
fd.Close() fd.Close()
if err != nil { if err != nil {
cryptfs.Debug.Printf("Rmdir: Readdirnames: %v\n", err) cryptfs.Debug.Printf("Rmdir: Readdirnames: %v", err)
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
if len(list) > 1 { if len(list) > 1 {
return fuse.ToStatus(syscall.ENOTEMPTY) return fuse.ToStatus(syscall.ENOTEMPTY)
} else if len(list) == 0 { } else if len(list) == 0 {
cryptfs.Warn.Printf("Rmdir: gocryptfs.diriv missing, allowing deletion\n") cryptfs.Warn.Printf("Rmdir: gocryptfs.diriv missing, allowing deletion")
return fuse.ToStatus(syscall.Rmdir(encPath)) return fuse.ToStatus(syscall.Rmdir(encPath))
} }
@ -121,14 +121,14 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
parentDir := filepath.Dir(encPath) parentDir := filepath.Dir(encPath)
tmpName := fmt.Sprintf("gocryptfs.diriv.rmdir.%d", cryptfs.RandUint64()) tmpName := fmt.Sprintf("gocryptfs.diriv.rmdir.%d", cryptfs.RandUint64())
tmpDirivPath := filepath.Join(parentDir, tmpName) tmpDirivPath := filepath.Join(parentDir, tmpName)
cryptfs.Debug.Printf("Rmdir: Renaming %s to %s\n", cryptfs.DIRIV_FILENAME, tmpDirivPath) cryptfs.Debug.Printf("Rmdir: Renaming %s to %s", cryptfs.DIRIV_FILENAME, tmpDirivPath)
// The directory is in an inconsistent state between rename and rmdir. Protect against // The directory is in an inconsistent state between rename and rmdir. Protect against
// concurrent readers. // concurrent readers.
fs.dirIVLock.Lock() fs.dirIVLock.Lock()
defer fs.dirIVLock.Unlock() defer fs.dirIVLock.Unlock()
err = os.Rename(dirivPath, tmpDirivPath) err = os.Rename(dirivPath, tmpDirivPath)
if err != nil { if err != nil {
cryptfs.Warn.Printf("Rmdir: Renaming %s to %s failed: %v\n", cryptfs.DIRIV_FILENAME, tmpDirivPath, err) cryptfs.Warn.Printf("Rmdir: Renaming %s to %s failed: %v", cryptfs.DIRIV_FILENAME, tmpDirivPath, err)
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
// Actual Rmdir // Actual Rmdir
@ -138,14 +138,14 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
// meantime, undo the rename // meantime, undo the rename
err2 := os.Rename(tmpDirivPath, dirivPath) err2 := os.Rename(tmpDirivPath, dirivPath)
if err2 != nil { if err2 != nil {
cryptfs.Warn.Printf("Rmdir: Rename rollback failed: %v\n", err2) cryptfs.Warn.Printf("Rmdir: Rename rollback failed: %v", err2)
} }
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
// Delete "gocryptfs.diriv.rmdir.INODENUMBER" // Delete "gocryptfs.diriv.rmdir.INODENUMBER"
err = syscall.Unlink(tmpDirivPath) err = syscall.Unlink(tmpDirivPath)
if err != nil { if err != nil {
cryptfs.Warn.Printf("Rmdir: Could not clean up %s: %v\n", tmpName, err) cryptfs.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err)
} }
// The now-deleted directory may have been in the DirIV cache. Clear it. // The now-deleted directory may have been in the DirIV cache. Clear it.
fs.CryptFS.DirIVCacheEnc.Clear() fs.CryptFS.DirIVCacheEnc.Clear()