Refactor ciphertext <-> plaintext offset translation functions

Move all the intelligence into the new file address_translation.go.
That the calculations were spread out too much became apparent when adding
the file header. This should make the code much easier to modify in the
future.
This commit is contained in:
Jakob Unterwurzacher 2015-11-01 12:11:36 +01:00
parent 14276c9632
commit 902babdf22
12 changed files with 158 additions and 186 deletions

View File

@ -0,0 +1,79 @@
package cryptfs
// CryptFS methods that translate offsets between ciphertext and plaintext
// get the block number at plain-text offset
func (be *CryptFS) PlainOffToBlockNo(plainOffset uint64) uint64 {
return plainOffset / be.plainBS
}
// get the block number at ciphter-text offset
func (be *CryptFS) CipherOffToBlockNo(cipherOffset uint64) uint64 {
return (cipherOffset - HEADER_LEN) / be.cipherBS
}
// get ciphertext offset of block "blockNo"
func (be *CryptFS) BlockNoToCipherOff(blockNo uint64) uint64 {
return HEADER_LEN + blockNo*be.cipherBS
}
// get plaintext offset of block "blockNo"
func (be *CryptFS) BlockNoToPlainOff(blockNo uint64) uint64 {
return blockNo * be.plainBS
}
// PlainSize - calculate plaintext size from ciphertext size
func (be *CryptFS) CipherSizeToPlainSize(cipherSize uint64) uint64 {
// Zero sized files stay zero-sized
if cipherSize == 0 {
return 0
}
// Block number at last byte
blockNo := be.CipherOffToBlockNo(cipherSize - 1)
blockCount := blockNo + 1
overhead := BLOCK_OVERHEAD*blockCount + HEADER_LEN
return cipherSize - overhead
}
// CipherSize - calculate ciphertext size from plaintext size
func (be *CryptFS) PlainSizeToCipherSize(plainSize uint64) uint64 {
// Block number at last byte
blockNo := be.PlainOffToBlockNo(plainSize - 1)
blockCount := blockNo + 1
overhead := BLOCK_OVERHEAD*blockCount + HEADER_LEN
return plainSize + overhead
}
// Split a plaintext byte range into (possibly partial) blocks
func (be *CryptFS) ExplodePlainRange(offset uint64, length uint64) []intraBlock {
var blocks []intraBlock
var nextBlock intraBlock
nextBlock.fs = be
for length > 0 {
nextBlock.BlockNo = be.PlainOffToBlockNo(offset)
nextBlock.Skip = offset - be.BlockNoToPlainOff(nextBlock.BlockNo)
// Minimum of remaining data and remaining space in the block
nextBlock.Length = MinUint64(length, be.plainBS-nextBlock.Skip)
blocks = append(blocks, nextBlock)
offset += nextBlock.Length
length -= nextBlock.Length
}
return blocks
}
func MinUint64(x uint64, y uint64) uint64 {
if x < y {
return x
}
return y
}

View File

@ -1,8 +1,8 @@
package cryptfs package cryptfs
import ( import (
"fmt"
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
) )
import "os" import "os"

View File

