Re: [Qemu-devel] [PATCH v2 4/5] usb-mtp: Introduce write support for MTP objects

2018-02-13 Thread Gerd Hoffmann
> @@ -66,7 +67,9 @@ enum mtp_code {
>  RES_STORE_READ_ONLY= 0x200e,
>  RES_PARTIAL_DELETE = 0x2012,
>  RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
> +RES_INVALID_OBJECTINFO = 0x2015,
>  RES_INVALID_PARENT_OBJECT  = 0x201a,
> +RES_STORE_FULL = 0x200c,

This is the wrong place or the wrong error code ...

cheers,
  Gerd




[Qemu-devel] [PATCH v2 4/5] usb-mtp: Introduce write support for MTP objects

2018-02-12 Thread Bandan Das
Allow write operations on behalf of the initiator. The
precursor to write is the sending of the write metadata
that consists of the ObjectInfo dataset. This patch introduces
a flag that is set when the responder is ready to receive
write data based on a previous SendObjectInfo operation by
the initiator (The SendObjectInfo implementation is in a
later patch)

Signed-off-by: Bandan Das 
---
 hw/usb/dev-mtp.c | 159 ++-
 1 file changed, 157 insertions(+), 2 deletions(-)

diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 5f53f200c4..8d615cabc0 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -47,6 +47,7 @@ enum mtp_code {
 CMD_GET_OBJECT_INFO= 0x1008,
 CMD_GET_OBJECT = 0x1009,
 CMD_DELETE_OBJECT  = 0x100b,
+CMD_SEND_OBJECT= 0x100d,
 CMD_GET_PARTIAL_OBJECT = 0x101b,
 CMD_GET_OBJECT_PROPS_SUPPORTED = 0x9801,
 CMD_GET_OBJECT_PROP_DESC   = 0x9802,
@@ -66,7 +67,9 @@ enum mtp_code {
 RES_STORE_READ_ONLY= 0x200e,
 RES_PARTIAL_DELETE = 0x2012,
 RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
+RES_INVALID_OBJECTINFO = 0x2015,
 RES_INVALID_PARENT_OBJECT  = 0x201a,
+RES_STORE_FULL = 0x200c,
 RES_INVALID_PARAMETER  = 0x201d,
 RES_SESSION_ALREADY_OPEN   = 0x201e,
 RES_INVALID_OBJECT_PROP_CODE   = 0xA801,
@@ -182,6 +185,14 @@ struct MTPState {
 int  inotifyfd;
 QTAILQ_HEAD(events, MTPMonEntry) events;
 #endif
+/* Responder is expecting a write operation */
+bool write_pending;
+struct {
+uint32_t parent_handle;
+uint16_t format;
+uint32_t size;
+char *filename;
+} dataset;
 };
 
 #define TYPE_USB_MTP "usb-mtp"
@@ -803,6 +814,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, 
MTPControl *c)
 CMD_GET_OBJECT_HANDLES,
 CMD_GET_OBJECT_INFO,
 CMD_DELETE_OBJECT,
+CMD_SEND_OBJECT,
 CMD_GET_OBJECT,
 CMD_GET_PARTIAL_OBJECT,
 CMD_GET_OBJECT_PROPS_SUPPORTED,
@@ -1381,6 +1393,14 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
 nres = 1;
 res0 = data_in->length;
 break;
+case CMD_SEND_OBJECT:
+if (!s->write_pending) {
+usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO,
+ c->trans, 0, 0, 0, 0);
+return;
+}
+s->data_out = usb_mtp_data_alloc(c);
+return;
 case CMD_GET_OBJECT_PROPS_SUPPORTED:
 if (c->argv[0] != FMT_UNDEFINED_OBJECT &&
 c->argv[0] != FMT_ASSOCIATION) {
@@ -1475,12 +1495,133 @@ static void usb_mtp_cancel_packet(USBDevice *dev, 
USBPacket *p)
 fprintf(stderr, "%s\n", __func__);
 }
 
+mode_t getumask(void)
+{
+mode_t mask = umask(0);
+umask(mask);
+return mask;
+}
+
+static void usb_mtp_write_data(MTPState *s)
+{
+MTPData *d = s->data_out;
+MTPObject *parent =
+usb_mtp_object_lookup(s, s->dataset.parent_handle);
+char *path = NULL;
+int rc = -1;
+mode_t mask = ~getumask() & 0666;
+
+assert(d != NULL);
+
+if (parent == NULL || !s->write_pending) {
+usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans,
+ 0, 0, 0, 0);
+return;
+}
+
+if (s->dataset.filename) {
+path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename);
+if (s->dataset.format == FMT_ASSOCIATION) {
+d->fd = mkdir(path, mask);
+goto free;
+}
+if (s->dataset.size < d->length) {
+usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
+ 0, 0, 0, 0);
+goto done;
+}
+d->fd = open(path, O_CREAT | O_WRONLY, mask);
+if (d->fd == -1) {
+usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
+ 0, 0, 0, 0);
+goto done;
+}
+
+/*
+ * Return success if initiator sent 0 sized data
+ */
+if (!s->dataset.size) {
+goto success;
+}
+
+rc = write(d->fd, d->data, s->dataset.size);
+if (rc == -1) {
+usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
+ 0, 0, 0, 0);
+goto done;
+}
+if (rc != s->dataset.size) {
+usb_mtp_queue_result(s, RES_INCOMPLETE_TRANSFER, d->trans,
+ 0, 0, 0, 0);
+goto done;
+}
+}
+
+success:
+usb_mtp_queue_result(s, RES_OK, d->trans,
+ 0, 0, 0, 0);
+
+done:
+/*
+ * The write dataset is kept around and freed only
+ * on success or if another write request comes in
+ */
+if (d->fd != -1) {
+close(d->fd);
+}
+free:
+g_free(s->dataset.filename);
+g_free(path);
+s->write_pending