summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2020-07-23 22:55:07 +0200
committerJakob Unterwurzacher2020-07-23 22:55:07 +0200
commit9cd24d79a2a5499eefc3403516eba9d9fcbf1079 (patch)
treeffb6551b91e1fc614eff04ebaede6143a1cf2a5b
parent8915785acf7e6e7908b32103406620f243093931 (diff)
v2api: implement Lseek
This also fixes the last remaining tests/fsck failure.
-rw-r--r--internal/fusefrontend/file2_api_check.go2
-rw-r--r--internal/fusefrontend/file2_holes.go40
-rw-r--r--tests/defaults/main_test.go32
3 files changed, 41 insertions, 33 deletions
diff --git a/internal/fusefrontend/file2_api_check.go b/internal/fusefrontend/file2_api_check.go
index 4a6d6a1..01f9a46 100644
--- a/internal/fusefrontend/file2_api_check.go
+++ b/internal/fusefrontend/file2_api_check.go
@@ -13,11 +13,11 @@ var _ = (fs.FileWriter)((*File2)(nil))
var _ = (fs.FileFsyncer)((*File2)(nil))
var _ = (fs.FileFlusher)((*File2)(nil))
var _ = (fs.FileAllocater)((*File2)(nil))
+var _ = (fs.FileLseeker)((*File2)(nil))
/* TODO
var _ = (fs.FileHandle)((*File2)(nil))
var _ = (fs.FileGetlker)((*File2)(nil))
var _ = (fs.FileSetlker)((*File2)(nil))
var _ = (fs.FileSetlkwer)((*File2)(nil))
-var _ = (fs.FileLseeker)((*File2)(nil))
*/
diff --git a/internal/fusefrontend/file2_holes.go b/internal/fusefrontend/file2_holes.go
index 83918d2..5c314d3 100644
--- a/internal/fusefrontend/file2_holes.go
+++ b/internal/fusefrontend/file2_holes.go
@@ -3,7 +3,7 @@ package fusefrontend
// Helper functions for sparse files (files with holes)
import (
- "runtime"
+ "context"
"syscall"
"github.com/hanwen/go-fuse/v2/fs"
@@ -56,37 +56,13 @@ func (f *File2) zeroPad(plainSize uint64) syscall.Errno {
return errno
}
-// SeekData calls the lseek syscall with SEEK_DATA. It returns the offset of the
-// next data bytes, skipping over file holes.
-func (f *File2) SeekData(oldOffset int64) (int64, error) {
- if runtime.GOOS != "linux" {
- // Does MacOS support something like this?
- return 0, syscall.EOPNOTSUPP
- }
- const SEEK_DATA = 3
-
- // 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)
+// Lseek - FUSE call.
+func (f *File2) Lseek(ctx context.Context, off uint64, whence uint32) (uint64, syscall.Errno) {
+ cipherOff := f.rootNode.contentEnc.PlainSizeToCipherSize(off)
+ newCipherOff, err := syscall.Seek(f.intFd(), int64(cipherOff), int(whence))
if err != nil {
- return 0, err
+ return uint64(newCipherOff), fs.ToErrno(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
+ newOff := f.contentEnc.CipherSizeToPlainSize(uint64(newCipherOff))
+ return newOff, 0
}
diff --git a/tests/defaults/main_test.go b/tests/defaults/main_test.go
index 51f5cd2..f59ea38 100644
--- a/tests/defaults/main_test.go
+++ b/tests/defaults/main_test.go
@@ -7,6 +7,7 @@ import (
"io/ioutil"
"os"
"os/exec"
+ "path/filepath"
"runtime"
"strings"
"sync"
@@ -261,3 +262,34 @@ func TestCpWarnings(t *testing.T) {
t.Fatalf("Got warnings from cp -a:\n%s", string(out))
}
}
+
+func TestSeekData(t *testing.T) {
+ fn := filepath.Join(test_helpers.DefaultPlainDir, t.Name())
+ f, err := os.Create(fn)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var oneTiB int64 = 1024 * 1024 * 1024 * 1024
+ if _, err = f.Seek(oneTiB, 0); err != nil {
+ t.Fatal(err)
+ }
+ if _, err = f.Write([]byte("foo")); err != nil {
+ t.Fatal(err)
+ }
+ f.Close()
+
+ const SEEK_DATA = 3
+
+ f, err = os.Open(fn)
+ if err != nil {
+ t.Fatal(err)
+ }
+ off, err := f.Seek(1024*1024, SEEK_DATA)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if off < oneTiB-1024*1024 {
+ t.Errorf("off=%d, expected=%d\n", off, oneTiB)
+ }
+ f.Close()
+}