Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Renaming.

Fix inode add/remove handing.
  • Loading branch information...
commit 087265e36e8ebfb2223b2c6231ad78d244fb8f37 1 parent 236f0af
@hanwen authored
Showing with 128 additions and 32 deletions.
  1. +84 −24 fs.go
  2. +13 −2 mtp.go
  3. +31 −6 test.sh
View
108 fs.go
@@ -31,8 +31,7 @@ func NewDeviceFs(d *Device, dir string) *DeviceFs {
/*
TODO:
-- We leak memory given by LIBMTP.
-- Renaming
+- Moving between directories
- Something intelligent with playlists/pictures, maybe?
- Statfs?
- expose properties as xattrs?
@@ -95,6 +94,10 @@ type fileNode struct {
dirty bool
}
+func (n *fileNode) Deletable() bool {
+ return false
+}
+
func (n *fileNode) OnForget() {
if n.file != nil {
n.file.Destroy()
@@ -228,7 +231,8 @@ func (n *fileNode) Utimens(file fuse.File, AtimeNs int64, MtimeNs int64, context
}
n.file.SetMtime(time.Unix(0, MtimeNs))
- // TODO - if we have no dirty backing store, should set object property.
+ // TODO - if we have no dirty backing store, should set the
+ // object property.
return fuse.OK
}
@@ -284,6 +288,70 @@ func (n *folderNode) GetAttr(file fuse.File, context *fuse.Context) (fi *fuse.At
return &fuse.Attr{Mode: fuse.S_IFDIR | 0755}, fuse.OK
}
+func (n *folderNode) getChild(name string) (f *File, isFolder bool) {
+ f, isFolder = n.folders[name]
+ if isFolder {
+ return
+ }
+ f, _ = n.files[name]
+ return f, false
+}
+
+func (n *folderNode) basenameRename(oldName string, newName string) error {
+ file, isFolder := n.getChild(oldName)
+
+ err := n.fs.dev.SetFileName(file, newName)
+ if err != nil {
+ return err
+ }
+
+ if isFolder {
+ delete(n.folders, oldName)
+ n.folders[newName] = file
+ } else {
+ delete(n.files,oldName)
+ n.files[newName] = file
+ }
+ ch := n.Inode().RmChild(oldName)
+ if ch == nil {
+ log.Panicf("child is not there for %q: got %v", oldName, n.Inode().Children())
+ }
+ n.Inode().AddChild(newName, ch)
+ return nil
+}
+
+func (n *folderNode) Rename(oldName string, newParent fuse.FsNode, newName string, context *fuse.Context) (code fuse.Status) {
+ fn, ok := newParent.(*folderNode);
+ if !ok {
+ return fuse.ENOSYS
+ }
+ fn.fetch()
+ n.fetch()
+
+ if f, _ := n.getChild(newName); f != nil {
+ if fn != n {
+ log.Println("old folder already has child %q", newName)
+ return fuse.ENOSYS
+ } else {
+ // does mtp overwrite the destination?
+ }
+ }
+
+ if fn != n {
+ return fuse.ENOSYS
+ }
+
+ if newName != oldName {
+ err := n.basenameRename(oldName, newName)
+ if err != nil {
+ log.Printf("basenameRename failed: %v", err)
+ return fuse.EIO
+ }
+ }
+
+ return fuse.OK
+}
+
func (n *folderNode) Lookup(name string, context *fuse.Context) (fi *fuse.Attr, node fuse.FsNode, code fuse.Status) {
if !n.fetch() {
return nil, nil, fuse.EIO
@@ -298,7 +366,8 @@ func (n *folderNode) Lookup(name string, context *fuse.Context) (fi *fuse.Attr,
}
if node != nil {
- n.Inode().New(true, node)
+ n.Inode().AddChild(name, n.Inode().New(true, node))
+
a, s := node.GetAttr(nil, context)
return a, node, s
}
@@ -316,7 +385,7 @@ func (n *folderNode) Mkdir(name string, mode uint32, context *fuse.Context) (*fu
}
f := n.fs.newFolder(newId, n.storageId)
- n.Inode().New(true, f)
+ n.Inode().AddChild(name, n.Inode().New(true, f))
if meta, err := n.fs.dev.Filemetadata(newId); err != nil {
log.Printf("Filemetadata failed for directory %q: %v", name, err)
@@ -333,7 +402,8 @@ func (n *folderNode) Unlink(name string, c *fuse.Context) fuse.Status {
if !n.fetch() {
return fuse.EIO
}
- f := n.files[name]
+
+ f, isFolder := n.getChild(name)
if f == nil {
return fuse.ENOENT
}
@@ -343,27 +413,17 @@ func (n *folderNode) Unlink(name string, c *fuse.Context) fuse.Status {
return fuse.EIO
}
n.Inode().RmChild(name)
- delete(n.files, name)
+
+ if isFolder {
+ delete(n.folders, name)
+ } else {
+ delete(n.files, name)
+ }
return fuse.OK
}
func (n *folderNode) Rmdir(name string, c *fuse.Context) fuse.Status {
- if !n.fetch() {
- return fuse.EIO
- }
-
- folderObj := n.folders[name]
- if folderObj == nil {
- return fuse.ENOENT
- }
- err := n.fs.dev.DeleteObject(folderObj.Id())
- if err != nil {
- log.Printf("DeleteObject failed: %v", err)
- return fuse.EIO
- }
- n.Inode().RmChild(name)
- delete(n.folders, name)
- return fuse.OK
+ return n.Unlink(name, c)
}
func (n *folderNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file fuse.File, fi *fuse.Attr, node fuse.FsNode, code fuse.Status) {
@@ -384,7 +444,7 @@ func (n *folderNode) Create(name string, flags uint32, mode uint32, context *fus
}
fn.backing = f.Name()
n.files[name] = fn.file
- n.Inode().New(false, fn)
+ n.Inode().AddChild(name, n.Inode().New(false, fn))
p := &pendingFile{
LoopbackFile: fuse.LoopbackFile{File: f},
View
15 mtp.go
@@ -20,6 +20,8 @@ This file has a partial cgo wrapping for libmtp, so users should
never have to call import "C"
*/
+// TODO - we leak C strings all over the place.
+
type Device C.LIBMTP_mtpdevice_t
type Error C.LIBMTP_error_t
type MtpError C.LIBMTP_error_number_t
@@ -189,12 +191,21 @@ func (d *Device) SendFromFileDescriptor(file *File, fd uintptr) error {
return nil
}
-// TODO should return modified name.
func (d *Device) CreateFolder(parent uint32, name string, storage uint32) (uint32, error) {
- id := C.LIBMTP_Create_Folder(d.me(), C.CString(name), C.uint32_t(parent), C.uint32_t(storage))
+ cname := C.CString(name)
+ id := C.LIBMTP_Create_Folder(d.me(), cname, C.uint32_t(parent), C.uint32_t(storage))
+
+ if newName := C.GoString(cname); newName != name {
+ log.Println("Folder name changed to %q", newName)
+ }
return uint32(id), d.ErrorStack()
}
+func (d *Device) SetFileName(f *File, name string) error {
+ C.LIBMTP_Set_File_Name(d.me(), f.me(), C.CString(name))
+ return d.ErrorStack()
+}
+
func (d *Device) DeleteObject(id uint32) error {
c := C.LIBMTP_Delete_Object(d.me(), C.uint32_t(id))
if c != 0 {
View
37 test.sh
@@ -1,20 +1,45 @@
#!/bin/sh
set -eux
-
+storage="Internal Storage"
mount=$(mktemp -d)
-./go-mtpfs $mount &
-sleep 1
-root="$mount/SD Card"
+root="$mount/$storage"
+delay="sleep 2"
+./go-mtpfs -fs-debug $mount &
+$delay
+test -d "$root"
rm -rf "$root/mtpfs-test"
mkdir "$root/mtpfs-test"
-rmdir "$root/mtpfs-test"
-mkdir "$root/mtpfs-test"
+mkdir "$root/mtpfs-test/create"
+mkdir "$root/mtpfs-test/delete"
+rmdir "$root/mtpfs-test/delete"
echo -n hello > "$root/mtpfs-test/test.txt"
ls -l "$root/mtpfs-test/test.txt"
test $(cat "$root/mtpfs-test/test.txt") == "hello"
touch "$root/mtpfs-test/test.txt"
echo something else > "$root/mtpfs-test/test.txt"
+mv "$root/mtpfs-test/test.txt" "$root/mtpfs-test/test2.txt"
+! test -f "$root/mtpfs-test/test.txt"
+test -f "$root/mtpfs-test/test2.txt"
+
+echo hoi > "$root/mtpfs-test/dest.txt"
+echo hoi > "$root/mtpfs-test/src.txt"
+mv "$root/mtpfs-test/src.txt" "$root/mtpfs-test/dest.txt"
+test -f "$root/mtpfs-test/dest.txt"
+! test -f "$root/mtpfs-test/src.txt"
+
+fusermount -u $mount
+
+./go-mtpfs $mount &
+$delay
+
+test -d "$root/mtpfs-test/create"
+! test -d "$root/mtpfs-test/delete"
+! test -f "$root/mtpfs-test/test.txt"
+test -f "$root/mtpfs-test/test2.txt"
+test -f "$root/mtpfs-test/dest.txt"
+! test -f "$root/mtpfs-test/src.txt"
+
fusermount -u $mount
Please sign in to comment.
Something went wrong with that request. Please try again.