cli: drop -forcedecode flag

The rewritten openssl backend does not support this flag anymore,
and it was inherently dangerour. Drop it (ignored for compatibility)
This commit is contained in:
Jakob Unterwurzacher 2021-09-10 12:14:19 +02:00
parent c974116322
commit d023cd6c95
17 changed files with 37 additions and 104 deletions

View File

@ -256,21 +256,8 @@ of a case where this may be useful is a situation where content is stored on a
filesystem that doesn't properly support UNIX ownership and permissions. filesystem that doesn't properly support UNIX ownership and permissions.
#### -forcedecode #### -forcedecode
Force decode of encrypted files even if the integrity check fails, instead of
failing with an IO error. Warning messages are still printed to syslog if corrupted
files are encountered.
It can be useful to recover files from disks with bad sectors or other corrupted
media. It shall not be used if the origin of corruption is unknown, specially
if you want to run executable files.
For corrupted media, note that you probably want to use dd_rescue(1) Obsolete and ignored on gocryptfs v2.2 and later.
instead, which will recover all but the corrupted 4kB block.
This option makes no sense in reverse mode. It requires gocryptfs to be compiled with openssl
support and implies -openssl true. Because of this, it is not compatible with -aessiv,
that uses built-in Go crypto.
Setting this option forces the filesystem to read-only and noexec.
#### -fsname string #### -fsname string
Override the filesystem name (first column in df -T). Can also be Override the filesystem name (first column in df -T). Can also be

View File

