func setup_dir(t testing.TB, chunkStore chunks.Store, dirents []*wire.Dirent) *wire.Dirent { blob, err := blobs.Open( chunkStore, blobs.EmptyManifest("dir"), ) if err != nil { t.Fatalf("unexpected blob open error: %v", err) } w := snap.NewWriter(blob) for _, de := range dirents { err := w.Add(de) if err != nil { t.Fatalf("unexpected add error: %v", err) } } manifest, err := blob.Save() if err != nil { t.Fatalf("unexpected save error: %v", err) } var de wire.Dirent de.Type.Dir = &wire.Dir{ Manifest: wirecas.FromBlob(manifest), } return &de }
func TestTwoLevels(t *testing.T) { tmp := tempdir.New(t) defer tmp.Cleanup() setup_fs := func() fs.FS { chunkStore := &mock.InMemory{} greeting := setup_greeting(t, chunkStore) dir1 := setup_dir(t, chunkStore, []*wire.Dirent{ &wire.Dirent{ Name: "hello", Type: wire.Type{ File: &wire.File{ Manifest: wirecas.FromBlob(greeting), }, }, // Space: uint64(len(GREETING)), // Written: TIME_1, }, }) dir1.Name = "second" dir2 := setup_dir(t, chunkStore, []*wire.Dirent{dir1}) filesys, err := newFS(chunkStore, dir2.Type.Dir) if err != nil { t.Fatalf("cannot serve snapshot as FUSE: %v", err) } return filesys } filesys := setup_fs() mnt, err := fstestutil.MountedT(t, filesys) if err != nil { t.Fatalf("Mount fail: %v\n", err) } defer mnt.Close() hello_path := path.Join(mnt.Dir, "second", "hello") f, err := os.Open(hello_path) if err != nil { t.Fatalf("hello open failed with %v", err) } buf, err := ioutil.ReadAll(f) if err != nil { t.Errorf("hello read failed with %v", err) } if string(buf) != GREETING { t.Errorf("hello read wrong content: %q", string(buf)) } err = f.Close() if err != nil { t.Fatalf("hello close failed with %v", err) } }
func (f *file) marshalInternal() (*wire.Dirent, error) { de := &wire.Dirent{ Inode: f.inode, } manifest, err := f.blob.Save() if err != nil { return nil, err } de.File = &wire.File{ Manifest: wirecas.FromBlob(manifest), } return de, nil }
func setup_fs(t *testing.T) fs.FS { chunkStore := &mock.InMemory{} greeting := setup_greeting(t, chunkStore) dir := setup_dir(t, chunkStore, []*wire.Dirent{ &wire.Dirent{ Name: "hello", File: &wire.File{ Manifest: wirecas.FromBlob(greeting), }, // Space: uint64(len(GREETING)), // Written: TIME_1, }, }) filesys, err := newFS(chunkStore, dir) if err != nil { t.Fatalf("cannot serve snapshot as FUSE: %v", err) } return filesys }
// snapshot records a snapshot of the directory and stores it in wde func (d *dir) snapshot(tx *bolt.Tx, out *wiresnap.Dir, intr fs.Intr) error { // NOT HOLDING THE LOCK, accessing database snapshot ONLY // TODO move bucket lookup to caller? bucket := d.fs.bucket(tx).Bucket(bucketDir) if bucket == nil { return errors.New("dir bucket missing") } manifest := blobs.EmptyManifest("dir") blob, err := blobs.Open(d.fs.chunkStore, manifest) if err != nil { return err } w := snap.NewWriter(blob) c := bucket.Cursor() prefix := pathToKey(d.inode, "") for k, v := c.Seek(prefix); k != nil; k, v = c.Next() { if !bytes.HasPrefix(k, prefix) { // past the end of the directory break } name := string(k[len(prefix):]) de, err := d.unmarshalDirent(v) if err != nil { return err } sde := wiresnap.Dirent{ Name: name, } switch { case de.Type.File != nil: // TODO d.reviveNode would do blobs.Open and that's a bit // too much work; rework the apis sde.Type.File = &wiresnap.File{ Manifest: de.Type.File.Manifest, } case de.Type.Dir != nil: child, err := d.reviveDir(de, name) if err != nil { return err } sde.Type.Dir = &wiresnap.Dir{} err = child.snapshot(tx, sde.Type.Dir, intr) if err != nil { return err } default: return errors.New("TODO") } err = w.Add(&sde) if err != nil { return err } } manifest, err = blob.Save() if err != nil { return err } out.Manifest = wirecas.FromBlob(manifest) out.Align = w.Align() return nil }