diff options
author | Sebastian Lackner | 2019-01-06 04:46:16 +0100 |
---|---|---|
committer | rfjakob | 2019-01-06 12:21:54 +0100 |
commit | 8310dd95be0675a1438481a423ba06cb3a8647da (patch) | |
tree | 9a6eeec4b644c12935f30bdd72357e2a2088251e | |
parent | bd055ed7de77b2e16c391a5bfe714bb5b07d5787 (diff) |
fusefrontend: Properly convert plaintext <-> ciphertext offsets in SeekData().
Fixes https://github.com/rfjakob/gocryptfs/issues/304
-rw-r--r-- | internal/fusefrontend/file_holes.go | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/internal/fusefrontend/file_holes.go b/internal/fusefrontend/file_holes.go index 3725f56..c9f7aa6 100644 --- a/internal/fusefrontend/file_holes.go +++ b/internal/fusefrontend/file_holes.go @@ -64,6 +64,29 @@ func (f *File) SeekData(oldOffset int64) (int64, error) { return 0, syscall.EOPNOTSUPP } const SEEK_DATA = 3 - fd := f.intFd() - return syscall.Seek(fd, oldOffset, SEEK_DATA) + + // Convert plaintext offset to ciphertext offset and round down to the + // start of the current block. File holes smaller than a full block will + // be ignored. + blockNo := f.contentEnc.PlainOffToBlockNo(uint64(oldOffset)) + oldCipherOff := int64(f.contentEnc.BlockNoToCipherOff(blockNo)) + + // Determine the next data offset. If the old offset points to (or beyond) + // the end of the file, the Seek syscall fails with syscall.ENXIO. + newCipherOff, err := syscall.Seek(f.intFd(), oldCipherOff, SEEK_DATA) + if err != nil { + return 0, err + } + + // Convert ciphertext offset back to plaintext offset. At this point, + // newCipherOff should always be >= contentenc.HeaderLen. Round down, + // but ensure that the result is never smaller than the initial offset + // (to avoid endless loops). + blockNo = f.contentEnc.CipherOffToBlockNo(uint64(newCipherOff)) + newOffset := int64(f.contentEnc.BlockNoToPlainOff(blockNo)) + if newOffset < oldOffset { + newOffset = oldOffset + } + + return newOffset, nil } |