func (f *loopbackFile) Flush() fuse.Status { f.lock.Lock() // Since Flush() may be called for each dup'd fd, we don't // want to really close the file, we just want to flush. This // is achieved by closing a dup'd fd. newFd, err := syscall.Dup(int(f.File.Fd())) f.lock.Unlock() if err != nil { return fuse.ToStatus(err) } err = syscall.Close(newFd) return fuse.ToStatus(err) }
func (f *loopbackFile) Truncate(size uint64) fuse.Status { f.lock.Lock() r := fuse.ToStatus(syscall.Ftruncate(int(f.File.Fd()), int64(size))) f.lock.Unlock() return r }
func (f *loopbackFile) Fsync(flags int) (code fuse.Status) { f.lock.Lock() r := fuse.ToStatus(syscall.Fsync(int(f.File.Fd()))) f.lock.Unlock() return r }
func (f *loopbackFile) Chown(uid uint32, gid uint32) fuse.Status { f.lock.Lock() r := fuse.ToStatus(f.File.Chown(int(uid), int(gid))) f.lock.Unlock() return r }
func (f *loopbackFile) Chmod(mode uint32) fuse.Status { f.lock.Lock() r := fuse.ToStatus(f.File.Chmod(os.FileMode(mode))) f.lock.Unlock() return r }
func TestUnionFSBarf(t *testing.T) { wd, clean := setupUfs(t) defer clean() if err := os.Mkdir(wd+"/mnt/dir", 0755); err != nil { t.Fatalf("os.Mkdir: %v", err) } if err := os.Mkdir(wd+"/mnt/dir2", 0755); err != nil { t.Fatalf("os.Mkdir: %v", err) } if err := ioutil.WriteFile(wd+"/rw/dir/file", []byte("bla"), 0644); err != nil { t.Fatalf("WriteFile failed: %v", err) } if _, err := os.Lstat(wd + "/mnt/dir/file"); err != nil { t.Fatalf("Lstat: %v", err) } if err := os.Rename(wd+"/rw/dir/file", wd+"/rw/file"); err != nil { t.Fatalf("os.Rename: %v", err) } err := os.Rename(wd+"/mnt/file", wd+"/mnt/dir2/file") if fuse.ToStatus(err) != fuse.ENOENT { // TODO - this should just succeed? t.Fatalf("os.Rename: %v", err) } }
func (fs *loopbackFileSystem) Open(name string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) { f, err := os.OpenFile(fs.GetPath(name), int(flags), 0) if err != nil { return nil, fuse.ToStatus(err) } return nodefs.NewLoopbackFile(f), fuse.OK }
func (n *memNode) Open(flags uint32, context *fuse.Context) (file File, code fuse.Status) { f, err := os.OpenFile(n.filename(), int(flags), 0666) if err != nil { return nil, fuse.ToStatus(err) } return n.newFile(f), fuse.OK }
func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status { f.lock.Lock() err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz)) f.lock.Unlock() if err != nil { return fuse.ToStatus(err) } return fuse.OK }
func (n *memNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, node *Inode, code fuse.Status) { ch := n.newNode(name, false) ch.info.Mode = mode | fuse.S_IFREG f, err := os.Create(ch.filename()) if err != nil { return nil, nil, fuse.ToStatus(err) } return ch.newFile(f), ch.Inode(), fuse.OK }
func (fs *loopbackFileSystem) Utimens(path string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) { var a time.Time if Atime != nil { a = *Atime } var m time.Time if Mtime != nil { m = *Mtime } return fuse.ToStatus(os.Chtimes(fs.GetPath(path), a, m)) }
func (f *loopbackFile) GetAttr(a *fuse.Attr) fuse.Status { st := syscall.Stat_t{} f.lock.Lock() err := syscall.Fstat(int(f.File.Fd()), &st) f.lock.Unlock() if err != nil { return fuse.ToStatus(err) } a.FromStat(&st) return fuse.OK }
func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status { // TODO: Handle `mode` parameter. // From `man fcntl` on OSX: // The F_PREALLOCATE command operates on the following structure: // // typedef struct fstore { // u_int32_t fst_flags; /* IN: flags word */ // int fst_posmode; /* IN: indicates offset field */ // off_t fst_offset; /* IN: start of the region */ // off_t fst_length; /* IN: size of the region */ // off_t fst_bytesalloc; /* OUT: number of bytes allocated */ // } fstore_t; // // The flags (fst_flags) for the F_PREALLOCATE command are as follows: // // F_ALLOCATECONTIG Allocate contiguous space. // // F_ALLOCATEALL Allocate all requested space or no space at all. // // The position modes (fst_posmode) for the F_PREALLOCATE command indicate how to use the offset field. The modes are as fol- // lows: // // F_PEOFPOSMODE Allocate from the physical end of file. // // F_VOLPOSMODE Allocate from the volume offset. k := struct { Flags uint32 // u_int32_t Posmode int64 // int Offset int64 // off_t Length int64 // off_t Bytesalloc int64 // off_t }{ 0, 0, int64(off), int64(sz), 0, } // Linux version for reference: // err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz)) f.lock.Lock() _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.File.Fd(), uintptr(syscall.F_PREALLOCATE), uintptr(unsafe.Pointer(&k))) f.lock.Unlock() if errno != 0 { return fuse.ToStatus(errno) } return fuse.OK }
func (n *memNodeFile) Flush() fuse.Status { code := n.File.Flush() if !code.Ok() { return code } st := syscall.Stat_t{} err := syscall.Stat(n.node.filename(), &st) n.node.info.Size = uint64(st.Size) n.node.info.Blocks = uint64(st.Blocks) return fuse.ToStatus(err) }
func TestCreationChecks(t *testing.T) { wd, clean := setup(t) defer clean() err := os.Mkdir(wd+"/store/foo", 0755) if err != nil { t.Fatalf("Mkdir failed: %v", err) } os.Symlink(wd+"/ro", wd+"/store/foo/READONLY") if err != nil { t.Fatalf("Symlink failed: %v", err) } err = os.Mkdir(wd+"/store/ws2", 0755) if err != nil { t.Fatalf("Mkdir failed: %v", err) } os.Symlink(wd+"/ro", wd+"/store/ws2/READONLY") if err != nil { t.Fatalf("Symlink failed: %v", err) } err = os.Symlink(wd+"/store/foo", wd+"/mnt/config/bar") if err != nil { t.Fatalf("Symlink failed: %v", err) } err = os.Symlink(wd+"/store/foo", wd+"/mnt/config/foo") code := fuse.ToStatus(err) if code != fuse.EBUSY { t.Error("Should return EBUSY", err) } err = os.Symlink(wd+"/store/ws2", wd+"/mnt/config/config") code = fuse.ToStatus(err) if code != fuse.EINVAL { t.Error("Should return EINVAL", err) } }
func TestUnionFsChown(t *testing.T) { wd, clean := setupUfs(t) defer clean() ro_fn := wd + "/ro/file" m_fn := wd + "/mnt/file" WriteFile(t, ro_fn, "a") err := os.Chown(m_fn, 0, 0) code := fuse.ToStatus(err) if code != fuse.EPERM { t.Error("Unexpected error code", code, err) } }
func TestMountRename(t *testing.T) { ts := NewTestCase(t) defer ts.Cleanup() fs := pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(ts.orig), nil) code := ts.connector.Mount(ts.rootNode(), "mnt", fs.Root(), nil) if !code.Ok() { t.Fatal("mount should succeed") } err := os.Rename(ts.mnt+"/mnt", ts.mnt+"/foobar") if fuse.ToStatus(err) != fuse.EBUSY { t.Fatal("rename mount point should fail with EBUSY:", err) } ts.pathFs.Unmount("mnt") }
func (n *memNode) Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status) { if file != nil { code = file.Truncate(size) } else { err := os.Truncate(n.filename(), int64(size)) code = fuse.ToStatus(err) } if code.Ok() { now := time.Now() n.info.SetTimes(nil, nil, &now) // TODO - should update mtime too? n.info.Size = size } return code }
func (fs *loopbackFileSystem) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, code fuse.Status) { fullPath := fs.GetPath(name) var err error = nil st := syscall.Stat_t{} if name == "" { // When GetAttr is called for the toplevel directory, we always want // to look through symlinks. err = syscall.Stat(fullPath, &st) } else { err = syscall.Lstat(fullPath, &st) } if err != nil { return nil, fuse.ToStatus(err) } a = &fuse.Attr{} a.FromStat(&st) return a, fuse.OK }
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status { var ts = make([]syscall.Timeval, 2) if a == nil { ts[0].Sec = _UTIME_OMIT } else { ts[0].Sec = a.Unix() } if m == nil { ts[1].Sec = _UTIME_OMIT } else { ts[1].Sec = m.Unix() } f.lock.Lock() err := syscall.Futimes(int(f.File.Fd()), ts) f.lock.Unlock() return fuse.ToStatus(err) }
func (fs *loopbackFileSystem) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) { // What other ways beyond O_RDONLY are there to open // directories? f, err := os.Open(fs.GetPath(name)) if err != nil { return nil, fuse.ToStatus(err) } want := 500 output := make([]fuse.DirEntry, 0, want) for { infos, err := f.Readdir(want) for i := range infos { // workaround forhttps://code.google.com/p/go/issues/detail?id=5960 if infos[i] == nil { continue } n := infos[i].Name() d := fuse.DirEntry{ Name: n, } if s := fuse.ToStatT(infos[i]); s != nil { d.Mode = uint32(s.Mode) } else { log.Printf("ReadDir entry %q for %q has no stat info", n, name) } output = append(output, d) } if len(infos) < want || err == io.EOF { break } if err != nil { log.Println("Readdir() returned err:", err) break } } f.Close() return output, fuse.OK }
func (f *loopbackFile) Write(data []byte, off int64) (uint32, fuse.Status) { f.lock.Lock() n, err := f.File.WriteAt(data, off) f.lock.Unlock() return uint32(n), fuse.ToStatus(err) }
func (fs *loopbackFileSystem) Create(path string, flags uint32, mode uint32, context *fuse.Context) (fuseFile nodefs.File, code fuse.Status) { f, err := os.OpenFile(fs.GetPath(path), int(flags)|os.O_CREATE, os.FileMode(mode)) return nodefs.NewLoopbackFile(f), fuse.ToStatus(err) }
func (fs *loopbackFileSystem) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (code fuse.Status) { return fuse.ToStatus(syscall.Mknod(fs.GetPath(name), mode, int(dev))) }
func (fs *loopbackFileSystem) Mkdir(path string, mode uint32, context *fuse.Context) (code fuse.Status) { return fuse.ToStatus(os.Mkdir(fs.GetPath(path), os.FileMode(mode))) }
func (fs *loopbackFileSystem) Rmdir(name string, context *fuse.Context) (code fuse.Status) { return fuse.ToStatus(syscall.Rmdir(fs.GetPath(name))) }
func (fs *loopbackFileSystem) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) { return fuse.ToStatus(os.Symlink(pointedTo, fs.GetPath(linkName))) }
func (fs *loopbackFileSystem) Rename(oldPath string, newPath string, context *fuse.Context) (codee fuse.Status) { err := os.Rename(fs.GetPath(oldPath), fs.GetPath(newPath)) return fuse.ToStatus(err) }
func (fs *loopbackFileSystem) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) { return fuse.ToStatus(syscall.Access(fs.GetPath(name), mode)) }
func (fs *loopbackFileSystem) Link(orig string, newName string, context *fuse.Context) (code fuse.Status) { return fuse.ToStatus(os.Link(fs.GetPath(orig), fs.GetPath(newName))) }