/* response codes */
RES_OK = 0x2001,
+ RES_GENERAL_ERROR = 0x2002,
RES_SESSION_NOT_OPEN = 0x2003,
RES_INVALID_TRANSACTION_ID = 0x2004,
RES_OPERATION_NOT_SUPPORTED = 0x2005,
RES_PARAMETER_NOT_SUPPORTED = 0x2006,
+ RES_INCOMPLETE_TRANSFER = 0x2007,
RES_INVALID_STORAGE_ID = 0x2008,
RES_INVALID_OBJECT_HANDLE = 0x2009,
RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
struct stat stat;
MTPObject *parent;
MTPObject **children;
- int32_t nchildren;
+ uint32_t nchildren;
+ bool have_children;
QTAILQ_ENTRY(MTPObject) next;
};
o->handle = handle;
o->parent = parent;
o->name = g_strdup(name);
- o->nchildren = -1;
if (parent == NULL) {
o->path = g_strdup(name);
} else {
goto ignore;
}
- fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+ trace_usb_mtp_object_alloc(s->dev.addr, o->handle, o->path);
QTAILQ_INSERT_TAIL(&s->objects, o, next);
return o;
{
int i;
- fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+ trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path);
QTAILQ_REMOVE(&s->objects, o, next);
for (i = 0; i < o->nchildren; i++) {
struct dirent *entry;
DIR *dir;
- o->nchildren = 0;
+ if (o->have_children) {
+ return;
+ }
+ o->have_children = true;
+
dir = opendir(o->path);
if (!dir) {
return;
static void usb_mtp_add_u64(MTPData *data, uint64_t val)
{
- usb_mtp_realloc(data, 4);
+ usb_mtp_realloc(data, 8);
data->data[data->length++] = (val >> 0) & 0xff;
data->data[data->length++] = (val >> 8) & 0xff;
data->data[data->length++] = (val >> 16) & 0xff;
data->data[data->length++] = (val >> 32) & 0xff;
data->data[data->length++] = (val >> 40) & 0xff;
data->data[data->length++] = (val >> 48) & 0xff;
- data->data[data->length++] = (val >> 54) & 0xff;
+ data->data[data->length++] = (val >> 56) & 0xff;
}
static void usb_mtp_add_u16_array(MTPData *data, uint32_t len,
trace_usb_mtp_op_get_device_info(s->dev.addr);
- usb_mtp_add_u16(d, 0x0100);
+ usb_mtp_add_u16(d, 100);
usb_mtp_add_u32(d, 0xffffffff);
usb_mtp_add_u16(d, 0x0101);
usb_mtp_add_wstr(d, L"");
usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER);
usb_mtp_add_wstr(d, L"" MTP_PRODUCT);
usb_mtp_add_wstr(d, L"0.1");
- usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef");
+ usb_mtp_add_wstr(d, L"0123456789abcdef0123456789abcdef");
return d;
}
d->fd = open(o->path, O_RDONLY);
if (d->fd == -1) {
+ usb_mtp_data_free(d);
return NULL;
}
d->length = o->stat.st_size;
d->fd = open(o->path, O_RDONLY);
if (d->fd == -1) {
+ usb_mtp_data_free(d);
return NULL;
}
if (offset > o->stat.st_size) {
offset = o->stat.st_size;
}
- lseek(d->fd, offset, SEEK_SET);
+ if (lseek(d->fd, offset, SEEK_SET) < 0) {
+ usb_mtp_data_free(d);
+ return NULL;
+ }
d->length = c->argv[2];
if (d->length > o->stat.st_size - offset) {
c->trans, 0, 0, 0);
return;
}
- if (o->nchildren == -1) {
- usb_mtp_object_readdir(s, o);
- }
+ usb_mtp_object_readdir(s, o);
if (c->code == CMD_GET_NUM_OBJECTS) {
trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
nres = 1;
}
data_in = usb_mtp_get_object(s, c, o);
if (NULL == data_in) {
- fprintf(stderr, "%s: TODO: handle error\n", __func__);
+ usb_mtp_queue_result(s, RES_GENERAL_ERROR,
+ c->trans, 0, 0, 0);
+ return;
}
break;
case CMD_GET_PARTIAL_OBJECT:
}
data_in = usb_mtp_get_partial_object(s, c, o);
if (NULL == data_in) {
- fprintf(stderr, "%s: TODO: handle error\n", __func__);
+ usb_mtp_queue_result(s, RES_GENERAL_ERROR,
+ c->trans, 0, 0, 0);
+ return;
}
nres = 1;
res0 = data_in->length;
break;
default:
- fprintf(stderr, "%s: unknown command code 0x%04x\n",
- __func__, c->code);
+ trace_usb_mtp_op_unknown(s->dev.addr, c->code);
usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
c->trans, 0, 0, 0);
return;
static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
{
+ /* we don't use async packets, so this should never be called */
fprintf(stderr, "%s\n", __func__);
}
}
rc = read(d->fd, d->data, dlen);
if (rc != dlen) {
- fprintf(stderr, "%s: TODO: handle read error\n", __func__);
+ memset(d->data, 0, dlen);
+ s->result->code = RES_INCOMPLETE_TRANSFER;
}
usb_packet_copy(p, d->data, dlen);
}
cmd.argc = (le32_to_cpu(container.length) - sizeof(container))
/ sizeof(uint32_t);
cmd.trans = le32_to_cpu(container.trans);
+ if (cmd.argc > ARRAY_SIZE(cmd.argv)) {
+ cmd.argc = ARRAY_SIZE(cmd.argv);
+ }
+ if (p->iov.size < sizeof(container) + cmd.argc * sizeof(uint32_t)) {
+ trace_usb_mtp_stall(s->dev.addr, "packet too small");
+ p->status = USB_RET_STALL;
+ return;
+ }
usb_packet_copy(p, ¶ms, cmd.argc * sizeof(uint32_t));
for (i = 0; i < cmd.argc; i++) {
cmd.argv[i] = le32_to_cpu(params[i]);
usb_mtp_command(s, &cmd);
break;
default:
- iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32);
- trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out");
+ /* not needed as long as the mtp device is read-only */
p->status = USB_RET_STALL;
return;
}
QTAILQ_INIT(&s->objects);
if (s->desc == NULL) {
s->desc = strrchr(s->root, '/');
- if (s->desc) {
+ if (s->desc && s->desc[0]) {
s->desc = g_strdup(s->desc + 1);
} else {
s->desc = g_strdup("none");