@ -29,7 +29,7 @@ type argContainer struct {
debug, init, zerokey, fusedebug, openssl, passwd, fg, version, debug, init, zerokey, fusedebug, openssl, passwd, fg, version,
plaintextnames, quiet, nosyslog, wpanic, plaintextnames, quiet, nosyslog, wpanic,
longnames, allow_other, reverse, aessiv, nonempty, raw64, longnames, allow_other, reverse, aessiv, nonempty, raw64,
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info, noprealloc, speed, hkdf, serialize_reads, hh, info,
sharedstorage, fsck, one_file_system, deterministic_names, sharedstorage, fsck, one_file_system, deterministic_names,
xchacha bool xchacha bool
// Mount options with opposites // Mount options with opposites
@ -172,8 +172,6 @@ func parseCliOpts(osArgs []string) (args argContainer) {
flagSet.BoolVar(&args.speed, "speed", false, "Run crypto speed test") flagSet.BoolVar(&args.speed, "speed", false, "Run crypto speed test")
flagSet.BoolVar(&args.hkdf, "hkdf", true, "Use HKDF as an additional key derivation step") flagSet.BoolVar(&args.hkdf, "hkdf", true, "Use HKDF as an additional key derivation step")
flagSet.BoolVar(&args.serialize_reads, "serialize_reads", false, "Try to serialize read operations") flagSet.BoolVar(&args.serialize_reads, "serialize_reads", false, "Try to serialize read operations")
flagSet.BoolVar(&args.forcedecode, "forcedecode", false, "Force decode of files even if integrity check fails."+
" Requires gocryptfs to be compiled with openssl support and implies -openssl true")
flagSet.BoolVar(&args.hh, "hh", false, "Show this long help text") flagSet.BoolVar(&args.hh, "hh", false, "Show this long help text")
flagSet.BoolVar(&args.info, "info", false, "Display information about CIPHERDIR") flagSet.BoolVar(&args.info, "info", false, "Display information about CIPHERDIR")
flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer") flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer")
@ -234,7 +232,8 @@ func parseCliOpts(osArgs []string) (args argContainer) {
{ {
var tmp bool var tmp bool
flagSet.BoolVar(&tmp, "nofail", false, "Ignored for /etc/fstab compatibility") flagSet.BoolVar(&tmp, "nofail", false, "Ignored for /etc/fstab compatibility")
flagSet.BoolVar(&tmp, "devrandom", false, "Deprecated (ignored for compatibility)") flagSet.BoolVar(&tmp, "devrandom", false, "Obsolete, ignored for compatibility")
flagSet.BoolVar(&tmp, "forcedecode", false, "Obsolete, ignored for compatibility")
} }
// Actual parsing // Actual parsing
@ -265,32 +264,6 @@ func parseCliOpts(osArgs []string) (args argContainer) {
os.Exit(exitcodes.Usage) os.Exit(exitcodes.Usage)
} }
} }
// "-forcedecode" only works with openssl. Check compilation and command line parameters
if args.forcedecode {
if stupidgcm.BuiltWithoutOpenssl {
tlog.Fatal.Printf("The -forcedecode flag requires openssl support, but gocryptfs was compiled without it!")
os.Exit(exitcodes.Usage)
}
if args.aessiv {
tlog.Fatal.Printf("The -forcedecode and -aessiv flags are incompatible because they use different crypto libs (openssl vs native Go)")
os.Exit(exitcodes.Usage)
}
if args.reverse {
tlog.Fatal.Printf("The reverse mode and the -forcedecode option are not compatible")
os.Exit(exitcodes.Usage)
}
// Has the user explicitly disabled openssl using "-openssl=false/0"?
if !args.openssl && opensslAuto != "auto" {
tlog.Fatal.Printf("-forcedecode requires openssl, but is disabled via command-line option")
os.Exit(exitcodes.Usage)
}
args.openssl = true
// Try to make it harder for the user to shoot himself in the foot.
args.ro = true
args.allow_other = false
args.ko = "noexec"
}
if len(args.extpass) > 0 && len(args.passfile) != 0 { if len(args.extpass) > 0 && len(args.passfile) != 0 {
tlog.Fatal.Printf("The options -extpass and -passfile cannot be used at the same time") tlog.Fatal.Printf("The options -extpass and -passfile cannot be used at the same time")
os.Exit(exitcodes.Usage) os.Exit(exitcodes.Usage)

View File

@ -298,8 +298,8 @@ func getKeyEncrypter(scryptHash []byte, useHKDF bool) *contentenc.ContentEnc {
if useHKDF { if useHKDF {
IVLen = contentenc.DefaultIVBits IVLen = contentenc.DefaultIVBits
} }
cc := cryptocore.New(scryptHash, cryptocore.BackendGoGCM, IVLen, useHKDF, false) cc := cryptocore.New(scryptHash, cryptocore.BackendGoGCM, IVLen, useHKDF)
ce := contentenc.New(cc, 4096, false) ce := contentenc.New(cc, 4096)
return ce return ce
} }

View File

@ -13,7 +13,6 @@ import (
"github.com/hanwen/go-fuse/v2/fuse" "github.com/hanwen/go-fuse/v2/fuse"
"github.com/rfjakob/gocryptfs/v2/internal/cryptocore" "github.com/rfjakob/gocryptfs/v2/internal/cryptocore"
"github.com/rfjakob/gocryptfs/v2/internal/stupidgcm"
"github.com/rfjakob/gocryptfs/v2/internal/tlog" "github.com/rfjakob/gocryptfs/v2/internal/tlog"
) )
@ -41,8 +40,6 @@ type ContentEnc struct {
allZeroBlock []byte allZeroBlock []byte
// All-zero block of size IVBitLen/8, for fast compares // All-zero block of size IVBitLen/8, for fast compares
allZeroNonce []byte allZeroNonce []byte
// Force decode even if integrity check fails (openSSL only)
forceDecode bool
// Ciphertext block "sync.Pool" pool. Always returns cipherBS-sized byte // Ciphertext block "sync.Pool" pool. Always returns cipherBS-sized byte
// slices (usually 4128 bytes). // slices (usually 4128 bytes).
@ -60,9 +57,8 @@ type ContentEnc struct {
} }
// New returns an initialized ContentEnc instance. // New returns an initialized ContentEnc instance.
func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEnc { func New(cc *cryptocore.CryptoCore, plainBS uint64) *ContentEnc {
tlog.Debug.Printf("contentenc.New: plainBS=%d, forceDecode=%v", tlog.Debug.Printf("contentenc.New: plainBS=%d", plainBS)
plainBS, forceDecode)
if fuse.MAX_KERNEL_WRITE%plainBS != 0 { if fuse.MAX_KERNEL_WRITE%plainBS != 0 {
log.Panicf("unaligned MAX_KERNEL_WRITE=%d", fuse.MAX_KERNEL_WRITE) log.Panicf("unaligned MAX_KERNEL_WRITE=%d", fuse.MAX_KERNEL_WRITE)
@ -81,7 +77,6 @@ func New(cc *cryptocore.CryptoCore, plainBS uint64, forceDecode bool) *ContentEn
cipherBS: cipherBS, cipherBS: cipherBS,
allZeroBlock: make([]byte, cipherBS), allZeroBlock: make([]byte, cipherBS),
allZeroNonce: make([]byte, cc.IVLen), allZeroNonce: make([]byte, cc.IVLen),
forceDecode: forceDecode,
cBlockPool: newBPool(int(cipherBS)), cBlockPool: newBPool(int(cipherBS)),
CReqPool: newBPool(cReqSize), CReqPool: newBPool(cReqSize),
pBlockPool: newBPool(int(plainBS)), pBlockPool: newBPool(int(plainBS)),
@ -111,11 +106,7 @@ func (be *ContentEnc) DecryptBlocks(ciphertext []byte, firstBlockNo uint64, file
var pBlock []byte var pBlock []byte
pBlock, err = be.DecryptBlock(cBlock, blockNo, fileID) pBlock, err = be.DecryptBlock(cBlock, blockNo, fileID)
if err != nil { if err != nil {
if be.forceDecode && err == stupidgcm.ErrAuth { break
tlog.Warn.Printf("DecryptBlocks: authentication failure in block #%d, overridden by forcedecode", firstBlockNo)
} else {
break
}
} }
pBuf.Write(pBlock) pBuf.Write(pBlock)
be.pBlockPool.Put(pBlock) be.pBlockPool.Put(pBlock)
@ -183,9 +174,6 @@ func (be *ContentEnc) DecryptBlock(ciphertext []byte, blockNo uint64, fileID []b
if err != nil { if err != nil {
tlog.Debug.Printf("DecryptBlock: %s, len=%d", err.Error(), len(ciphertextOrig)) tlog.Debug.Printf("DecryptBlock: %s, len=%d", err.Error(), len(ciphertextOrig))
tlog.Debug.Println(hex.Dump(ciphertextOrig)) tlog.Debug.Println(hex.Dump(ciphertextOrig))
if be.forceDecode && err == stupidgcm.ErrAuth {
return plaintext, err
}
return nil, err return nil, err
} }

View File

@ -23,8 +23,8 @@ func TestSplitRange(t *testing.T) {
testRange{6654, 8945}) testRange{6654, 8945})
key := make([]byte, cryptocore.KeyLen) key := make([]byte, cryptocore.KeyLen)
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true, false) cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
f := New(cc, DefaultBS, false) f := New(cc, DefaultBS)
for _, r := range ranges { for _, r := range ranges {
parts := f.ExplodePlainRange(r.offset, r.length) parts := f.ExplodePlainRange(r.offset, r.length)
@ -51,8 +51,8 @@ func TestCiphertextRange(t *testing.T) {
testRange{6654, 8945}) testRange{6654, 8945})
key := make([]byte, cryptocore.KeyLen) key := make([]byte, cryptocore.KeyLen)
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true, false) cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
f := New(cc, DefaultBS, false) f := New(cc, DefaultBS)
for _, r := range ranges { for _, r := range ranges {
@ -74,8 +74,8 @@ func TestCiphertextRange(t *testing.T) {
func TestBlockNo(t *testing.T) { func TestBlockNo(t *testing.T) {
key := make([]byte, cryptocore.KeyLen) key := make([]byte, cryptocore.KeyLen)
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true, false) cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
f := New(cc, DefaultBS, false) f := New(cc, DefaultBS)
b := f.CipherOffToBlockNo(788) b := f.CipherOffToBlockNo(788)
if b != 0 { if b != 0 {

View File

@ -10,8 +10,8 @@ import (
// TestSizeToSize tests CipherSizeToPlainSize and PlainSizeToCipherSize // TestSizeToSize tests CipherSizeToPlainSize and PlainSizeToCipherSize
func TestSizeToSize(t *testing.T) { func TestSizeToSize(t *testing.T) {
key := make([]byte, cryptocore.KeyLen) key := make([]byte, cryptocore.KeyLen)
cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true, false) cc := cryptocore.New(key, cryptocore.BackendGoGCM, DefaultIVBits, true)
ce := New(cc, DefaultBS, false) ce := New(cc, DefaultBS)
const rangeMax = 10000 const rangeMax = 10000

View File

@ -73,9 +73,9 @@ type CryptoCore struct {
// //
// Note: "key" is either the scrypt hash of the password (when decrypting // Note: "key" is either the scrypt hash of the password (when decrypting
// a config file) or the masterkey (when finally mounting the filesystem). // a config file) or the masterkey (when finally mounting the filesystem).
func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDecode bool) *CryptoCore { func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool) *CryptoCore {
tlog.Debug.Printf("cryptocore.New: key=%d bytes, aeadType=%v, IVBitLen=%d, useHKDF=%v, forceDecode=%v", tlog.Debug.Printf("cryptocore.New: key=%d bytes, aeadType=%v, IVBitLen=%d, useHKDF=%v",
len(key), aeadType, IVBitLen, useHKDF, forceDecode) len(key), aeadType, IVBitLen, useHKDF)
if len(key) != KeyLen { if len(key) != KeyLen {
log.Panicf("Unsupported key length of %d bytes", len(key)) log.Panicf("Unsupported key length of %d bytes", len(key))
@ -120,7 +120,7 @@ func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDec
if IVBitLen != 128 { if IVBitLen != 128 {
log.Panicf("stupidgcm only supports 128-bit IVs, you wanted %d", IVBitLen) log.Panicf("stupidgcm only supports 128-bit IVs, you wanted %d", IVBitLen)
} }
aeadCipher = stupidgcm.NewAES256GCM(gcmKey, forceDecode) aeadCipher = stupidgcm.NewAES256GCM(gcmKey)
case BackendGoGCM: case BackendGoGCM:
goGcmBlockCipher, err := aes.NewCipher(gcmKey) goGcmBlockCipher, err := aes.NewCipher(gcmKey)
if err != nil { if err != nil {

View File

@ -10,18 +10,18 @@ import (
func TestCryptoCoreNew(t *testing.T) { func TestCryptoCoreNew(t *testing.T) {
key := make([]byte, 32) key := make([]byte, 32)
for _, useHKDF := range []bool{true, false} { for _, useHKDF := range []bool{true, false} {
c := New(key, BackendGoGCM, 96, useHKDF, false) c := New(key, BackendGoGCM, 96, useHKDF)
if c.IVLen != 12 { if c.IVLen != 12 {
t.Fail() t.Fail()
} }
c = New(key, BackendGoGCM, 128, useHKDF, false) c = New(key, BackendGoGCM, 128, useHKDF)
if c.IVLen != 16 { if c.IVLen != 16 {
t.Fail() t.Fail()
} }
if stupidgcm.BuiltWithoutOpenssl { if stupidgcm.BuiltWithoutOpenssl {
continue continue
} }
c = New(key, BackendOpenSSL, 128, useHKDF, false) c = New(key, BackendOpenSSL, 128, useHKDF)
if c.IVLen != 16 { if c.IVLen != 16 {
t.Fail() t.Fail()
} }
@ -37,5 +37,5 @@ func TestNewPanic(t *testing.T) {
}() }()
key := make([]byte, 16) key := make([]byte, 16)
New(key, BackendOpenSSL, 128, true, false) New(key, BackendOpenSSL, 128, true)
} }

View File

@ -26,8 +26,6 @@ type Args struct {
ConfigCustom bool ConfigCustom bool
// NoPrealloc disables automatic preallocation before writing // NoPrealloc disables automatic preallocation before writing
NoPrealloc bool NoPrealloc bool
// Force decode even if integrity check fails (openSSL only)
ForceDecode bool
// Exclude is a list of paths to make inaccessible, starting match at // Exclude is a list of paths to make inaccessible, starting match at
// the filesystem root // the filesystem root
Exclude []string Exclude []string

View File

@ -20,7 +20,6 @@ import (
"github.com/rfjakob/gocryptfs/v2/internal/contentenc" "github.com/rfjakob/gocryptfs/v2/internal/contentenc"
"github.com/rfjakob/gocryptfs/v2/internal/inomap" "github.com/rfjakob/gocryptfs/v2/internal/inomap"
"github.com/rfjakob/gocryptfs/v2/internal/openfiletable" "github.com/rfjakob/gocryptfs/v2/internal/openfiletable"
"github.com/rfjakob/gocryptfs/v2/internal/stupidgcm"
"github.com/rfjakob/gocryptfs/v2/internal/syscallcompat" "github.com/rfjakob/gocryptfs/v2/internal/syscallcompat"
"github.com/rfjakob/gocryptfs/v2/internal/tlog" "github.com/rfjakob/gocryptfs/v2/internal/tlog"
) )
@ -208,16 +207,9 @@ func (f *File) doRead(dst []byte, off uint64, length uint64) ([]byte, syscall.Er
plaintext, err := f.contentEnc.DecryptBlocks(ciphertext, firstBlockNo, fileID) plaintext, err := f.contentEnc.DecryptBlocks(ciphertext, firstBlockNo, fileID)
f.rootNode.contentEnc.CReqPool.Put(ciphertext) f.rootNode.contentEnc.CReqPool.Put(ciphertext)
if err != nil { if err != nil {
if f.rootNode.args.ForceDecode && err == stupidgcm.ErrAuth { curruptBlockNo := firstBlockNo + f.contentEnc.PlainOffToBlockNo(uint64(len(plaintext)))
// We do not have the information which block was corrupt here anymore, tlog.Warn.Printf("doRead %d: corrupt block #%d: %v", f.qIno.Ino, curruptBlockNo, err)
// but DecryptBlocks() has already logged it anyway. return nil, syscall.EIO
tlog.Warn.Printf("doRead %d: off=%d len=%d: returning corrupt data due to forcedecode",
f.qIno.Ino, off, length)
} else {
curruptBlockNo := firstBlockNo + f.contentEnc.PlainOffToBlockNo(uint64(len(plaintext)))
tlog.Warn.Printf("doRead %d: corrupt block #%d: %v", f.qIno.Ino, curruptBlockNo, err)
return nil, syscall.EIO
}
} }
// Crop down to the relevant part // Crop down to the relevant part

View File

@ -17,8 +17,8 @@ import (
func newTestFS(args Args) *RootNode { func newTestFS(args Args) *RootNode {
// Init crypto backend // Init crypto backend
key := make([]byte, cryptocore.KeyLen) key := make([]byte, cryptocore.KeyLen)
cCore := cryptocore.New(key, cryptocore.BackendGoGCM, contentenc.DefaultIVBits, true, false) cCore := cryptocore.New(key, cryptocore.BackendGoGCM, contentenc.DefaultIVBits, true)
cEnc := contentenc.New(cCore, contentenc.DefaultBS, false) cEnc := contentenc.New(cCore, contentenc.DefaultBS)
n := nametransform.New(cCore.EMECipher, true, true, nil, false) n := nametransform.New(cCore.EMECipher, true, true, nil, false)
rn := NewRootNode(args, cEnc, n) rn := NewRootNode(args, cEnc, n)
oneSec := time.Second oneSec := time.Second

View File

@ -114,7 +114,7 @@ func bStupidGCM(b *testing.B) {
if stupidgcm.BuiltWithoutOpenssl { if stupidgcm.BuiltWithoutOpenssl {
b.Skip("openssl has been disabled at compile-time") b.Skip("openssl has been disabled at compile-time")
} }
bEncrypt(b, stupidgcm.NewAES256GCM(randBytes(32), false)) bEncrypt(b, stupidgcm.NewAES256GCM(randBytes(32)))
} }
// bGoGCM benchmarks Go stdlib GCM // bGoGCM benchmarks Go stdlib GCM

View File

@ -31,7 +31,7 @@ func BenchmarkStupidGCMDecrypt(b *testing.B) {
if stupidgcm.BuiltWithoutOpenssl { if stupidgcm.BuiltWithoutOpenssl {
b.Skip("openssl has been disabled at compile-time") b.Skip("openssl has been disabled at compile-time")
} }
bDecrypt(b, stupidgcm.NewAES256GCM(randBytes(32), false)) bDecrypt(b, stupidgcm.NewAES256GCM(randBytes(32)))
} }
func BenchmarkGoGCM(b *testing.B) { func BenchmarkGoGCM(b *testing.B) {

View File

@ -26,7 +26,7 @@ type stupidGCM struct {
// NewAES256GCM returns a new AES-256-GCM cipher that satisfies the cipher.AEAD interface. // NewAES256GCM returns a new AES-256-GCM cipher that satisfies the cipher.AEAD interface.
// //
// Only 32-bytes keys and 16-byte IVs are supported. // Only 32-bytes keys and 16-byte IVs are supported.
func NewAES256GCM(keyIn []byte, forceDecode bool) cipher.AEAD { func NewAES256GCM(keyIn []byte) cipher.AEAD {
if len(keyIn) != keyLen { if len(keyIn) != keyLen {
log.Panicf("Only %d-byte keys are supported", keyLen) log.Panicf("Only %d-byte keys are supported", keyLen)
} }

View File

@ -13,7 +13,7 @@ import (
func TestStupidGCM(t *testing.T) { func TestStupidGCM(t *testing.T) {
key := randBytes(32) key := randBytes(32)
sGCM := NewAES256GCM(key, false) sGCM := NewAES256GCM(key)
gAES, err := aes.NewCipher(key) gAES, err := aes.NewCipher(key)
if err != nil { if err != nil {

View File

@ -21,7 +21,7 @@ func errExit() {
os.Exit(exitcodes.OpenSSL) os.Exit(exitcodes.OpenSSL)
} }
func NewAES256GCM(_ []byte, _ bool) cipher.AEAD { func NewAES256GCM(_ []byte) cipher.AEAD {
errExit() errExit()
return nil return nil
} }

View File

@ -277,7 +277,6 @@ func initFuseFrontend(args *argContainer) (rootNode fs.InodeEmbedder, wipeKeys f
LongNames: args.longnames, LongNames: args.longnames,
ConfigCustom: args._configCustom, ConfigCustom: args._configCustom,
NoPrealloc: args.noprealloc, NoPrealloc: args.noprealloc,
ForceDecode: args.forcedecode,
ForceOwner: args._forceOwner, ForceOwner: args._forceOwner,
Exclude: args.exclude, Exclude: args.exclude,
ExcludeWildcard: args.excludeWildcard, ExcludeWildcard: args.excludeWildcard,
@ -323,8 +322,8 @@ func initFuseFrontend(args *argContainer) (rootNode fs.InodeEmbedder, wipeKeys f
} }
// Init crypto backend // Init crypto backend
cCore := cryptocore.New(masterkey, cryptoBackend, IVBits, args.hkdf, args.forcedecode) cCore := cryptocore.New(masterkey, cryptoBackend, IVBits, args.hkdf)
cEnc := contentenc.New(cCore, contentenc.DefaultBS, args.forcedecode) cEnc := contentenc.New(cCore, contentenc.DefaultBS)
nameTransform := nametransform.New(cCore.EMECipher, frontendArgs.LongNames, nameTransform := nametransform.New(cCore.EMECipher, frontendArgs.LongNames,
args.raw64, []string(args.badname), frontendArgs.DeterministicNames) args.raw64, []string(args.badname), frontendArgs.DeterministicNames)
// After the crypto backend is initialized, // After the crypto backend is initialized,
@ -408,10 +407,6 @@ func initGoFuse(rootNode fs.InodeEmbedder, args *argContainer) *fuse.Server {
if args.acl { if args.acl {
mOpts.EnableAcl = true mOpts.EnableAcl = true
} }
if args.forcedecode {
tlog.Info.Printf(tlog.ColorYellow + "THE OPTION \"-forcedecode\" IS ACTIVE. GOCRYPTFS WILL RETURN CORRUPT DATA!" +
tlog.ColorReset)
}
// fusermount from libfuse 3.x removed the "nonempty" option and exits // fusermount from libfuse 3.x removed the "nonempty" option and exits
// with an error if it sees it. Only add it to the options on libfuse 2.x. // with an error if it sees it. Only add it to the options on libfuse 2.x.
if args.nonempty && haveFusermount2() { if args.nonempty && haveFusermount2() {