blob: 2a96ac96c428bf9096ec7c33d65a72d8afe9cbda [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
Jerry Zhang487be612016-10-24 12:10:41 -070017#include <android-base/properties.h>
18#include <chrono>
19#include <cutils/properties.h>
20#include <dirent.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <inttypes.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040024#include <stdio.h>
25#include <stdlib.h>
26#include <sys/types.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040027#include <sys/stat.h>
Mike Lockwoodd3211492010-09-13 17:15:58 -040028#include <sys/stat.h>
Mike Lockwoodc42aa122010-06-14 17:58:08 -070029
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 Lockwood7850ef92010-05-14 10:10:36 -040040namespace android {
41
Mike Lockwood16864ba2010-05-11 17:16:59 -040042static const MtpOperationCode kSupportedOperationCodes[] = {
43 MTP_OPERATION_GET_DEVICE_INFO,
44 MTP_OPERATION_OPEN_SESSION,
45 MTP_OPERATION_CLOSE_SESSION,
46 MTP_OPERATION_GET_STORAGE_IDS,
47 MTP_OPERATION_GET_STORAGE_INFO,
48 MTP_OPERATION_GET_NUM_OBJECTS,
49 MTP_OPERATION_GET_OBJECT_HANDLES,
50 MTP_OPERATION_GET_OBJECT_INFO,
51 MTP_OPERATION_GET_OBJECT,
Mike Lockwood64000782011-04-24 18:40:17 -070052 MTP_OPERATION_GET_THUMB,
Mike Lockwood16864ba2010-05-11 17:16:59 -040053 MTP_OPERATION_DELETE_OBJECT,
54 MTP_OPERATION_SEND_OBJECT_INFO,
55 MTP_OPERATION_SEND_OBJECT,
56// MTP_OPERATION_INITIATE_CAPTURE,
57// MTP_OPERATION_FORMAT_STORE,
58// MTP_OPERATION_RESET_DEVICE,
59// MTP_OPERATION_SELF_TEST,
60// MTP_OPERATION_SET_OBJECT_PROTECTION,
61// MTP_OPERATION_POWER_DOWN,
Mike Lockwoode3e76c42010-09-02 14:57:30 -040062 MTP_OPERATION_GET_DEVICE_PROP_DESC,
Mike Lockwood8277cec2010-08-10 15:20:35 -040063 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
64 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
65 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040066// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
67// MTP_OPERATION_MOVE_OBJECT,
68// MTP_OPERATION_COPY_OBJECT,
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -050069 MTP_OPERATION_GET_PARTIAL_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040070// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
71 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
Mike Lockwood8277cec2010-08-10 15:20:35 -040072 MTP_OPERATION_GET_OBJECT_PROP_DESC,
Mike Lockwood677f5702010-09-23 23:04:28 -040073 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
74 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
Mike Lockwoodb6da06e2010-10-14 18:03:25 -040075 MTP_OPERATION_GET_OBJECT_PROP_LIST,
76// MTP_OPERATION_SET_OBJECT_PROP_LIST,
77// MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
78// MTP_OPERATION_SEND_OBJECT_PROP_LIST,
Mike Lockwood438344f2010-08-03 15:30:09 -040079 MTP_OPERATION_GET_OBJECT_REFERENCES,
80 MTP_OPERATION_SET_OBJECT_REFERENCES,
Mike Lockwood16864ba2010-05-11 17:16:59 -040081// MTP_OPERATION_SKIP,
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070082 // Android extension for direct file IO
83 MTP_OPERATION_GET_PARTIAL_OBJECT_64,
84 MTP_OPERATION_SEND_PARTIAL_OBJECT,
85 MTP_OPERATION_TRUNCATE_OBJECT,
86 MTP_OPERATION_BEGIN_EDIT_OBJECT,
87 MTP_OPERATION_END_EDIT_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040088};
89
Mike Lockwood873871f2010-07-12 18:54:16 -040090static const MtpEventCode kSupportedEventCodes[] = {
91 MTP_EVENT_OBJECT_ADDED,
92 MTP_EVENT_OBJECT_REMOVED,
Mike Lockwooda8494402011-02-18 09:07:14 -050093 MTP_EVENT_STORE_ADDED,
94 MTP_EVENT_STORE_REMOVED,
Mike Lockwood0fa848d2014-03-07 13:29:59 -080095 MTP_EVENT_DEVICE_PROP_CHANGED,
Mike Lockwood873871f2010-07-12 18:54:16 -040096};
97
Jerry Zhang487be612016-10-24 12:10:41 -070098MtpServer::MtpServer(MtpDatabase* database, bool ptp,
Mike Lockwood8e2a2802010-07-02 15:15:07 -040099 int fileGroup, int filePerm, int directoryPerm)
Jerry Zhang487be612016-10-24 12:10:41 -0700100 : mDatabase(database),
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400101 mPtp(ptp),
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400102 mFileGroup(fileGroup),
103 mFilePermission(filePerm),
104 mDirectoryPermission(directoryPerm),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400105 mSessionID(0),
106 mSessionOpen(false),
107 mSendObjectHandle(kInvalidObjectHandle),
Mike Lockwood4714b072010-07-12 08:49:01 -0400108 mSendObjectFormat(0),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400109 mSendObjectFileSize(0)
110{
Mike Lockwood16864ba2010-05-11 17:16:59 -0400111}
112
113MtpServer::~MtpServer() {
114}
115
Jerry Zhang487be612016-10-24 12:10:41 -0700116IMtpHandle* MtpServer::sHandle = nullptr;
117
118int MtpServer::configure(bool usePtp) {
119 if (sHandle == nullptr) {
120 bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
121 sHandle = ffs_ok ? get_ffs_handle() : get_mtp_handle();
122 }
123
124 int ret = sHandle->configure(usePtp);
125 if (ret) ALOGE("Failed to configure MTP driver!");
126 else android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
127
128 return ret;
129}
130
Mike Lockwooda8494402011-02-18 09:07:14 -0500131void MtpServer::addStorage(MtpStorage* storage) {
132 Mutex::Autolock autoLock(mMutex);
133
134 mStorages.push(storage);
135 sendStoreAdded(storage->getStorageID());
136}
137
138void MtpServer::removeStorage(MtpStorage* storage) {
139 Mutex::Autolock autoLock(mMutex);
140
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700141 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500142 if (mStorages[i] == storage) {
143 mStorages.removeAt(i);
144 sendStoreRemoved(storage->getStorageID());
145 break;
146 }
147 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400148}
149
150MtpStorage* MtpServer::getStorage(MtpStorageID id) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800151 if (id == 0)
152 return mStorages[0];
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700153 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800154 MtpStorage* storage = mStorages[i];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400155 if (storage->getStorageID() == id)
156 return storage;
157 }
Jerry Zhang487be612016-10-24 12:10:41 -0700158 return nullptr;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400159}
160
Mike Lockwooda8494402011-02-18 09:07:14 -0500161bool MtpServer::hasStorage(MtpStorageID id) {
162 if (id == 0 || id == 0xFFFFFFFF)
163 return mStorages.size() > 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700164 return (getStorage(id) != nullptr);
Mike Lockwooda8494402011-02-18 09:07:14 -0500165}
166
Mike Lockwood16864ba2010-05-11 17:16:59 -0400167void MtpServer::run() {
Jerry Zhang487be612016-10-24 12:10:41 -0700168 if (!sHandle) {
169 ALOGE("MtpServer was never configured!");
170 return;
171 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400172
Jerry Zhang487be612016-10-24 12:10:41 -0700173 if (sHandle->start()) {
174 ALOGE("Failed to start usb driver!");
175 return;
176 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400177
178 while (1) {
Jerry Zhang487be612016-10-24 12:10:41 -0700179 int ret = mRequest.read(sHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400180 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700181 ALOGE("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400182 if (errno == ECANCELED) {
183 // return to top of loop and wait for next command
184 continue;
185 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400186 break;
187 }
188 MtpOperationCode operation = mRequest.getOperationCode();
189 MtpTransactionID transaction = mRequest.getTransactionID();
190
Steve Block3856b092011-10-20 11:56:00 +0100191 ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400192 // FIXME need to generalize this
Mike Lockwood438344f2010-08-03 15:30:09 -0400193 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood8277cec2010-08-10 15:20:35 -0400194 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
195 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
196 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400197 if (dataIn) {
Jerry Zhang487be612016-10-24 12:10:41 -0700198 int ret = mData.read(sHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400199 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000200 ALOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400201 if (errno == ECANCELED) {
202 // return to top of loop and wait for next command
203 continue;
204 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400205 break;
206 }
Steve Block3856b092011-10-20 11:56:00 +0100207 ALOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400208 } else {
209 mData.reset();
210 }
211
Mike Lockwood916076c2010-06-04 09:49:21 -0400212 if (handleRequest()) {
213 if (!dataIn && mData.hasData()) {
214 mData.setOperationCode(operation);
215 mData.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100216 ALOGV("sending data:");
Jerry Zhang487be612016-10-24 12:10:41 -0700217 ret = mData.write(sHandle);
Mike Lockwood916076c2010-06-04 09:49:21 -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 }
224 break;
225 }
226 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400227
Mike Lockwood916076c2010-06-04 09:49:21 -0400228 mResponse.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100229 ALOGV("sending response %04X", mResponse.getResponseCode());
Jerry Zhang487be612016-10-24 12:10:41 -0700230 ret = mResponse.write(sHandle);
tao.pei07a9e542015-07-17 17:18:41 +0800231 const int savedErrno = errno;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400232 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000233 ALOGE("request write returned %d, errno: %d", ret, errno);
tao.pei07a9e542015-07-17 17:18:41 +0800234 if (savedErrno == ECANCELED) {
Mike Lockwood916076c2010-06-04 09:49:21 -0400235 // return to top of loop and wait for next command
236 continue;
237 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400238 break;
239 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400240 } else {
Steve Block3856b092011-10-20 11:56:00 +0100241 ALOGV("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400242 }
243 }
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400244
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700245 // commit any open edits
246 int count = mObjectEditList.size();
247 for (int i = 0; i < count; i++) {
248 ObjectEdit* edit = mObjectEditList[i];
249 commitEdit(edit);
250 delete edit;
251 }
252 mObjectEditList.clear();
253
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400254 if (mSessionOpen)
255 mDatabase->sessionEnded();
Jerry Zhang487be612016-10-24 12:10:41 -0700256
257 sHandle->close();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400258}
259
Mike Lockwood873871f2010-07-12 18:54:16 -0400260void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100261 ALOGV("sendObjectAdded %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500262 sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
Mike Lockwood873871f2010-07-12 18:54:16 -0400263}
264
265void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100266 ALOGV("sendObjectRemoved %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500267 sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
268}
269
270void MtpServer::sendStoreAdded(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100271 ALOGV("sendStoreAdded %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500272 sendEvent(MTP_EVENT_STORE_ADDED, id);
273}
274
275void MtpServer::sendStoreRemoved(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100276 ALOGV("sendStoreRemoved %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500277 sendEvent(MTP_EVENT_STORE_REMOVED, id);
278}
279
Mike Lockwood0fa848d2014-03-07 13:29:59 -0800280void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
281 ALOGV("sendDevicePropertyChanged %d\n", property);
282 sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
283}
284
Mike Lockwooda8494402011-02-18 09:07:14 -0500285void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400286 if (mSessionOpen) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500287 mEvent.setEventCode(code);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400288 mEvent.setTransactionID(mRequest.getTransactionID());
Mike Lockwooda8494402011-02-18 09:07:14 -0500289 mEvent.setParameter(1, param1);
Jerry Zhang487be612016-10-24 12:10:41 -0700290 if (mEvent.write(sHandle))
291 ALOGE("Mtp send event failed: %s", strerror(errno));
Mike Lockwood73ecd232010-07-19 14:29:58 -0400292 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400293}
294
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700295void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
296 uint64_t size, MtpObjectFormat format, int fd) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700297 ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700298 mObjectEditList.add(edit);
299}
300
301MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
302 int count = mObjectEditList.size();
303 for (int i = 0; i < count; i++) {
304 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700305 if (edit->mHandle == handle) return edit;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700306 }
Jerry Zhang487be612016-10-24 12:10:41 -0700307 return nullptr;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700308}
309
310void MtpServer::removeEditObject(MtpObjectHandle handle) {
311 int count = mObjectEditList.size();
312 for (int i = 0; i < count; i++) {
313 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700314 if (edit->mHandle == handle) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700315 delete edit;
316 mObjectEditList.removeAt(i);
317 return;
318 }
319 }
Steve Block29357bc2012-01-06 19:20:56 +0000320 ALOGE("ObjectEdit not found in removeEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700321}
322
323void MtpServer::commitEdit(ObjectEdit* edit) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700324 mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700325}
326
327
Mike Lockwood916076c2010-06-04 09:49:21 -0400328bool MtpServer::handleRequest() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500329 Mutex::Autolock autoLock(mMutex);
330
Mike Lockwood16864ba2010-05-11 17:16:59 -0400331 MtpOperationCode operation = mRequest.getOperationCode();
332 MtpResponseCode response;
333
334 mResponse.reset();
335
336 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
337 // FIXME - need to delete mSendObjectHandle from the database
Steve Block29357bc2012-01-06 19:20:56 +0000338 ALOGE("expected SendObject after SendObjectInfo");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400339 mSendObjectHandle = kInvalidObjectHandle;
340 }
341
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700342 int containertype = mRequest.getContainerType();
343 if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
344 ALOGE("wrong container type %d", containertype);
345 return false;
346 }
347
348 ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
349
Mike Lockwood16864ba2010-05-11 17:16:59 -0400350 switch (operation) {
351 case MTP_OPERATION_GET_DEVICE_INFO:
352 response = doGetDeviceInfo();
353 break;
354 case MTP_OPERATION_OPEN_SESSION:
355 response = doOpenSession();
356 break;
357 case MTP_OPERATION_CLOSE_SESSION:
358 response = doCloseSession();
359 break;
360 case MTP_OPERATION_GET_STORAGE_IDS:
361 response = doGetStorageIDs();
362 break;
363 case MTP_OPERATION_GET_STORAGE_INFO:
364 response = doGetStorageInfo();
365 break;
366 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
367 response = doGetObjectPropsSupported();
368 break;
369 case MTP_OPERATION_GET_OBJECT_HANDLES:
370 response = doGetObjectHandles();
371 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400372 case MTP_OPERATION_GET_NUM_OBJECTS:
373 response = doGetNumObjects();
374 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400375 case MTP_OPERATION_GET_OBJECT_REFERENCES:
376 response = doGetObjectReferences();
377 break;
378 case MTP_OPERATION_SET_OBJECT_REFERENCES:
379 response = doSetObjectReferences();
380 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400381 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
382 response = doGetObjectPropValue();
383 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400384 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
385 response = doSetObjectPropValue();
386 break;
387 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
388 response = doGetDevicePropValue();
389 break;
390 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
391 response = doSetDevicePropValue();
392 break;
393 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
394 response = doResetDevicePropValue();
395 break;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400396 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
397 response = doGetObjectPropList();
398 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400399 case MTP_OPERATION_GET_OBJECT_INFO:
400 response = doGetObjectInfo();
401 break;
402 case MTP_OPERATION_GET_OBJECT:
403 response = doGetObject();
404 break;
Mike Lockwood64000782011-04-24 18:40:17 -0700405 case MTP_OPERATION_GET_THUMB:
406 response = doGetThumb();
407 break;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500408 case MTP_OPERATION_GET_PARTIAL_OBJECT:
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700409 case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
410 response = doGetPartialObject(operation);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500411 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400412 case MTP_OPERATION_SEND_OBJECT_INFO:
413 response = doSendObjectInfo();
414 break;
415 case MTP_OPERATION_SEND_OBJECT:
416 response = doSendObject();
417 break;
418 case MTP_OPERATION_DELETE_OBJECT:
419 response = doDeleteObject();
420 break;
421 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400422 response = doGetObjectPropDesc();
423 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400424 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
425 response = doGetDevicePropDesc();
426 break;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700427 case MTP_OPERATION_SEND_PARTIAL_OBJECT:
428 response = doSendPartialObject();
429 break;
430 case MTP_OPERATION_TRUNCATE_OBJECT:
431 response = doTruncateObject();
432 break;
433 case MTP_OPERATION_BEGIN_EDIT_OBJECT:
434 response = doBeginEditObject();
435 break;
436 case MTP_OPERATION_END_EDIT_OBJECT:
437 response = doEndEditObject();
438 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400439 default:
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700440 ALOGE("got unsupported command %s (%x)",
441 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400442 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
443 break;
444 }
445
Mike Lockwood916076c2010-06-04 09:49:21 -0400446 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
447 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400448 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400449 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400450}
451
452MtpResponseCode MtpServer::doGetDeviceInfo() {
453 MtpStringBuffer string;
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700454 char prop_value[PROPERTY_VALUE_MAX];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400455
Mike Lockwood782aef12010-08-10 07:37:50 -0400456 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
457 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
458 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
459
Mike Lockwood16864ba2010-05-11 17:16:59 -0400460 // fill in device info
461 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400462 if (mPtp) {
463 mData.putUInt32(0);
464 } else {
465 // MTP Vendor Extension ID
466 mData.putUInt32(6);
467 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400468 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400469 if (mPtp) {
470 // no extensions
471 string.set("");
472 } else {
473 // MTP extensions
474 string.set("microsoft.com: 1.0; android.com: 1.0;");
475 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400476 mData.putString(string); // MTP Extensions
477 mData.putUInt16(0); //Functional Mode
478 mData.putAUInt16(kSupportedOperationCodes,
479 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400480 mData.putAUInt16(kSupportedEventCodes,
481 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400482 mData.putAUInt16(deviceProperties); // Device Properties Supported
483 mData.putAUInt16(captureFormats); // Capture Formats
484 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500485
486 property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
487 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400488 mData.putString(string); // Manufacturer
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700489
490 property_get("ro.product.model", prop_value, "MTP Device");
491 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400492 mData.putString(string); // Model
493 string.set("1.0");
494 mData.putString(string); // Device Version
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700495
496 property_get("ro.serialno", prop_value, "????????");
497 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400498 mData.putString(string); // Serial Number
499
Mike Lockwood782aef12010-08-10 07:37:50 -0400500 delete playbackFormats;
501 delete captureFormats;
502 delete deviceProperties;
503
Mike Lockwood16864ba2010-05-11 17:16:59 -0400504 return MTP_RESPONSE_OK;
505}
506
507MtpResponseCode MtpServer::doOpenSession() {
508 if (mSessionOpen) {
509 mResponse.setParameter(1, mSessionID);
510 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
511 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800512 if (mRequest.getParameterCount() < 1)
513 return MTP_RESPONSE_INVALID_PARAMETER;
514
Mike Lockwood16864ba2010-05-11 17:16:59 -0400515 mSessionID = mRequest.getParameter(1);
516 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400517
518 mDatabase->sessionStarted();
519
Mike Lockwood16864ba2010-05-11 17:16:59 -0400520 return MTP_RESPONSE_OK;
521}
522
523MtpResponseCode MtpServer::doCloseSession() {
524 if (!mSessionOpen)
525 return MTP_RESPONSE_SESSION_NOT_OPEN;
526 mSessionID = 0;
527 mSessionOpen = false;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400528 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400529 return MTP_RESPONSE_OK;
530}
531
532MtpResponseCode MtpServer::doGetStorageIDs() {
533 if (!mSessionOpen)
534 return MTP_RESPONSE_SESSION_NOT_OPEN;
535
536 int count = mStorages.size();
537 mData.putUInt32(count);
538 for (int i = 0; i < count; i++)
539 mData.putUInt32(mStorages[i]->getStorageID());
540
541 return MTP_RESPONSE_OK;
542}
543
544MtpResponseCode MtpServer::doGetStorageInfo() {
545 MtpStringBuffer string;
546
547 if (!mSessionOpen)
548 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800549 if (mRequest.getParameterCount() < 1)
550 return MTP_RESPONSE_INVALID_PARAMETER;
551
Mike Lockwood16864ba2010-05-11 17:16:59 -0400552 MtpStorageID id = mRequest.getParameter(1);
553 MtpStorage* storage = getStorage(id);
554 if (!storage)
555 return MTP_RESPONSE_INVALID_STORAGE_ID;
556
557 mData.putUInt16(storage->getType());
558 mData.putUInt16(storage->getFileSystemType());
559 mData.putUInt16(storage->getAccessCapability());
560 mData.putUInt64(storage->getMaxCapacity());
561 mData.putUInt64(storage->getFreeSpace());
562 mData.putUInt32(1024*1024*1024); // Free Space in Objects
563 string.set(storage->getDescription());
564 mData.putString(string);
565 mData.putEmptyString(); // Volume Identifier
566
567 return MTP_RESPONSE_OK;
568}
569
570MtpResponseCode MtpServer::doGetObjectPropsSupported() {
571 if (!mSessionOpen)
572 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800573 if (mRequest.getParameterCount() < 1)
574 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400575 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800576 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400577 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400578 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400579 return MTP_RESPONSE_OK;
580}
581
582MtpResponseCode MtpServer::doGetObjectHandles() {
583 if (!mSessionOpen)
584 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800585 if (mRequest.getParameterCount() < 3)
586 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400587 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400588 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400589 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400590 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500591
592 if (!hasStorage(storageID))
593 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400594
595 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
596 mData.putAUInt32(handles);
597 delete handles;
598 return MTP_RESPONSE_OK;
599}
600
Mike Lockwood343af4e2010-08-02 10:52:20 -0400601MtpResponseCode MtpServer::doGetNumObjects() {
602 if (!mSessionOpen)
603 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800604 if (mRequest.getParameterCount() < 3)
605 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400606 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
607 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
608 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400609 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500610 if (!hasStorage(storageID))
611 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400612
613 int count = mDatabase->getNumObjects(storageID, format, parent);
614 if (count >= 0) {
615 mResponse.setParameter(1, count);
616 return MTP_RESPONSE_OK;
617 } else {
618 mResponse.setParameter(1, 0);
619 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
620 }
621}
622
Mike Lockwood438344f2010-08-03 15:30:09 -0400623MtpResponseCode MtpServer::doGetObjectReferences() {
624 if (!mSessionOpen)
625 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500626 if (!hasStorage())
627 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800628 if (mRequest.getParameterCount() < 1)
629 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500630 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400631
632 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400633 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400634 if (handles) {
635 mData.putAUInt32(handles);
636 delete handles;
637 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400638 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400639 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400640 return MTP_RESPONSE_OK;
641}
642
643MtpResponseCode MtpServer::doSetObjectReferences() {
644 if (!mSessionOpen)
645 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500646 if (!hasStorage())
647 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800648 if (mRequest.getParameterCount() < 1)
649 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400650 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500651
Mike Lockwood438344f2010-08-03 15:30:09 -0400652 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800653 if (!references)
654 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400655 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
656 delete references;
657 return result;
658}
659
Mike Lockwood16864ba2010-05-11 17:16:59 -0400660MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500661 if (!hasStorage())
662 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800663 if (mRequest.getParameterCount() < 2)
664 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400665 MtpObjectHandle handle = mRequest.getParameter(1);
666 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100667 ALOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400668 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400669
Mike Lockwood8277cec2010-08-10 15:20:35 -0400670 return mDatabase->getObjectPropertyValue(handle, property, mData);
671}
672
673MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500674 if (!hasStorage())
675 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800676 if (mRequest.getParameterCount() < 2)
677 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400678 MtpObjectHandle handle = mRequest.getParameter(1);
679 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100680 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400681 MtpDebug::getObjectPropCodeName(property));
682
683 return mDatabase->setObjectPropertyValue(handle, property, mData);
684}
685
686MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800687 if (mRequest.getParameterCount() < 1)
688 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400689 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100690 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400691 MtpDebug::getDevicePropCodeName(property));
692
693 return mDatabase->getDevicePropertyValue(property, mData);
694}
695
696MtpResponseCode MtpServer::doSetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800697 if (mRequest.getParameterCount() < 1)
698 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400699 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100700 ALOGV("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400701 MtpDebug::getDevicePropCodeName(property));
702
703 return mDatabase->setDevicePropertyValue(property, mData);
704}
705
706MtpResponseCode MtpServer::doResetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800707 if (mRequest.getParameterCount() < 1)
708 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400709 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100710 ALOGV("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400711 MtpDebug::getDevicePropCodeName(property));
712
713 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400714}
715
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400716MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500717 if (!hasStorage())
718 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800719 if (mRequest.getParameterCount() < 5)
720 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400721
722 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500723 // use uint32_t so we can support 0xFFFFFFFF
724 uint32_t format = mRequest.getParameter(2);
725 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400726 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500727 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100728 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400729 handle, MtpDebug::getFormatCodeName(format),
730 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
731
732 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
733}
734
Mike Lockwood16864ba2010-05-11 17:16:59 -0400735MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500736 if (!hasStorage())
737 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800738 if (mRequest.getParameterCount() < 1)
739 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400740 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700741 MtpObjectInfo info(handle);
742 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
743 if (result == MTP_RESPONSE_OK) {
744 char date[20];
745
746 mData.putUInt32(info.mStorageID);
747 mData.putUInt16(info.mFormat);
748 mData.putUInt16(info.mProtectionStatus);
749
750 // if object is being edited the database size may be out of date
751 uint32_t size = info.mCompressedSize;
752 ObjectEdit* edit = getEditObject(handle);
753 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700754 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700755 mData.putUInt32(size);
756
757 mData.putUInt16(info.mThumbFormat);
758 mData.putUInt32(info.mThumbCompressedSize);
759 mData.putUInt32(info.mThumbPixWidth);
760 mData.putUInt32(info.mThumbPixHeight);
761 mData.putUInt32(info.mImagePixWidth);
762 mData.putUInt32(info.mImagePixHeight);
763 mData.putUInt32(info.mImagePixDepth);
764 mData.putUInt32(info.mParent);
765 mData.putUInt16(info.mAssociationType);
766 mData.putUInt32(info.mAssociationDesc);
767 mData.putUInt32(info.mSequenceNumber);
768 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700769 formatDateTime(info.mDateCreated, date, sizeof(date));
770 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700771 formatDateTime(info.mDateModified, date, sizeof(date));
772 mData.putString(date); // date modified
773 mData.putEmptyString(); // keywords
774 }
775 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400776}
777
778MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500779 if (!hasStorage())
780 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800781 if (mRequest.getParameterCount() < 1)
782 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400783 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400784 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400785 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800786 MtpObjectFormat format;
787 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400788 if (result != MTP_RESPONSE_OK)
789 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400790
Jerry Zhang487be612016-10-24 12:10:41 -0700791 auto start = std::chrono::steady_clock::now();
792
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400793 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400794 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400795 mfr.fd = open(filePath, O_RDONLY);
796 if (mfr.fd < 0) {
797 return MTP_RESPONSE_GENERAL_ERROR;
798 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400799 mfr.offset = 0;
800 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400801 mfr.command = mRequest.getOperationCode();
802 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400803
804 // then transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700805 int ret = sHandle->sendFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +0800806 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700807 ALOGE("Mtp send file got error %s", strerror(errno));
tao.pei07a9e542015-07-17 17:18:41 +0800808 if (errno == ECANCELED) {
809 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
810 } else {
811 result = MTP_RESPONSE_GENERAL_ERROR;
812 }
813 } else {
814 result = MTP_RESPONSE_OK;
815 }
816
Jerry Zhang487be612016-10-24 12:10:41 -0700817 auto end = std::chrono::steady_clock::now();
818 std::chrono::duration<double> diff = end - start;
819 struct stat sstat;
820 fstat(mfr.fd, &sstat);
821 uint64_t finalsize = sstat.st_size;
822 ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
823 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwoodc6588762010-06-22 15:03:53 -0400824 close(mfr.fd);
tao.pei07a9e542015-07-17 17:18:41 +0800825 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400826}
827
Mike Lockwood64000782011-04-24 18:40:17 -0700828MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800829 if (mRequest.getParameterCount() < 1)
830 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700831 MtpObjectHandle handle = mRequest.getParameter(1);
832 size_t thumbSize;
833 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
834 if (thumb) {
835 // send data
836 mData.setOperationCode(mRequest.getOperationCode());
837 mData.setTransactionID(mRequest.getTransactionID());
Jerry Zhang487be612016-10-24 12:10:41 -0700838 mData.writeData(sHandle, thumb, thumbSize);
Mike Lockwood64000782011-04-24 18:40:17 -0700839 free(thumb);
840 return MTP_RESPONSE_OK;
841 } else {
842 return MTP_RESPONSE_GENERAL_ERROR;
843 }
844}
845
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700846MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500847 if (!hasStorage())
848 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500849 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700850 uint64_t offset;
851 uint32_t length;
852 offset = mRequest.getParameter(2);
853 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800854 // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
855 if (mRequest.getParameterCount() < 4)
856 return MTP_RESPONSE_INVALID_PARAMETER;
857
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700858 // android extension with 64 bit offset
859 uint64_t offset2 = mRequest.getParameter(3);
860 offset = offset | (offset2 << 32);
861 length = mRequest.getParameter(4);
862 } else {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800863 // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
864 if (mRequest.getParameterCount() < 3)
865 return MTP_RESPONSE_INVALID_PARAMETER;
866
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700867 // standard GetPartialObject
868 length = mRequest.getParameter(3);
869 }
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500870 MtpString pathBuf;
871 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800872 MtpObjectFormat format;
873 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500874 if (result != MTP_RESPONSE_OK)
875 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700876 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500877 length = fileLength - offset;
878
879 const char* filePath = (const char *)pathBuf;
880 mtp_file_range mfr;
881 mfr.fd = open(filePath, O_RDONLY);
882 if (mfr.fd < 0) {
883 return MTP_RESPONSE_GENERAL_ERROR;
884 }
885 mfr.offset = offset;
886 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400887 mfr.command = mRequest.getOperationCode();
888 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500889 mResponse.setParameter(1, length);
890
Mike Lockwoodef441d92011-07-14 21:00:02 -0400891 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700892 int ret = sHandle->sendFile(mfr);
Steve Block3856b092011-10-20 11:56:00 +0100893 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
tao.pei07a9e542015-07-17 17:18:41 +0800894 result = MTP_RESPONSE_OK;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500895 if (ret < 0) {
896 if (errno == ECANCELED)
tao.pei07a9e542015-07-17 17:18:41 +0800897 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500898 else
tao.pei07a9e542015-07-17 17:18:41 +0800899 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500900 }
tao.pei07a9e542015-07-17 17:18:41 +0800901 close(mfr.fd);
902 return result;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500903}
904
Mike Lockwood16864ba2010-05-11 17:16:59 -0400905MtpResponseCode MtpServer::doSendObjectInfo() {
906 MtpString path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800907 uint16_t temp16;
908 uint32_t temp32;
909
910 if (mRequest.getParameterCount() < 2)
911 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400912 MtpStorageID storageID = mRequest.getParameter(1);
913 MtpStorage* storage = getStorage(storageID);
914 MtpObjectHandle parent = mRequest.getParameter(2);
915 if (!storage)
916 return MTP_RESPONSE_INVALID_STORAGE_ID;
917
918 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400919 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400920 path = storage->getPath();
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400921 parent = 0;
922 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800923 int64_t length;
924 MtpObjectFormat format;
925 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400926 if (result != MTP_RESPONSE_OK)
927 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800928 if (format != MTP_FORMAT_ASSOCIATION)
929 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400930 }
931
932 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800933 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
934 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
935 MtpObjectFormat format = temp16;
936 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
937 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
938 mSendObjectFileSize = temp32;
939 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
940 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
941 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
942 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
943 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
944 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
945 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
946 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
947 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800948 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800949 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400950 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800951 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
Marco Nelissen7ea72dc2016-09-19 14:08:16 -0700952 if (name.getCharCount() == 0) {
953 ALOGE("empty name");
954 return MTP_RESPONSE_INVALID_PARAMETER;
955 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800956 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
957 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400958 // keywords follow
959
Steve Block3856b092011-10-20 11:56:00 +0100960 ALOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400961 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400962 if (!parseDateTime(modified, modifiedTime))
963 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400964
965 if (path[path.size() - 1] != '/')
966 path += "/";
967 path += (const char *)name;
968
Mike Lockwood20c3be02010-12-12 12:17:43 -0800969 // check space first
970 if (mSendObjectFileSize > storage->getFreeSpace())
971 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400972 uint64_t maxFileSize = storage->getMaxFileSize();
973 // check storage max file size
974 if (maxFileSize != 0) {
975 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
976 // is >= 0xFFFFFFFF
977 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
978 return MTP_RESPONSE_OBJECT_TOO_LARGE;
979 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800980
Steve Blockb8a80522011-12-20 16:23:08 +0000981 ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Mike Lockwood4714b072010-07-12 08:49:01 -0400982 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
983 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400984 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400985 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400986 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400987
988 if (format == MTP_FORMAT_ASSOCIATION) {
989 mode_t mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400990 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400991 umask(mask);
992 if (ret && ret != -EEXIST)
993 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400994 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwoodaa952402011-01-18 11:06:19 -0800995
996 // SendObject does not get sent for directories, so call endSendObject here instead
997 mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400998 } else {
999 mSendObjectFilePath = path;
1000 // save the handle for the SendObject call, which should follow
1001 mSendObjectHandle = handle;
Mike Lockwood4714b072010-07-12 08:49:01 -04001002 mSendObjectFormat = format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001003 }
1004
1005 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001006 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001007 mResponse.setParameter(3, handle);
1008
1009 return MTP_RESPONSE_OK;
1010}
1011
1012MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001013 if (!hasStorage())
1014 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -04001015 MtpResponseCode result = MTP_RESPONSE_OK;
1016 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001017 int ret, initialData;
tao.pei07a9e542015-07-17 17:18:41 +08001018 bool isCanceled = false;
Mike Lockwood4714b072010-07-12 08:49:01 -04001019
Jerry Zhang487be612016-10-24 12:10:41 -07001020 auto start = std::chrono::steady_clock::now();
1021
Mike Lockwood16864ba2010-05-11 17:16:59 -04001022 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +00001023 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -04001024 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
1025 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001026 }
1027
Mike Lockwoodef441d92011-07-14 21:00:02 -04001028 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001029 ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001030 if (ret < MTP_CONTAINER_HEADER_SIZE) {
1031 result = MTP_RESPONSE_GENERAL_ERROR;
1032 goto done;
1033 }
1034 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001035
1036 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -07001037 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001038 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001039 result = MTP_RESPONSE_GENERAL_ERROR;
1040 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001041 }
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001042 fchown(mfr.fd, getuid(), mFileGroup);
1043 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001044 mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001045 fchmod(mfr.fd, mFilePermission);
1046 umask(mask);
1047
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001048 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001049 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001050 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001051
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001052 if (ret < 0) {
1053 ALOGE("failed to write initial data");
1054 result = MTP_RESPONSE_GENERAL_ERROR;
1055 } else {
1056 if (mSendObjectFileSize - initialData > 0) {
1057 mfr.offset = initialData;
1058 if (mSendObjectFileSize == 0xFFFFFFFF) {
1059 // tell driver to read until it receives a short packet
1060 mfr.length = 0xFFFFFFFF;
1061 } else {
1062 mfr.length = mSendObjectFileSize - initialData;
1063 }
1064
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001065 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -07001066 ret = sHandle->receiveFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +08001067 if ((ret < 0) && (errno == ECANCELED)) {
1068 isCanceled = true;
1069 }
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001070 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001071 }
Jerry Zhang487be612016-10-24 12:10:41 -07001072 struct stat sstat;
1073 fstat(mfr.fd, &sstat);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001074 close(mfr.fd);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001075
Mike Lockwood916076c2010-06-04 09:49:21 -04001076 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -07001077 ALOGE("Mtp receive file got error %s", strerror(errno));
Mike Lockwood916076c2010-06-04 09:49:21 -04001078 unlink(mSendObjectFilePath);
tao.pei07a9e542015-07-17 17:18:41 +08001079 if (isCanceled)
Mike Lockwood4714b072010-07-12 08:49:01 -04001080 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001081 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001082 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001083 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001084
1085done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001086 // reset so we don't attempt to send the data back
1087 mData.reset();
1088
Mike Lockwood4714b072010-07-12 08:49:01 -04001089 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
Mike Lockwoodaa952402011-01-18 11:06:19 -08001090 result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001091 mSendObjectHandle = kInvalidObjectHandle;
1092 mSendObjectFormat = 0;
Jerry Zhang487be612016-10-24 12:10:41 -07001093
1094 auto end = std::chrono::steady_clock::now();
1095 std::chrono::duration<double> diff = end - start;
1096 uint64_t finalsize = sstat.st_size;
1097 ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
1098 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwood4714b072010-07-12 08:49:01 -04001099 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001100}
1101
Mike Lockwoodd3211492010-09-13 17:15:58 -04001102static void deleteRecursive(const char* path) {
1103 char pathbuf[PATH_MAX];
Mark Salyzynd239cb62014-06-18 16:32:27 -07001104 size_t pathLength = strlen(path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001105 if (pathLength >= sizeof(pathbuf) - 1) {
Steve Block29357bc2012-01-06 19:20:56 +00001106 ALOGE("path too long: %s\n", path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001107 }
1108 strcpy(pathbuf, path);
1109 if (pathbuf[pathLength - 1] != '/') {
1110 pathbuf[pathLength++] = '/';
1111 }
1112 char* fileSpot = pathbuf + pathLength;
1113 int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1114
1115 DIR* dir = opendir(path);
1116 if (!dir) {
Steve Block29357bc2012-01-06 19:20:56 +00001117 ALOGE("opendir %s failed: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001118 return;
1119 }
1120
1121 struct dirent* entry;
1122 while ((entry = readdir(dir))) {
1123 const char* name = entry->d_name;
1124
1125 // ignore "." and ".."
1126 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1127 continue;
1128 }
1129
1130 int nameLength = strlen(name);
1131 if (nameLength > pathRemaining) {
Steve Block29357bc2012-01-06 19:20:56 +00001132 ALOGE("path %s/%s too long\n", path, name);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001133 continue;
1134 }
1135 strcpy(fileSpot, name);
1136
Mike Lockwoodd3211492010-09-13 17:15:58 -04001137 if (entry->d_type == DT_DIR) {
1138 deleteRecursive(pathbuf);
1139 rmdir(pathbuf);
1140 } else {
1141 unlink(pathbuf);
1142 }
1143 }
Mike Lockwood7ce05cf2010-11-11 11:22:32 -05001144 closedir(dir);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001145}
1146
1147static void deletePath(const char* path) {
1148 struct stat statbuf;
1149 if (stat(path, &statbuf) == 0) {
1150 if (S_ISDIR(statbuf.st_mode)) {
1151 deleteRecursive(path);
1152 rmdir(path);
1153 } else {
1154 unlink(path);
1155 }
1156 } else {
Steve Block29357bc2012-01-06 19:20:56 +00001157 ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001158 }
1159}
1160
Mike Lockwood16864ba2010-05-11 17:16:59 -04001161MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001162 if (!hasStorage())
1163 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Marco Nelissenea9f2152015-01-23 10:55:25 -08001164 if (mRequest.getParameterCount() < 1)
Mike Lockwoodab063842014-11-12 14:20:06 -08001165 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001166 MtpObjectHandle handle = mRequest.getParameter(1);
Marco Nelissenea9f2152015-01-23 10:55:25 -08001167 MtpObjectFormat format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001168 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1169 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001170
1171 MtpString filePath;
1172 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001173 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001174 if (result == MTP_RESPONSE_OK) {
Steve Block3856b092011-10-20 11:56:00 +01001175 ALOGV("deleting %s", (const char *)filePath);
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001176 result = mDatabase->deleteFile(handle);
1177 // Don't delete the actual files unless the database deletion is allowed
1178 if (result == MTP_RESPONSE_OK) {
1179 deletePath((const char *)filePath);
1180 }
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001181 }
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001182
1183 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001184}
1185
1186MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001187 if (mRequest.getParameterCount() < 2)
1188 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001189 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001190 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001191 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001192 MtpDebug::getFormatCodeName(format));
1193 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001194 if (!property)
1195 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001196 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001197 delete property;
1198 return MTP_RESPONSE_OK;
1199}
1200
1201MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001202 if (mRequest.getParameterCount() < 1)
1203 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001204 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001205 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001206 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1207 if (!property)
1208 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1209 property->write(mData);
1210 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001211 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001212}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001213
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001214MtpResponseCode MtpServer::doSendPartialObject() {
1215 if (!hasStorage())
1216 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001217 if (mRequest.getParameterCount() < 4)
1218 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001219 MtpObjectHandle handle = mRequest.getParameter(1);
1220 uint64_t offset = mRequest.getParameter(2);
1221 uint64_t offset2 = mRequest.getParameter(3);
1222 offset = offset | (offset2 << 32);
1223 uint32_t length = mRequest.getParameter(4);
1224
1225 ObjectEdit* edit = getEditObject(handle);
1226 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001227 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001228 return MTP_RESPONSE_GENERAL_ERROR;
1229 }
1230
1231 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001232 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001233 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1234 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001235 return MTP_RESPONSE_GENERAL_ERROR;
1236 }
1237
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001238 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001239 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001240
Mike Lockwoodef441d92011-07-14 21:00:02 -04001241 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001242 int ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001243 if (ret < MTP_CONTAINER_HEADER_SIZE)
1244 return MTP_RESPONSE_GENERAL_ERROR;
1245 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1246
1247 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001248 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001249 offset += initialData;
1250 length -= initialData;
1251 }
1252
tao.pei07a9e542015-07-17 17:18:41 +08001253 bool isCanceled = false;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001254 if (ret < 0) {
1255 ALOGE("failed to write initial data");
1256 } else {
1257 if (length > 0) {
1258 mtp_file_range mfr;
1259 mfr.fd = edit->mFD;
1260 mfr.offset = offset;
1261 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001262
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001263 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -07001264 ret = sHandle->receiveFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +08001265 if ((ret < 0) && (errno == ECANCELED)) {
1266 isCanceled = true;
1267 }
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001268 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001269 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001270 if (ret < 0) {
1271 mResponse.setParameter(1, 0);
tao.pei07a9e542015-07-17 17:18:41 +08001272 if (isCanceled)
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001273 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1274 else
1275 return MTP_RESPONSE_GENERAL_ERROR;
1276 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001277
1278 // reset so we don't attempt to send this back
1279 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001280 mResponse.setParameter(1, length);
1281 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001282 if (end > edit->mSize) {
1283 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001284 }
1285 return MTP_RESPONSE_OK;
1286}
1287
1288MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001289 if (mRequest.getParameterCount() < 3)
1290 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001291 MtpObjectHandle handle = mRequest.getParameter(1);
1292 ObjectEdit* edit = getEditObject(handle);
1293 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001294 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001295 return MTP_RESPONSE_GENERAL_ERROR;
1296 }
1297
1298 uint64_t offset = mRequest.getParameter(2);
1299 uint64_t offset2 = mRequest.getParameter(3);
1300 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001301 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001302 return MTP_RESPONSE_GENERAL_ERROR;
1303 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001304 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001305 return MTP_RESPONSE_OK;
1306 }
1307}
1308
1309MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001310 if (mRequest.getParameterCount() < 1)
1311 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001312 MtpObjectHandle handle = mRequest.getParameter(1);
1313 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001314 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001315 return MTP_RESPONSE_GENERAL_ERROR;
1316 }
1317
1318 MtpString path;
1319 int64_t fileLength;
1320 MtpObjectFormat format;
1321 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1322 if (result != MTP_RESPONSE_OK)
1323 return result;
1324
1325 int fd = open((const char *)path, O_RDWR | O_EXCL);
1326 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001327 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001328 return MTP_RESPONSE_GENERAL_ERROR;
1329 }
1330
1331 addEditObject(handle, path, fileLength, format, fd);
1332 return MTP_RESPONSE_OK;
1333}
1334
1335MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001336 if (mRequest.getParameterCount() < 1)
1337 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001338 MtpObjectHandle handle = mRequest.getParameter(1);
1339 ObjectEdit* edit = getEditObject(handle);
1340 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001341 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001342 return MTP_RESPONSE_GENERAL_ERROR;
1343 }
1344
1345 commitEdit(edit);
1346 removeEditObject(handle);
1347 return MTP_RESPONSE_OK;
1348}
1349
Mike Lockwood7850ef92010-05-14 10:10:36 -04001350} // namespace android