Added unlink support.

geesefs-0-30-9
Aaron Jacobs 2015-03-06 23:34:11 -06:00
commit 067cbee281
5 changed files with 101 additions and 26 deletions

View File

@ -118,6 +118,15 @@ type FileSystem interface {
ctx context.Context,
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
///////////////////////////////////
@ -515,6 +524,18 @@ type RmDirRequest struct {
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 {
}

View File

@ -76,6 +76,12 @@ func (fs *NotImplementedFileSystem) RmDir(
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(
ctx context.Context,
req *fuse.OpenDirRequest) (*fuse.OpenDirResponse, error) {

View File

@ -417,6 +417,38 @@ func (fs *memFS) RmDir(
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(
ctx context.Context,
req *fuse.OpenDirRequest) (resp *fuse.OpenDirResponse, err error) {

View File

@ -598,20 +598,22 @@ func (t *MemFSTest) UnlinkFile_StillOpen() {
AssertEq(nil, err)
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.
buf := make([]byte, 1024)
n, err = f.ReadAt(buf, 0)
AssertEq(nil, err)
AssertEq(io.EOF, err)
AssertEq(4, n)
ExpectEq("taco", buf[:4])
ExpectEq("taco", string(buf[:4]))
// Writing should still work, too.
n, err = f.Write([]byte("burrito"))
AssertEq(nil, err)
AssertEq(4, n)
AssertEq(len("burrito"), n)
}
func (t *MemFSTest) Rmdir_NonEmpty() {

View File

@ -265,31 +265,45 @@ func (s *server) handleFuseRequest(fuseReq bazilfuse.Request) {
typed.Respond(fuseResp)
case *bazilfuse.RemoveRequest:
// We don't yet support files.
if !typed.Dir {
s.logger.Println("Not supported for files. Returning ENOSYS.")
typed.RespondError(ENOSYS)
return
}
if typed.Dir {
// Convert the request.
req := &RmDirRequest{
Header: convertHeader(typed.Header),
Parent: InodeID(typed.Header.Node),
Name: typed.Name,
}
// Convert the request.
req := &RmDirRequest{
Header: convertHeader(typed.Header),
Parent: InodeID(typed.Header.Node),
Name: typed.Name,
}
// Call the file system.
_, err := s.fs.RmDir(ctx, req)
if err != nil {
s.logger.Println("Responding:", err)
typed.RespondError(err)
return
}
// Call the file system.
_, err := s.fs.RmDir(ctx, req)
if err != nil {
s.logger.Println("Responding:", err)
typed.RespondError(err)
return
}
// Respond successfully.
s.logger.Println("Responding OK.")
typed.Respond()
} else {
// Convert the request.
req := &UnlinkRequest{
Header: convertHeader(typed.Header),
Parent: InodeID(typed.Header.Node),
Name: typed.Name,
}
// Respond successfully.
s.logger.Println("Responding OK.")
typed.Respond()
// 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:
// Directory or file?