blob: 931a09de654d2428e9f6edabbce0d66266290583 [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>
Mark Salyzyndb43b342014-04-04 14:47:28 -070023#include <inttypes.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040024#include <errno.h>
Mike Lockwoodd3211492010-09-13 17:15:58 -040025#include <sys/stat.h>
26#include <dirent.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040027
Mike Lockwoodc42aa122010-06-14 17:58:08 -070028#include <cutils/properties.h>
29
Mike Lockwooda881b442010-09-23 22:32:05 -040030#define LOG_TAG "MtpServer"
31
Mike Lockwood16864ba2010-05-11 17:16:59 -040032#include "MtpDebug.h"
Mike Lockwood7f53a192010-07-09 10:45:22 -040033#include "MtpDatabase.h"
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070034#include "MtpObjectInfo.h"
Mike Lockwood21ef7d02010-06-30 17:00:35 -040035#include "MtpProperty.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040036#include "MtpServer.h"
37#include "MtpStorage.h"
38#include "MtpStringBuffer.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040039
Mike Lockwood8065e202010-07-15 13:36:52 -040040#include <linux/usb/f_mtp.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040041
Mike Lockwood7850ef92010-05-14 10:10:36 -040042namespace android {
43
Mike Lockwood16864ba2010-05-11 17:16:59 -040044static const MtpOperationCode kSupportedOperationCodes[] = {
45 MTP_OPERATION_GET_DEVICE_INFO,
46 MTP_OPERATION_OPEN_SESSION,
47 MTP_OPERATION_CLOSE_SESSION,
48 MTP_OPERATION_GET_STORAGE_IDS,
49 MTP_OPERATION_GET_STORAGE_INFO,
50 MTP_OPERATION_GET_NUM_OBJECTS,
51 MTP_OPERATION_GET_OBJECT_HANDLES,
52 MTP_OPERATION_GET_OBJECT_INFO,
53 MTP_OPERATION_GET_OBJECT,
Mike Lockwood64000782011-04-24 18:40:17 -070054 MTP_OPERATION_GET_THUMB,
Mike Lockwood16864ba2010-05-11 17:16:59 -040055 MTP_OPERATION_DELETE_OBJECT,
56 MTP_OPERATION_SEND_OBJECT_INFO,
57 MTP_OPERATION_SEND_OBJECT,
58// MTP_OPERATION_INITIATE_CAPTURE,
59// MTP_OPERATION_FORMAT_STORE,
60// MTP_OPERATION_RESET_DEVICE,
61// MTP_OPERATION_SELF_TEST,
62// MTP_OPERATION_SET_OBJECT_PROTECTION,
63// MTP_OPERATION_POWER_DOWN,
Mike Lockwoode3e76c42010-09-02 14:57:30 -040064 MTP_OPERATION_GET_DEVICE_PROP_DESC,
Mike Lockwood8277cec2010-08-10 15:20:35 -040065 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
66 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
67 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040068// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
69// MTP_OPERATION_MOVE_OBJECT,
70// MTP_OPERATION_COPY_OBJECT,
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -050071 MTP_OPERATION_GET_PARTIAL_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040072// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
73 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
Mike Lockwood8277cec2010-08-10 15:20:35 -040074 MTP_OPERATION_GET_OBJECT_PROP_DESC,
Mike Lockwood677f5702010-09-23 23:04:28 -040075 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
76 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
Mike Lockwoodb6da06e2010-10-14 18:03:25 -040077 MTP_OPERATION_GET_OBJECT_PROP_LIST,
78// MTP_OPERATION_SET_OBJECT_PROP_LIST,
79// MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
80// MTP_OPERATION_SEND_OBJECT_PROP_LIST,
Mike Lockwood438344f2010-08-03 15:30:09 -040081 MTP_OPERATION_GET_OBJECT_REFERENCES,
82 MTP_OPERATION_SET_OBJECT_REFERENCES,
Mike Lockwood16864ba2010-05-11 17:16:59 -040083// MTP_OPERATION_SKIP,
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070084 // Android extension for direct file IO
85 MTP_OPERATION_GET_PARTIAL_OBJECT_64,
86 MTP_OPERATION_SEND_PARTIAL_OBJECT,
87 MTP_OPERATION_TRUNCATE_OBJECT,
88 MTP_OPERATION_BEGIN_EDIT_OBJECT,
89 MTP_OPERATION_END_EDIT_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040090};
91
Mike Lockwood873871f2010-07-12 18:54:16 -040092static const MtpEventCode kSupportedEventCodes[] = {
93 MTP_EVENT_OBJECT_ADDED,
94 MTP_EVENT_OBJECT_REMOVED,
Mike Lockwooda8494402011-02-18 09:07:14 -050095 MTP_EVENT_STORE_ADDED,
96 MTP_EVENT_STORE_REMOVED,
Mike Lockwood0fa848d2014-03-07 13:29:59 -080097 MTP_EVENT_DEVICE_PROP_CHANGED,
Mike Lockwood873871f2010-07-12 18:54:16 -040098};
99
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400100MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400101 int fileGroup, int filePerm, int directoryPerm)
Mike Lockwood16864ba2010-05-11 17:16:59 -0400102 : mFD(fd),
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400103 mDatabase(database),
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400104 mPtp(ptp),
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400105 mFileGroup(fileGroup),
106 mFilePermission(filePerm),
107 mDirectoryPermission(directoryPerm),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400108 mSessionID(0),
109 mSessionOpen(false),
110 mSendObjectHandle(kInvalidObjectHandle),
Mike Lockwood4714b072010-07-12 08:49:01 -0400111 mSendObjectFormat(0),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400112 mSendObjectFileSize(0)
113{
Mike Lockwood16864ba2010-05-11 17:16:59 -0400114}
115
116MtpServer::~MtpServer() {
117}
118
Mike Lockwooda8494402011-02-18 09:07:14 -0500119void MtpServer::addStorage(MtpStorage* storage) {
120 Mutex::Autolock autoLock(mMutex);
121
122 mStorages.push(storage);
123 sendStoreAdded(storage->getStorageID());
124}
125
126void MtpServer::removeStorage(MtpStorage* storage) {
127 Mutex::Autolock autoLock(mMutex);
128
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700129 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500130 if (mStorages[i] == storage) {
131 mStorages.removeAt(i);
132 sendStoreRemoved(storage->getStorageID());
133 break;
134 }
135 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400136}
137
138MtpStorage* MtpServer::getStorage(MtpStorageID id) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800139 if (id == 0)
140 return mStorages[0];
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700141 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800142 MtpStorage* storage = mStorages[i];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400143 if (storage->getStorageID() == id)
144 return storage;
145 }
146 return NULL;
147}
148
Mike Lockwooda8494402011-02-18 09:07:14 -0500149bool MtpServer::hasStorage(MtpStorageID id) {
150 if (id == 0 || id == 0xFFFFFFFF)
151 return mStorages.size() > 0;
152 return (getStorage(id) != NULL);
153}
154
Mike Lockwood16864ba2010-05-11 17:16:59 -0400155void MtpServer::run() {
156 int fd = mFD;
157
Steve Block3856b092011-10-20 11:56:00 +0100158 ALOGV("MtpServer::run fd: %d\n", fd);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400159
160 while (1) {
161 int ret = mRequest.read(fd);
162 if (ret < 0) {
Steve Block3856b092011-10-20 11:56:00 +0100163 ALOGV("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400164 if (errno == ECANCELED) {
165 // return to top of loop and wait for next command
166 continue;
167 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400168 break;
169 }
170 MtpOperationCode operation = mRequest.getOperationCode();
171 MtpTransactionID transaction = mRequest.getTransactionID();
172
Steve Block3856b092011-10-20 11:56:00 +0100173 ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400174 mRequest.dump();
175
176 // FIXME need to generalize this
Mike Lockwood438344f2010-08-03 15:30:09 -0400177 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood8277cec2010-08-10 15:20:35 -0400178 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
179 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
180 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400181 if (dataIn) {
182 int ret = mData.read(fd);
183 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000184 ALOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400185 if (errno == ECANCELED) {
186 // return to top of loop and wait for next command
187 continue;
188 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400189 break;
190 }
Steve Block3856b092011-10-20 11:56:00 +0100191 ALOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400192 mData.dump();
193 } else {
194 mData.reset();
195 }
196
Mike Lockwood916076c2010-06-04 09:49:21 -0400197 if (handleRequest()) {
198 if (!dataIn && mData.hasData()) {
199 mData.setOperationCode(operation);
200 mData.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100201 ALOGV("sending data:");
Mike Lockwood23d20712010-10-11 17:31:44 -0400202 mData.dump();
Mike Lockwood916076c2010-06-04 09:49:21 -0400203 ret = mData.write(fd);
204 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000205 ALOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400206 if (errno == ECANCELED) {
207 // return to top of loop and wait for next command
208 continue;
209 }
210 break;
211 }
212 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400213
Mike Lockwood916076c2010-06-04 09:49:21 -0400214 mResponse.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100215 ALOGV("sending response %04X", mResponse.getResponseCode());
Mike Lockwood916076c2010-06-04 09:49:21 -0400216 ret = mResponse.write(fd);
Mike Lockwood23d20712010-10-11 17:31:44 -0400217 mResponse.dump();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400218 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000219 ALOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400220 if (errno == ECANCELED) {
221 // return to top of loop and wait for next command
222 continue;
223 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400224 break;
225 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400226 } else {
Steve Block3856b092011-10-20 11:56:00 +0100227 ALOGV("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400228 }
229 }
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400230
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700231 // commit any open edits
232 int count = mObjectEditList.size();
233 for (int i = 0; i < count; i++) {
234 ObjectEdit* edit = mObjectEditList[i];
235 commitEdit(edit);
236 delete edit;
237 }
238 mObjectEditList.clear();
239
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400240 if (mSessionOpen)
241 mDatabase->sessionEnded();
Mike Lockwooddec73882011-07-11 15:04:38 -0400242 close(fd);
243 mFD = -1;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400244}
245
Mike Lockwood873871f2010-07-12 18:54:16 -0400246void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100247 ALOGV("sendObjectAdded %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500248 sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
Mike Lockwood873871f2010-07-12 18:54:16 -0400249}
250
251void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100252 ALOGV("sendObjectRemoved %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500253 sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
254}
255
256void MtpServer::sendStoreAdded(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100257 ALOGV("sendStoreAdded %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500258 sendEvent(MTP_EVENT_STORE_ADDED, id);
259}
260
261void MtpServer::sendStoreRemoved(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100262 ALOGV("sendStoreRemoved %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500263 sendEvent(MTP_EVENT_STORE_REMOVED, id);
264}
265
Mike Lockwood0fa848d2014-03-07 13:29:59 -0800266void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
267 ALOGV("sendDevicePropertyChanged %d\n", property);
268 sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
269}
270
Mike Lockwooda8494402011-02-18 09:07:14 -0500271void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400272 if (mSessionOpen) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500273 mEvent.setEventCode(code);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400274 mEvent.setTransactionID(mRequest.getTransactionID());
Mike Lockwooda8494402011-02-18 09:07:14 -0500275 mEvent.setParameter(1, param1);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400276 int ret = mEvent.write(mFD);
Steve Block3856b092011-10-20 11:56:00 +0100277 ALOGV("mEvent.write returned %d\n", ret);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400278 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400279}
280
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700281void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
282 uint64_t size, MtpObjectFormat format, int fd) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700283 ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700284 mObjectEditList.add(edit);
285}
286
287MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
288 int count = mObjectEditList.size();
289 for (int i = 0; i < count; i++) {
290 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700291 if (edit->mHandle == handle) return edit;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700292 }
293 return NULL;
294}
295
296void MtpServer::removeEditObject(MtpObjectHandle handle) {
297 int count = mObjectEditList.size();
298 for (int i = 0; i < count; i++) {
299 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700300 if (edit->mHandle == handle) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700301 delete edit;
302 mObjectEditList.removeAt(i);
303 return;
304 }
305 }
Steve Block29357bc2012-01-06 19:20:56 +0000306 ALOGE("ObjectEdit not found in removeEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700307}
308
309void MtpServer::commitEdit(ObjectEdit* edit) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700310 mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700311}
312
313
Mike Lockwood916076c2010-06-04 09:49:21 -0400314bool MtpServer::handleRequest() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500315 Mutex::Autolock autoLock(mMutex);
316
Mike Lockwood16864ba2010-05-11 17:16:59 -0400317 MtpOperationCode operation = mRequest.getOperationCode();
318 MtpResponseCode response;
319
320 mResponse.reset();
321
322 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
323 // FIXME - need to delete mSendObjectHandle from the database
Steve Block29357bc2012-01-06 19:20:56 +0000324 ALOGE("expected SendObject after SendObjectInfo");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400325 mSendObjectHandle = kInvalidObjectHandle;
326 }
327
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700328 int containertype = mRequest.getContainerType();
329 if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
330 ALOGE("wrong container type %d", containertype);
331 return false;
332 }
333
334 ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
335
Mike Lockwood16864ba2010-05-11 17:16:59 -0400336 switch (operation) {
337 case MTP_OPERATION_GET_DEVICE_INFO:
338 response = doGetDeviceInfo();
339 break;
340 case MTP_OPERATION_OPEN_SESSION:
341 response = doOpenSession();
342 break;
343 case MTP_OPERATION_CLOSE_SESSION:
344 response = doCloseSession();
345 break;
346 case MTP_OPERATION_GET_STORAGE_IDS:
347 response = doGetStorageIDs();
348 break;
349 case MTP_OPERATION_GET_STORAGE_INFO:
350 response = doGetStorageInfo();
351 break;
352 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
353 response = doGetObjectPropsSupported();
354 break;
355 case MTP_OPERATION_GET_OBJECT_HANDLES:
356 response = doGetObjectHandles();
357 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400358 case MTP_OPERATION_GET_NUM_OBJECTS:
359 response = doGetNumObjects();
360 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400361 case MTP_OPERATION_GET_OBJECT_REFERENCES:
362 response = doGetObjectReferences();
363 break;
364 case MTP_OPERATION_SET_OBJECT_REFERENCES:
365 response = doSetObjectReferences();
366 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400367 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
368 response = doGetObjectPropValue();
369 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400370 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
371 response = doSetObjectPropValue();
372 break;
373 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
374 response = doGetDevicePropValue();
375 break;
376 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
377 response = doSetDevicePropValue();
378 break;
379 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
380 response = doResetDevicePropValue();
381 break;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400382 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
383 response = doGetObjectPropList();
384 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400385 case MTP_OPERATION_GET_OBJECT_INFO:
386 response = doGetObjectInfo();
387 break;
388 case MTP_OPERATION_GET_OBJECT:
389 response = doGetObject();
390 break;
Mike Lockwood64000782011-04-24 18:40:17 -0700391 case MTP_OPERATION_GET_THUMB:
392 response = doGetThumb();
393 break;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500394 case MTP_OPERATION_GET_PARTIAL_OBJECT:
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700395 case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
396 response = doGetPartialObject(operation);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500397 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400398 case MTP_OPERATION_SEND_OBJECT_INFO:
399 response = doSendObjectInfo();
400 break;
401 case MTP_OPERATION_SEND_OBJECT:
402 response = doSendObject();
403 break;
404 case MTP_OPERATION_DELETE_OBJECT:
405 response = doDeleteObject();
406 break;
407 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400408 response = doGetObjectPropDesc();
409 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400410 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
411 response = doGetDevicePropDesc();
412 break;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700413 case MTP_OPERATION_SEND_PARTIAL_OBJECT:
414 response = doSendPartialObject();
415 break;
416 case MTP_OPERATION_TRUNCATE_OBJECT:
417 response = doTruncateObject();
418 break;
419 case MTP_OPERATION_BEGIN_EDIT_OBJECT:
420 response = doBeginEditObject();
421 break;
422 case MTP_OPERATION_END_EDIT_OBJECT:
423 response = doEndEditObject();
424 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400425 default:
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700426 ALOGE("got unsupported command %s (%x)",
427 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400428 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
429 break;
430 }
431
Mike Lockwood916076c2010-06-04 09:49:21 -0400432 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
433 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400434 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400435 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400436}
437
438MtpResponseCode MtpServer::doGetDeviceInfo() {
439 MtpStringBuffer string;
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700440 char prop_value[PROPERTY_VALUE_MAX];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400441
Mike Lockwood782aef12010-08-10 07:37:50 -0400442 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
443 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
444 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
445
Mike Lockwood16864ba2010-05-11 17:16:59 -0400446 // fill in device info
447 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400448 if (mPtp) {
449 mData.putUInt32(0);
450 } else {
451 // MTP Vendor Extension ID
452 mData.putUInt32(6);
453 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400454 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400455 if (mPtp) {
456 // no extensions
457 string.set("");
458 } else {
459 // MTP extensions
460 string.set("microsoft.com: 1.0; android.com: 1.0;");
461 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400462 mData.putString(string); // MTP Extensions
463 mData.putUInt16(0); //Functional Mode
464 mData.putAUInt16(kSupportedOperationCodes,
465 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400466 mData.putAUInt16(kSupportedEventCodes,
467 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400468 mData.putAUInt16(deviceProperties); // Device Properties Supported
469 mData.putAUInt16(captureFormats); // Capture Formats
470 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500471
472 property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
473 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400474 mData.putString(string); // Manufacturer
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700475
476 property_get("ro.product.model", prop_value, "MTP Device");
477 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400478 mData.putString(string); // Model
479 string.set("1.0");
480 mData.putString(string); // Device Version
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700481
482 property_get("ro.serialno", prop_value, "????????");
483 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400484 mData.putString(string); // Serial Number
485
Mike Lockwood782aef12010-08-10 07:37:50 -0400486 delete playbackFormats;
487 delete captureFormats;
488 delete deviceProperties;
489
Mike Lockwood16864ba2010-05-11 17:16:59 -0400490 return MTP_RESPONSE_OK;
491}
492
493MtpResponseCode MtpServer::doOpenSession() {
494 if (mSessionOpen) {
495 mResponse.setParameter(1, mSessionID);
496 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
497 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800498 if (mRequest.getParameterCount() < 1)
499 return MTP_RESPONSE_INVALID_PARAMETER;
500
Mike Lockwood16864ba2010-05-11 17:16:59 -0400501 mSessionID = mRequest.getParameter(1);
502 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400503
504 mDatabase->sessionStarted();
505
Mike Lockwood16864ba2010-05-11 17:16:59 -0400506 return MTP_RESPONSE_OK;
507}
508
509MtpResponseCode MtpServer::doCloseSession() {
510 if (!mSessionOpen)
511 return MTP_RESPONSE_SESSION_NOT_OPEN;
512 mSessionID = 0;
513 mSessionOpen = false;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400514 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400515 return MTP_RESPONSE_OK;
516}
517
518MtpResponseCode MtpServer::doGetStorageIDs() {
519 if (!mSessionOpen)
520 return MTP_RESPONSE_SESSION_NOT_OPEN;
521
522 int count = mStorages.size();
523 mData.putUInt32(count);
524 for (int i = 0; i < count; i++)
525 mData.putUInt32(mStorages[i]->getStorageID());
526
527 return MTP_RESPONSE_OK;
528}
529
530MtpResponseCode MtpServer::doGetStorageInfo() {
531 MtpStringBuffer string;
532
533 if (!mSessionOpen)
534 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800535 if (mRequest.getParameterCount() < 1)
536 return MTP_RESPONSE_INVALID_PARAMETER;
537
Mike Lockwood16864ba2010-05-11 17:16:59 -0400538 MtpStorageID id = mRequest.getParameter(1);
539 MtpStorage* storage = getStorage(id);
540 if (!storage)
541 return MTP_RESPONSE_INVALID_STORAGE_ID;
542
543 mData.putUInt16(storage->getType());
544 mData.putUInt16(storage->getFileSystemType());
545 mData.putUInt16(storage->getAccessCapability());
546 mData.putUInt64(storage->getMaxCapacity());
547 mData.putUInt64(storage->getFreeSpace());
548 mData.putUInt32(1024*1024*1024); // Free Space in Objects
549 string.set(storage->getDescription());
550 mData.putString(string);
551 mData.putEmptyString(); // Volume Identifier
552
553 return MTP_RESPONSE_OK;
554}
555
556MtpResponseCode MtpServer::doGetObjectPropsSupported() {
557 if (!mSessionOpen)
558 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800559 if (mRequest.getParameterCount() < 1)
560 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400561 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800562 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400563 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400564 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400565 return MTP_RESPONSE_OK;
566}
567
568MtpResponseCode MtpServer::doGetObjectHandles() {
569 if (!mSessionOpen)
570 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800571 if (mRequest.getParameterCount() < 3)
572 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400573 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400574 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400575 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400576 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500577
578 if (!hasStorage(storageID))
579 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400580
581 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
582 mData.putAUInt32(handles);
583 delete handles;
584 return MTP_RESPONSE_OK;
585}
586
Mike Lockwood343af4e2010-08-02 10:52:20 -0400587MtpResponseCode MtpServer::doGetNumObjects() {
588 if (!mSessionOpen)
589 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800590 if (mRequest.getParameterCount() < 3)
591 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400592 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
593 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
594 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400595 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500596 if (!hasStorage(storageID))
597 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400598
599 int count = mDatabase->getNumObjects(storageID, format, parent);
600 if (count >= 0) {
601 mResponse.setParameter(1, count);
602 return MTP_RESPONSE_OK;
603 } else {
604 mResponse.setParameter(1, 0);
605 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
606 }
607}
608
Mike Lockwood438344f2010-08-03 15:30:09 -0400609MtpResponseCode MtpServer::doGetObjectReferences() {
610 if (!mSessionOpen)
611 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500612 if (!hasStorage())
613 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800614 if (mRequest.getParameterCount() < 1)
615 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500616 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400617
618 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400619 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400620 if (handles) {
621 mData.putAUInt32(handles);
622 delete handles;
623 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400624 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400625 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400626 return MTP_RESPONSE_OK;
627}
628
629MtpResponseCode MtpServer::doSetObjectReferences() {
630 if (!mSessionOpen)
631 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500632 if (!hasStorage())
633 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800634 if (mRequest.getParameterCount() < 1)
635 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400636 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500637
Mike Lockwood438344f2010-08-03 15:30:09 -0400638 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800639 if (!references)
640 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400641 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
642 delete references;
643 return result;
644}
645
Mike Lockwood16864ba2010-05-11 17:16:59 -0400646MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500647 if (!hasStorage())
648 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800649 if (mRequest.getParameterCount() < 2)
650 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400651 MtpObjectHandle handle = mRequest.getParameter(1);
652 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100653 ALOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400654 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400655
Mike Lockwood8277cec2010-08-10 15:20:35 -0400656 return mDatabase->getObjectPropertyValue(handle, property, mData);
657}
658
659MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500660 if (!hasStorage())
661 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800662 if (mRequest.getParameterCount() < 2)
663 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400664 MtpObjectHandle handle = mRequest.getParameter(1);
665 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100666 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400667 MtpDebug::getObjectPropCodeName(property));
668
669 return mDatabase->setObjectPropertyValue(handle, property, mData);
670}
671
672MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800673 if (mRequest.getParameterCount() < 1)
674 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400675 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100676 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400677 MtpDebug::getDevicePropCodeName(property));
678
679 return mDatabase->getDevicePropertyValue(property, mData);
680}
681
682MtpResponseCode MtpServer::doSetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800683 if (mRequest.getParameterCount() < 1)
684 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400685 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100686 ALOGV("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400687 MtpDebug::getDevicePropCodeName(property));
688
689 return mDatabase->setDevicePropertyValue(property, mData);
690}
691
692MtpResponseCode MtpServer::doResetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800693 if (mRequest.getParameterCount() < 1)
694 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400695 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100696 ALOGV("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400697 MtpDebug::getDevicePropCodeName(property));
698
699 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400700}
701
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400702MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500703 if (!hasStorage())
704 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800705 if (mRequest.getParameterCount() < 5)
706 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400707
708 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500709 // use uint32_t so we can support 0xFFFFFFFF
710 uint32_t format = mRequest.getParameter(2);
711 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400712 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500713 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100714 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400715 handle, MtpDebug::getFormatCodeName(format),
716 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
717
718 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
719}
720
Mike Lockwood16864ba2010-05-11 17:16:59 -0400721MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500722 if (!hasStorage())
723 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800724 if (mRequest.getParameterCount() < 1)
725 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400726 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700727 MtpObjectInfo info(handle);
728 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
729 if (result == MTP_RESPONSE_OK) {
730 char date[20];
731
732 mData.putUInt32(info.mStorageID);
733 mData.putUInt16(info.mFormat);
734 mData.putUInt16(info.mProtectionStatus);
735
736 // if object is being edited the database size may be out of date
737 uint32_t size = info.mCompressedSize;
738 ObjectEdit* edit = getEditObject(handle);
739 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700740 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700741 mData.putUInt32(size);
742
743 mData.putUInt16(info.mThumbFormat);
744 mData.putUInt32(info.mThumbCompressedSize);
745 mData.putUInt32(info.mThumbPixWidth);
746 mData.putUInt32(info.mThumbPixHeight);
747 mData.putUInt32(info.mImagePixWidth);
748 mData.putUInt32(info.mImagePixHeight);
749 mData.putUInt32(info.mImagePixDepth);
750 mData.putUInt32(info.mParent);
751 mData.putUInt16(info.mAssociationType);
752 mData.putUInt32(info.mAssociationDesc);
753 mData.putUInt32(info.mSequenceNumber);
754 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700755 formatDateTime(info.mDateCreated, date, sizeof(date));
756 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700757 formatDateTime(info.mDateModified, date, sizeof(date));
758 mData.putString(date); // date modified
759 mData.putEmptyString(); // keywords
760 }
761 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400762}
763
764MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500765 if (!hasStorage())
766 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800767 if (mRequest.getParameterCount() < 1)
768 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400769 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400770 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400771 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800772 MtpObjectFormat format;
773 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400774 if (result != MTP_RESPONSE_OK)
775 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400776
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400777 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400778 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400779 mfr.fd = open(filePath, O_RDONLY);
780 if (mfr.fd < 0) {
781 return MTP_RESPONSE_GENERAL_ERROR;
782 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400783 mfr.offset = 0;
784 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400785 mfr.command = mRequest.getOperationCode();
786 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400787
788 // then transfer the file
Mike Lockwoodef441d92011-07-14 21:00:02 -0400789 int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
Steve Block3856b092011-10-20 11:56:00 +0100790 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400791 close(mfr.fd);
Mike Lockwood916076c2010-06-04 09:49:21 -0400792 if (ret < 0) {
793 if (errno == ECANCELED)
794 return MTP_RESPONSE_TRANSACTION_CANCELLED;
795 else
796 return MTP_RESPONSE_GENERAL_ERROR;
797 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400798 return MTP_RESPONSE_OK;
799}
800
Mike Lockwood64000782011-04-24 18:40:17 -0700801MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800802 if (mRequest.getParameterCount() < 1)
803 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700804 MtpObjectHandle handle = mRequest.getParameter(1);
805 size_t thumbSize;
806 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
807 if (thumb) {
808 // send data
809 mData.setOperationCode(mRequest.getOperationCode());
810 mData.setTransactionID(mRequest.getTransactionID());
811 mData.writeData(mFD, thumb, thumbSize);
812 free(thumb);
813 return MTP_RESPONSE_OK;
814 } else {
815 return MTP_RESPONSE_GENERAL_ERROR;
816 }
817}
818
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700819MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500820 if (!hasStorage())
821 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800822 if (mRequest.getParameterCount() < 4)
823 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500824 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700825 uint64_t offset;
826 uint32_t length;
827 offset = mRequest.getParameter(2);
828 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
829 // android extension with 64 bit offset
830 uint64_t offset2 = mRequest.getParameter(3);
831 offset = offset | (offset2 << 32);
832 length = mRequest.getParameter(4);
833 } else {
834 // standard GetPartialObject
835 length = mRequest.getParameter(3);
836 }
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500837 MtpString pathBuf;
838 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800839 MtpObjectFormat format;
840 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500841 if (result != MTP_RESPONSE_OK)
842 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700843 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500844 length = fileLength - offset;
845
846 const char* filePath = (const char *)pathBuf;
847 mtp_file_range mfr;
848 mfr.fd = open(filePath, O_RDONLY);
849 if (mfr.fd < 0) {
850 return MTP_RESPONSE_GENERAL_ERROR;
851 }
852 mfr.offset = offset;
853 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400854 mfr.command = mRequest.getOperationCode();
855 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500856 mResponse.setParameter(1, length);
857
Mike Lockwoodef441d92011-07-14 21:00:02 -0400858 // transfer the file
859 int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
Steve Block3856b092011-10-20 11:56:00 +0100860 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500861 close(mfr.fd);
862 if (ret < 0) {
863 if (errno == ECANCELED)
864 return MTP_RESPONSE_TRANSACTION_CANCELLED;
865 else
866 return MTP_RESPONSE_GENERAL_ERROR;
867 }
868 return MTP_RESPONSE_OK;
869}
870
Mike Lockwood16864ba2010-05-11 17:16:59 -0400871MtpResponseCode MtpServer::doSendObjectInfo() {
872 MtpString path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800873 uint16_t temp16;
874 uint32_t temp32;
875
876 if (mRequest.getParameterCount() < 2)
877 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400878 MtpStorageID storageID = mRequest.getParameter(1);
879 MtpStorage* storage = getStorage(storageID);
880 MtpObjectHandle parent = mRequest.getParameter(2);
881 if (!storage)
882 return MTP_RESPONSE_INVALID_STORAGE_ID;
883
884 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400885 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400886 path = storage->getPath();
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400887 parent = 0;
888 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800889 int64_t length;
890 MtpObjectFormat format;
891 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400892 if (result != MTP_RESPONSE_OK)
893 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800894 if (format != MTP_FORMAT_ASSOCIATION)
895 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400896 }
897
898 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800899 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
900 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
901 MtpObjectFormat format = temp16;
902 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
903 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
904 mSendObjectFileSize = temp32;
905 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
906 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
907 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
908 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
909 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
910 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
911 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
912 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
913 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
914 uint16_t associationType = temp16;
915 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
916 uint32_t associationDesc = temp32; // association desc
917 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400918 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800919 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
920 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
921 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400922 // keywords follow
923
Steve Block3856b092011-10-20 11:56:00 +0100924 ALOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400925 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400926 if (!parseDateTime(modified, modifiedTime))
927 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400928
929 if (path[path.size() - 1] != '/')
930 path += "/";
931 path += (const char *)name;
932
Mike Lockwood20c3be02010-12-12 12:17:43 -0800933 // check space first
934 if (mSendObjectFileSize > storage->getFreeSpace())
935 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400936 uint64_t maxFileSize = storage->getMaxFileSize();
937 // check storage max file size
938 if (maxFileSize != 0) {
939 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
940 // is >= 0xFFFFFFFF
941 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
942 return MTP_RESPONSE_OBJECT_TOO_LARGE;
943 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800944
Steve Blockb8a80522011-12-20 16:23:08 +0000945 ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Mike Lockwood4714b072010-07-12 08:49:01 -0400946 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
947 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400948 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400949 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400950 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400951
952 if (format == MTP_FORMAT_ASSOCIATION) {
953 mode_t mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400954 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400955 umask(mask);
956 if (ret && ret != -EEXIST)
957 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400958 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwoodaa952402011-01-18 11:06:19 -0800959
960 // SendObject does not get sent for directories, so call endSendObject here instead
961 mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400962 } else {
963 mSendObjectFilePath = path;
964 // save the handle for the SendObject call, which should follow
965 mSendObjectHandle = handle;
Mike Lockwood4714b072010-07-12 08:49:01 -0400966 mSendObjectFormat = format;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400967 }
968
969 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400970 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400971 mResponse.setParameter(3, handle);
972
973 return MTP_RESPONSE_OK;
974}
975
976MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500977 if (!hasStorage())
978 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -0400979 MtpResponseCode result = MTP_RESPONSE_OK;
980 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400981 int ret, initialData;
Mike Lockwood4714b072010-07-12 08:49:01 -0400982
Mike Lockwood16864ba2010-05-11 17:16:59 -0400983 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +0000984 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -0400985 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
986 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400987 }
988
Mike Lockwoodef441d92011-07-14 21:00:02 -0400989 // read the header, and possibly some data
990 ret = mData.read(mFD);
991 if (ret < MTP_CONTAINER_HEADER_SIZE) {
992 result = MTP_RESPONSE_GENERAL_ERROR;
993 goto done;
994 }
995 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400996
997 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -0700998 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400999 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001000 result = MTP_RESPONSE_GENERAL_ERROR;
1001 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001002 }
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001003 fchown(mfr.fd, getuid(), mFileGroup);
1004 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001005 mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001006 fchmod(mfr.fd, mFilePermission);
1007 umask(mask);
1008
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001009 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001010 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001011 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001012
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001013 if (ret < 0) {
1014 ALOGE("failed to write initial data");
1015 result = MTP_RESPONSE_GENERAL_ERROR;
1016 } else {
1017 if (mSendObjectFileSize - initialData > 0) {
1018 mfr.offset = initialData;
1019 if (mSendObjectFileSize == 0xFFFFFFFF) {
1020 // tell driver to read until it receives a short packet
1021 mfr.length = 0xFFFFFFFF;
1022 } else {
1023 mfr.length = mSendObjectFileSize - initialData;
1024 }
1025
1026 ALOGV("receiving %s\n", (const char *)mSendObjectFilePath);
1027 // transfer the file
1028 ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
1029 ALOGV("MTP_RECEIVE_FILE returned %d\n", ret);
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001030 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001031 }
Mike Lockwoodc6588762010-06-22 15:03:53 -04001032 close(mfr.fd);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001033
Mike Lockwood916076c2010-06-04 09:49:21 -04001034 if (ret < 0) {
1035 unlink(mSendObjectFilePath);
1036 if (errno == ECANCELED)
Mike Lockwood4714b072010-07-12 08:49:01 -04001037 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001038 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001039 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001040 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001041
1042done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001043 // reset so we don't attempt to send the data back
1044 mData.reset();
1045
Mike Lockwood4714b072010-07-12 08:49:01 -04001046 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
Mike Lockwoodaa952402011-01-18 11:06:19 -08001047 result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001048 mSendObjectHandle = kInvalidObjectHandle;
1049 mSendObjectFormat = 0;
1050 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001051}
1052
Mike Lockwoodd3211492010-09-13 17:15:58 -04001053static void deleteRecursive(const char* path) {
1054 char pathbuf[PATH_MAX];
Mark Salyzynd239cb62014-06-18 16:32:27 -07001055 size_t pathLength = strlen(path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001056 if (pathLength >= sizeof(pathbuf) - 1) {
Steve Block29357bc2012-01-06 19:20:56 +00001057 ALOGE("path too long: %s\n", path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001058 }
1059 strcpy(pathbuf, path);
1060 if (pathbuf[pathLength - 1] != '/') {
1061 pathbuf[pathLength++] = '/';
1062 }
1063 char* fileSpot = pathbuf + pathLength;
1064 int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1065
1066 DIR* dir = opendir(path);
1067 if (!dir) {
Steve Block29357bc2012-01-06 19:20:56 +00001068 ALOGE("opendir %s failed: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001069 return;
1070 }
1071
1072 struct dirent* entry;
1073 while ((entry = readdir(dir))) {
1074 const char* name = entry->d_name;
1075
1076 // ignore "." and ".."
1077 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1078 continue;
1079 }
1080
1081 int nameLength = strlen(name);
1082 if (nameLength > pathRemaining) {
Steve Block29357bc2012-01-06 19:20:56 +00001083 ALOGE("path %s/%s too long\n", path, name);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001084 continue;
1085 }
1086 strcpy(fileSpot, name);
1087
1088 int type = entry->d_type;
1089 if (entry->d_type == DT_DIR) {
1090 deleteRecursive(pathbuf);
1091 rmdir(pathbuf);
1092 } else {
1093 unlink(pathbuf);
1094 }
1095 }
Mike Lockwood7ce05cf2010-11-11 11:22:32 -05001096 closedir(dir);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001097}
1098
1099static void deletePath(const char* path) {
1100 struct stat statbuf;
1101 if (stat(path, &statbuf) == 0) {
1102 if (S_ISDIR(statbuf.st_mode)) {
1103 deleteRecursive(path);
1104 rmdir(path);
1105 } else {
1106 unlink(path);
1107 }
1108 } else {
Steve Block29357bc2012-01-06 19:20:56 +00001109 ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001110 }
1111}
1112
Mike Lockwood16864ba2010-05-11 17:16:59 -04001113MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001114 if (!hasStorage())
1115 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001116 if (mRequest.getParameterCount() < 2)
1117 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001118 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001119 MtpObjectFormat format = mRequest.getParameter(2);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001120 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1121 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001122
1123 MtpString filePath;
1124 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001125 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001126 if (result == MTP_RESPONSE_OK) {
Steve Block3856b092011-10-20 11:56:00 +01001127 ALOGV("deleting %s", (const char *)filePath);
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001128 result = mDatabase->deleteFile(handle);
1129 // Don't delete the actual files unless the database deletion is allowed
1130 if (result == MTP_RESPONSE_OK) {
1131 deletePath((const char *)filePath);
1132 }
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001133 }
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001134
1135 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001136}
1137
1138MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001139 if (mRequest.getParameterCount() < 2)
1140 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001141 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001142 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001143 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001144 MtpDebug::getFormatCodeName(format));
1145 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001146 if (!property)
1147 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001148 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001149 delete property;
1150 return MTP_RESPONSE_OK;
1151}
1152
1153MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001154 if (mRequest.getParameterCount() < 1)
1155 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001156 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001157 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001158 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1159 if (!property)
1160 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1161 property->write(mData);
1162 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001163 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001164}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001165
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001166MtpResponseCode MtpServer::doSendPartialObject() {
1167 if (!hasStorage())
1168 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001169 if (mRequest.getParameterCount() < 4)
1170 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001171 MtpObjectHandle handle = mRequest.getParameter(1);
1172 uint64_t offset = mRequest.getParameter(2);
1173 uint64_t offset2 = mRequest.getParameter(3);
1174 offset = offset | (offset2 << 32);
1175 uint32_t length = mRequest.getParameter(4);
1176
1177 ObjectEdit* edit = getEditObject(handle);
1178 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001179 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001180 return MTP_RESPONSE_GENERAL_ERROR;
1181 }
1182
1183 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001184 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001185 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1186 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001187 return MTP_RESPONSE_GENERAL_ERROR;
1188 }
1189
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001190 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001191 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001192
Mike Lockwoodef441d92011-07-14 21:00:02 -04001193 // read the header, and possibly some data
1194 int ret = mData.read(mFD);
1195 if (ret < MTP_CONTAINER_HEADER_SIZE)
1196 return MTP_RESPONSE_GENERAL_ERROR;
1197 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1198
1199 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001200 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001201 offset += initialData;
1202 length -= initialData;
1203 }
1204
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001205 if (ret < 0) {
1206 ALOGE("failed to write initial data");
1207 } else {
1208 if (length > 0) {
1209 mtp_file_range mfr;
1210 mfr.fd = edit->mFD;
1211 mfr.offset = offset;
1212 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001213
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001214 // transfer the file
1215 ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
1216 ALOGV("MTP_RECEIVE_FILE returned %d", ret);
1217 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001218 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001219 if (ret < 0) {
1220 mResponse.setParameter(1, 0);
1221 if (errno == ECANCELED)
1222 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1223 else
1224 return MTP_RESPONSE_GENERAL_ERROR;
1225 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001226
1227 // reset so we don't attempt to send this back
1228 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001229 mResponse.setParameter(1, length);
1230 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001231 if (end > edit->mSize) {
1232 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001233 }
1234 return MTP_RESPONSE_OK;
1235}
1236
1237MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001238 if (mRequest.getParameterCount() < 3)
1239 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001240 MtpObjectHandle handle = mRequest.getParameter(1);
1241 ObjectEdit* edit = getEditObject(handle);
1242 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001243 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001244 return MTP_RESPONSE_GENERAL_ERROR;
1245 }
1246
1247 uint64_t offset = mRequest.getParameter(2);
1248 uint64_t offset2 = mRequest.getParameter(3);
1249 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001250 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001251 return MTP_RESPONSE_GENERAL_ERROR;
1252 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001253 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001254 return MTP_RESPONSE_OK;
1255 }
1256}
1257
1258MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001259 if (mRequest.getParameterCount() < 1)
1260 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001261 MtpObjectHandle handle = mRequest.getParameter(1);
1262 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001263 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001264 return MTP_RESPONSE_GENERAL_ERROR;
1265 }
1266
1267 MtpString path;
1268 int64_t fileLength;
1269 MtpObjectFormat format;
1270 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1271 if (result != MTP_RESPONSE_OK)
1272 return result;
1273
1274 int fd = open((const char *)path, O_RDWR | O_EXCL);
1275 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001276 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001277 return MTP_RESPONSE_GENERAL_ERROR;
1278 }
1279
1280 addEditObject(handle, path, fileLength, format, fd);
1281 return MTP_RESPONSE_OK;
1282}
1283
1284MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001285 if (mRequest.getParameterCount() < 1)
1286 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001287 MtpObjectHandle handle = mRequest.getParameter(1);
1288 ObjectEdit* edit = getEditObject(handle);
1289 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001290 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001291 return MTP_RESPONSE_GENERAL_ERROR;
1292 }
1293
1294 commitEdit(edit);
1295 removeEditObject(handle);
1296 return MTP_RESPONSE_OK;
1297}
1298
Mike Lockwood7850ef92010-05-14 10:10:36 -04001299} // namespace android