func main() { // Scans the arg list and sets up flags debug := flag.Bool("debug", false, "print debugging messages.") flag.Parse() if flag.NArg() < 2 { // TODO - where to get program name? fmt.Println("usage: main MOUNTPOINT BACKING-PREFIX") os.Exit(2) } mountPoint := flag.Arg(0) prefix := flag.Arg(1) fs := fuse.NewMemNodeFs(prefix) conn := fuse.NewFileSystemConnector(fs, nil) state := fuse.NewMountState(conn) state.Debug = *debug fmt.Println("Mounting") err := state.Mount(mountPoint, nil) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } fmt.Println("Mounted!") state.Loop() }
func (me *WorkerDaemon) newWorkerTask(req *WorkRequest, rep *WorkReply) (*WorkerTask, os.Error) { fs, err := me.getFileServer(req.FileServer) if err != nil { return nil, err } w := &WorkerTask{ WorkRequest: req, WorkReply: rep, daemon: me, } tmpDir, err := ioutil.TempDir("", "rpcfs-tmp") type dirInit struct { dst *string val string } for _, v := range []dirInit{ dirInit{&w.rwDir, "rw"}, dirInit{&w.mount, "mnt"}, } { *v.dst = filepath.Join(tmpDir, v.val) err = os.Mkdir(*v.dst, 0700) if err != nil { return nil, err } } rwFs := fuse.NewLoopbackFileSystem(w.rwDir) roFs := NewRpcFs(fs, me.contentCache) // High ttl, since all writes come through fuse. ttl := 100.0 opts := unionfs.UnionFsOptions{ BranchCacheTTLSecs: ttl, DeletionCacheTTLSecs: ttl, DeletionDirName: _DELETIONS, } mOpts := fuse.FileSystemOptions{ EntryTimeout: ttl, AttrTimeout: ttl, NegativeTimeout: ttl, } ufs := unionfs.NewUnionFs("ufs", []fuse.FileSystem{rwFs, roFs}, opts) conn := fuse.NewFileSystemConnector(ufs, &mOpts) state := fuse.NewMountState(conn) state.Mount(w.mount, &fuse.MountOptions{AllowOther: true}) if err != nil { return nil, err } w.MountState = state go state.Loop(true) return w, nil }
func main() { fsdebug := flag.Bool("fs-debug", false, "switch on FS debugging") mtpDebug := flag.Bool("mtp-debug", false, "switch on MTP debugging") vfat := flag.Bool("vfat", true, "assume removable RAM media uses VFAT, and rewrite names.") other := flag.Bool("allow-other", false, "allow other users to access mounted fuse. Default: false.") deviceFilter := flag.String("dev", "", "regular expression to filter devices.") storageFilter := flag.String("storage", "", "regular expression to filter storage areas.") flag.Parse() if len(flag.Args()) != 1 { log.Fatalf("Usage: %s [options] MOUNT-POINT\n", os.Args[0]) } mountpoint := flag.Arg(0) dev, err := mtp.SelectDevice(*deviceFilter) if err != nil { log.Fatalf("detect failed: %v", err) } defer dev.Close() if err = dev.OpenSession(); err != nil { log.Fatalf("OpenSession failed: %v", err) } sids, err := fs.SelectStorages(dev, *storageFilter) if err != nil { log.Fatalf("selectStorages failed: %v", err) } dev.DebugPrint = *mtpDebug opts := fs.DeviceFsOptions{ RemovableVFat: *vfat, } fs, err := fs.NewDeviceFs(dev, sids, opts) if err != nil { log.Fatalf("NewDeviceFs failed: %v", err) } conn := fuse.NewFileSystemConnector(fs, fuse.NewFileSystemOptions()) rawFs := fuse.NewLockingRawFileSystem(conn) mount := fuse.NewMountState(rawFs) mOpts := &fuse.MountOptions{ AllowOther: *other, } if err := mount.Mount(mountpoint, mOpts); err != nil { log.Fatalf("mount failed: %v", err) } conn.Debug = *fsdebug mount.Debug = *fsdebug log.Printf("starting FUSE %v", fuse.Version()) mount.Loop() }
func main() { // Scans the arg list and sets up flags debug := flag.Bool("debug", false, "print debugging messages.") other := flag.Bool("allow-other", false, "mount with -o allowother.") flag.Parse() if flag.NArg() < 2 { // TODO - where to get program name? fmt.Println("usage: main MOUNTPOINT ORIGINAL") os.Exit(2) } var finalFs fuse.FileSystem orig := flag.Arg(1) loopbackfs := fuse.NewLoopbackFileSystem(orig) finalFs = loopbackfs opts := &fuse.FileSystemOptions{ // These options are to be compatible with libfuse defaults, // making benchmarking easier. NegativeTimeout: time.Second, AttrTimeout: time.Second, EntryTimeout: time.Second, } pathFs := fuse.NewPathNodeFs(finalFs, nil) conn := fuse.NewFileSystemConnector(pathFs, opts) state := fuse.NewMountState(conn) state.Debug = *debug mountPoint := flag.Arg(0) fmt.Println("Mounting") mOpts := &fuse.MountOptions{ AllowOther: *other, } err := state.Mount(mountPoint, mOpts) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } fmt.Println("Mounted!") state.Loop() }
func main() { cachedir := flag.String("cachedir", "/tmp/termite-cache", "content cache") server := flag.String("server", "localhost:1234", "file server") secretFile := flag.String("secret", "/tmp/secret.txt", "file containing password.") flag.Parse() if flag.NArg() < 1 { fmt.Fprintf(os.Stderr, "usage: %s MOUNTPOINT\n", os.Args[0]) os.Exit(2) } secret, err := ioutil.ReadFile(*secretFile) if err != nil { log.Fatal("ReadFile", err) } rpcConn, err := termite.SetupClient(*server, secret) if err != nil { log.Fatal("dialing:", err) } var fs fuse.FileSystem cache := termite.NewDiskFileCache(*cachedir) fs = termite.NewRpcFs(rpc.NewClient(rpcConn), cache) conn := fuse.NewFileSystemConnector(fs, nil) state := fuse.NewMountState(conn) opts := fuse.MountOptions{} if os.Geteuid() == 0 { opts.AllowOther = true } state.Mount(flag.Arg(0), &opts) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } state.Debug = true state.Loop(false) }
func MountVfs(databasePath string, mountPath string, allowOther bool) (*FuseVfs, error) { fuseVfs := FuseVfs{} pathNodeFs := fuse.NewPathNodeFs(&fuseVfs, nil) conn := fuse.NewFileSystemConnector(pathNodeFs, nil) state := fuse.NewMountState(conn) mountOptions := fuse.MountOptions{AllowOther: allowOther} err := state.Mount(mountPath, &mountOptions) if err != nil { return nil, fmt.Errorf("could not mount virtual filesystem at '%v': %v", mountPath, err) } store, err := storage.OpenAt(databasePath) if err != nil { return nil, fmt.Errorf("could not open database at '%v': %v", databasePath, err) } fuseVfs.store = store fuseVfs.mountPath = mountPath fuseVfs.state = state return &fuseVfs, nil }
func main() { fsdebug := flag.Bool("fs-debug", false, "switch on FS debugging") mtpDebug := flag.Int("mtp-debug", 0, "switch on MTP debugging") flag.Parse() if len(flag.Args()) != 1 { log.Fatal("Usage: mtpfs MOUNT-POINT") } mountpoint := flag.Arg(0) Init() SetDebug(*mtpDebug) devs, err := Detect() if err != nil { log.Fatalf("detect: %v", err) } for _, d := range devs { log.Printf("device %v: ", d) } if len(devs) == 0 { log.Fatal("no device found. Try replugging it.") } if len(devs) > 1 { log.Fatal("must have exactly one device") } rdev := devs[0] dev, err := rdev.Open() if err != nil { log.Fatalf("rdev.open: %v", err) } defer dev.Release() dev.GetStorage(0) for _, s := range dev.ListStorage() { log.Printf("storage ID %d: %s", s.Id(), s.Description()) } if len(dev.ListStorage()) == 0 { log.Fatalf("No storages found. Try unlocking the device.") } backing, err := ioutil.TempDir("", "go-mtpfs") if err != nil { log.Fatalf("TempDir failed: %v", err) } fs := NewDeviceFs(dev, backing) conn := fuse.NewFileSystemConnector(fs, fuse.NewFileSystemOptions()) rawFs := fuse.NewLockingRawFileSystem(conn) mount := fuse.NewMountState(rawFs) if err := mount.Mount(mountpoint, nil); err != nil { log.Fatalf("mount failed: %v", err) } conn.Debug = *fsdebug mount.Debug = *fsdebug log.Println("starting FUSE.") mount.Loop() os.RemoveAll(backing) }
func main() { fsdebug := flag.Bool("fs-debug", false, "switch on FS debugging") mtpDebug := flag.Int("mtp-debug", 0, "switch on MTP debugging. 1=PTP, 2=PLST, 4=USB, 8=DATA") backing := flag.String("backing-dir", "", "backing store for locally cached files. Default: use a temporary directory.") vfat := flag.Bool("vfat", true, "assume removable RAM media uses VFAT, and rewrite names.") other := flag.Bool("allow-other", false, "allow other users to access mounted fuse. Default: false.") deviceFilter := flag.String("dev", "", "regular expression to filter devices.") storageFilter := flag.String("storage", "", "regular expression to filter storage areas.") flag.Parse() if len(flag.Args()) != 1 { log.Fatalf("Usage: %s [options] MOUNT-POINT\n", os.Args[0]) } mountpoint := flag.Arg(0) Init() SetDebug(*mtpDebug) devs, err := Detect() if err != nil { log.Fatalf("detect failed: %v", err) } if *deviceFilter != "" { re, err := regexp.Compile(*deviceFilter) if err != nil { log.Fatalf("invalid regexp %q: %v", *deviceFilter, err) } filtered := []*RawDevice{} for _, d := range devs { if re.FindStringIndex(d.String()) != nil { filtered = append(filtered, d) } else { log.Printf("filtering out device %v: ", d) } } devs = filtered } else { for _, d := range devs { log.Printf("found device %v: ", d) } } if len(devs) == 0 { log.Fatal("no device found. Try replugging it.") } if len(devs) > 1 { log.Fatal("must have exactly one device. Try using -dev") } rdev := devs[0] dev, err := rdev.Open() if err != nil { log.Fatalf("rdev.open failed: %v", err) } defer dev.Release() dev.GetStorage(0) storages := []*DeviceStorage{} for _, s := range dev.ListStorage() { if !s.IsHierarchical() { log.Printf("skipping non hierarchical storage %q", s.Description()) continue } storages = append(storages, s) } if *storageFilter != "" { re, err := regexp.Compile(*storageFilter) if err != nil { log.Fatalf("invalid regexp %q: %v", *storageFilter, err) } filtered := []*DeviceStorage{} for _, s := range storages { if re.FindStringIndex(s.Description()) == nil { log.Printf("filtering out storage %q", s.Description()) continue } filtered = append(filtered, s) } if len(filtered) == 0 { log.Fatalf("No storages found. Try changing the -storage flag.") } storages = filtered } else { for _, s := range storages { log.Printf("storage ID %d: %s", s.Id(), s.Description()) } } if len(storages) == 0 { log.Fatalf("No storages found. Try unlocking the device.") } if *backing == "" { *backing, err = ioutil.TempDir("", "go-mtpfs") if err != nil { log.Fatalf("TempDir failed: %v", err) } } else { *backing = *backing + "/go-mtpfs" err = os.Mkdir(*backing, 0700) if err != nil { log.Fatalf("Mkdir failed: %v", err) } } log.Println("backing data", *backing) defer os.RemoveAll(*backing) opts := DeviceFsOptions{ Dir: *backing, RemovableVFat: *vfat, } fs := NewDeviceFs(dev, storages, opts) conn := fuse.NewFileSystemConnector(fs, fuse.NewFileSystemOptions()) rawFs := fuse.NewLockingRawFileSystem(conn) mount := fuse.NewMountState(rawFs) mOpts := &fuse.MountOptions{ AllowOther: *other, } if err := mount.Mount(mountpoint, mOpts); err != nil { log.Fatalf("mount failed: %v", err) } conn.Debug = *fsdebug mount.Debug = *fsdebug log.Printf("starting FUSE %v", fuse.Version()) mount.Loop() }
func main() { fsdebug := flag.Bool("fs-debug", false, "switch on FS debugging") mtpDebug := flag.Int("mtp-debug", 0, "switch on MTP debugging. 1=PTP, 2=PLST, 4=USB, 8=DATA") backing := flag.String("backing-dir", "", "backing store for locally cached files. Default: use a temporary directory.") vfat := flag.Bool("vfat", true, "assume removable RAM media uses VFAT, and rewrite names.") other := flag.Bool("allow-other", false, "allow other users to access mounted fuse. Default: false.") flag.Parse() if len(flag.Args()) != 1 { log.Fatal("Usage: mtpfs MOUNT-POINT") } mountpoint := flag.Arg(0) Init() SetDebug(*mtpDebug) devs, err := Detect() if err != nil { log.Fatalf("detect: %v", err) } for _, d := range devs { log.Printf("device %v: ", d) } if len(devs) == 0 { log.Fatal("no device found. Try replugging it.") } if len(devs) > 1 { log.Fatal("must have exactly one device") } rdev := devs[0] dev, err := rdev.Open() if err != nil { log.Fatalf("rdev.open: %v", err) } defer dev.Release() dev.GetStorage(0) for _, s := range dev.ListStorage() { log.Printf("storage ID %d: %s", s.Id(), s.Description()) } if len(dev.ListStorage()) == 0 { log.Fatalf("No storages found. Try unlocking the device.") } if *backing == "" { *backing, err = ioutil.TempDir("", "go-mtpfs") if err != nil { log.Fatalf("TempDir failed: %v", err) } } else { *backing = *backing + "/go-mtpfs" err = os.Mkdir(*backing, 0700) if err != nil { log.Fatalf("Mkdir failed: %v", err) } } log.Println("backing data", *backing) defer os.RemoveAll(*backing) opts := DeviceFsOptions{ Dir: *backing, RemovableVFat: *vfat, } fs := NewDeviceFs(dev, &opts) conn := fuse.NewFileSystemConnector(fs, fuse.NewFileSystemOptions()) rawFs := fuse.NewLockingRawFileSystem(conn) mount := fuse.NewMountState(rawFs) mOpts := &fuse.MountOptions{ AllowOther: *other, } if err := mount.Mount(mountpoint, mOpts); err != nil { log.Fatalf("mount failed: %v", err) } conn.Debug = *fsdebug mount.Debug = *fsdebug log.Println("starting FUSE.") mount.Loop() }
func newWorkerFuseFs(tmpDir string, rpcFs fuse.FileSystem, writableRoot string, nobody *User) (*workerFuseFs, error) { tmpDir, err := ioutil.TempDir(tmpDir, "termite-task") if err != nil { return nil, err } me := &workerFuseFs{ tmpDir: tmpDir, writableRoot: strings.TrimLeft(writableRoot, "/"), tasks: map[*WorkerTask]bool{}, } type dirInit struct { dst *string val string } tmpBacking := "" for _, v := range []dirInit{ {&me.rwDir, "rw"}, {&me.mount, "mnt"}, {&tmpBacking, "tmp-backing"}, } { *v.dst = filepath.Join(me.tmpDir, v.val) err = os.Mkdir(*v.dst, 0700) if err != nil { return nil, err } } fuseOpts := fuse.MountOptions{} if os.Geteuid() == 0 { fuseOpts.AllowOther = true } me.rpcNodeFs = fuse.NewPathNodeFs(rpcFs, nil) ttl := 30 * time.Second mOpts := fuse.FileSystemOptions{ EntryTimeout: ttl, AttrTimeout: ttl, NegativeTimeout: ttl, // 32-bit programs have trouble with 64-bit inode // numbers. PortableInodes: true, } me.fsConnector = fuse.NewFileSystemConnector(me.rpcNodeFs, &mOpts) me.MountState = fuse.NewMountState(me.fsConnector) err = me.MountState.Mount(me.mount, &fuseOpts) if err != nil { return nil, err } go me.MountState.Loop() me.unionFs = fs.NewMemUnionFs( me.rwDir, &fuse.PrefixFileSystem{rpcFs, me.writableRoot}) me.procFs = fs.NewProcFs() me.procFs.StripPrefix = me.mount if nobody != nil { me.procFs.Uid = nobody.Uid } type submount struct { mountpoint string fs fuse.NodeFileSystem } mounts := []submount{ {"proc", fuse.NewPathNodeFs(me.procFs, nil)}, {"sys", fuse.NewPathNodeFs(&fuse.ReadonlyFileSystem{fuse.NewLoopbackFileSystem("/sys")}, nil)}, {"tmp", fuse.NewMemNodeFs(tmpBacking + "/tmp")}, {"dev", fs.NewDevNullFs()}, {"var/tmp", fuse.NewMemNodeFs(tmpBacking + "/vartmp")}, } for _, s := range mounts { subOpts := &mOpts if s.mountpoint == "proc" { subOpts = nil } code := me.rpcNodeFs.Mount(s.mountpoint, s.fs, subOpts) if !code.Ok() { if err := me.MountState.Unmount(); err != nil { log.Fatal("FUSE unmount error during cleanup:", err) } return nil, errors.New(fmt.Sprintf("submount error for %s: %v", s.mountpoint, code)) } } if strings.HasPrefix(me.writableRoot, "tmp/") { parent, _ := filepath.Split(me.writableRoot) err := os.MkdirAll(filepath.Join(me.mount, parent), 0755) if err != nil { if err := me.MountState.Unmount(); err != nil { log.Fatal("FUSE unmount error during cleanup:", err) } return nil, errors.New(fmt.Sprintf("Mkdir of %q in /tmp fail: %v", parent, err)) } // This is hackish, but we don't want rpcfs/fsserver // getting confused by asking for tmp/foo/bar // directly. rpcFs.GetAttr("tmp", nil) rpcFs.GetAttr(me.writableRoot, nil) } code := me.rpcNodeFs.Mount(me.writableRoot, me.unionFs, &mOpts) if !code.Ok() { if err := me.MountState.Unmount(); err != nil { log.Fatal("FUSE unmount error during cleanup:", err) } return nil, errors.New(fmt.Sprintf("submount error for %s: %v", me.writableRoot, code)) } return me, nil }
func main() { debug := flag.String("debug", "", "comma-separated list of debugging options: usb, data, mtp, fuse") usbTimeout := flag.Int("usb-timeout", 5000, "timeout in milliseconds") vfat := flag.Bool("vfat", true, "assume removable RAM media uses VFAT, and rewrite names.") other := flag.Bool("allow-other", false, "allow other users to access mounted fuse. Default: false.") deviceFilter := flag.String("dev", "", "regular expression to filter devices.") storageFilter := flag.String("storage", "", "regular expression to filter storage areas.") android := flag.Bool("android", true, "use android extensions if available") flag.Parse() if len(flag.Args()) != 1 { log.Fatalf("Usage: %s [options] MOUNT-POINT\n", os.Args[0]) } mountpoint := flag.Arg(0) dev, err := mtp.SelectDevice(*deviceFilter) if err != nil { log.Fatalf("detect failed: %v", err) } defer dev.Close() debugs := map[string]bool{} for _, s := range strings.Split(*debug, ",") { debugs[s] = true } dev.MTPDebug = debugs["mtp"] dev.DataDebug = debugs["data"] dev.USBDebug = debugs["usb"] dev.Timeout = *usbTimeout if err = dev.Configure(); err != nil { log.Fatalf("Configure failed: %v", err) } sids, err := fs.SelectStorages(dev, *storageFilter) if err != nil { log.Fatalf("selectStorages failed: %v", err) } opts := fs.DeviceFsOptions{ RemovableVFat: *vfat, Android: *android, } fs, err := fs.NewDeviceFs(dev, sids, opts) if err != nil { log.Fatalf("NewDeviceFs failed: %v", err) } conn := fuse.NewFileSystemConnector(fs, fuse.NewFileSystemOptions()) rawFs := fuse.NewLockingRawFileSystem(conn) mount := fuse.NewMountState(rawFs) mOpts := &fuse.MountOptions{ AllowOther: *other, } if err := mount.Mount(mountpoint, mOpts); err != nil { log.Fatalf("mount failed: %v", err) } conn.Debug = debugs["fuse"] || debugs["fs"] mount.Debug = debugs["fuse"] || debugs["fs"] log.Printf("starting FUSE %v", fuse.Version()) mount.Loop() fs.OnUnmount() }
func main() { // Scans the arg list and sets up flags debug := flag.Bool("debug", false, "print debugging messages.") latencies := flag.Bool("latencies", false, "record latencies.") threaded := flag.Bool("threaded", true, "switch off threading; print debugging messages.") flag.Parse() if flag.NArg() < 2 { // TODO - where to get program name? fmt.Println("usage: main MOUNTPOINT ORIGINAL") os.Exit(2) } var finalFs fuse.FileSystem orig := flag.Arg(1) loopbackfs := fuse.NewLoopbackFileSystem(orig) finalFs = loopbackfs debugFs := fuse.NewFileSystemDebug() if *latencies { timing := fuse.NewTimingFileSystem(finalFs) debugFs.AddTimingFileSystem(timing) finalFs = timing } opts := &fuse.FileSystemOptions{ // These options are to be compatible with libfuse defaults, // making benchmarking easier. NegativeTimeout: 1.0, AttrTimeout: 1.0, EntryTimeout: 1.0, } if *latencies { debugFs.FileSystem = finalFs finalFs = debugFs } conn := fuse.NewFileSystemConnector(finalFs, opts) var finalRawFs fuse.RawFileSystem = conn if *latencies { rawTiming := fuse.NewTimingRawFileSystem(conn) debugFs.AddRawTimingFileSystem(rawTiming) finalRawFs = rawTiming } state := fuse.NewMountState(finalRawFs) state.Debug = *debug if *latencies { state.SetRecordStatistics(true) debugFs.AddMountState(state) debugFs.AddFileSystemConnector(conn) } mountPoint := flag.Arg(0) fmt.Println("Mounting") err := state.Mount(mountPoint, nil) if err != nil { fmt.Printf("Mount fail: %v\n", err) os.Exit(1) } fmt.Println("Mounted!") state.Loop(*threaded) }
func startFs(t *testing.T, useAndroid bool) (root string, cleanup func()) { dev, err := mtp.SelectDevice("") if err != nil { t.Fatalf("SelectDevice failed: %v", err) } defer func() { if dev != nil { dev.Close() } }() if err = dev.Configure(); err != nil { t.Fatalf("Configure failed: %v", err) } sids, err := SelectStorages(dev, "") if err != nil { t.Fatalf("selectStorages failed: %v", err) } if len(sids) == 0 { t.Fatal("no storages found. Unlock device?") } tempdir, err := ioutil.TempDir("", "mtpfs") if err != nil { t.Fatal(err) } opts := DeviceFsOptions{ Android: useAndroid, } fs, err := NewDeviceFs(dev, sids, opts) if err != nil { t.Fatal("NewDeviceFs failed:", err) } conn := fuse.NewFileSystemConnector(fs, fuse.NewFileSystemOptions()) rawFs := fuse.NewLockingRawFileSystem(conn) mount := fuse.NewMountState(rawFs) if err := mount.Mount(tempdir, nil); err != nil { t.Fatalf("mount failed: %v", err) } mount.Debug = fuse.VerboseTest() dev.MTPDebug = fuse.VerboseTest() dev.USBDebug = fuse.VerboseTest() dev.DataDebug = fuse.VerboseTest() go mount.Loop() for i := 0; i < 10; i++ { fis, err := ioutil.ReadDir(tempdir) if err == nil && len(fis) > 0 { root = filepath.Join(tempdir, fis[0].Name()) break } time.Sleep(1) } if root == "" { mount.Unmount() t.Fatal("could not find entries in mount point.") } d := dev dev = nil return root, func() { mount.Unmount() d.Close() } }
func TestDevice(t *testing.T) { dev, err := mtp.SelectDevice("") if err != nil { t.Fatalf("detect failed: %v", err) } defer dev.Close() if err = dev.OpenSession(); err != nil { t.Fatalf("OpenSession failed: %v", err) } sids, err := SelectStorages(dev, "") if err != nil { t.Fatalf("selectStorages failed: %v", err) } tempdir, err := ioutil.TempDir("", "mtpfs") if err != nil { t.Fatal(err) } opts := DeviceFsOptions{} fs, err := NewDeviceFs(dev, sids, opts) conn := fuse.NewFileSystemConnector(fs, fuse.NewFileSystemOptions()) rawFs := fuse.NewLockingRawFileSystem(conn) mount := fuse.NewMountState(rawFs) if err := mount.Mount(tempdir, nil); err != nil { t.Fatalf("mount failed: %v", err) } mount.Debug = true dev.DebugPrint = true defer mount.Unmount() go mount.Loop() var root string for i := 0; i < 10; i++ { fis, err := ioutil.ReadDir(tempdir) if err != nil || len(fis) == 0 { time.Sleep(1) continue } root = filepath.Join(tempdir, fis[0].Name()) break if i == 9 { t.Fatal("mount unsuccessful") } } _, err = os.Lstat(root + "/Music") if err != nil { t.Fatal("Music not found", err) } name := filepath.Join(root, fmt.Sprintf("mtpfs-test-%x", rand.Int31())) golden := "abcpxq134" if err := ioutil.WriteFile(name, []byte("abcpxq134"), 0644); err != nil { t.Fatal(err) } got, err := ioutil.ReadFile(name) if err != nil { t.Fatal("ReadFile failed", err) } if string(got) != golden { t.Fatalf("got %q, want %q", got, golden) } f, err := os.OpenFile(name, os.O_RDWR|os.O_APPEND, 0644) if err != nil { t.Fatal("OpenFile failed:", err) } log.Println("writing...") golden += "hello" f.Write([]byte("hello")) log.Println("done...") f.Close() got, err = ioutil.ReadFile(name) if err != nil { t.Fatal("ReadFile failed", err) } if string(got) != golden { t.Fatalf("got %q, want %q", got, golden) } newName := filepath.Join(root, fmt.Sprintf("mtpfs-test-%x", rand.Int31())) err = os.Rename(name, newName) if err != nil { t.Fatal("Rename failed", err) } if fi, err := os.Lstat(name); err == nil { t.Fatal("should have disappeared after rename", fi) } if _, err := os.Lstat(newName); err != nil { t.Fatal("should be able to stat after rename", err) } err = os.Remove(newName) if err != nil { t.Fatal("Remove failed", err) } if fi, err := os.Lstat(newName); err == nil { t.Fatal("should have disappeared after Remove", fi) } }