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:
parent
14276c9632
commit
902babdf22
79
cryptfs/address_translation.go
Normal file
79
cryptfs/address_translation.go
Normal 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
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package cryptfs
|
package cryptfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
import "os"
|
import "os"
|
||||||
|
@ -24,7 +24,7 @@ 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 {
|
||||||
@ -51,7 +51,11 @@ 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)
|
||||||
}
|
}
|
||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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))
|
||||||
@ -240,10 +242,6 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user