Hello community, here is the log from the commit of package go-go-mtpfs for openSUSE:Factory checked in at 2014-09-23 10:42:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/go-go-mtpfs (Old) and /work/SRC/openSUSE:Factory/.go-go-mtpfs.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "go-go-mtpfs" Changes: -------- --- /work/SRC/openSUSE:Factory/go-go-mtpfs/go-go-mtpfs.changes 2013-11-13 10:03:06.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.go-go-mtpfs.new/go-go-mtpfs.changes 2014-09-23 10:42:49.000000000 +0200 @@ -1,0 +2,5 @@ +Fri Sep 19 17:35:48 UTC 2014 - i@marguerite.su + +- update version 0.0.0+git20140903.689b5b4 + +------------------------------------------------------------------- Old: ---- go-mtpfs-0.0.0+git20131015.bb3f0c2.tar.bz2 New: ---- go-mtpfs-0.0.0+git20140903.689b5b4.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ go-go-mtpfs.spec ++++++ --- /var/tmp/diff_new_pack.dBXNbb/_old 2014-09-23 10:42:51.000000000 +0200 +++ /var/tmp/diff_new_pack.dBXNbb/_new 2014-09-23 10:42:51.000000000 +0200 @@ -1,7 +1,7 @@ # # spec file for package go-go-mtpfs # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,26 +17,28 @@ Name: go-go-mtpfs -Version: 0.0.0+git20131015.bb3f0c2 +Version: 0.0.0+git20140903.689b5b4 Release: 0 Summary: Mount MTP devices over FUSE -Group: Productivity/Multimedia/Sound/Players License: BSD-3-Clause +Group: Productivity/Multimedia/Sound/Players Url: https://github.com/hanwen/go-mtpfs Source: go-mtpfs-%{version}.tar.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: go-devel BuildRequires: go-go-fuse -BuildRequires: pkgconfig +BuildRequires: go-hanwen-usb +BuildRequires: pkg-config BuildRequires: pkgconfig(libmtp) -BuildRequires: pkgconfig(libusb-1.0) -%if 0%{?suse_version} >= 1100 -Recommends: %{name}-doc -%endif +Requires: go-go-fuse +Requires: go-hanwen-usb +Requires: pkg-config +Requires: pkgconfig(libmtp) Provides: go-mtpfs = 0.0+git6b55d1f9 Obsoletes: go-mtpfs < 0.0+git6b55d1f9 %{go_requires} %{go_provides} +%{go_recommends} %description Go-mtpfs is a simple FUSE filesystem for mounting Android devices as a @@ -51,13 +53,7 @@ Nexus 7). As of Jan. 2013, it uses a pure Go implementation of MTP, which is based on libusb. -%package doc -Summary: API documenation -Group: Documentation/Other -Requires: %{name} = %{version} - -%description doc -API, examples and documentation. +%godoc_package %prep %setup -q -n go-mtpfs-%{version} ++++++ go-mtpfs-0.0.0+git20131015.bb3f0c2.tar.bz2 -> go-mtpfs-0.0.0+git20140903.689b5b4.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/all.bash new/go-mtpfs-0.0.0+git20140903.689b5b4/all.bash --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/all.bash 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/all.bash 2014-09-19 19:29:28.000000000 +0200 @@ -3,8 +3,6 @@ # Script to exercise everything. set -eux -# mtp-detect still does a better job at resetting device to a sane state. -mtp-detect for x in fs mtp do go build github.com/hanwen/go-mtpfs/$x diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/fs/android.go new/go-mtpfs-0.0.0+git20140903.689b5b4/fs/android.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/fs/android.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/fs/android.go 2014-09-19 19:29:28.000000000 +0200 @@ -93,7 +93,7 @@ } func (f *androidFile) Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status) { - if off >= f.node.Size { + if off > f.node.Size { // ENXIO = no such address. return nil, fuse.Status(int(syscall.ENXIO)) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/fs/classic.go new/go-mtpfs-0.0.0+git20140903.689b5b4/fs/classic.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/fs/classic.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/fs/classic.go 2014-09-19 19:29:28.000000000 +0200 @@ -281,7 +281,7 @@ //////////////////////////////////////////////////////////////// -func (fs *DeviceFs) trimUnused(todo int64, node *nodefs.Inode) (done int64) { +func (fs *deviceFS) trimUnused(todo int64, node *nodefs.Inode) (done int64) { for _, ch := range node.Children() { if done > todo { break @@ -296,7 +296,7 @@ return } -func (fs *DeviceFs) freeBacking() (int64, error) { +func (fs *deviceFS) freeBacking() (int64, error) { t := syscall.Statfs_t{} err := syscall.Statfs(fs.options.Dir, &t) if err != nil { @@ -306,7 +306,7 @@ return int64(t.Bfree * uint64(t.Bsize)), nil } -func (fs *DeviceFs) ensureFreeSpace(want int64) error { +func (fs *deviceFS) ensureFreeSpace(want int64) error { free, err := fs.freeBacking() if err != nil { return err @@ -329,7 +329,7 @@ return fmt.Errorf("not enough space in %s. Have %d, want %d", fs.options.Dir, free, want) } -func (fs *DeviceFs) setupClassic() error { +func (fs *deviceFS) setupClassic() error { if fs.options.Dir == "" { var err error fs.options.Dir, err = ioutil.TempDir(os.TempDir(), "go-mtpfs") @@ -344,19 +344,13 @@ return nil } -func (fs *DeviceFs) OnUnmount() { - if fs.delBackingDir { - os.RemoveAll(fs.options.Dir) - } -} - -func (fs *DeviceFs) createClassicFile(obj mtp.ObjectInfo) (file nodefs.File, node nodefs.Node, err error) { +func (fs *deviceFS) createClassicFile(obj mtp.ObjectInfo) (file nodefs.File, node nodefs.Node, err error) { backingFile, err := ioutil.TempFile(fs.options.Dir, "") cl := &classicNode{ mtpNodeImpl: mtpNodeImpl{ - Node: nodefs.NewDefaultNode(), - obj: &obj, - fs: fs, + Node: nodefs.NewDefaultNode(), + obj: &obj, + fs: fs, }, dirty: true, backing: backingFile.Name(), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/fs/device_test.go new/go-mtpfs-0.0.0+git20140903.689b5b4/fs/device_test.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/fs/device_test.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/fs/device_test.go 2014-09-19 19:29:28.000000000 +0200 @@ -3,7 +3,10 @@ // This test requires an unlocked android MTP device plugged in. import ( + "bytes" + "flag" "fmt" + "io" "io/ioutil" "math/rand" "os" @@ -16,11 +19,17 @@ "github.com/hanwen/go-mtpfs/mtp" ) +// VerboseTest returns true if the testing framework is run with -v. +func VerboseTest() bool { + flag := flag.Lookup("test.v") + return flag != nil && flag.Value.String() == "true" +} + func init() { rand.Seed(time.Now().UnixNano()) } -func startFs(t *testing.T, useAndroid bool) (root string, cleanup func()) { +func startFs(t *testing.T, useAndroid bool) (storageRoot string, cleanup func()) { dev, err := mtp.SelectDevice("") if err != nil { t.Fatalf("SelectDevice failed: %v", err) @@ -49,40 +58,40 @@ opts := DeviceFsOptions{ Android: useAndroid, } - fs, err := NewDeviceFs(dev, sids, opts) + root, err := NewDeviceFSRoot(dev, sids, opts) if err != nil { t.Fatal("NewDeviceFs failed:", err) } - conn := nodefs.NewFileSystemConnector(fs, nodefs.NewOptions()) + conn := nodefs.NewFileSystemConnector(root, 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() + mount.SetDebug(VerboseTest()) + dev.MTPDebug = VerboseTest() + dev.USBDebug = VerboseTest() + dev.DataDebug = 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()) + storageRoot = filepath.Join(tempdir, fis[0].Name()) break } time.Sleep(1) } - if root == "" { + if storageRoot == "" { mount.Unmount() t.Fatal("could not find entries in mount point.") } d := dev dev = nil - return root, func() { + return storageRoot, func() { mount.Unmount() d.Close() } @@ -173,6 +182,46 @@ } } +func testReadBlockBoundary(t *testing.T, android bool) { + root, cleanup := startFs(t, android) + defer cleanup() + + name := filepath.Join(root, fmt.Sprintf("mtpfs-test-%x", rand.Int31())) + + page := 4096 + buf := bytes.Repeat([]byte("a"), 32*page) + if err := ioutil.WriteFile(name, buf, 0644); err != nil { + t.Fatalf("WriteFile: %v", err) + } + + f, err := os.Open(name) + if err != nil { + t.Fatalf("Open: %v", name) + } + + total := 0 + for { + b := make([]byte, page) + n, err := f.Read(b) + total += n + if n == 0 && err == io.EOF { + break + } + if n != 4096 || err != nil { + t.Fatalf("Read: %v (%d bytes)", err, n) + } + } + f.Close() +} + +func TestReadBlockBoundaryAndroid(t *testing.T) { + testReadBlockBoundary(t, true) +} + +func TestReadBlockBoundaryNormal(t *testing.T) { + testReadBlockBoundary(t, false) +} + func TestAndroid(t *testing.T) { testDevice(t, true) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/fs/fs.go new/go-mtpfs-0.0.0+git20140903.689b5b4/fs/fs.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/fs/fs.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/fs/fs.go 2014-09-19 19:29:28.000000000 +0200 @@ -8,6 +8,7 @@ "bytes" "fmt" "log" + "os" "strings" "time" @@ -30,9 +31,7 @@ // DeviceFS implements a fuse.NodeFileSystem that mounts multiple // storages. -type DeviceFs struct { - nodefs.FileSystem - +type deviceFS struct { backingDir string delBackingDir bool root *rootNode @@ -49,19 +48,18 @@ // threadsafe. The file system assumes the device does not touch the // storage. Arguments are the opened mtp device and a directory for the // backing store. -func NewDeviceFs(d *mtp.Device, storages []uint32, options DeviceFsOptions) (*DeviceFs, error) { +func NewDeviceFSRoot(d *mtp.Device, storages []uint32, options DeviceFsOptions) (nodefs.Node, error) { root := rootNode{Node: nodefs.NewDefaultNode()} - fs := &DeviceFs{ - FileSystem: nodefs.NewDefaultFileSystem(), - root: &root, - dev: d, - options: &options, + fs := &deviceFS{ + root: &root, + dev: d, + options: &options, } root.fs = fs fs.storages = storages err := d.GetDeviceInfo(&fs.devInfo) if err != nil { - return fs, nil + return nil, err } if !strings.Contains(fs.devInfo.MTPExtension, "android.com") { @@ -85,21 +83,39 @@ fs.mungeVfat[sid] = info.IsRemovable() && fs.options.RemovableVFat } - return fs, nil + return fs.Root(), nil } -func (fs *DeviceFs) Root() nodefs.Node { +func (fs *deviceFS) Root() nodefs.Node { return fs.root } -func (fs *DeviceFs) String() string { - return fmt.Sprintf("DeviceFs(%s)", fs.devInfo.Model) +func (fs *deviceFS) String() string { + return fmt.Sprintf("deviceFS(%s)", fs.devInfo.Model) +} + +func (fs *deviceFS) onMount() { + for _, sid := range fs.storages { + var info mtp.StorageInfo + if err := fs.dev.GetStorageInfo(sid, &info); err != nil { + log.Printf("GetStorageInfo %x: %v", sid, err) + continue + } + + obj := mtp.ObjectInfo{ + ParentObject: NOPARENT_ID, + StorageID: sid, + Filename: info.StorageDescription, + } + folder := fs.newFolder(obj, NOPARENT_ID) + fs.root.Inode().NewChild(info.StorageDescription, true, folder) + } } // TODO - this should be per storage and return just the free space in // the storage. -func (fs *DeviceFs) newFile(obj mtp.ObjectInfo, size int64, id uint32) (node nodefs.Node) { +func (fs *deviceFS) newFile(obj mtp.ObjectInfo, size int64, id uint32) (node nodefs.Node) { if obj.CompressedSize != 0xFFFFFFFF { size = int64(obj.CompressedSize) } @@ -125,27 +141,19 @@ type rootNode struct { nodefs.Node - fs *DeviceFs + fs *deviceFS } const NOPARENT_ID = 0xFFFFFFFF -func (fs *DeviceFs) OnMount(conn *nodefs.FileSystemConnector) { - for _, sid := range fs.storages { - var info mtp.StorageInfo - if err := fs.dev.GetStorageInfo(sid, &info); err != nil { - log.Printf("GetStorageInfo %x: %v", sid, err) - continue - } +func (n *rootNode) OnMount(conn *nodefs.FileSystemConnector) { + n.fs.onMount() +} - obj := mtp.ObjectInfo{ - ParentObject: NOPARENT_ID, - StorageID: sid, - Filename: info.StorageDescription, - } - folder := fs.newFolder(obj, NOPARENT_ID) - inode := fs.root.Inode().New(true, folder) - fs.root.Inode().AddChild(info.StorageDescription, inode) +func (n *rootNode) OnUnmount() { + if n.fs.delBackingDir { + os.RemoveAll(n.fs.options.Dir) + n.fs.delBackingDir = false } } @@ -202,7 +210,7 @@ obj *mtp.ObjectInfo - fs *DeviceFs + fs *deviceFS // This is needed because obj.CompressedSize only goes to // 0xFFFFFFFF @@ -288,7 +296,7 @@ fetched bool } -func (fs *DeviceFs) newFolder(obj mtp.ObjectInfo, h uint32) *folderNode { +func (fs *deviceFS) newFolder(obj mtp.ObjectInfo, h uint32) *folderNode { obj.AssociationType = mtp.OFC_Association return &folderNode{ mtpNodeImpl: mtpNodeImpl{ @@ -359,7 +367,7 @@ node = n.fs.newFile(*info, sz, handle) } - n.Inode().AddChild(info.Filename, n.Inode().New(isdir, node)) + n.Inode().NewChild(info.Filename, isdir, node) } n.fetched = true return true @@ -428,7 +436,7 @@ return fuse.OK } -func (n *folderNode) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node nodefs.Node, code fuse.Status) { +func (n *folderNode) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node *nodefs.Inode, code fuse.Status) { if !n.fetch() { return nil, fuse.EIO } @@ -437,11 +445,10 @@ return nil, fuse.ENOENT } - s := ch.Node().GetAttr(out, nil, context) - return ch.Node(), s + return ch, ch.Node().GetAttr(out, nil, context) } -func (n *folderNode) Mkdir(name string, mode uint32, context *fuse.Context) (nodefs.Node, fuse.Status) { +func (n *folderNode) Mkdir(name string, mode uint32, context *fuse.Context) (*nodefs.Inode, fuse.Status) { if !n.fetch() { return nil, fuse.EIO } @@ -460,8 +467,7 @@ } f := n.fs.newFolder(obj, newId) - n.Inode().AddChild(name, n.Inode().New(true, f)) - return f, fuse.OK + return n.Inode().NewChild(name, true, f), fuse.OK } func (n *folderNode) Unlink(name string, c *fuse.Context) fuse.Status { @@ -492,7 +498,7 @@ return n.Unlink(name, c) } -func (n *folderNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, node nodefs.Node, code fuse.Status) { +func (n *folderNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (nodefs.File, *nodefs.Inode, fuse.Status) { if !n.fetch() { return nil, nil, fuse.EIO } @@ -506,6 +512,8 @@ CompressedSize: 0, } + var file nodefs.File + var fsNode nodefs.Node if n.fs.options.Android { _, _, handle, err := n.fs.dev.SendObjectInfo(n.StorageID(), n.Handle(), &obj) if err != nil { @@ -535,14 +543,13 @@ File: nodefs.NewDefaultFile(), node: aNode, } - node = aNode + fsNode = aNode } else { var err error - file, node, err = n.fs.createClassicFile(obj) + file, fsNode, err = n.fs.createClassicFile(obj) if err != nil { return nil, nil, fuse.ToStatus(err) } } - n.Inode().AddChild(name, n.Inode().New(false, node)) - return file, node, fuse.OK + return file, n.Inode().NewChild(name, false, fsNode), fuse.OK } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/main.go new/go-mtpfs-0.0.0+git20140903.689b5b4/main.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/main.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/main.go 2014-09-19 19:29:28.000000000 +0200 @@ -9,6 +9,7 @@ "log" "os" "strings" + "sync" "github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse/nodefs" @@ -22,8 +23,8 @@ 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.") + "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() @@ -59,11 +60,11 @@ RemovableVFat: *vfat, Android: *android, } - fs, err := fs.NewDeviceFs(dev, sids, opts) + root, err := fs.NewDeviceFSRoot(dev, sids, opts) if err != nil { log.Fatalf("NewDeviceFs failed: %v", err) } - conn := nodefs.NewFileSystemConnector(fs, nodefs.NewOptions()) + conn := nodefs.NewFileSystemConnector(root, nodefs.NewOptions()) rawFs := fuse.NewLockingRawFileSystem(conn.RawFS()) mOpts := &fuse.MountOptions{ @@ -76,7 +77,14 @@ conn.SetDebug(debugs["fuse"] || debugs["fs"]) mount.SetDebug(debugs["fuse"] || debugs["fs"]) - log.Printf("starting FUSE.") - mount.Serve() - fs.OnUnmount() + var wg sync.WaitGroup + wg.Add(1) + go func() { + mount.Serve() + wg.Done() + }() + mount.WaitMount() + log.Printf("FUSE mounted") + wg.Wait() + root.OnUnmount() } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/mtp/encoding.go new/go-mtpfs-0.0.0+git20140903.689b5b4/mtp/encoding.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/mtp/encoding.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/mtp/encoding.go 2014-09-19 19:29:28.000000000 +0200 @@ -45,27 +45,28 @@ } func encodeStr(buf []byte, s string) ([]byte, error) { - if len(s) > 254 { - return nil, fmt.Errorf("range") - } - if s == "" { buf[0] = 0 return buf[:1], nil } - i := 0 - buf[i] = byte(len(s) + 1) - i++ + codepoints := 0 + buf = append(buf[:0], 0) + + var rune [2]byte for _, r := range s { - byteOrder.PutUint16(buf[i:], uint16(r)) - i += 2 + byteOrder.PutUint16(rune[:], uint16(r)) + buf = append(buf, rune[0], rune[1]) + codepoints++ } - buf[i] = 0 - i++ - buf[i] = 0 - i++ - return buf[:i], nil + buf = append(buf, 0, 0) + codepoints++ + if codepoints > 254 { + return nil, fmt.Errorf("string too long") + } + + buf[0] = byte(codepoints) + return buf, nil } func encodeStrField(w io.Writer, f reflect.Value) error { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/mtp/encoding_test.go new/go-mtpfs-0.0.0+git20140903.689b5b4/mtp/encoding_test.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/mtp/encoding_test.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/mtp/encoding_test.go 2014-09-19 19:29:28.000000000 +0200 @@ -240,3 +240,31 @@ dp, back) } } + +func TestDecodeStr(t *testing.T) { + enc := make([]byte, 100) + test := "ö" + out, err := encodeStr(enc, test) + if err != nil { + t.Fatalf("encodeStr: %v", err) + } + buf := bytes.NewBuffer(out) + roundtrip, err := decodeStr(buf) + if err != nil { + t.Fatalf("encodeStr: %v", err) + } + if roundtrip != test { + t.Fatalf("got %q, want %q", roundtrip, test) + } +} + +func TestEncodeStr(t *testing.T) { + mtpStr := []byte("\x02\xe4\x00\x00\x00") + str := "ä" + + if out, err := encodeStr(nil, str); err != nil { + t.Fatalf("encodeStr: %v", err) + } else if bytes.Compare(out, mtpStr) != 0 { + t.Fatalf("got %q, want %q", out, mtpStr) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/mtp/mtp.go new/go-mtpfs-0.0.0+git20140903.689b5b4/mtp/mtp.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/mtp/mtp.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/mtp/mtp.go 2014-09-19 19:29:28.000000000 +0200 @@ -10,7 +10,7 @@ "strings" "time" - "github.com/hanwen/go-mtpfs/usb" + "github.com/hanwen/usb" ) // An MTP device. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/mtp/select.go new/go-mtpfs-0.0.0+git20140903.689b5b4/mtp/select.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/mtp/select.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/mtp/select.go 2014-09-19 19:29:28.000000000 +0200 @@ -5,7 +5,7 @@ "regexp" "strings" - "github.com/hanwen/go-mtpfs/usb" + "github.com/hanwen/usb" ) func candidateFromDeviceDescriptor(d *usb.Device) *Device { @@ -107,15 +107,15 @@ } } - if len(cands) == 0 { + if len(found) == 0 { return nil, fmt.Errorf("no device matched") } - - if len(cands) > 1 { + + if len(found) > 1 { return nil, fmt.Errorf("mtp: more than 1 device: %s", strings.Join(ids, ",")) } - - cand := cands[0] + + cand := found[0] config, err := cand.h.GetConfiguration() if err != nil { return nil, fmt.Errorf("could not get configuration of %v: %v", @@ -128,7 +128,7 @@ ids[0], err) } } - return cands[0], nil + return found[0], nil } // Return opened MTP device that matches given pattern. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/usb/print.go new/go-mtpfs-0.0.0+git20140903.689b5b4/usb/print.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/usb/print.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/usb/print.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,118 +0,0 @@ -package usb - -func ClassToStr(c byte) string { - switch c { - case CLASS_PER_INTERFACE: - return "PER_INTERFACE" - case CLASS_AUDIO: - return "AUDIO" - case CLASS_COMM: - return "COMM" - case CLASS_HID: - return "HID" - case CLASS_PHYSICAL: - return "PHYSICAL" - case CLASS_PRINTER: - return "PRINTER" - case CLASS_IMAGE: - return "IMAGE" - case CLASS_MASS_STORAGE: - return "MASS_STORAGE" - case CLASS_HUB: - return "HUB" - case CLASS_DATA: - return "DATA" - case CLASS_SMART_CARD: - return "SMART_CARD" - case CLASS_CONTENT_SECURITY: - return "CONTENT_SECURITY" - case CLASS_VIDEO: - return "VIDEO" - case CLASS_PERSONAL_HEALTHCARE: - return "PERSONAL_HEALTHCARE" - case CLASS_DIAGNOSTIC_DEVICE: - return "DIAGNOSTIC_DEVICE" - case CLASS_WIRELESS: - return "WIRELESS" - case CLASS_APPLICATION: - return "APPLICATION" - case CLASS_VENDOR_SPEC: - return "VENDOR_SPEC" - } - return "other" -} - -func dtToStr(c int) string { - switch c { - case DT_DEVICE: - return "DEVICE" - case DT_CONFIG: - return "CONFIG" - case DT_STRING: - return "STRING" - case DT_INTERFACE: - return "INTERFACE" - case DT_ENDPOINT: - return "ENDPOINT" - case DT_HID: - return "HID" - case DT_REPORT: - return "REPORT" - case DT_PHYSICAL: - return "PHYSICAL" - case DT_HUB: - return "HUB" - } - return "other" -} - -func requestToStr(c int) string { - switch c { - case REQUEST_GET_STATUS: - return "GET_STATUS" - case REQUEST_CLEAR_FEATURE: - return "CLEAR_FEATURE" - /** Set or enable a specific feature */ - case REQUEST_SET_FEATURE: - return "SET_FEATURE" - /** Set device address for all future accesses */ - case REQUEST_SET_ADDRESS: - return "SET_ADDRESS" - /** Get the specified descriptor */ - case REQUEST_GET_DESCRIPTOR: - return "GET_DESCRIPTOR" - /** Used to update existing descriptors or add new descriptors */ - case REQUEST_SET_DESCRIPTOR: - return "SET_DESCRIPTOR" - /** Get the current device configuration value */ - case REQUEST_GET_CONFIGURATION: - return "GET_CONFIGURATION" - /** Set device configuration */ - case REQUEST_SET_CONFIGURATION: - return "SET_CONFIGURATION" - /** Return the selected alternate setting for the specified interface */ - case REQUEST_GET_INTERFACE: - return "GET_INTERFACE" - /** Select an alternate interface for the specified interface */ - case REQUEST_SET_INTERFACE: - return "SET_INTERFACE" - /** Set then report an endpoint's synchronization frame */ - case REQUEST_SYNCH_FRAME: - return "SYNCH_FRAME" - } - return "other" -} - -func transferTypeString(t byte) string { - switch t { - case TRANSFER_TYPE_CONTROL: - return "control" - case TRANSFER_TYPE_ISOCHRONOUS: - return "iso" - case TRANSFER_TYPE_BULK: - return "bulk" - case TRANSFER_TYPE_INTERRUPT: - return "int" - } - panic("unknown") -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/usb/usb.go new/go-mtpfs-0.0.0+git20140903.689b5b4/usb/usb.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/usb/usb.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/usb/usb.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,720 +0,0 @@ -// The usb package is a straighforward cgo wrapping of the libusb 1.0 -// API. It only supports the synchronous API, since Goroutines can be -// used for asynchronous use-cases. - -package usb - -// #cgo pkg-config: libusb-1.0 -// #include <libusb.h> -import "C" -import ( - "fmt" - "reflect" - "unsafe" -) - -const SPEED_UNKNOWN = C.LIBUSB_SPEED_UNKNOWN -const SPEED_LOW = C.LIBUSB_SPEED_LOW -const SPEED_FULL = C.LIBUSB_SPEED_FULL -const SPEED_HIGH = C.LIBUSB_SPEED_HIGH -const SPEED_SUPER = C.LIBUSB_SPEED_SUPER - -var SPEED_names = map[byte]string{ - byte(C.LIBUSB_SPEED_UNKNOWN): "UNKNOWN", - byte(C.LIBUSB_SPEED_LOW): "LOW", - byte(C.LIBUSB_SPEED_FULL): "FULL", - byte(C.LIBUSB_SPEED_HIGH): "HIGH", - byte(C.LIBUSB_SPEED_SUPER): "SUPER", -} - -type ControlSetup C.struct_libusb_control_setup -type Transfer C.struct_libusb_transfer - -// Device and/or interface class codes. -const CLASS_PER_INTERFACE = 0 -const CLASS_AUDIO = 1 -const CLASS_COMM = 2 -const CLASS_HID = 3 -const CLASS_PHYSICAL = 5 -const CLASS_PRINTER = 7 -const CLASS_IMAGE = 6 -const CLASS_MASS_STORAGE = 8 -const CLASS_HUB = 9 -const CLASS_DATA = 10 -const CLASS_SMART_CARD = 0x0b -const CLASS_CONTENT_SECURITY = 0x0d -const CLASS_VIDEO = 0x0e -const CLASS_PERSONAL_HEALTHCARE = 0x0f -const CLASS_DIAGNOSTIC_DEVICE = 0xdc -const CLASS_WIRELESS = 0xe0 -const CLASS_APPLICATION = 0xfe -const CLASS_VENDOR_SPEC = 0xff - -// Device and/or interface class codes. -var CLASS_names = map[byte]string{ - 0: "PER_INTERFACE", - 1: "AUDIO", - 2: "COMM", - 3: "HID", - 5: "PHYSICAL", - 7: "PRINTER", - 6: "IMAGE", - 8: "MASS_STORAGE", - 9: "HUB", - 10: "DATA", - 0x0b: "SMART_CARD", - 0x0d: "CONTENT_SECURITY", - 0x0e: "VIDEO", - 0x0f: "PERSONAL_HEALTHCARE", - 0xdc: "DIAGNOSTIC_DEVICE", - 0xe0: "WIRELESS", - 0xfe: "APPLICATION", - 0xff: "VENDOR_SPEC", -} - -// Descriptor types as defined by the USB specification. -const DT_DEVICE = 0x01 -const DT_CONFIG = 0x02 -const DT_STRING = 0x03 -const DT_INTERFACE = 0x04 -const DT_ENDPOINT = 0x05 -const DT_HID = 0x21 -const DT_REPORT = 0x22 -const DT_PHYSICAL = 0x23 -const DT_HUB = 0x29 - -// Standard request types, as defined in table 9-3 of the USB2 specifications -const REQUEST_GET_STATUS = 0x00 -const REQUEST_CLEAR_FEATURE = 0x01 - -// Set or enable a specific feature -const REQUEST_SET_FEATURE = 0x03 - -// Set device address for all future accesses -const REQUEST_SET_ADDRESS = 0x05 - -// Get the specified descriptor -const REQUEST_GET_DESCRIPTOR = 0x06 - -// Used to update existing descriptors or add new descriptors -const REQUEST_SET_DESCRIPTOR = 0x07 - -// Get the current device configuration value -const REQUEST_GET_CONFIGURATION = 0x08 - -// Set device configuration -const REQUEST_SET_CONFIGURATION = 0x09 - -// Return the selected alternate setting for the specified interface. -const REQUEST_GET_INTERFACE = 0x0A - -// Select an alternate interface for the specified interface -const REQUEST_SET_INTERFACE = 0x0B - -// Set then report an endpoint's synchronization frame -const REQUEST_SYNCH_FRAME = 0x0C - -// The error codes returned by libusb. -type Error int - -func (e Error) Error() string { - return C.GoString(C.libusb_error_name(C.int(e))) -} - -func toErr(e C.int) error { - if e < 0 { - return Error(e) - } - return nil -} - -const SUCCESS = Error(0) -const ERROR_IO = Error(-1) -const ERROR_INVALID_PARAM = Error(-2) -const ERROR_ACCESS = Error(-3) -const ERROR_NO_DEVICE = Error(-4) -const ERROR_NOT_FOUND = Error(-5) -const ERROR_BUSY = Error(-6) -const ERROR_TIMEOUT = Error(-7) -const ERROR_OVERFLOW = Error(-8) -const ERROR_PIPE = Error(-9) -const ERROR_INTERRUPTED = Error(-10) -const ERROR_NO_MEM = Error(-11) -const ERROR_NOT_SUPPORTED = Error(-12) -const ERROR_OTHER = Error(-99) - -const TRANSFER_COMPLETED = 0 -const TRANSFER_ERROR = 1 -const TRANSFER_TIMED_OUT = 2 -const TRANSFER_CANCELLED = 3 -const TRANSFER_STALL = 4 -const TRANSFER_NO_DEVICE = 5 -const TRANSFER_OVERFLOW = 6 - -const TRANSFER_SHORT_NOT_OK = 1 << 0 -const TRANSFER_FREE_BUFFER = 1 << 1 -const TRANSFER_FREE_TRANSFER = 1 << 2 - -// Request types to use in ControlTransfer(). -const REQUEST_TYPE_STANDARD = (0x00 << 5) -const REQUEST_TYPE_CLASS = (0x01 << 5) -const REQUEST_TYPE_VENDOR = (0x02 << 5) -const REQUEST_TYPE_RESERVED = (0x03 << 5) - -// Recipient bits for the reqType of ControlTransfer(). Values 4 - 31 -// are reserved. -const RECIPIENT_DEVICE = 0x00 -const RECIPIENT_INTERFACE = 0x01 -const RECIPIENT_ENDPOINT = 0x02 -const RECIPIENT_OTHER = 0x03 - -// Synchronization types for isochronous endpoints, used in -// EndpointDescriptor.Attributes, bits 2:3. -const ISO_SYNC_TYPE_NONE = 0 -const ISO_SYNC_TYPE_ASYNC = 1 -const ISO_SYNC_TYPE_ADAPTIVE = 2 -const ISO_SYNC_TYPE_SYNC = 3 - -// Usage types used in EndpointDescriptor.Attributes, bits 4:5. -const ISO_USAGE_TYPE_DATA = 0 -const ISO_USAGE_TYPE_FEEDBACK = 1 -const ISO_USAGE_TYPE_IMPLICIT = 2 - -// DeviceDescriptor is the standard USB device descriptor as -// documented in section 9.6.1 of the USB 2.0 specification. -type DeviceDescriptor struct { - // Size of this descriptor (in bytes) - Length byte - // Descriptor type. - DescriptorType byte - // USB specification release number in binary-coded decimal. - USBRelease uint16 - - // USB-IF class code for the device. - DeviceClass byte - // USB-IF subclass code for the device, qualified by the - // DeviceClass value. - DeviceSubClass byte - // USB-IF protocol code for the device, qualified by the - // DeviceClass and DeviceSubClass values. - DeviceProtocol byte - // Maximum packet size for endpoint 0. - MaxPacketSize0 byte - // USB-IF vendor ID. - IdVendor uint16 - // USB-IF product ID. - IdProduct uint16 - // Device release number in binary-coded decimal. - Device uint16 - - // Index of string descriptor describing manufacturer. - Manufacturer byte - // Index of string descriptor describing product. - Product byte - // Index of string descriptor containing device serial number. - SerialNumber byte - - // Number of possible configurations. - NumConfigurations byte -} - -// A collection of alternate settings for a USB interface. -type Interface struct { - AltSetting []InterfaceDescriptor -} - -func (f *Interface) fromC(c *C.struct_libusb_interface) { - f.AltSetting = make([]InterfaceDescriptor, c.num_altsetting) - - ds := []C.struct_libusb_interface_descriptor{} - cSlice(unsafe.Pointer(&ds), unsafe.Pointer(c.altsetting), c.num_altsetting) - for i, s := range ds { - f.AltSetting[i].fromC(&s) - } -} - -// EndpointDescriptor represents the standard USB endpoint -// descriptor. This descriptor is documented in section 9.6.3 of the -// USB 2.0 specification. -type EndpointDescriptor struct { - // Size of this descriptor (in bytes) - Length byte - - // Descriptor type. Will have value LIBUSB_DT_ENDPOINT in this - // context. - DescriptorType byte - - // The address of the endpoint described by this descriptor. Bits 0:3 are - // the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction. - EndpointAddress byte - - // Attributes which apply to the endpoint when it is configured using - // the ConfigurationValue. Bits 0:1 determine the transfer type and - // correspond to libusb_transfer_type. Bits 2:3 are only used for - // isochronous endpoints and correspond to libusb_iso_sync_type. - // Bits 4:5 are also only used for isochronous endpoints and correspond to - // libusb_iso_usage_type. Bits 6:7 are reserved. - Attributes byte - - // Maximum packet size this endpoint is capable of sending/receiving. - MaxPacketSize uint16 - - // Interval for polling endpoint for data transfers. - Interval byte - - // For audio devices only: the rate at which synchronization feedback - // is provided. - Refresh byte - - // For audio devices only: the address if the synch endpoint - SynchAddress byte - - // Extra descriptors. If libusb encounters unknown endpoint - // descriptors, it will store them here, should you wish to - // parse them. - Extra []byte -} - -// Endpoint transfer types, for bits 0:1 of -// EndpointDescriptor.Attributes -const TRANSFER_TYPE_CONTROL = 0 -const TRANSFER_TYPE_ISOCHRONOUS = 1 -const TRANSFER_TYPE_BULK = 2 -const TRANSFER_TYPE_INTERRUPT = 3 - -// in: device-to-host -const ENDPOINT_IN = 0x80 - -// out: host-to-device -const ENDPOINT_OUT = 0x00 - -func (e *EndpointDescriptor) TransferType() byte { - return e.Attributes & 0x3 -} - -func (e *EndpointDescriptor) Direction() byte { - return e.EndpointAddress & ENDPOINT_IN -} - -func (e *EndpointDescriptor) Number() byte { - return e.EndpointAddress & 0x0f -} - -func (e *EndpointDescriptor) String() string { - tDir := "out" - if e.EndpointAddress&ENDPOINT_IN != 0 { - tDir = "in" - } - - // TODO - print isochronous data too. - s := fmt.Sprintf("ep num %x dir %s ttype %s maxpacket %d", - e.Number(), tDir, transferTypeString(e.TransferType()), - e.MaxPacketSize) - - return s -} - -func byteArrToSlice(a *C.uchar, n C.int) []byte { - var g []C.uchar - - b := make([]byte, int(n)) - for i, c := range g { - b[i] = byte(c) - } - return b -} - -func cSlice(slice unsafe.Pointer, arr unsafe.Pointer, n C.int) { - h := (*reflect.SliceHeader)(slice) - h.Cap = int(n) - h.Len = int(n) - h.Data = uintptr(unsafe.Pointer(arr)) -} - -func (d *EndpointDescriptor) fromC(c *C.struct_libusb_endpoint_descriptor) { - d.Length = byte(c.bLength) - d.DescriptorType = byte(c.bDescriptorType) - d.EndpointAddress = byte(c.bEndpointAddress) - d.Attributes = byte(c.bmAttributes) - d.MaxPacketSize = uint16(c.wMaxPacketSize) - d.Interval = byte(c.bInterval) - d.Refresh = byte(c.bRefresh) - d.SynchAddress = byte(c.bSynchAddress) - - d.Extra = byteArrToSlice(c.extra, c.extra_length) -} - -// InterfaceDescriptor contains the standard USB interface descriptor, -// according to section 9.6.5 of the USB 2.0 specification. -type InterfaceDescriptor struct { - // Size of this descriptor (in bytes) - Length byte - - // Descriptor type. Will have value DT_INTERFACE - // LIBUSB_DT_INTERFACE in this context. - DescriptorType byte - - // Number of this interface - InterfaceNumber byte - - // Value used to select this alternate setting for this interface - AlternateSetting byte - - // USB-IF class code for this interface. - InterfaceClass byte - - // USB-IF subclass code for this interface, qualified by the - // InterfaceClass value - InterfaceSubClass byte - - // USB-IF protocol code for this interface, qualified by the - // InterfaceClass and InterfaceSubClass values - InterfaceProtocol byte - - // Index of string descriptor describing this interface - InterfaceStringIndex byte - - // Array of endpoint descriptors. - EndPoints []EndpointDescriptor - - // Extra descriptors. If libusb encounters unknown interface - // descriptors, it will store them here, should you wish to - // parse them. - Extra []byte -} - -func (d *InterfaceDescriptor) fromC(c *C.struct_libusb_interface_descriptor) { - d.Length = byte(c.bLength) - d.DescriptorType = byte(c.bDescriptorType) - d.InterfaceNumber = byte(c.bInterfaceNumber) - d.AlternateSetting = byte(c.bAlternateSetting) - d.InterfaceClass = byte(c.bInterfaceClass) - d.InterfaceSubClass = byte(c.bInterfaceSubClass) - d.InterfaceProtocol = byte(c.bInterfaceProtocol) - d.InterfaceStringIndex = byte(c.iInterface) - d.EndPoints = make([]EndpointDescriptor, c.bNumEndpoints) - - cs := []C.struct_libusb_endpoint_descriptor{} - cSlice(unsafe.Pointer(&cs), unsafe.Pointer(c.endpoint), C.int(c.bNumEndpoints)) - for i, s := range cs { - d.EndPoints[i].fromC(&s) - } - - d.Extra = byteArrToSlice(c.extra, c.extra_length) -} - -type IsoPacketDescriptor struct { - // Length of data to request in this packet - Length uint - - // Amount of data that was actually transferred - ActualLength uint - - // Status code for this packet - Status int -} - -type ConfigDescriptor struct { - // Size of this descriptor (in bytes) - Length byte - - // Descriptor type. Will have value DT_CONFIG LIBUSB_DT_CONFIG - // in this context. - DescriptorType byte - - // Total length of data returned for this configuration - TotalLength uint16 - - // Identifier value for this configuration - ConfigurationValue byte - - // Index of string descriptor describing this configuration - ConfigurationIndex byte - - // Configuration characteristics - Attributes byte - - // Maximum power consumption of the USB device from this bus in this - // configuration when the device is fully opreation. Expressed in units - // of 2 mA. - MaxPower byte - - // Array of interfaces supported by this configuration. - Interfaces []Interface - - // Extra descriptors. If libusb encounters unknown configuration - // descriptors, it will store them here, should you wish to parse them. - Extra []byte -} - -func (d *ConfigDescriptor) fromC(c *C.struct_libusb_config_descriptor) { - d.Length = byte(c.bLength) - d.DescriptorType = byte(c.bDescriptorType) - d.TotalLength = uint16(c.wTotalLength) - d.ConfigurationValue = byte(c.bConfigurationValue) - d.ConfigurationIndex = byte(c.iConfiguration) - d.Attributes = byte(c.bmAttributes) - d.MaxPower = byte(c.MaxPower) - - d.Interfaces = make([]Interface, c.bNumInterfaces) - - cis := []C.struct_libusb_interface{} - cSlice(unsafe.Pointer(&cis), unsafe.Pointer(c._interface), C.int(c.bNumInterfaces)) - for i, iface := range cis { - d.Interfaces[i].fromC(&iface) - } - d.Extra = byteArrToSlice(c.extra, c.extra_length) -} - -type Context C.struct_libusb_context -type Device C.struct_libusb_device -type DeviceHandle C.struct_libusb_device_handle - -func NewContext() *Context { - var r *C.struct_libusb_context - C.libusb_init(&r) - return (*Context)(r) -} - -func (c *Context) me() *C.struct_libusb_context { - return (*C.struct_libusb_context)(c) -} - -func (c *Context) SetDebug(level int) { - C.libusb_set_debug(c.me(), C.int(level)) -} - -func (c *Context) Exit() { - C.libusb_exit(c.me()) -} - -type DeviceList []*Device - -func (d DeviceList) Done() { - C.libusb_free_device_list((**C.libusb_device)(unsafe.Pointer((&d[0]))), 1) -} - -func (c *Context) GetDeviceList() (DeviceList, error) { - var devs **C.libusb_device - count := C.libusb_get_device_list(c.me(), &devs) - if count < 0 { - return nil, Error(count) - } - slice := &reflect.SliceHeader{uintptr(unsafe.Pointer(devs)), int(count), int(count)} - rdevs := *(*[]*Device)(unsafe.Pointer(slice)) - return DeviceList(rdevs), nil -} - -func (d *Device) me() *C.libusb_device { - return (*C.libusb_device)(d) -} - -// Get the number of the bus that a device is connected to. -func (d *Device) GetBusNumber() uint8 { - return uint8(C.libusb_get_bus_number(d.me())) -} - -// Get the address of the device on the bus it is connected to. -func (d *Device) GetDeviceAddress() uint8 { - return uint8(C.libusb_get_device_address(d.me())) -} - -// Get the negotiated connection speed for a device. -func (d *Device) GetDeviceSpeed() int { - return int(C.libusb_get_device_speed(d.me())) -} - -// Convenience function to retrieve the MaxPacketSize value for a particular endpoint in the active device configuration. -func (d *Device) GetMaxPacketSize(endpoint byte) int { - return int(C.libusb_get_max_packet_size(d.me(), C.uchar(endpoint))) -} - -// Calculate the maximum packet size which a specific endpoint is capable is sending or receiving in the duration of 1 microframe. -func (d *Device) GetMaxIsoPacketSize(endpoint byte) int { - return int(C.libusb_get_max_iso_packet_size(d.me(), C.uchar(endpoint))) -} - -func (d *Device) Ref() *Device { - return (*Device)(C.libusb_ref_device((*C.libusb_device)(d.me()))) -} - -// Decrement the reference count of a device. -func (d *Device) Unref() { - C.libusb_unref_device((*C.libusb_device)(d.me())) -} - -func (d *Device) GetDeviceDescriptor() (*DeviceDescriptor, error) { - // this relies on struct packing being equal. - var dd DeviceDescriptor - r := C.libusb_get_device_descriptor(d.me(), (*C.struct_libusb_device_descriptor)(unsafe.Pointer(&dd))) - return &dd, toErr(r) -} - -func (d *Device) GetActiveConfigDescriptor() (*ConfigDescriptor, error) { - var desc *C.struct_libusb_config_descriptor - r := C.libusb_get_active_config_descriptor(d.me(), &desc) - if r < 0 { - return nil, toErr(r) - } - - var cd ConfigDescriptor - cd.fromC(desc) - C.libusb_free_config_descriptor(desc) - return &cd, nil -} - -func (d *Device) GetConfigDescriptor(config byte) (*ConfigDescriptor, error) { - var desc *C.struct_libusb_config_descriptor - r := C.libusb_get_config_descriptor(d.me(), C.uint8_t(config), &desc) - if r < 0 { - return nil, toErr(r) - } - - var cd ConfigDescriptor - cd.fromC(desc) - C.libusb_free_config_descriptor(desc) - return &cd, nil -} - -func (d *Device) GetConfigDescriptorByValue(value byte) (*ConfigDescriptor, error) { - var desc *C.struct_libusb_config_descriptor - r := C.libusb_get_config_descriptor_by_value(d.me(), C.uint8_t(value), &desc) - if r < 0 { - return nil, toErr(r) - } - - var cd ConfigDescriptor - cd.fromC(desc) - C.libusb_free_config_descriptor(desc) - return &cd, nil -} - -// Determine the ConfigurationValue of the currently active configuration. -func (h *DeviceHandle) GetConfiguration() (byte, error) { - var r C.int - err := C.libusb_get_configuration(h.me(), &r) - return byte(r), toErr(err) -} - -// Set the active configuration for a device. The argument should be -// a ConfigurationValue, as given in the ConfigDescriptor. -func (h *DeviceHandle) SetConfiguration(c byte) error { - err := C.libusb_set_configuration(h.me(), C.int(c)) - return toErr(err) -} - -// Open a device and obtain a device handle. -func (d *Device) Open() (*DeviceHandle, error) { - var h *C.libusb_device_handle - r := C.libusb_open(d.me(), &h) - return (*DeviceHandle)(h), toErr(r) -} - -func (h *DeviceHandle) me() *C.libusb_device_handle { - return (*C.libusb_device_handle)(h) -} - -// Close a device handle. -func (h *DeviceHandle) Close() error { - C.libusb_close(h.me()) - return nil -} - -// Get the underlying device for a handle. -func (h *DeviceHandle) Device() *Device { - return (*Device)(C.libusb_get_device(h.me())) -} - -// Claim an interface on a given device handle. -func (h *DeviceHandle) ClaimInterface(num byte) error { - return toErr(C.libusb_claim_interface(h.me(), C.int(num))) -} - -// Release an interface previously claimed with libusb_claim_interface(). -func (h *DeviceHandle) ReleaseInterface(num byte) error { - return toErr(C.libusb_release_interface(h.me(), C.int(num))) -} - -// Activate an alternate setting for an interface. -func (h *DeviceHandle) SetInterfaceAltSetting(num int, alternate int) error { - return toErr(C.libusb_set_interface_alt_setting(h.me(), C.int(num), C.int(alternate))) -} - -func (h *DeviceHandle) GetStringDescriptorASCII(descIndex byte) (string, error) { - data := make([]byte, 1024) - start := (*C.uchar)(unsafe.Pointer(&data[0])) - r := C.libusb_get_string_descriptor_ascii(h.me(), - C.uint8_t(descIndex), start, C.int(len(data))) - return C.GoString((*C.char)(unsafe.Pointer(&data[0]))), toErr(r) -} - -func (h *DeviceHandle) ControlTransfer(reqType, req byte, value, index uint16, - data []byte, timeout int) error { - var ptr *byte - if len(data) > 0 { - ptr = &data[0] - } - if len(data) > 0xffff { - return fmt.Errorf("overflow") - } - err := C.libusb_control_transfer(h.me(), - C.uint8_t(reqType), C.uint8_t(req), C.uint16_t(value), C.uint16_t(index), - (*C.uchar)(ptr), C.uint16_t(len(data)), C.uint(timeout)) - return toErr(err) -} - -func (h *DeviceHandle) BulkTransfer(endpoint byte, data []byte, timeout int) (actual int, err error) { - var ptr *byte - if len(data) > 0 { - ptr = &data[0] - } - - var n C.int - e := C.libusb_bulk_transfer(h.me(), C.uchar(endpoint), (*C.uchar)(ptr), - C.int(len(data)), &n, C.uint(timeout)) - return int(n), toErr(e) -} - -func (h *DeviceHandle) InterruptTransfer(endpoint byte, data []byte, timeout int) (actual int, err error) { - var ptr *byte - if len(data) > 0 { - ptr = &data[0] - } - - var n C.int - e := C.libusb_bulk_transfer(h.me(), C.uchar(endpoint), (*C.uchar)(ptr), - C.int(len(data)), &n, C.uint(timeout)) - return int(n), toErr(e) -} - -// Perform a USB port reset to reinitialize a device. -func (h *DeviceHandle) Reset() error { - return toErr(C.libusb_reset_device(h.me())) -} - -// Clear an halt/stall for a endpoint. -func (h *DeviceHandle) ClearHalt(endpoint byte) error { - return toErr(C.libusb_clear_halt(h.me(), C.uchar(endpoint))) -} - -// Determine if a kernel driver is active on an interface. -func (h *DeviceHandle) KernelDriverActive(ifaceNum byte) (bool, error) { - ret := C.libusb_kernel_driver_active(h.me(), C.int(ifaceNum)) - if ret == 0 { - return false, nil - } - if ret == 1 { - return true, nil - } - return false, toErr(ret) -} - -// Detach a kernel driver from an interface. -func (h *DeviceHandle) DetachKernelDriver(ifaceNum byte) error { - return toErr(C.libusb_detach_kernel_driver(h.me(), C.int(ifaceNum))) -} - -// Re-attach an interface's kernel driver, which was previously detached using libusb_detach_kernel_driver(). -func (h *DeviceHandle) AttachKernelDriver(ifaceNum byte) error { - return toErr(C.libusb_attach_kernel_driver(h.me(), C.int(ifaceNum))) -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/go-mtpfs-0.0.0+git20131015.bb3f0c2/usb/usb_test.go new/go-mtpfs-0.0.0+git20140903.689b5b4/usb/usb_test.go --- old/go-mtpfs-0.0.0+git20131015.bb3f0c2/usb/usb_test.go 2013-11-11 11:27:55.000000000 +0100 +++ new/go-mtpfs-0.0.0+git20140903.689b5b4/usb/usb_test.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,69 +0,0 @@ -package usb - -import ( - "testing" -) - -func TestDevice(t *testing.T) { - c := NewContext() - defer c.Exit() - l, err := c.GetDeviceList() - if err != nil { - t.Fatal("GetDeviceList failed:", err) - } - - for _, dev := range l { - t.Logf("bus 0x%x addr 0x%x speed 0x%x\n", - dev.GetBusNumber(), dev.GetDeviceAddress(), dev.GetDeviceSpeed()) - dd, err := dev.GetDeviceDescriptor() - if err != nil { - t.Logf("GetDeviceDescriptor failed: %v", err) - continue - } - - t.Logf("Vendor/Product %x:%x Class/subclass/protocol %x:%x:%x: %s\n", - dd.IdVendor, dd.IdProduct, dd.DeviceClass, dd.DeviceSubClass, dd.DeviceProtocol, CLASS_names[dd.DeviceClass]) - - stringDescs := []byte{ - dd.Manufacturer, dd.Product, dd.SerialNumber, - } - - for i := 0; i < int(dd.NumConfigurations); i++ { - cd, err := dev.GetConfigDescriptor(byte(i)) - if err != nil { - t.Logf("GetConfigDescriptor failed: %v", err) - continue - } - stringDescs = append(stringDescs, cd.ConfigurationIndex) - t.Logf(" config value %x, attributes %x power %d\n", cd.ConfigurationValue, - cd.Attributes, cd.MaxPower) - for idx, iface := range cd.Interfaces { - t.Logf(" iface %d\n", idx) - for _, alt := range iface.AltSetting { - t.Logf(" num %d class/subclass/protocol %x/%x/%x\n", - alt.InterfaceNumber, alt.InterfaceClass, alt.InterfaceSubClass, alt.InterfaceProtocol) - for _, ep := range alt.EndPoints { - t.Logf(" %v", &ep) - } - stringDescs = append(stringDescs, alt.InterfaceStringIndex) - } - } - } - - dh, err := dev.Open() - if err != nil { - t.Logf("can't open: %v", err) - continue - } - - for _, c := range stringDescs { - str, err := dh.GetStringDescriptorASCII(c) - if err != nil { - t.Logf("GetStringDescriptorASCII %d failed: %v", c, err) - continue - } - t.Logf(" desc %d: %s", c, str) - } - dh.Close() - } -} -- To unsubscribe, e-mail: opensuse-commit+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-commit+help@opensuse.org