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 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 := nodefs.NewFileSystemConnector(fs, nodefs.NewOptions()) rawFs := fuse.NewLockingRawFileSystem(conn.RawFS()) mount, err := fuse.NewServer(rawFs, tempdir, nil) if err != nil { t.Fatalf("mount failed: %v", err) } mount.SetDebug(fuse.VerboseTest()) dev.MTPDebug = fuse.VerboseTest() dev.USBDebug = fuse.VerboseTest() dev.DataDebug = fuse.VerboseTest() go mount.Serve() 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 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() { 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 device IDs, "+ "which are composed of manufacturer/product/serial.") 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, } root, err := fs.NewDeviceFSRoot(dev, sids, opts) if err != nil { log.Fatalf("NewDeviceFs failed: %v", err) } conn := nodefs.NewFileSystemConnector(root, nodefs.NewOptions()) rawFs := fuse.NewLockingRawFileSystem(conn.RawFS()) mOpts := &fuse.MountOptions{ AllowOther: *other, } mount, err := fuse.NewServer(rawFs, mountpoint, mOpts) if err != nil { log.Fatalf("mount failed: %v", err) } conn.SetDebug(debugs["fuse"] || debugs["fs"]) mount.SetDebug(debugs["fuse"] || debugs["fs"]) var wg sync.WaitGroup wg.Add(1) go func() { mount.Serve() wg.Done() }() mount.WaitMount() log.Printf("FUSE mounted") wg.Wait() root.OnUnmount() }
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) } }