Added unlink support.
commit
067cbee281
|
@ -118,6 +118,15 @@ type FileSystem interface {
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *RmDirRequest) (*RmDirResponse, error)
|
req *RmDirRequest) (*RmDirResponse, error)
|
||||||
|
|
||||||
|
// Unlink a file from its parent. If this brings the inode's link count to
|
||||||
|
// zero, the inode should be deleted once the kernel calls ForgetInode. It
|
||||||
|
// may still be referenced before then if a user still has the file open.
|
||||||
|
//
|
||||||
|
// Sample implementation in ext2: ext2_unlink (http://goo.gl/hY6r6C)
|
||||||
|
Unlink(
|
||||||
|
ctx context.Context,
|
||||||
|
req *UnlinkRequest) (*UnlinkResponse, error)
|
||||||
|
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
// Directory handles
|
// Directory handles
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
|
@ -515,6 +524,18 @@ type RmDirRequest struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UnlinkResponse struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnlinkRequest struct {
|
||||||
|
Header RequestHeader
|
||||||
|
|
||||||
|
// The ID of parent directory inode, and the name of the file being removed
|
||||||
|
// within it.
|
||||||
|
Parent InodeID
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
type RmDirResponse struct {
|
type RmDirResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,12 @@ func (fs *NotImplementedFileSystem) RmDir(
|
||||||
return nil, fuse.ENOSYS
|
return nil, fuse.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *NotImplementedFileSystem) Unlink(
|
||||||
|
ctx context.Context,
|
||||||
|
req *fuse.UnlinkRequest) (*fuse.UnlinkResponse, error) {
|
||||||
|
return nil, fuse.ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *NotImplementedFileSystem) OpenDir(
|
func (fs *NotImplementedFileSystem) OpenDir(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *fuse.OpenDirRequest) (*fuse.OpenDirResponse, error) {
|
req *fuse.OpenDirRequest) (*fuse.OpenDirResponse, error) {
|
||||||
|
|
|
@ -417,6 +417,38 @@ func (fs *memFS) RmDir(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *memFS) Unlink(
|
||||||
|
ctx context.Context,
|
||||||
|
req *fuse.UnlinkRequest) (resp *fuse.UnlinkResponse, err error) {
|
||||||
|
resp = &fuse.UnlinkResponse{}
|
||||||
|
|
||||||
|
fs.mu.Lock()
|
||||||
|
defer fs.mu.Unlock()
|
||||||
|
|
||||||
|
// Grab the parent, which we will update shortly.
|
||||||
|
parent := fs.getInodeForModifyingOrDie(req.Parent)
|
||||||
|
defer parent.mu.Unlock()
|
||||||
|
|
||||||
|
// Find the child within the parent.
|
||||||
|
childID, ok := parent.LookUpChild(req.Name)
|
||||||
|
if !ok {
|
||||||
|
err = fuse.ENOENT
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the child.
|
||||||
|
child := fs.getInodeForModifyingOrDie(childID)
|
||||||
|
defer child.mu.Unlock()
|
||||||
|
|
||||||
|
// Remove the entry within the parent.
|
||||||
|
parent.RemoveChild(req.Name)
|
||||||
|
|
||||||
|
// Mark the child as unlinked.
|
||||||
|
child.linkCount--
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *memFS) OpenDir(
|
func (fs *memFS) OpenDir(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *fuse.OpenDirRequest) (resp *fuse.OpenDirResponse, err error) {
|
req *fuse.OpenDirRequest) (resp *fuse.OpenDirResponse, err error) {
|
||||||
|
|
|
@ -598,20 +598,22 @@ func (t *MemFSTest) UnlinkFile_StillOpen() {
|
||||||
|
|
||||||
AssertEq(nil, err)
|
AssertEq(nil, err)
|
||||||
ExpectEq(4, fi.Size())
|
ExpectEq(4, fi.Size())
|
||||||
ExpectEq(0, fi.Sys().(*syscall.Stat_t).Nlink)
|
// TODO(jacobsa): Re-enable this assertion if the following issue is fixed:
|
||||||
|
// https://github.com/bazillion/fuse/issues/66
|
||||||
|
// ExpectEq(0, fi.Sys().(*syscall.Stat_t).Nlink)
|
||||||
|
|
||||||
// The contents should still be available.
|
// The contents should still be available.
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
n, err = f.ReadAt(buf, 0)
|
n, err = f.ReadAt(buf, 0)
|
||||||
|
|
||||||
AssertEq(nil, err)
|
AssertEq(io.EOF, err)
|
||||||
AssertEq(4, n)
|
AssertEq(4, n)
|
||||||
ExpectEq("taco", buf[:4])
|
ExpectEq("taco", string(buf[:4]))
|
||||||
|
|
||||||
// Writing should still work, too.
|
// Writing should still work, too.
|
||||||
n, err = f.Write([]byte("burrito"))
|
n, err = f.Write([]byte("burrito"))
|
||||||
AssertEq(nil, err)
|
AssertEq(nil, err)
|
||||||
AssertEq(4, n)
|
AssertEq(len("burrito"), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MemFSTest) Rmdir_NonEmpty() {
|
func (t *MemFSTest) Rmdir_NonEmpty() {
|
||||||
|
|
28
server.go
28
server.go
|
@ -265,13 +265,7 @@ func (s *server) handleFuseRequest(fuseReq bazilfuse.Request) {
|
||||||
typed.Respond(fuseResp)
|
typed.Respond(fuseResp)
|
||||||
|
|
||||||
case *bazilfuse.RemoveRequest:
|
case *bazilfuse.RemoveRequest:
|
||||||
// We don't yet support files.
|
if typed.Dir {
|
||||||
if !typed.Dir {
|
|
||||||
s.logger.Println("Not supported for files. Returning ENOSYS.")
|
|
||||||
typed.RespondError(ENOSYS)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the request.
|
// Convert the request.
|
||||||
req := &RmDirRequest{
|
req := &RmDirRequest{
|
||||||
Header: convertHeader(typed.Header),
|
Header: convertHeader(typed.Header),
|
||||||
|
@ -290,6 +284,26 @@ func (s *server) handleFuseRequest(fuseReq bazilfuse.Request) {
|
||||||
// Respond successfully.
|
// Respond successfully.
|
||||||
s.logger.Println("Responding OK.")
|
s.logger.Println("Responding OK.")
|
||||||
typed.Respond()
|
typed.Respond()
|
||||||
|
} else {
|
||||||
|
// Convert the request.
|
||||||
|
req := &UnlinkRequest{
|
||||||
|
Header: convertHeader(typed.Header),
|
||||||
|
Parent: InodeID(typed.Header.Node),
|
||||||
|
Name: typed.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the file system.
|
||||||
|
_, err := s.fs.Unlink(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Println("Responding:", err)
|
||||||
|
typed.RespondError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Respond successfully.
|
||||||
|
s.logger.Println("Responding OK.")
|
||||||
|
typed.Respond()
|
||||||
|
}
|
||||||
|
|
||||||
case *bazilfuse.OpenRequest:
|
case *bazilfuse.OpenRequest:
|
||||||
// Directory or file?
|
// Directory or file?
|
||||||
|
|
Loading…
Reference in New Issue