blob: 3d3bd6263af3555b14010960cc445e7323b5065d [file] [log] [blame]
Mike Lockwood16864ba2010-05-11 17:16:59 -04001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/types.h>
20#include <sys/ioctl.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <errno.h>
24
Mike Lockwoodc42aa122010-06-14 17:58:08 -070025#include <cutils/properties.h>
26
Mike Lockwood16864ba2010-05-11 17:16:59 -040027#include "MtpDebug.h"
Mike Lockwood7f53a192010-07-09 10:45:22 -040028#include "MtpDatabase.h"
Mike Lockwood21ef7d02010-06-30 17:00:35 -040029#include "MtpProperty.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040030#include "MtpServer.h"
31#include "MtpStorage.h"
32#include "MtpStringBuffer.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040033
Mike Lockwood8065e202010-07-15 13:36:52 -040034#include <linux/usb/f_mtp.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040035
Mike Lockwood7850ef92010-05-14 10:10:36 -040036namespace android {
37
Mike Lockwood16864ba2010-05-11 17:16:59 -040038static const MtpOperationCode kSupportedOperationCodes[] = {
39 MTP_OPERATION_GET_DEVICE_INFO,
40 MTP_OPERATION_OPEN_SESSION,
41 MTP_OPERATION_CLOSE_SESSION,
42 MTP_OPERATION_GET_STORAGE_IDS,
43 MTP_OPERATION_GET_STORAGE_INFO,
44 MTP_OPERATION_GET_NUM_OBJECTS,
45 MTP_OPERATION_GET_OBJECT_HANDLES,
46 MTP_OPERATION_GET_OBJECT_INFO,
47 MTP_OPERATION_GET_OBJECT,
48// MTP_OPERATION_GET_THUMB,
49 MTP_OPERATION_DELETE_OBJECT,
50 MTP_OPERATION_SEND_OBJECT_INFO,
51 MTP_OPERATION_SEND_OBJECT,
52// MTP_OPERATION_INITIATE_CAPTURE,
53// MTP_OPERATION_FORMAT_STORE,
54// MTP_OPERATION_RESET_DEVICE,
55// MTP_OPERATION_SELF_TEST,
56// MTP_OPERATION_SET_OBJECT_PROTECTION,
57// MTP_OPERATION_POWER_DOWN,
Mike Lockwoode3e76c42010-09-02 14:57:30 -040058 MTP_OPERATION_GET_DEVICE_PROP_DESC,
Mike Lockwood8277cec2010-08-10 15:20:35 -040059 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
60 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
61 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040062// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
63// MTP_OPERATION_MOVE_OBJECT,
64// MTP_OPERATION_COPY_OBJECT,
65// MTP_OPERATION_GET_PARTIAL_OBJECT,
66// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
67 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
Mike Lockwood8277cec2010-08-10 15:20:35 -040068 MTP_OPERATION_GET_OBJECT_PROP_DESC,
69// MTP_OPERATION_GET_OBJECT_PROP_VALUE,
Mike Lockwood343af4e2010-08-02 10:52:20 -040070// MTP_OPERATION_SET_OBJECT_PROP_VALUE,
Mike Lockwood438344f2010-08-03 15:30:09 -040071 MTP_OPERATION_GET_OBJECT_REFERENCES,
72 MTP_OPERATION_SET_OBJECT_REFERENCES,
Mike Lockwood16864ba2010-05-11 17:16:59 -040073// MTP_OPERATION_SKIP,
74};
75
Mike Lockwood873871f2010-07-12 18:54:16 -040076static const MtpEventCode kSupportedEventCodes[] = {
77 MTP_EVENT_OBJECT_ADDED,
78 MTP_EVENT_OBJECT_REMOVED,
79};
80
Mike Lockwood1865a5d2010-07-03 00:44:05 -040081MtpServer::MtpServer(int fd, MtpDatabase* database,
Mike Lockwood8e2a2802010-07-02 15:15:07 -040082 int fileGroup, int filePerm, int directoryPerm)
Mike Lockwood16864ba2010-05-11 17:16:59 -040083 : mFD(fd),
Mike Lockwood1865a5d2010-07-03 00:44:05 -040084 mDatabase(database),
Mike Lockwood8e2a2802010-07-02 15:15:07 -040085 mFileGroup(fileGroup),
86 mFilePermission(filePerm),
87 mDirectoryPermission(directoryPerm),
Mike Lockwood16864ba2010-05-11 17:16:59 -040088 mSessionID(0),
89 mSessionOpen(false),
90 mSendObjectHandle(kInvalidObjectHandle),
Mike Lockwood4714b072010-07-12 08:49:01 -040091 mSendObjectFormat(0),
Mike Lockwood16864ba2010-05-11 17:16:59 -040092 mSendObjectFileSize(0)
93{
Mike Lockwood16864ba2010-05-11 17:16:59 -040094}
95
96MtpServer::~MtpServer() {
97}
98
99void MtpServer::addStorage(const char* filePath) {
100 int index = mStorages.size() + 1;
101 index |= index << 16; // set high and low part to our index
102 MtpStorage* storage = new MtpStorage(index, filePath, mDatabase);
103 addStorage(storage);
104}
105
106MtpStorage* MtpServer::getStorage(MtpStorageID id) {
107 for (int i = 0; i < mStorages.size(); i++) {
108 MtpStorage* storage = mStorages[i];
109 if (storage->getStorageID() == id)
110 return storage;
111 }
112 return NULL;
113}
114
Mike Lockwood16864ba2010-05-11 17:16:59 -0400115void MtpServer::run() {
116 int fd = mFD;
117
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400118 LOGV("MtpServer::run fd: %d\n", fd);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400119
120 while (1) {
121 int ret = mRequest.read(fd);
122 if (ret < 0) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400123 LOGE("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400124 if (errno == ECANCELED) {
125 // return to top of loop and wait for next command
126 continue;
127 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400128 break;
129 }
130 MtpOperationCode operation = mRequest.getOperationCode();
131 MtpTransactionID transaction = mRequest.getTransactionID();
132
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400133 LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400134 mRequest.dump();
135
136 // FIXME need to generalize this
Mike Lockwood438344f2010-08-03 15:30:09 -0400137 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood8277cec2010-08-10 15:20:35 -0400138 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
139 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
140 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400141 if (dataIn) {
142 int ret = mData.read(fd);
143 if (ret < 0) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400144 LOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400145 if (errno == ECANCELED) {
146 // return to top of loop and wait for next command
147 continue;
148 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400149 break;
150 }
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400151 LOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400152 mData.dump();
153 } else {
154 mData.reset();
155 }
156
Mike Lockwood916076c2010-06-04 09:49:21 -0400157 if (handleRequest()) {
158 if (!dataIn && mData.hasData()) {
159 mData.setOperationCode(operation);
160 mData.setTransactionID(transaction);
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400161 LOGV("sending data:");
Mike Lockwood916076c2010-06-04 09:49:21 -0400162 ret = mData.write(fd);
163 if (ret < 0) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400164 LOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400165 if (errno == ECANCELED) {
166 // return to top of loop and wait for next command
167 continue;
168 }
169 break;
170 }
171 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400172
Mike Lockwood916076c2010-06-04 09:49:21 -0400173 mResponse.setTransactionID(transaction);
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400174 LOGV("sending response %04X", mResponse.getResponseCode());
Mike Lockwood916076c2010-06-04 09:49:21 -0400175 ret = mResponse.write(fd);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400176 if (ret < 0) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400177 LOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400178 if (errno == ECANCELED) {
179 // return to top of loop and wait for next command
180 continue;
181 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400182 break;
183 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400184 } else {
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400185 LOGV("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400186 }
187 }
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400188
189 if (mSessionOpen)
190 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400191}
192
Mike Lockwood873871f2010-07-12 18:54:16 -0400193void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400194 if (mSessionOpen) {
195 LOGD("sendObjectAdded %d\n", handle);
196 mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
197 mEvent.setTransactionID(mRequest.getTransactionID());
198 mEvent.setParameter(1, handle);
199 int ret = mEvent.write(mFD);
200 LOGD("mEvent.write returned %d\n", ret);
201 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400202}
203
204void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400205 if (mSessionOpen) {
206 LOGD("sendObjectRemoved %d\n", handle);
207 mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
208 mEvent.setTransactionID(mRequest.getTransactionID());
209 mEvent.setParameter(1, handle);
210 int ret = mEvent.write(mFD);
211 LOGD("mEvent.write returned %d\n", ret);
212 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400213}
214
Mike Lockwood916076c2010-06-04 09:49:21 -0400215bool MtpServer::handleRequest() {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400216 MtpOperationCode operation = mRequest.getOperationCode();
217 MtpResponseCode response;
218
219 mResponse.reset();
220
221 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
222 // FIXME - need to delete mSendObjectHandle from the database
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400223 LOGE("expected SendObject after SendObjectInfo");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400224 mSendObjectHandle = kInvalidObjectHandle;
225 }
226
227 switch (operation) {
228 case MTP_OPERATION_GET_DEVICE_INFO:
229 response = doGetDeviceInfo();
230 break;
231 case MTP_OPERATION_OPEN_SESSION:
232 response = doOpenSession();
233 break;
234 case MTP_OPERATION_CLOSE_SESSION:
235 response = doCloseSession();
236 break;
237 case MTP_OPERATION_GET_STORAGE_IDS:
238 response = doGetStorageIDs();
239 break;
240 case MTP_OPERATION_GET_STORAGE_INFO:
241 response = doGetStorageInfo();
242 break;
243 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
244 response = doGetObjectPropsSupported();
245 break;
246 case MTP_OPERATION_GET_OBJECT_HANDLES:
247 response = doGetObjectHandles();
248 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400249 case MTP_OPERATION_GET_NUM_OBJECTS:
250 response = doGetNumObjects();
251 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400252 case MTP_OPERATION_GET_OBJECT_REFERENCES:
253 response = doGetObjectReferences();
254 break;
255 case MTP_OPERATION_SET_OBJECT_REFERENCES:
256 response = doSetObjectReferences();
257 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400258 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
259 response = doGetObjectPropValue();
260 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400261 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
262 response = doSetObjectPropValue();
263 break;
264 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
265 response = doGetDevicePropValue();
266 break;
267 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
268 response = doSetDevicePropValue();
269 break;
270 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
271 response = doResetDevicePropValue();
272 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400273 case MTP_OPERATION_GET_OBJECT_INFO:
274 response = doGetObjectInfo();
275 break;
276 case MTP_OPERATION_GET_OBJECT:
277 response = doGetObject();
278 break;
279 case MTP_OPERATION_SEND_OBJECT_INFO:
280 response = doSendObjectInfo();
281 break;
282 case MTP_OPERATION_SEND_OBJECT:
283 response = doSendObject();
284 break;
285 case MTP_OPERATION_DELETE_OBJECT:
286 response = doDeleteObject();
287 break;
288 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400289 response = doGetObjectPropDesc();
290 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400291 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
292 response = doGetDevicePropDesc();
293 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400294 default:
295 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
296 break;
297 }
298
Mike Lockwood916076c2010-06-04 09:49:21 -0400299 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
300 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400301 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400302 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400303}
304
305MtpResponseCode MtpServer::doGetDeviceInfo() {
306 MtpStringBuffer string;
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700307 char prop_value[PROPERTY_VALUE_MAX];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400308
Mike Lockwood782aef12010-08-10 07:37:50 -0400309 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
310 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
311 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
312
Mike Lockwood16864ba2010-05-11 17:16:59 -0400313 // fill in device info
314 mData.putUInt16(MTP_STANDARD_VERSION);
315 mData.putUInt32(6); // MTP Vendor Extension ID
316 mData.putUInt16(MTP_STANDARD_VERSION);
317 string.set("microsoft.com: 1.0;");
318 mData.putString(string); // MTP Extensions
319 mData.putUInt16(0); //Functional Mode
320 mData.putAUInt16(kSupportedOperationCodes,
321 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400322 mData.putAUInt16(kSupportedEventCodes,
323 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400324 mData.putAUInt16(deviceProperties); // Device Properties Supported
325 mData.putAUInt16(captureFormats); // Capture Formats
326 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400327 // FIXME
328 string.set("Google, Inc.");
329 mData.putString(string); // Manufacturer
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700330
331 property_get("ro.product.model", prop_value, "MTP Device");
332 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400333 mData.putString(string); // Model
334 string.set("1.0");
335 mData.putString(string); // Device Version
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700336
337 property_get("ro.serialno", prop_value, "????????");
338 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400339 mData.putString(string); // Serial Number
340
Mike Lockwood782aef12010-08-10 07:37:50 -0400341 delete playbackFormats;
342 delete captureFormats;
343 delete deviceProperties;
344
Mike Lockwood16864ba2010-05-11 17:16:59 -0400345 return MTP_RESPONSE_OK;
346}
347
348MtpResponseCode MtpServer::doOpenSession() {
349 if (mSessionOpen) {
350 mResponse.setParameter(1, mSessionID);
351 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
352 }
353 mSessionID = mRequest.getParameter(1);
354 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400355
356 mDatabase->sessionStarted();
357
Mike Lockwood16864ba2010-05-11 17:16:59 -0400358 return MTP_RESPONSE_OK;
359}
360
361MtpResponseCode MtpServer::doCloseSession() {
362 if (!mSessionOpen)
363 return MTP_RESPONSE_SESSION_NOT_OPEN;
364 mSessionID = 0;
365 mSessionOpen = false;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400366 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400367 return MTP_RESPONSE_OK;
368}
369
370MtpResponseCode MtpServer::doGetStorageIDs() {
371 if (!mSessionOpen)
372 return MTP_RESPONSE_SESSION_NOT_OPEN;
373
374 int count = mStorages.size();
375 mData.putUInt32(count);
376 for (int i = 0; i < count; i++)
377 mData.putUInt32(mStorages[i]->getStorageID());
378
379 return MTP_RESPONSE_OK;
380}
381
382MtpResponseCode MtpServer::doGetStorageInfo() {
383 MtpStringBuffer string;
384
385 if (!mSessionOpen)
386 return MTP_RESPONSE_SESSION_NOT_OPEN;
387 MtpStorageID id = mRequest.getParameter(1);
388 MtpStorage* storage = getStorage(id);
389 if (!storage)
390 return MTP_RESPONSE_INVALID_STORAGE_ID;
391
392 mData.putUInt16(storage->getType());
393 mData.putUInt16(storage->getFileSystemType());
394 mData.putUInt16(storage->getAccessCapability());
395 mData.putUInt64(storage->getMaxCapacity());
396 mData.putUInt64(storage->getFreeSpace());
397 mData.putUInt32(1024*1024*1024); // Free Space in Objects
398 string.set(storage->getDescription());
399 mData.putString(string);
400 mData.putEmptyString(); // Volume Identifier
401
402 return MTP_RESPONSE_OK;
403}
404
405MtpResponseCode MtpServer::doGetObjectPropsSupported() {
406 if (!mSessionOpen)
407 return MTP_RESPONSE_SESSION_NOT_OPEN;
408 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood782aef12010-08-10 07:37:50 -0400409 MtpDevicePropertyList* properties = mDatabase->getSupportedObjectProperties(format);
410 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400411 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400412 return MTP_RESPONSE_OK;
413}
414
415MtpResponseCode MtpServer::doGetObjectHandles() {
416 if (!mSessionOpen)
417 return MTP_RESPONSE_SESSION_NOT_OPEN;
418 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400419 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400420 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
421 // 0x00000000 for all objects?
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400422 if (parent == 0xFFFFFFFF)
423 parent = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400424
425 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
426 mData.putAUInt32(handles);
427 delete handles;
428 return MTP_RESPONSE_OK;
429}
430
Mike Lockwood343af4e2010-08-02 10:52:20 -0400431MtpResponseCode MtpServer::doGetNumObjects() {
432 if (!mSessionOpen)
433 return MTP_RESPONSE_SESSION_NOT_OPEN;
434 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
435 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
436 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
437 // 0x00000000 for all objects?
438 if (parent == 0xFFFFFFFF)
439 parent = 0;
440
441 int count = mDatabase->getNumObjects(storageID, format, parent);
442 if (count >= 0) {
443 mResponse.setParameter(1, count);
444 return MTP_RESPONSE_OK;
445 } else {
446 mResponse.setParameter(1, 0);
447 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
448 }
449}
450
Mike Lockwood438344f2010-08-03 15:30:09 -0400451MtpResponseCode MtpServer::doGetObjectReferences() {
452 if (!mSessionOpen)
453 return MTP_RESPONSE_SESSION_NOT_OPEN;
454 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400455
456 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400457 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400458 if (handles) {
459 mData.putAUInt32(handles);
460 delete handles;
461 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400462 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400463 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400464 return MTP_RESPONSE_OK;
465}
466
467MtpResponseCode MtpServer::doSetObjectReferences() {
468 if (!mSessionOpen)
469 return MTP_RESPONSE_SESSION_NOT_OPEN;
470 MtpStorageID handle = mRequest.getParameter(1);
471 MtpObjectHandleList* references = mData.getAUInt32();
472 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
473 delete references;
474 return result;
475}
476
Mike Lockwood16864ba2010-05-11 17:16:59 -0400477MtpResponseCode MtpServer::doGetObjectPropValue() {
478 MtpObjectHandle handle = mRequest.getParameter(1);
479 MtpObjectProperty property = mRequest.getParameter(2);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400480 LOGD("GetObjectPropValue %d %s\n", handle,
481 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400482
Mike Lockwood8277cec2010-08-10 15:20:35 -0400483 return mDatabase->getObjectPropertyValue(handle, property, mData);
484}
485
486MtpResponseCode MtpServer::doSetObjectPropValue() {
487 MtpObjectHandle handle = mRequest.getParameter(1);
488 MtpObjectProperty property = mRequest.getParameter(2);
489 LOGD("SetObjectPropValue %d %s\n", handle,
490 MtpDebug::getObjectPropCodeName(property));
491
492 return mDatabase->setObjectPropertyValue(handle, property, mData);
493}
494
495MtpResponseCode MtpServer::doGetDevicePropValue() {
496 MtpDeviceProperty property = mRequest.getParameter(1);
497 LOGD("GetDevicePropValue %s\n",
498 MtpDebug::getDevicePropCodeName(property));
499
500 return mDatabase->getDevicePropertyValue(property, mData);
501}
502
503MtpResponseCode MtpServer::doSetDevicePropValue() {
504 MtpDeviceProperty property = mRequest.getParameter(1);
505 LOGD("SetDevicePropValue %s\n",
506 MtpDebug::getDevicePropCodeName(property));
507
508 return mDatabase->setDevicePropertyValue(property, mData);
509}
510
511MtpResponseCode MtpServer::doResetDevicePropValue() {
512 MtpDeviceProperty property = mRequest.getParameter(1);
513 LOGD("ResetDevicePropValue %s\n",
514 MtpDebug::getDevicePropCodeName(property));
515
516 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400517}
518
519MtpResponseCode MtpServer::doGetObjectInfo() {
520 MtpObjectHandle handle = mRequest.getParameter(1);
521 return mDatabase->getObjectInfo(handle, mData);
522}
523
524MtpResponseCode MtpServer::doGetObject() {
525 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400526 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400527 int64_t fileLength;
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400528 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength);
529 if (result != MTP_RESPONSE_OK)
530 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400531
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400532 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400533 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400534 mfr.fd = open(filePath, O_RDONLY);
535 if (mfr.fd < 0) {
536 return MTP_RESPONSE_GENERAL_ERROR;
537 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400538 mfr.offset = 0;
539 mfr.length = fileLength;
540
541 // send data header
542 mData.setOperationCode(mRequest.getOperationCode());
543 mData.setTransactionID(mRequest.getTransactionID());
544 mData.writeDataHeader(mFD, fileLength);
545
546 // then transfer the file
547 int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400548 close(mfr.fd);
Mike Lockwood916076c2010-06-04 09:49:21 -0400549 if (ret < 0) {
550 if (errno == ECANCELED)
551 return MTP_RESPONSE_TRANSACTION_CANCELLED;
552 else
553 return MTP_RESPONSE_GENERAL_ERROR;
554 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400555 return MTP_RESPONSE_OK;
556}
557
558MtpResponseCode MtpServer::doSendObjectInfo() {
559 MtpString path;
560 MtpStorageID storageID = mRequest.getParameter(1);
561 MtpStorage* storage = getStorage(storageID);
562 MtpObjectHandle parent = mRequest.getParameter(2);
563 if (!storage)
564 return MTP_RESPONSE_INVALID_STORAGE_ID;
565
566 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400567 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400568 path = storage->getPath();
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400569 parent = 0;
570 } else {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400571 int64_t dummy;
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400572 int result = mDatabase->getObjectFilePath(parent, path, dummy);
573 if (result != MTP_RESPONSE_OK)
574 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400575 }
576
577 // read only the fields we need
578 mData.getUInt32(); // storage ID
579 MtpObjectFormat format = mData.getUInt16();
580 mData.getUInt16(); // protection status
581 mSendObjectFileSize = mData.getUInt32();
582 mData.getUInt16(); // thumb format
583 mData.getUInt32(); // thumb compressed size
584 mData.getUInt32(); // thumb pix width
585 mData.getUInt32(); // thumb pix height
586 mData.getUInt32(); // image pix width
587 mData.getUInt32(); // image pix height
588 mData.getUInt32(); // image bit depth
589 mData.getUInt32(); // parent
590 uint16_t associationType = mData.getUInt16();
591 uint32_t associationDesc = mData.getUInt32(); // association desc
592 mData.getUInt32(); // sequence number
593 MtpStringBuffer name, created, modified;
594 mData.getString(name); // file name
595 mData.getString(created); // date created
596 mData.getString(modified); // date modified
597 // keywords follow
598
Mike Lockwoodfceef462010-05-14 15:35:17 -0400599 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400600 if (!parseDateTime(modified, modifiedTime))
601 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400602
603 if (path[path.size() - 1] != '/')
604 path += "/";
605 path += (const char *)name;
606
Mike Lockwood4714b072010-07-12 08:49:01 -0400607 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
608 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400609 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400610 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400611 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400612
613 if (format == MTP_FORMAT_ASSOCIATION) {
614 mode_t mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400615 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400616 umask(mask);
617 if (ret && ret != -EEXIST)
618 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400619 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400620 } else {
621 mSendObjectFilePath = path;
622 // save the handle for the SendObject call, which should follow
623 mSendObjectHandle = handle;
Mike Lockwood4714b072010-07-12 08:49:01 -0400624 mSendObjectFormat = format;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400625 }
626
627 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400628 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400629 mResponse.setParameter(3, handle);
630
631 return MTP_RESPONSE_OK;
632}
633
634MtpResponseCode MtpServer::doSendObject() {
Mike Lockwood4714b072010-07-12 08:49:01 -0400635 MtpResponseCode result = MTP_RESPONSE_OK;
636 mode_t mask;
637 int ret;
638
Mike Lockwood16864ba2010-05-11 17:16:59 -0400639 if (mSendObjectHandle == kInvalidObjectHandle) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400640 LOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -0400641 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
642 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400643 }
644
645 // read the header
Mike Lockwood4714b072010-07-12 08:49:01 -0400646 ret = mData.readDataHeader(mFD);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400647 // FIXME - check for errors here.
648
649 // reset so we don't attempt to send this back
650 mData.reset();
651
652 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400653 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
654 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -0400655 result = MTP_RESPONSE_GENERAL_ERROR;
656 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400657 }
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400658 fchown(mfr.fd, getuid(), mFileGroup);
659 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -0400660 mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400661 fchmod(mfr.fd, mFilePermission);
662 umask(mask);
663
Mike Lockwood16864ba2010-05-11 17:16:59 -0400664 mfr.offset = 0;
665 mfr.length = mSendObjectFileSize;
666
667 // transfer the file
668 ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400669 close(mfr.fd);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400670
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400671 LOGV("MTP_RECEIVE_FILE returned %d", ret);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400672
Mike Lockwood916076c2010-06-04 09:49:21 -0400673 if (ret < 0) {
674 unlink(mSendObjectFilePath);
675 if (errno == ECANCELED)
Mike Lockwood4714b072010-07-12 08:49:01 -0400676 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -0400677 else
Mike Lockwood4714b072010-07-12 08:49:01 -0400678 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -0400679 }
Mike Lockwood4714b072010-07-12 08:49:01 -0400680
681done:
682 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
683 result == MTP_RESPONSE_OK);
684 mSendObjectHandle = kInvalidObjectHandle;
685 mSendObjectFormat = 0;
686 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400687}
688
689MtpResponseCode MtpServer::doDeleteObject() {
690 MtpObjectHandle handle = mRequest.getParameter(1);
691 MtpObjectFormat format = mRequest.getParameter(1);
692 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
693 // FIXME - implement deleting objects by format
694 // FIXME - handle non-empty directories
695
696 MtpString filePath;
697 int64_t fileLength;
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400698 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength);
699 if (result == MTP_RESPONSE_OK) {
700 LOGV("deleting %s", (const char *)filePath);
701 // one of these should work
702 rmdir((const char *)filePath);
703 unlink((const char *)filePath);
704 return mDatabase->deleteFile(handle);
705 } else {
706 return result;
707 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400708}
709
710MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400711 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400712 MtpObjectFormat format = mRequest.getParameter(2);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400713 LOGD("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
714 MtpDebug::getFormatCodeName(format));
715 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400716 if (!property)
717 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400718 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400719 delete property;
720 return MTP_RESPONSE_OK;
721}
722
723MtpResponseCode MtpServer::doGetDevicePropDesc() {
724 MtpDeviceProperty propCode = mRequest.getParameter(1);
725 LOGD("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
726 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
727 if (!property)
728 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
729 property->write(mData);
730 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400731 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400732}
Mike Lockwood7850ef92010-05-14 10:10:36 -0400733
734} // namespace android