usb-mtp: Added support for sending files larger than 4gb
v3 cover usb-mtp: Added support for sending files larger than 4gb
Added support for sending files larger than 4gb from the host to the guest. The first patch adds support on Linux guests. The second patch is to add support on Windows guests. Windows requires object properties to read the file size from.
We have to implement a minimum set of commands and object properties to support object properties, though. But most of the properties are data that we already have access to.
Isaac Lozano (2):
usb-mtp: fix sending files larger than 4gb
usb-mtp: added object properties
hw/usb/dev-mtp.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 192 insertions(+), 5 deletions(-)
Signature · 1 line
2.9.0
PATCH v3 2/2 usb-mtp: added object properties
Windows uses object properties to determine the size of a file, so to add object properties, we must also add a minimum set of new commands and object properties. Most object properties are data that we already have, except for the unique persistant object identifier. Windows doesn't use this property, it seems, so we can cheat a bit and just use the object handle for it.
--- hw/usb/dev-mtp.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+)
hw/usb/dev-mtp.c +177 -0
@@ -48,6 +48,9 @@ enum mtp_code {CMD_GET_OBJECT_INFO =0x1008 ,CMD_GET_OBJECT =0x1009 ,CMD_GET_PARTIAL_OBJECT =0x101b , +CMD_GET_OBJECT_PROPS_SUPPORTED =0x9801 , +CMD_GET_OBJECT_PROP_DESC =0x9802 , +CMD_GET_OBJECT_PROP_VALUE =0x9803 ,/* response codes */ RES_OK = 0x2001,
@@ -59,10 +62,12 @@ enum mtp_code {RES_INCOMPLETE_TRANSFER =0x2007 ,RES_INVALID_STORAGE_ID =0x2008 ,RES_INVALID_OBJECT_HANDLE =0x2009 , +RES_INVALID_OBJECT_FORMAT_CODE =0x200b ,RES_SPEC_BY_FORMAT_UNSUPPORTED =0x2014 ,RES_INVALID_PARENT_OBJECT =0x201a ,RES_INVALID_PARAMETER =0x201d ,RES_SESSION_ALREADY_OPEN =0x201e , +RES_INVALID_OBJECT_PROP_CODE =0xA801 ,/* format codes */ FMT_UNDEFINED_OBJECT = 0x3000,
@@ -72,6 +77,22 @@ enum mtp_code {EVT_OBJ_ADDED =0x4002 ,EVT_OBJ_REMOVED =0x4003 ,EVT_OBJ_INFO_CHANGED =0x4007 , + +/* object properties */ +PROP_STORAGE_ID =0xDC01 , +PROP_OBJECT_FORMAT =0xDC02 , +PROP_OBJECT_COMPRESSED_SIZE =0xDC04 , +PROP_PARENT_OBJECT =0xDC0B , +PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER =0xDC41 , + PROP_NAME = 0xDC44, +}; + +enum mtp_data_type { +DATA_TYPE_UINT16 =0x0004 , +DATA_TYPE_UINT32 =0x0006 , +DATA_TYPE_UINT64 =0x0008 , +DATA_TYPE_UINT128 =0x000a , +DATA_TYPE_STRING =0xffff , }; typedef struct {
@@ -778,6 +799,9 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)CMD_GET_OBJECT_INFO ,CMD_GET_OBJECT ,CMD_GET_PARTIAL_OBJECT , +CMD_GET_OBJECT_PROPS_SUPPORTED , +CMD_GET_OBJECT_PROP_DESC , + CMD_GET_OBJECT_PROP_VALUE, };static const uint16_t fmt[] = { FMT_UNDEFINED_OBJECT,
@@ -971,6 +995,122 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,return d; } +static MTPData *usb_mtp_get_object_props_supported (MTPState *s,MTPControl *c) +{ +static const uint16_t props[] = { +PROP_STORAGE_ID , +PROP_OBJECT_FORMAT , +PROP_OBJECT_COMPRESSED_SIZE , +PROP_PARENT_OBJECT , +PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER , +PROP_NAME , + }; +MTPData *d =usb_mtp_data_alloc (c); +usb_mtp_add_u16_array (d,ARRAY_SIZE (props), props); + +return d; +} + +static MTPData *usb_mtp_get_object_prop_desc (MTPState *s,MTPControl *c) +{ +MTPData *d =usb_mtp_data_alloc (c); +switch (c->argv[0 ]) { +case PROP_STORAGE_ID : +usb_mtp_add_u16 (d,PROP_STORAGE_ID ); +usb_mtp_add_u16 (d,DATA_TYPE_UINT32 ); +usb_mtp_add_u8 (d,0x00 ); +usb_mtp_add_u32 (d,0x00000000 ); +usb_mtp_add_u32 (d,0x00000000 ); +usb_mtp_add_u8 (d,0x00 ); +break ; +case PROP_OBJECT_FORMAT : +usb_mtp_add_u16 (d,PROP_OBJECT_FORMAT ); +usb_mtp_add_u16 (d,DATA_TYPE_UINT16 ); +usb_mtp_add_u8 (d,0x00 ); +usb_mtp_add_u16 (d,0x0000 ); +usb_mtp_add_u32 (d,0x00000000 ); +usb_mtp_add_u8 (d,0x00 ); +break ; +case PROP_OBJECT_COMPRESSED_SIZE : +usb_mtp_add_u16 (d,PROP_OBJECT_COMPRESSED_SIZE ); +usb_mtp_add_u16 (d,DATA_TYPE_UINT64 ); +usb_mtp_add_u8 (d,0x00 ); +usb_mtp_add_u64 (d,0x0000000000000000 ); +usb_mtp_add_u32 (d,0x00000000 ); +usb_mtp_add_u8 (d,0x00 ); +break ; +case PROP_PARENT_OBJECT : +usb_mtp_add_u16 (d,PROP_PARENT_OBJECT ); +usb_mtp_add_u16 (d,DATA_TYPE_UINT32 ); +usb_mtp_add_u8 (d,0x00 ); +usb_mtp_add_u32 (d,0x00000000 ); +usb_mtp_add_u32 (d,0x00000000 ); +usb_mtp_add_u8 (d,0x00 ); +break ; +case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER : +usb_mtp_add_u16 (d,PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER ); +usb_mtp_add_u16 (d,DATA_TYPE_UINT128 ); +usb_mtp_add_u8 (d,0x00 ); +usb_mtp_add_u64 (d,0x0000000000000000 ); +usb_mtp_add_u64 (d,0x0000000000000000 ); +usb_mtp_add_u32 (d,0x00000000 ); +usb_mtp_add_u8 (d,0x00 ); +break ; +case PROP_NAME : +usb_mtp_add_u16 (d,PROP_NAME ); +usb_mtp_add_u16 (d,DATA_TYPE_STRING ); +usb_mtp_add_u8 (d,0x00 ); +usb_mtp_add_u8 (d,0x00 ); +usb_mtp_add_u32 (d,0x00000000 ); +usb_mtp_add_u8 (d,0x00 ); +break ; +default : +usb_mtp_data_free (d); +return NULL ; + } + +return d; +} + +static MTPData *usb_mtp_get_object_prop_value (MTPState *s,MTPControl *c, +MTPObject *o) +{ +MTPData *d =usb_mtp_data_alloc (c); +switch (c->argv[1 ]) { +case PROP_STORAGE_ID : +usb_mtp_add_u32 (d,QEMU_STORAGE_ID ); +break ; +case PROP_OBJECT_FORMAT : +usb_mtp_add_u16 (d, o->format); +break ; +case PROP_OBJECT_COMPRESSED_SIZE : +usb_mtp_add_u64 (d, o->stat.st_size); +break ; +case PROP_PARENT_OBJECT : +if (o->parent ==NULL ) { +usb_mtp_add_u32 (d,0x00000000 ); + }else { +usb_mtp_add_u32 (d, o->parent->handle); + } +break ; +case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER : +/* Should be persistant between sessions, +* but using our objedt ID is "good enough" +* for now */ +usb_mtp_add_u64 (d,0x0000000000000000 ); +usb_mtp_add_u64 (d, o->handle); +break ; +case PROP_NAME : +usb_mtp_add_str (d, o->name); +break ; +default : +usb_mtp_data_free (d); +return NULL ; + } + +return d; +} +static void usb_mtp_command (MTPState *s,MTPControl *c) {MTPData *data_in =NULL ;
@@ -1118,6 +1258,43 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) nres =1 ; res0 = data_in->length;break ; +case CMD_GET_OBJECT_PROPS_SUPPORTED : +if (c->argv[0 ] !=FMT_UNDEFINED_OBJECT && + c->argv[0 ] !=FMT_ASSOCIATION ) { +usb_mtp_queue_result (s,RES_INVALID_OBJECT_FORMAT_CODE , + c->trans,0 ,0 ,0 ); +return ; + } + data_in =usb_mtp_get_object_props_supported (s, c); +break ; +case CMD_GET_OBJECT_PROP_DESC : +if (c->argv[1 ] !=FMT_UNDEFINED_OBJECT && + c->argv[1 ] !=FMT_ASSOCIATION ) { +usb_mtp_queue_result (s,RES_INVALID_OBJECT_FORMAT_CODE , + c->trans,0 ,0 ,0 ); +return ; + } + data_in =usb_mtp_get_object_prop_desc (s, c); +if (data_in ==NULL ) { +usb_mtp_queue_result (s,RES_INVALID_OBJECT_PROP_CODE , + c->trans,0 ,0 ,0 ); +return ; + } +break ; +case CMD_GET_OBJECT_PROP_VALUE : + o =usb_mtp_object_lookup (s, c->argv[0 ]); +if (o ==NULL ) { +usb_mtp_queue_result (s,RES_INVALID_OBJECT_HANDLE , + c->trans,0 ,0 ,0 ); +return ; + } + data_in =usb_mtp_get_object_prop_value (s, c, o); +if (data_in ==NULL ) { +usb_mtp_queue_result (s,RES_INVALID_OBJECT_PROP_CODE , + c->trans,0 ,0 ,0 ); +return ; + } +break ;default :trace_usb_mtp_op_unknown (s->dev.addr, c->code); usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
Signature · 1 line
2.9.0
Re: [Qemu-devel] [PATCH v3 2/2] usb-mtp: added object properties
Hi,
hw/usb/dev-mtp.c static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, · line 1102
Quoted 10 lines
and object properties. Most object properties are data that we already have, except for the unique persistant object identifier. Windows
hw/usb/dev-mtp.c +7
-0+case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER : +/* Should be persistant between sessions, +* but using our objedt ID is "good enough" +* for now */ +usb_mtp_add_u64 (d,0x0000000000000000 ); +usb_mtp_add_u64 (d, o->handle); +break ;
Didn't I mention for an older version already that the inode number would be a better fit? The inode number is persistent and unique per filesystem. While being at it we might also add the device id, to handle the (unlikely) case that the mtp device spans multiple filesystems.
We stat() the file already and cache the result, so this is as simple as using o->stat.st_{dev,ino}. See "man 2 stat" for details.
Other than that the patch series looks fine.
Sorry for the delay. Now that vacation time, kvm forum and qemu 2.7 freeze are over things should go faster for v4.
cheers,
Gerd
Re: [Qemu-devel] [PATCH v3 2/2] usb-mtp: added object properties
Quoted 13 lines · Gerd Hoffmann
Hi,
hw/usb/dev-mtp.c static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, · line 1102
Quoted 10 lines
and object properties. Most object properties are data that we already have, except for the unique persistant object identifier. Windows
hw/usb/dev-mtp.c +7
-0+case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER : +/* Should be persistant between sessions, +* but using our objedt ID is "good enough" +* for now */ +usb_mtp_add_u64 (d,0x0000000000000000 ); +usb_mtp_add_u64 (d, o->handle); +break ;
Quoted 5 lines
Didn't I mention for an older version already that the inode number would be a better fit? The inode number is persistent and unique per filesystem. While being at it we might also add the device id, to handle the (unlikely) case that the mtp device spans multiple filesystems.
Seems Isaac is busy with school and stuff. I will pick these up and post a follow up soon.
Bandan
Quoted 10 lines
We
stat()the file already and cache the result, so this is as simple as using o->stat.st_{dev,ino}. See "man 2 stat" for details.Other than that the patch series looks fine.
Sorry for the delay. Now that vacation time, kvm forum and qemu 2.7 freeze are over things should go faster for v4.
cheers,
Gerd