@ -16,7 +16,7 @@ func TestSplitRange(t *testing.T) {
testRange{0, 10}, testRange{0, 10},
testRange{234, 6511}, testRange{234, 6511},
testRange{65444, 54}, testRange{65444, 54},
testRange{0, 1024*1024}, testRange{0, 1024 * 1024},
testRange{0, 65536}, testRange{0, 65536},
testRange{6654, 8945}) testRange{6654, 8945})
@ -24,8 +24,8 @@ func TestSplitRange(t *testing.T) {
f := NewCryptFS(key, true) f := NewCryptFS(key, true)
for _, r := range ranges { for _, r := range ranges {
parts := f.SplitRange(r.offset, r.length) parts := f.ExplodePlainRange(r.offset, r.length)
var lastBlockNo uint64 = 1<<63 var lastBlockNo uint64 = 1 << 63
for _, p := range parts { for _, p := range parts {
if p.BlockNo == lastBlockNo { if p.BlockNo == lastBlockNo {
t.Errorf("Duplicate block number %d", p.BlockNo) t.Errorf("Duplicate block number %d", p.BlockNo)
@ -51,11 +51,15 @@ func TestCiphertextRange(t *testing.T) {
f := NewCryptFS(key, true) f := NewCryptFS(key, true)
for _, r := range ranges { for _, r := range ranges {
alignedOffset, alignedLength, skipBytes := f.CiphertextRange(r.offset, r.length)
blocks := f.ExplodePlainRange(r.offset, r.length)
alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks)
skipBytes := blocks[0].Skip
if alignedLength < r.length { if alignedLength < r.length {
t.Errorf("alignedLength=%s is smaller than length=%d", alignedLength, r.length) t.Errorf("alignedLength=%s is smaller than length=%d", alignedLength, r.length)
} }
if (alignedOffset - HEADER_LEN)%f.cipherBS != 0 { if (alignedOffset-HEADER_LEN)%f.cipherBS != 0 {
t.Errorf("alignedOffset=%d is not aligned", alignedOffset) t.Errorf("alignedOffset=%d is not aligned", alignedOffset)
} }
if r.offset%f.plainBS != 0 && skipBytes == 0 { if r.offset%f.plainBS != 0 && skipBytes == 0 {
@ -68,19 +72,19 @@ func TestBlockNo(t *testing.T) {
key := make([]byte, KEY_LEN) key := make([]byte, KEY_LEN)
f := NewCryptFS(key, true) f := NewCryptFS(key, true)
b := f.BlockNoCipherOff(788) b := f.CipherOffToBlockNo(788)
if b != 0 { if b != 0 {
t.Errorf("actual: %d", b) t.Errorf("actual: %d", b)
} }
b = f.BlockNoCipherOff(HEADER_LEN + f.CipherBS()) b = f.CipherOffToBlockNo(HEADER_LEN + f.cipherBS)
if b != 1 { if b != 1 {
t.Errorf("actual: %d", b) t.Errorf("actual: %d", b)
} }
b = f.BlockNoPlainOff(788) b = f.PlainOffToBlockNo(788)
if b != 0 { if b != 0 {
t.Errorf("actual: %d", b) t.Errorf("actual: %d", b)
} }
b = f.BlockNoPlainOff(f.PlainBS()) b = f.PlainOffToBlockNo(f.plainBS)
if b != 1 { if b != 1 {
t.Errorf("actual: %d", b) t.Errorf("actual: %d", b)
} }

View File

@ -13,7 +13,7 @@ const (
KEY_LEN = 32 // AES-256 KEY_LEN = 32 // AES-256
NONCE_LEN = 12 NONCE_LEN = 12
AUTH_TAG_LEN = 16 AUTH_TAG_LEN = 16
BLOCK_OVERHEAD = NONCE_LEN + AUTH_TAG_LEN BLOCK_OVERHEAD = NONCE_LEN + AUTH_TAG_LEN
) )
type CryptFS struct { type CryptFS struct {
@ -61,8 +61,3 @@ func NewCryptFS(key []byte, useOpenssl bool) *CryptFS {
func (be *CryptFS) PlainBS() uint64 { func (be *CryptFS) PlainBS() uint64 {
return be.plainBS return be.plainBS
} }
// Get ciphertext block size
func (be *CryptFS) CipherBS() uint64 {
return be.cipherBS
}

View File

@ -12,11 +12,6 @@ import (
"os" "os"
) )
const (
// A block of 4124 zero bytes has this md5
ZeroBlockMd5 = "64331af89bd15a987b39855338336237"
)
// md5sum - debug helper, return md5 hex string // md5sum - debug helper, return md5 hex string
func md5sum(buf []byte) string { func md5sum(buf []byte) string {
rawHash := md5.Sum(buf) rawHash := md5.Sum(buf)
@ -110,106 +105,6 @@ func (be *CryptFS) EncryptBlock(plaintext []byte, blockNo uint64, fileId []byte)
return ciphertext return ciphertext
} }
// Split a plaintext byte range into (possibly partial) blocks
func (be *CryptFS) SplitRange(offset uint64, length uint64) []intraBlock {
var b intraBlock
var parts []intraBlock
b.fs = be
for length > 0 {
b.BlockNo = offset / be.plainBS
b.Skip = offset % be.plainBS
// Minimum of remaining data and remaining space in the block
b.Length = be.minu64(length, be.plainBS-b.Skip)
parts = append(parts, b)
offset += b.Length
length -= b.Length
}
return parts
}
// PlainSize - calculate plaintext size from ciphertext size
func (be *CryptFS) PlainSize(size uint64) uint64 {
// Zero sized files stay zero-sized
if size == 0 {
return 0
}
// Account for header
size -= HEADER_LEN
overhead := be.cipherBS - be.plainBS
nBlocks := (size + be.cipherBS - 1) / be.cipherBS
if nBlocks*overhead > size {
Warn.Printf("PlainSize: Negative size, returning 0 instead\n")
return 0
}
size -= nBlocks * overhead
return size
}
// CipherSize - calculate ciphertext size from plaintext size
func (be *CryptFS) CipherSize(size uint64) uint64 {
overhead := be.cipherBS - be.plainBS
nBlocks := (size + be.plainBS - 1) / be.plainBS
size += nBlocks * overhead
return size
}
func (be *CryptFS) minu64(x uint64, y uint64) uint64 {
if x < y {
return x
}
return y
}
// CiphertextRange - Get byte range in backing ciphertext corresponding
// to plaintext range. Returns a range aligned to ciphertext blocks.
func (be *CryptFS) CiphertextRange(offset uint64, length uint64) (alignedOffset uint64, alignedLength uint64, skipBytes int) {
// Decrypting the ciphertext will yield too many plaintext bytes. Skip this number
// of bytes from the front.
skip := offset % be.plainBS
firstBlockNo := offset / be.plainBS
lastBlockNo := (offset + length - 1) / be.plainBS
alignedOffset = HEADER_LEN + firstBlockNo * be.cipherBS
alignedLength = (lastBlockNo - firstBlockNo + 1) * be.cipherBS
skipBytes = int(skip)
return alignedOffset, alignedLength, skipBytes
}
// Get the byte range in the ciphertext corresponding to blocks
// (full blocks!)
func (be *CryptFS) JoinCiphertextRange(blocks []intraBlock) (uint64, uint64) {
offset, _ := blocks[0].CiphertextRange()
last := blocks[len(blocks)-1]
length := (last.BlockNo - blocks[0].BlockNo + 1) * be.cipherBS
return offset, length
}
// Crop plaintext that correspons to complete cipher blocks down to what is
// requested according to "iblocks"
func (be *CryptFS) CropPlaintext(plaintext []byte, blocks []intraBlock) []byte {
offset := blocks[0].Skip
last := blocks[len(blocks)-1]
length := (last.BlockNo - blocks[0].BlockNo + 1) * be.plainBS
var cropped []byte
if offset+length > uint64(len(plaintext)) {
cropped = plaintext[offset:]
} else {
cropped = plaintext[offset : offset+length]
}
return cropped
}
// MergeBlocks - Merge newData into oldData at offset // MergeBlocks - Merge newData into oldData at offset
// New block may be bigger than both newData and oldData // New block may be bigger than both newData and oldData
func (be *CryptFS) MergeBlocks(oldData []byte, newData []byte, offset int) []byte { func (be *CryptFS) MergeBlocks(oldData []byte, newData []byte, offset int) []byte {
@ -230,13 +125,3 @@ func (be *CryptFS) MergeBlocks(oldData []byte, newData []byte, offset int) []byt
} }
return out[0:outLen] return out[0:outLen]
} }
// Get the block number at plain-text offset
func (be *CryptFS) BlockNoPlainOff(plainOffset uint64) uint64 {
return plainOffset / be.plainBS
}
// Get the block number at ciphter-text offset
func (be *CryptFS) BlockNoCipherOff(cipherOffset uint64) uint64 {
return (cipherOffset - HEADER_LEN) / be.cipherBS
}

View File

@ -10,15 +10,15 @@ import (
) )
const ( const (
HEADER_CURRENT_VERSION = 1 // Current on-disk-format version HEADER_CURRENT_VERSION = 1 // Current on-disk-format version
HEADER_VERSION_LEN = 2 // uint16 HEADER_VERSION_LEN = 2 // uint16
HEADER_ID_LEN = 16 // 128 bit random file id HEADER_ID_LEN = 16 // 128 bit random file id
HEADER_LEN = HEADER_VERSION_LEN + HEADER_ID_LEN // Total header length HEADER_LEN = HEADER_VERSION_LEN + HEADER_ID_LEN // Total header length
) )
type FileHeader struct { type FileHeader struct {
Version uint16 Version uint16
Id []byte Id []byte
} }
// Pack - serialize fileHeader object // Pack - serialize fileHeader object

View File

@ -19,13 +19,13 @@ func (ib *intraBlock) IsPartial() bool {
// CiphertextRange - get byte range in ciphertext file corresponding to BlockNo // CiphertextRange - get byte range in ciphertext file corresponding to BlockNo
// (complete block) // (complete block)
func (ib *intraBlock) CiphertextRange() (offset uint64, length uint64) { func (ib *intraBlock) CiphertextRange() (offset uint64, length uint64) {
return HEADER_LEN + ib.BlockNo * ib.fs.cipherBS, ib.fs.cipherBS return ib.fs.BlockNoToCipherOff(ib.BlockNo), ib.fs.cipherBS
} }
// PlaintextRange - get byte range in plaintext corresponding to BlockNo // PlaintextRange - get byte range in plaintext corresponding to BlockNo
// (complete block) // (complete block)
func (ib *intraBlock) PlaintextRange() (offset uint64, length uint64) { func (ib *intraBlock) PlaintextRange() (offset uint64, length uint64) {
return ib.BlockNo * ib.fs.plainBS, ib.fs.plainBS return ib.fs.BlockNoToPlainOff(ib.BlockNo), ib.fs.plainBS
} }
// CropBlock - crop a potentially larger plaintext block down to the relevant part // CropBlock - crop a potentially larger plaintext block down to the relevant part
@ -37,3 +37,15 @@ func (ib *intraBlock) CropBlock(d []byte) []byte {
} }
return d[ib.Skip:lenWant] return d[ib.Skip:lenWant]
} }
// Ciphertext range corresponding to the sum of all "blocks" (complete blocks)
func (ib *intraBlock) JointCiphertextRange(blocks []intraBlock) (offset uint64, length uint64) {
firstBlock := blocks[0]
lastBlock := blocks[len(blocks)-1]
offset = ib.fs.BlockNoToCipherOff(firstBlock.BlockNo)
offsetLast := ib.fs.BlockNoToCipherOff(lastBlock.BlockNo)
length = offsetLast + ib.fs.cipherBS - offset
return offset, length
}

View File

@ -1,8 +1,6 @@
package main package main
import ( import (
"runtime"
"sync"
"bytes" "bytes"
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
@ -11,6 +9,8 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"runtime"
"sync"
"testing" "testing"
) )
@ -121,7 +121,7 @@ func testWriteN(t *testing.T, fn string, n int) string {
} }
file.Close() file.Close()
verifySize(t, plainDir + fn, n) verifySize(t, plainDir+fn, n)
bin := md5.Sum(d) bin := md5.Sum(d)
hashWant := hex.EncodeToString(bin[:]) hashWant := hex.EncodeToString(bin[:])
@ -244,12 +244,12 @@ func TestFileHoles(t *testing.T) {
} }
func sContains(haystack []string, needle string) bool { func sContains(haystack []string, needle string) bool {
for _, element := range haystack { for _, element := range haystack {
if element == needle { if element == needle {
return true return true
} }
} }
return false return false
} }
func TestRmwRace(t *testing.T) { func TestRmwRace(t *testing.T) {
@ -313,10 +313,10 @@ func TestRmwRace(t *testing.T) {
goodMd5[m] = goodMd5[m] + 1 goodMd5[m] = goodMd5[m] + 1
/* /*
if m == "6c1660fdabccd448d1359f27b3db3c99" { if m == "6c1660fdabccd448d1359f27b3db3c99" {
fmt.Println(hex.Dump(buf)) fmt.Println(hex.Dump(buf))
t.FailNow() t.FailNow()
} }
*/ */
} }
fmt.Println(goodMd5) fmt.Println(goodMd5)

View File

@ -128,8 +128,10 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
} }
// Read the backing ciphertext in one go // Read the backing ciphertext in one go
alignedOffset, alignedLength, skip := f.cfs.CiphertextRange(off, length) blocks := f.cfs.ExplodePlainRange(off, length)
cryptfs.Debug.Printf("CiphertextRange(%d, %d) -> %d, %d, %d\n", off, length, alignedOffset, alignedLength, skip) alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks)
skip := blocks[0].Skip
cryptfs.Debug.Printf("JointCiphertextRange(%d, %d) -> %d, %d, %d\n", 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))
@ -141,27 +143,27 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
// Truncate ciphertext buffer down to actually read bytes // Truncate ciphertext buffer down to actually read bytes
ciphertext = ciphertext[0:n] ciphertext = ciphertext[0:n]
blockNo := (alignedOffset - cryptfs.HEADER_LEN) / f.cfs.CipherBS() firstBlockNo := blocks[0].BlockNo
cryptfs.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d\n", alignedOffset, blockNo, alignedLength, n) cryptfs.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d\n", alignedOffset, firstBlockNo, alignedLength, n)
// Decrypt it // Decrypt it
plaintext, err := f.cfs.DecryptBlocks(ciphertext, blockNo, f.header.Id) plaintext, err := f.cfs.DecryptBlocks(ciphertext, firstBlockNo, f.header.Id)
if err != nil { if err != nil {
blockNo := (alignedOffset + uint64(len(plaintext))) / f.cfs.PlainBS() curruptBlockNo := firstBlockNo + f.cfs.PlainOffToBlockNo(uint64(len(plaintext)))
cipherOff := cryptfs.HEADER_LEN + blockNo * f.cfs.CipherBS() cipherOff := f.cfs.BlockNoToCipherOff(curruptBlockNo)
plainOff := blockNo * f.cfs.PlainBS() plainOff := f.cfs.BlockNoToPlainOff(curruptBlockNo)
cryptfs.Warn.Printf("ino%d: doRead: corrupt block #%d (plainOff=%d/%d, cipherOff=%d/%d)\n", cryptfs.Warn.Printf("ino%d: doRead: corrupt block #%d (plainOff=%d, cipherOff=%d)\n",
f.ino, blockNo, plainOff, f.cfs.PlainBS(), cipherOff, f.cfs.CipherBS()) f.ino, curruptBlockNo, plainOff, cipherOff)
return nil, fuse.EIO return nil, fuse.EIO
} }
// Crop down to the relevant part // Crop down to the relevant part
var out []byte var out []byte
lenHave := len(plaintext) lenHave := len(plaintext)
lenWant := skip + int(length) lenWant := int(skip + length)
if lenHave > lenWant { if lenHave > lenWant {
out = plaintext[skip : skip+int(length)] out = plaintext[skip:lenWant]
} else if lenHave > skip { } else if lenHave > int(skip) {
out = plaintext[skip:lenHave] out = plaintext[skip:lenHave]
} }
// else: out stays empty, file was smaller than the requested offset // else: out stays empty, file was smaller than the requested offset
@ -216,7 +218,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
var written uint32 var written uint32
status := fuse.OK status := fuse.OK
dataBuf := bytes.NewBuffer(data) dataBuf := bytes.NewBuffer(data)
blocks := f.cfs.SplitRange(uint64(off), uint64(len(data))) blocks := f.cfs.ExplodePlainRange(uint64(off), uint64(len(data)))
for _, b := range blocks { for _, b := range blocks {
blockData := dataBuf.Next(int(b.Length)) blockData := dataBuf.Next(int(b.Length))
@ -239,11 +241,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
blockOffset, _ := b.CiphertextRange() blockOffset, _ := 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, md5=%s\n",
f.ino, len(blockData) - cryptfs.BLOCK_OVERHEAD, b.BlockNo, cryptfs.Debug.Md5sum(blockData)) f.ino, len(blockData)-cryptfs.BLOCK_OVERHEAD, b.BlockNo, cryptfs.Debug.Md5sum(blockData))
if len(blockData) != int(f.cfs.CipherBS()) {
cryptfs.Debug.Printf("ino%d: Writing partial block #%d (%d bytes)\n",
f.ino, b.BlockNo, len(blockData) - cryptfs.BLOCK_OVERHEAD)
}
f.fdLock.Lock() f.fdLock.Lock()
_, err := f.fd.WriteAt(blockData, int64(blockOffset)) _, err := f.fd.WriteAt(blockData, int64(blockOffset))
f.fdLock.Unlock() f.fdLock.Unlock()
@ -267,7 +265,7 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {
cryptfs.Warn.Printf("Write: Fstat failed: %v\n", err) cryptfs.Warn.Printf("Write: Fstat failed: %v\n", err)
return 0, fuse.ToStatus(err) return 0, fuse.ToStatus(err)
} }
plainSize := f.cfs.PlainSize(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 {
@ -332,7 +330,7 @@ func (f *file) Truncate(newSize uint64) fuse.Status {
cryptfs.Warn.Printf("Truncate: Fstat failed: %v\n", err) cryptfs.Warn.Printf("Truncate: Fstat failed: %v\n", err)
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
oldSize := f.cfs.PlainSize(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())
@ -350,7 +348,7 @@ func (f *file) Truncate(newSize uint64) fuse.Status {
} }
} }
blocks := f.cfs.SplitRange(oldSize, newSize-oldSize) blocks := f.cfs.ExplodePlainRange(oldSize, newSize-oldSize)
for _, b := range blocks { for _, b := range blocks {
// First and last block may be partial // First and last block may be partial
if b.IsPartial() { if b.IsPartial() {
@ -374,9 +372,9 @@ func (f *file) Truncate(newSize uint64) fuse.Status {
return fuse.OK return fuse.OK
} else { } else {
// File shrinks // File shrinks
blockNo := f.cfs.BlockNoPlainOff(newSize) blockNo := f.cfs.PlainOffToBlockNo(newSize)
cipherOff := cryptfs.HEADER_LEN + blockNo * f.cfs.CipherBS() cipherOff := f.cfs.BlockNoToCipherOff(blockNo)
plainOff := blockNo * f.cfs.PlainBS() plainOff := f.cfs.BlockNoToPlainOff(blockNo)
lastBlockLen := newSize - plainOff lastBlockLen := newSize - plainOff
var data []byte var data []byte
if lastBlockLen > 0 { if lastBlockLen > 0 {
@ -430,7 +428,7 @@ func (f *file) GetAttr(a *fuse.Attr) fuse.Status {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
a.FromStat(&st) a.FromStat(&st)
a.Size = f.cfs.PlainSize(a.Size) a.Size = f.cfs.CipherSizeToPlainSize(a.Size)
return fuse.OK return fuse.OK
} }

View File

@ -7,8 +7,8 @@ import (
// Will a write to offset "off" create a file hole? // Will a write to offset "off" create a file hole?
func (f *file) createsHole(plainSize uint64, off int64) bool { func (f *file) createsHole(plainSize uint64, off int64) bool {
nextBlock := f.cfs.BlockNoPlainOff(plainSize) nextBlock := f.cfs.PlainOffToBlockNo(plainSize)
targetBlock := f.cfs.BlockNoPlainOff(uint64(off)) targetBlock := f.cfs.PlainOffToBlockNo(uint64(off))
if targetBlock > nextBlock { if targetBlock > nextBlock {
return true return true
} }

View File

@ -41,7 +41,7 @@ func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Stat
return a, status return a, status
} }
if a.IsRegular() { if a.IsRegular() {
a.Size = fs.PlainSize(a.Size) a.Size = fs.CipherSizeToPlainSize(a.Size)
} else if a.IsSymlink() { } else if a.IsSymlink() {
target, _ := fs.Readlink(name, context) target, _ := fs.Readlink(name, context)
a.Size = uint64(len(target)) a.Size = uint64(len(target))

View File

@ -2,11 +2,10 @@
set -eux set -eux
cd cryptfs for i in ./cryptfs .
go build do
go test
cd ..
go build go build $i
go test go test $i
done