diff options
Diffstat (limited to 'internal')
| -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  } | 
