blob: 8d56c167b18f51fd05e39b5c55d154fd9e1de3b0 [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>
Jerry Zhang487be612016-10-24 12:10:41 -070019#include <dirent.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <inttypes.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040023#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040026#include <sys/stat.h>
Mike Lockwoodd3211492010-09-13 17:15:58 -040027#include <sys/stat.h>
Mike Lockwoodc42aa122010-06-14 17:58:08 -070028
Mike Lockwooda881b442010-09-23 22:32:05 -040029#define LOG_TAG "MtpServer"
30
Mike Lockwood16864ba2010-05-11 17:16:59 -040031#include "MtpDebug.h"
Mike Lockwood7f53a192010-07-09 10:45:22 -040032#include "MtpDatabase.h"
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070033#include "MtpObjectInfo.h"
Mike Lockwood21ef7d02010-06-30 17:00:35 -040034#include "MtpProperty.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040035#include "MtpServer.h"
36#include "MtpStorage.h"
37#include "MtpStringBuffer.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040038
Mike Lockwood7850ef92010-05-14 10:10:36 -040039namespace android {
40
Mike Lockwood16864ba2010-05-11 17:16:59 -040041static const MtpOperationCode kSupportedOperationCodes[] = {
42 MTP_OPERATION_GET_DEVICE_INFO,
43 MTP_OPERATION_OPEN_SESSION,
44 MTP_OPERATION_CLOSE_SESSION,
45 MTP_OPERATION_GET_STORAGE_IDS,
46 MTP_OPERATION_GET_STORAGE_INFO,
47 MTP_OPERATION_GET_NUM_OBJECTS,
48 MTP_OPERATION_GET_OBJECT_HANDLES,
49 MTP_OPERATION_GET_OBJECT_INFO,
50 MTP_OPERATION_GET_OBJECT,
Mike Lockwood64000782011-04-24 18:40:17 -070051 MTP_OPERATION_GET_THUMB,
Mike Lockwood16864ba2010-05-11 17:16:59 -040052 MTP_OPERATION_DELETE_OBJECT,
53 MTP_OPERATION_SEND_OBJECT_INFO,
54 MTP_OPERATION_SEND_OBJECT,
55// MTP_OPERATION_INITIATE_CAPTURE,
56// MTP_OPERATION_FORMAT_STORE,
57// MTP_OPERATION_RESET_DEVICE,
58// MTP_OPERATION_SELF_TEST,
59// MTP_OPERATION_SET_OBJECT_PROTECTION,
60// MTP_OPERATION_POWER_DOWN,
Mike Lockwoode3e76c42010-09-02 14:57:30 -040061 MTP_OPERATION_GET_DEVICE_PROP_DESC,
Mike Lockwood8277cec2010-08-10 15:20:35 -040062 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
63 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
64 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040065// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
66// MTP_OPERATION_MOVE_OBJECT,
67// MTP_OPERATION_COPY_OBJECT,
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -050068 MTP_OPERATION_GET_PARTIAL_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040069// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
70 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
Mike Lockwood8277cec2010-08-10 15:20:35 -040071 MTP_OPERATION_GET_OBJECT_PROP_DESC,
Mike Lockwood677f5702010-09-23 23:04:28 -040072 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
73 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
Mike Lockwoodb6da06e2010-10-14 18:03:25 -040074 MTP_OPERATION_GET_OBJECT_PROP_LIST,
75// MTP_OPERATION_SET_OBJECT_PROP_LIST,
76// MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
77// MTP_OPERATION_SEND_OBJECT_PROP_LIST,
Mike Lockwood438344f2010-08-03 15:30:09 -040078 MTP_OPERATION_GET_OBJECT_REFERENCES,
79 MTP_OPERATION_SET_OBJECT_REFERENCES,
Mike Lockwood16864ba2010-05-11 17:16:59 -040080// MTP_OPERATION_SKIP,
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070081 // Android extension for direct file IO
82 MTP_OPERATION_GET_PARTIAL_OBJECT_64,
83 MTP_OPERATION_SEND_PARTIAL_OBJECT,
84 MTP_OPERATION_TRUNCATE_OBJECT,
85 MTP_OPERATION_BEGIN_EDIT_OBJECT,
86 MTP_OPERATION_END_EDIT_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040087};
88
Mike Lockwood873871f2010-07-12 18:54:16 -040089static const MtpEventCode kSupportedEventCodes[] = {
90 MTP_EVENT_OBJECT_ADDED,
91 MTP_EVENT_OBJECT_REMOVED,
Mike Lockwooda8494402011-02-18 09:07:14 -050092 MTP_EVENT_STORE_ADDED,
93 MTP_EVENT_STORE_REMOVED,
Mike Lockwood0fa848d2014-03-07 13:29:59 -080094 MTP_EVENT_DEVICE_PROP_CHANGED,
Mike Lockwood873871f2010-07-12 18:54:16 -040095};
96
Jerry Zhang487be612016-10-24 12:10:41 -070097MtpServer::MtpServer(MtpDatabase* database, bool ptp,
Alex Klyubin792298f2016-12-21 11:20:22 -080098 int fileGroup, int filePerm, int directoryPerm,
99 const MtpString& deviceInfoManufacturer,
100 const MtpString& deviceInfoModel,
101 const MtpString& deviceInfoDeviceVersion,
102 const MtpString& deviceInfoSerialNumber)
Jerry Zhang487be612016-10-24 12:10:41 -0700103 : 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),
Alex Klyubin792298f2016-12-21 11:20:22 -0800108 mDeviceInfoManufacturer(deviceInfoManufacturer),
109 mDeviceInfoModel(deviceInfoModel),
110 mDeviceInfoDeviceVersion(deviceInfoDeviceVersion),
111 mDeviceInfoSerialNumber(deviceInfoSerialNumber),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400112 mSessionID(0),
113 mSessionOpen(false),
114 mSendObjectHandle(kInvalidObjectHandle),
Mike Lockwood4714b072010-07-12 08:49:01 -0400115 mSendObjectFormat(0),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400116 mSendObjectFileSize(0)
117{
Mike Lockwood16864ba2010-05-11 17:16:59 -0400118}
119
120MtpServer::~MtpServer() {
121}
122
Jerry Zhang487be612016-10-24 12:10:41 -0700123IMtpHandle* MtpServer::sHandle = nullptr;
124
125int MtpServer::configure(bool usePtp) {
126 if (sHandle == nullptr) {
127 bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
128 sHandle = ffs_ok ? get_ffs_handle() : get_mtp_handle();
129 }
130
131 int ret = sHandle->configure(usePtp);
132 if (ret) ALOGE("Failed to configure MTP driver!");
133 else android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
134
135 return ret;
136}
137
Mike Lockwooda8494402011-02-18 09:07:14 -0500138void MtpServer::addStorage(MtpStorage* storage) {
139 Mutex::Autolock autoLock(mMutex);
140
141 mStorages.push(storage);
142 sendStoreAdded(storage->getStorageID());
143}
144
145void MtpServer::removeStorage(MtpStorage* storage) {
146 Mutex::Autolock autoLock(mMutex);
147
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700148 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500149 if (mStorages[i] == storage) {
150 mStorages.removeAt(i);
151 sendStoreRemoved(storage->getStorageID());
152 break;
153 }
154 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400155}
156
157MtpStorage* MtpServer::getStorage(MtpStorageID id) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800158 if (id == 0)
159 return mStorages[0];
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700160 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800161 MtpStorage* storage = mStorages[i];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400162 if (storage->getStorageID() == id)
163 return storage;
164 }
Jerry Zhang487be612016-10-24 12:10:41 -0700165 return nullptr;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400166}
167
Mike Lockwooda8494402011-02-18 09:07:14 -0500168bool MtpServer::hasStorage(MtpStorageID id) {
169 if (id == 0 || id == 0xFFFFFFFF)
170 return mStorages.size() > 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700171 return (getStorage(id) != nullptr);
Mike Lockwooda8494402011-02-18 09:07:14 -0500172}
173
Mike Lockwood16864ba2010-05-11 17:16:59 -0400174void MtpServer::run() {
Jerry Zhang487be612016-10-24 12:10:41 -0700175 if (!sHandle) {
176 ALOGE("MtpServer was never configured!");
177 return;
178 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400179
Jerry Zhang487be612016-10-24 12:10:41 -0700180 if (sHandle->start()) {
181 ALOGE("Failed to start usb driver!");
182 return;
183 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400184
185 while (1) {
Jerry Zhang487be612016-10-24 12:10:41 -0700186 int ret = mRequest.read(sHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400187 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700188 ALOGE("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400189 if (errno == ECANCELED) {
190 // return to top of loop and wait for next command
191 continue;
192 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400193 break;
194 }
195 MtpOperationCode operation = mRequest.getOperationCode();
196 MtpTransactionID transaction = mRequest.getTransactionID();
197
Steve Block3856b092011-10-20 11:56:00 +0100198 ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400199 // FIXME need to generalize this
Mike Lockwood438344f2010-08-03 15:30:09 -0400200 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood8277cec2010-08-10 15:20:35 -0400201 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
202 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
203 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400204 if (dataIn) {
Jerry Zhang487be612016-10-24 12:10:41 -0700205 int ret = mData.read(sHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400206 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000207 ALOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400208 if (errno == ECANCELED) {
209 // return to top of loop and wait for next command
210 continue;
211 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400212 break;
213 }
Steve Block3856b092011-10-20 11:56:00 +0100214 ALOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400215 } else {
216 mData.reset();
217 }
218
Mike Lockwood916076c2010-06-04 09:49:21 -0400219 if (handleRequest()) {
220 if (!dataIn && mData.hasData()) {
221 mData.setOperationCode(operation);
222 mData.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100223 ALOGV("sending data:");
Jerry Zhang487be612016-10-24 12:10:41 -0700224 ret = mData.write(sHandle);
Mike Lockwood916076c2010-06-04 09:49:21 -0400225 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000226 ALOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400227 if (errno == ECANCELED) {
228 // return to top of loop and wait for next command
229 continue;
230 }
231 break;
232 }
233 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400234
Mike Lockwood916076c2010-06-04 09:49:21 -0400235 mResponse.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100236 ALOGV("sending response %04X", mResponse.getResponseCode());
Jerry Zhang487be612016-10-24 12:10:41 -0700237 ret = mResponse.write(sHandle);
tao.pei07a9e542015-07-17 17:18:41 +0800238 const int savedErrno = errno;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400239 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000240 ALOGE("request write returned %d, errno: %d", ret, errno);
tao.pei07a9e542015-07-17 17:18:41 +0800241 if (savedErrno == ECANCELED) {
Mike Lockwood916076c2010-06-04 09:49:21 -0400242 // return to top of loop and wait for next command
243 continue;
244 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400245 break;
246 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400247 } else {
Steve Block3856b092011-10-20 11:56:00 +0100248 ALOGV("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400249 }
250 }
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400251
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700252 // commit any open edits
253 int count = mObjectEditList.size();
254 for (int i = 0; i < count; i++) {
255 ObjectEdit* edit = mObjectEditList[i];
256 commitEdit(edit);
257 delete edit;
258 }
259 mObjectEditList.clear();
260
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400261 if (mSessionOpen)
262 mDatabase->sessionEnded();
Jerry Zhang487be612016-10-24 12:10:41 -0700263
264 sHandle->close();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400265}
266
Mike Lockwood873871f2010-07-12 18:54:16 -0400267void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100268 ALOGV("sendObjectAdded %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500269 sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
Mike Lockwood873871f2010-07-12 18:54:16 -0400270}
271
272void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100273 ALOGV("sendObjectRemoved %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500274 sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
275}
276
277void MtpServer::sendStoreAdded(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100278 ALOGV("sendStoreAdded %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500279 sendEvent(MTP_EVENT_STORE_ADDED, id);
280}
281
282void MtpServer::sendStoreRemoved(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100283 ALOGV("sendStoreRemoved %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500284 sendEvent(MTP_EVENT_STORE_REMOVED, id);
285}
286
Mike Lockwood0fa848d2014-03-07 13:29:59 -0800287void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
288 ALOGV("sendDevicePropertyChanged %d\n", property);
289 sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
290}
291
Mike Lockwooda8494402011-02-18 09:07:14 -0500292void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400293 if (mSessionOpen) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500294 mEvent.setEventCode(code);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400295 mEvent.setTransactionID(mRequest.getTransactionID());
Mike Lockwooda8494402011-02-18 09:07:14 -0500296 mEvent.setParameter(1, param1);
Jerry Zhang487be612016-10-24 12:10:41 -0700297 if (mEvent.write(sHandle))
298 ALOGE("Mtp send event failed: %s", strerror(errno));
Mike Lockwood73ecd232010-07-19 14:29:58 -0400299 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400300}
301
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700302void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
303 uint64_t size, MtpObjectFormat format, int fd) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700304 ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700305 mObjectEditList.add(edit);
306}
307
308MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
309 int count = mObjectEditList.size();
310 for (int i = 0; i < count; i++) {
311 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700312 if (edit->mHandle == handle) return edit;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700313 }
Jerry Zhang487be612016-10-24 12:10:41 -0700314 return nullptr;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700315}
316
317void MtpServer::removeEditObject(MtpObjectHandle handle) {
318 int count = mObjectEditList.size();
319 for (int i = 0; i < count; i++) {
320 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700321 if (edit->mHandle == handle) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700322 delete edit;
323 mObjectEditList.removeAt(i);
324 return;
325 }
326 }
Steve Block29357bc2012-01-06 19:20:56 +0000327 ALOGE("ObjectEdit not found in removeEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700328}
329
330void MtpServer::commitEdit(ObjectEdit* edit) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700331 mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700332}
333
334
Mike Lockwood916076c2010-06-04 09:49:21 -0400335bool MtpServer::handleRequest() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500336 Mutex::Autolock autoLock(mMutex);
337
Mike Lockwood16864ba2010-05-11 17:16:59 -0400338 MtpOperationCode operation = mRequest.getOperationCode();
339 MtpResponseCode response;
340
341 mResponse.reset();
342
343 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
344 // FIXME - need to delete mSendObjectHandle from the database
Steve Block29357bc2012-01-06 19:20:56 +0000345 ALOGE("expected SendObject after SendObjectInfo");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400346 mSendObjectHandle = kInvalidObjectHandle;
347 }
348
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700349 int containertype = mRequest.getContainerType();
350 if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
351 ALOGE("wrong container type %d", containertype);
352 return false;
353 }
354
355 ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
356
Mike Lockwood16864ba2010-05-11 17:16:59 -0400357 switch (operation) {
358 case MTP_OPERATION_GET_DEVICE_INFO:
359 response = doGetDeviceInfo();
360 break;
361 case MTP_OPERATION_OPEN_SESSION:
362 response = doOpenSession();
363 break;
364 case MTP_OPERATION_CLOSE_SESSION:
365 response = doCloseSession();
366 break;
367 case MTP_OPERATION_GET_STORAGE_IDS:
368 response = doGetStorageIDs();
369 break;
370 case MTP_OPERATION_GET_STORAGE_INFO:
371 response = doGetStorageInfo();
372 break;
373 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
374 response = doGetObjectPropsSupported();
375 break;
376 case MTP_OPERATION_GET_OBJECT_HANDLES:
377 response = doGetObjectHandles();
378 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400379 case MTP_OPERATION_GET_NUM_OBJECTS:
380 response = doGetNumObjects();
381 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400382 case MTP_OPERATION_GET_OBJECT_REFERENCES:
383 response = doGetObjectReferences();
384 break;
385 case MTP_OPERATION_SET_OBJECT_REFERENCES:
386 response = doSetObjectReferences();
387 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400388 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
389 response = doGetObjectPropValue();
390 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400391 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
392 response = doSetObjectPropValue();
393 break;
394 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
395 response = doGetDevicePropValue();
396 break;
397 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
398 response = doSetDevicePropValue();
399 break;
400 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
401 response = doResetDevicePropValue();
402 break;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400403 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
404 response = doGetObjectPropList();
405 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400406 case MTP_OPERATION_GET_OBJECT_INFO:
407 response = doGetObjectInfo();
408 break;
409 case MTP_OPERATION_GET_OBJECT:
410 response = doGetObject();
411 break;
Mike Lockwood64000782011-04-24 18:40:17 -0700412 case MTP_OPERATION_GET_THUMB:
413 response = doGetThumb();
414 break;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500415 case MTP_OPERATION_GET_PARTIAL_OBJECT:
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700416 case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
417 response = doGetPartialObject(operation);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500418 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400419 case MTP_OPERATION_SEND_OBJECT_INFO:
420 response = doSendObjectInfo();
421 break;
422 case MTP_OPERATION_SEND_OBJECT:
423 response = doSendObject();
424 break;
425 case MTP_OPERATION_DELETE_OBJECT:
426 response = doDeleteObject();
427 break;
428 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400429 response = doGetObjectPropDesc();
430 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400431 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
432 response = doGetDevicePropDesc();
433 break;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700434 case MTP_OPERATION_SEND_PARTIAL_OBJECT:
435 response = doSendPartialObject();
436 break;
437 case MTP_OPERATION_TRUNCATE_OBJECT:
438 response = doTruncateObject();
439 break;
440 case MTP_OPERATION_BEGIN_EDIT_OBJECT:
441 response = doBeginEditObject();
442 break;
443 case MTP_OPERATION_END_EDIT_OBJECT:
444 response = doEndEditObject();
445 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400446 default:
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700447 ALOGE("got unsupported command %s (%x)",
448 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400449 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
450 break;
451 }
452
Mike Lockwood916076c2010-06-04 09:49:21 -0400453 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
454 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400455 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400456 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400457}
458
459MtpResponseCode MtpServer::doGetDeviceInfo() {
460 MtpStringBuffer string;
461
Mike Lockwood782aef12010-08-10 07:37:50 -0400462 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
463 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
464 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
465
Mike Lockwood16864ba2010-05-11 17:16:59 -0400466 // fill in device info
467 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400468 if (mPtp) {
469 mData.putUInt32(0);
470 } else {
471 // MTP Vendor Extension ID
472 mData.putUInt32(6);
473 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400474 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400475 if (mPtp) {
476 // no extensions
477 string.set("");
478 } else {
479 // MTP extensions
480 string.set("microsoft.com: 1.0; android.com: 1.0;");
481 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400482 mData.putString(string); // MTP Extensions
483 mData.putUInt16(0); //Functional Mode
484 mData.putAUInt16(kSupportedOperationCodes,
485 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400486 mData.putAUInt16(kSupportedEventCodes,
487 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400488 mData.putAUInt16(deviceProperties); // Device Properties Supported
489 mData.putAUInt16(captureFormats); // Capture Formats
490 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500491
Alex Klyubin792298f2016-12-21 11:20:22 -0800492 mData.putString(mDeviceInfoManufacturer); // Manufacturer
493 mData.putString(mDeviceInfoModel); // Model
494 mData.putString(mDeviceInfoDeviceVersion); // Device Version
495 mData.putString(mDeviceInfoSerialNumber); // Serial Number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400496
Mike Lockwood782aef12010-08-10 07:37:50 -0400497 delete playbackFormats;
498 delete captureFormats;
499 delete deviceProperties;
500
Mike Lockwood16864ba2010-05-11 17:16:59 -0400501 return MTP_RESPONSE_OK;
502}
503
504MtpResponseCode MtpServer::doOpenSession() {
505 if (mSessionOpen) {
506 mResponse.setParameter(1, mSessionID);
507 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
508 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800509 if (mRequest.getParameterCount() < 1)
510 return MTP_RESPONSE_INVALID_PARAMETER;
511
Mike Lockwood16864ba2010-05-11 17:16:59 -0400512 mSessionID = mRequest.getParameter(1);
513 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400514
515 mDatabase->sessionStarted();
516
Mike Lockwood16864ba2010-05-11 17:16:59 -0400517 return MTP_RESPONSE_OK;
518}
519
520MtpResponseCode MtpServer::doCloseSession() {
521 if (!mSessionOpen)
522 return MTP_RESPONSE_SESSION_NOT_OPEN;
523 mSessionID = 0;
524 mSessionOpen = false;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400525 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400526 return MTP_RESPONSE_OK;
527}
528
529MtpResponseCode MtpServer::doGetStorageIDs() {
530 if (!mSessionOpen)
531 return MTP_RESPONSE_SESSION_NOT_OPEN;
532
533 int count = mStorages.size();
534 mData.putUInt32(count);
535 for (int i = 0; i < count; i++)
536 mData.putUInt32(mStorages[i]->getStorageID());
537
538 return MTP_RESPONSE_OK;
539}
540
541MtpResponseCode MtpServer::doGetStorageInfo() {
542 MtpStringBuffer string;
543
544 if (!mSessionOpen)
545 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800546 if (mRequest.getParameterCount() < 1)
547 return MTP_RESPONSE_INVALID_PARAMETER;
548
Mike Lockwood16864ba2010-05-11 17:16:59 -0400549 MtpStorageID id = mRequest.getParameter(1);
550 MtpStorage* storage = getStorage(id);
551 if (!storage)
552 return MTP_RESPONSE_INVALID_STORAGE_ID;
553
554 mData.putUInt16(storage->getType());
555 mData.putUInt16(storage->getFileSystemType());
556 mData.putUInt16(storage->getAccessCapability());
557 mData.putUInt64(storage->getMaxCapacity());
558 mData.putUInt64(storage->getFreeSpace());
559 mData.putUInt32(1024*1024*1024); // Free Space in Objects
560 string.set(storage->getDescription());
561 mData.putString(string);
562 mData.putEmptyString(); // Volume Identifier
563
564 return MTP_RESPONSE_OK;
565}
566
567MtpResponseCode MtpServer::doGetObjectPropsSupported() {
568 if (!mSessionOpen)
569 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800570 if (mRequest.getParameterCount() < 1)
571 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400572 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800573 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400574 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400575 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400576 return MTP_RESPONSE_OK;
577}
578
579MtpResponseCode MtpServer::doGetObjectHandles() {
580 if (!mSessionOpen)
581 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800582 if (mRequest.getParameterCount() < 3)
583 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400584 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400585 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400586 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400587 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500588
589 if (!hasStorage(storageID))
590 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400591
592 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
593 mData.putAUInt32(handles);
594 delete handles;
595 return MTP_RESPONSE_OK;
596}
597
Mike Lockwood343af4e2010-08-02 10:52:20 -0400598MtpResponseCode MtpServer::doGetNumObjects() {
599 if (!mSessionOpen)
600 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800601 if (mRequest.getParameterCount() < 3)
602 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400603 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
604 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
605 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400606 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500607 if (!hasStorage(storageID))
608 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400609
610 int count = mDatabase->getNumObjects(storageID, format, parent);
611 if (count >= 0) {
612 mResponse.setParameter(1, count);
613 return MTP_RESPONSE_OK;
614 } else {
615 mResponse.setParameter(1, 0);
616 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
617 }
618}
619
Mike Lockwood438344f2010-08-03 15:30:09 -0400620MtpResponseCode MtpServer::doGetObjectReferences() {
621 if (!mSessionOpen)
622 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500623 if (!hasStorage())
624 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800625 if (mRequest.getParameterCount() < 1)
626 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500627 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400628
629 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400630 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400631 if (handles) {
632 mData.putAUInt32(handles);
633 delete handles;
634 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400635 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400636 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400637 return MTP_RESPONSE_OK;
638}
639
640MtpResponseCode MtpServer::doSetObjectReferences() {
641 if (!mSessionOpen)
642 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500643 if (!hasStorage())
644 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800645 if (mRequest.getParameterCount() < 1)
646 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400647 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500648
Mike Lockwood438344f2010-08-03 15:30:09 -0400649 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800650 if (!references)
651 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400652 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
653 delete references;
654 return result;
655}
656
Mike Lockwood16864ba2010-05-11 17:16:59 -0400657MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500658 if (!hasStorage())
659 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800660 if (mRequest.getParameterCount() < 2)
661 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400662 MtpObjectHandle handle = mRequest.getParameter(1);
663 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100664 ALOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400665 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400666
Mike Lockwood8277cec2010-08-10 15:20:35 -0400667 return mDatabase->getObjectPropertyValue(handle, property, mData);
668}
669
670MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500671 if (!hasStorage())
672 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800673 if (mRequest.getParameterCount() < 2)
674 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400675 MtpObjectHandle handle = mRequest.getParameter(1);
676 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100677 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400678 MtpDebug::getObjectPropCodeName(property));
679
680 return mDatabase->setObjectPropertyValue(handle, property, mData);
681}
682
683MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800684 if (mRequest.getParameterCount() < 1)
685 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400686 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100687 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400688 MtpDebug::getDevicePropCodeName(property));
689
690 return mDatabase->getDevicePropertyValue(property, mData);
691}
692
693MtpResponseCode MtpServer::doSetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800694 if (mRequest.getParameterCount() < 1)
695 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400696 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100697 ALOGV("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400698 MtpDebug::getDevicePropCodeName(property));
699
700 return mDatabase->setDevicePropertyValue(property, mData);
701}
702
703MtpResponseCode MtpServer::doResetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800704 if (mRequest.getParameterCount() < 1)
705 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400706 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100707 ALOGV("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400708 MtpDebug::getDevicePropCodeName(property));
709
710 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400711}
712
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400713MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500714 if (!hasStorage())
715 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800716 if (mRequest.getParameterCount() < 5)
717 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400718
719 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500720 // use uint32_t so we can support 0xFFFFFFFF
721 uint32_t format = mRequest.getParameter(2);
722 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400723 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500724 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100725 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400726 handle, MtpDebug::getFormatCodeName(format),
727 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
728
729 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
730}
731
Mike Lockwood16864ba2010-05-11 17:16:59 -0400732MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500733 if (!hasStorage())
734 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800735 if (mRequest.getParameterCount() < 1)
736 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400737 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700738 MtpObjectInfo info(handle);
739 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
740 if (result == MTP_RESPONSE_OK) {
741 char date[20];
742
743 mData.putUInt32(info.mStorageID);
744 mData.putUInt16(info.mFormat);
745 mData.putUInt16(info.mProtectionStatus);
746
747 // if object is being edited the database size may be out of date
748 uint32_t size = info.mCompressedSize;
749 ObjectEdit* edit = getEditObject(handle);
750 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700751 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700752 mData.putUInt32(size);
753
754 mData.putUInt16(info.mThumbFormat);
755 mData.putUInt32(info.mThumbCompressedSize);
756 mData.putUInt32(info.mThumbPixWidth);
757 mData.putUInt32(info.mThumbPixHeight);
758 mData.putUInt32(info.mImagePixWidth);
759 mData.putUInt32(info.mImagePixHeight);
760 mData.putUInt32(info.mImagePixDepth);
761 mData.putUInt32(info.mParent);
762 mData.putUInt16(info.mAssociationType);
763 mData.putUInt32(info.mAssociationDesc);
764 mData.putUInt32(info.mSequenceNumber);
765 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700766 formatDateTime(info.mDateCreated, date, sizeof(date));
767 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700768 formatDateTime(info.mDateModified, date, sizeof(date));
769 mData.putString(date); // date modified
770 mData.putEmptyString(); // keywords
771 }
772 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400773}
774
775MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500776 if (!hasStorage())
777 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800778 if (mRequest.getParameterCount() < 1)
779 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400780 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400781 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400782 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800783 MtpObjectFormat format;
784 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400785 if (result != MTP_RESPONSE_OK)
786 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400787
Jerry Zhang487be612016-10-24 12:10:41 -0700788 auto start = std::chrono::steady_clock::now();
789
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400790 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400791 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400792 mfr.fd = open(filePath, O_RDONLY);
793 if (mfr.fd < 0) {
794 return MTP_RESPONSE_GENERAL_ERROR;
795 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400796 mfr.offset = 0;
797 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400798 mfr.command = mRequest.getOperationCode();
799 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400800
801 // then transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700802 int ret = sHandle->sendFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +0800803 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700804 ALOGE("Mtp send file got error %s", strerror(errno));
tao.pei07a9e542015-07-17 17:18:41 +0800805 if (errno == ECANCELED) {
806 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
807 } else {
808 result = MTP_RESPONSE_GENERAL_ERROR;
809 }
810 } else {
811 result = MTP_RESPONSE_OK;
812 }
813
Jerry Zhang487be612016-10-24 12:10:41 -0700814 auto end = std::chrono::steady_clock::now();
815 std::chrono::duration<double> diff = end - start;
816 struct stat sstat;
817 fstat(mfr.fd, &sstat);
818 uint64_t finalsize = sstat.st_size;
819 ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
820 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwoodc6588762010-06-22 15:03:53 -0400821 close(mfr.fd);
tao.pei07a9e542015-07-17 17:18:41 +0800822 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400823}
824
Mike Lockwood64000782011-04-24 18:40:17 -0700825MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800826 if (mRequest.getParameterCount() < 1)
827 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700828 MtpObjectHandle handle = mRequest.getParameter(1);
829 size_t thumbSize;
830 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
831 if (thumb) {
832 // send data
833 mData.setOperationCode(mRequest.getOperationCode());
834 mData.setTransactionID(mRequest.getTransactionID());
Jerry Zhang487be612016-10-24 12:10:41 -0700835 mData.writeData(sHandle, thumb, thumbSize);
Mike Lockwood64000782011-04-24 18:40:17 -0700836 free(thumb);
837 return MTP_RESPONSE_OK;
838 } else {
839 return MTP_RESPONSE_GENERAL_ERROR;
840 }
841}
842
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700843MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500844 if (!hasStorage())
845 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500846 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700847 uint64_t offset;
848 uint32_t length;
849 offset = mRequest.getParameter(2);
850 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800851 // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
852 if (mRequest.getParameterCount() < 4)
853 return MTP_RESPONSE_INVALID_PARAMETER;
854
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700855 // android extension with 64 bit offset
856 uint64_t offset2 = mRequest.getParameter(3);
857 offset = offset | (offset2 << 32);
858 length = mRequest.getParameter(4);
859 } else {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800860 // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
861 if (mRequest.getParameterCount() < 3)
862 return MTP_RESPONSE_INVALID_PARAMETER;
863
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700864 // standard GetPartialObject
865 length = mRequest.getParameter(3);
866 }
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500867 MtpString pathBuf;
868 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800869 MtpObjectFormat format;
870 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500871 if (result != MTP_RESPONSE_OK)
872 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700873 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500874 length = fileLength - offset;
875
876 const char* filePath = (const char *)pathBuf;
877 mtp_file_range mfr;
878 mfr.fd = open(filePath, O_RDONLY);
879 if (mfr.fd < 0) {
880 return MTP_RESPONSE_GENERAL_ERROR;
881 }
882 mfr.offset = offset;
883 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400884 mfr.command = mRequest.getOperationCode();
885 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500886 mResponse.setParameter(1, length);
887
Mike Lockwoodef441d92011-07-14 21:00:02 -0400888 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700889 int ret = sHandle->sendFile(mfr);
Steve Block3856b092011-10-20 11:56:00 +0100890 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
tao.pei07a9e542015-07-17 17:18:41 +0800891 result = MTP_RESPONSE_OK;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500892 if (ret < 0) {
893 if (errno == ECANCELED)
tao.pei07a9e542015-07-17 17:18:41 +0800894 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500895 else
tao.pei07a9e542015-07-17 17:18:41 +0800896 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500897 }
tao.pei07a9e542015-07-17 17:18:41 +0800898 close(mfr.fd);
899 return result;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500900}
901
Mike Lockwood16864ba2010-05-11 17:16:59 -0400902MtpResponseCode MtpServer::doSendObjectInfo() {
903 MtpString path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800904 uint16_t temp16;
905 uint32_t temp32;
906
907 if (mRequest.getParameterCount() < 2)
908 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400909 MtpStorageID storageID = mRequest.getParameter(1);
910 MtpStorage* storage = getStorage(storageID);
911 MtpObjectHandle parent = mRequest.getParameter(2);
912 if (!storage)
913 return MTP_RESPONSE_INVALID_STORAGE_ID;
914
915 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400916 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400917 path = storage->getPath();
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400918 parent = 0;
919 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800920 int64_t length;
921 MtpObjectFormat format;
922 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400923 if (result != MTP_RESPONSE_OK)
924 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800925 if (format != MTP_FORMAT_ASSOCIATION)
926 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400927 }
928
929 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800930 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
931 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
932 MtpObjectFormat format = temp16;
933 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
934 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
935 mSendObjectFileSize = temp32;
936 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
937 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
938 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
939 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
940 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
941 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
942 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
943 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
944 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800945 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800946 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400947 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800948 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
Marco Nelissen7ea72dc2016-09-19 14:08:16 -0700949 if (name.getCharCount() == 0) {
950 ALOGE("empty name");
951 return MTP_RESPONSE_INVALID_PARAMETER;
952 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800953 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
954 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400955 // keywords follow
956
Steve Block3856b092011-10-20 11:56:00 +0100957 ALOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400958 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400959 if (!parseDateTime(modified, modifiedTime))
960 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400961
962 if (path[path.size() - 1] != '/')
963 path += "/";
964 path += (const char *)name;
965
Mike Lockwood20c3be02010-12-12 12:17:43 -0800966 // check space first
967 if (mSendObjectFileSize > storage->getFreeSpace())
968 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400969 uint64_t maxFileSize = storage->getMaxFileSize();
970 // check storage max file size
971 if (maxFileSize != 0) {
972 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
973 // is >= 0xFFFFFFFF
974 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
975 return MTP_RESPONSE_OBJECT_TOO_LARGE;
976 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800977
Steve Blockb8a80522011-12-20 16:23:08 +0000978 ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Mike Lockwood4714b072010-07-12 08:49:01 -0400979 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
980 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400981 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400982 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400983 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400984
985 if (format == MTP_FORMAT_ASSOCIATION) {
986 mode_t mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400987 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400988 umask(mask);
989 if (ret && ret != -EEXIST)
990 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400991 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwoodaa952402011-01-18 11:06:19 -0800992
993 // SendObject does not get sent for directories, so call endSendObject here instead
994 mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400995 } else {
996 mSendObjectFilePath = path;
997 // save the handle for the SendObject call, which should follow
998 mSendObjectHandle = handle;
Mike Lockwood4714b072010-07-12 08:49:01 -0400999 mSendObjectFormat = format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001000 }
1001
1002 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001003 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001004 mResponse.setParameter(3, handle);
1005
1006 return MTP_RESPONSE_OK;
1007}
1008
1009MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001010 if (!hasStorage())
1011 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -04001012 MtpResponseCode result = MTP_RESPONSE_OK;
1013 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001014 int ret, initialData;
tao.pei07a9e542015-07-17 17:18:41 +08001015 bool isCanceled = false;
Mike Lockwood4714b072010-07-12 08:49:01 -04001016
Jerry Zhang487be612016-10-24 12:10:41 -07001017 auto start = std::chrono::steady_clock::now();
1018
Mike Lockwood16864ba2010-05-11 17:16:59 -04001019 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +00001020 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -04001021 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
1022 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001023 }
1024
Mike Lockwoodef441d92011-07-14 21:00:02 -04001025 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001026 ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001027 if (ret < MTP_CONTAINER_HEADER_SIZE) {
1028 result = MTP_RESPONSE_GENERAL_ERROR;
1029 goto done;
1030 }
1031 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001032
1033 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -07001034 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001035 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001036 result = MTP_RESPONSE_GENERAL_ERROR;
1037 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001038 }
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001039 fchown(mfr.fd, getuid(), mFileGroup);
1040 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001041 mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001042 fchmod(mfr.fd, mFilePermission);
1043 umask(mask);
1044
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001045 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001046 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001047 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001048
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001049 if (ret < 0) {
1050 ALOGE("failed to write initial data");
1051 result = MTP_RESPONSE_GENERAL_ERROR;
1052 } else {
1053 if (mSendObjectFileSize - initialData > 0) {
1054 mfr.offset = initialData;
1055 if (mSendObjectFileSize == 0xFFFFFFFF) {
1056 // tell driver to read until it receives a short packet
1057 mfr.length = 0xFFFFFFFF;
1058 } else {
1059 mfr.length = mSendObjectFileSize - initialData;
1060 }
1061
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001062 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -07001063 ret = sHandle->receiveFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +08001064 if ((ret < 0) && (errno == ECANCELED)) {
1065 isCanceled = true;
1066 }
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001067 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001068 }
Jerry Zhang487be612016-10-24 12:10:41 -07001069 struct stat sstat;
1070 fstat(mfr.fd, &sstat);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001071 close(mfr.fd);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001072
Mike Lockwood916076c2010-06-04 09:49:21 -04001073 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -07001074 ALOGE("Mtp receive file got error %s", strerror(errno));
Mike Lockwood916076c2010-06-04 09:49:21 -04001075 unlink(mSendObjectFilePath);
tao.pei07a9e542015-07-17 17:18:41 +08001076 if (isCanceled)
Mike Lockwood4714b072010-07-12 08:49:01 -04001077 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001078 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001079 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001080 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001081
1082done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001083 // reset so we don't attempt to send the data back
1084 mData.reset();
1085
Mike Lockwood4714b072010-07-12 08:49:01 -04001086 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
Mike Lockwoodaa952402011-01-18 11:06:19 -08001087 result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001088 mSendObjectHandle = kInvalidObjectHandle;
1089 mSendObjectFormat = 0;
Jerry Zhang487be612016-10-24 12:10:41 -07001090
1091 auto end = std::chrono::steady_clock::now();
1092 std::chrono::duration<double> diff = end - start;
1093 uint64_t finalsize = sstat.st_size;
1094 ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
1095 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwood4714b072010-07-12 08:49:01 -04001096 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001097}
1098
Mike Lockwoodd3211492010-09-13 17:15:58 -04001099static void deleteRecursive(const char* path) {
1100 char pathbuf[PATH_MAX];
Mark Salyzynd239cb62014-06-18 16:32:27 -07001101 size_t pathLength = strlen(path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001102 if (pathLength >= sizeof(pathbuf) - 1) {
Steve Block29357bc2012-01-06 19:20:56 +00001103 ALOGE("path too long: %s\n", path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001104 }
1105 strcpy(pathbuf, path);
1106 if (pathbuf[pathLength - 1] != '/') {
1107 pathbuf[pathLength++] = '/';
1108 }
1109 char* fileSpot = pathbuf + pathLength;
1110 int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1111
1112 DIR* dir = opendir(path);
1113 if (!dir) {
Steve Block29357bc2012-01-06 19:20:56 +00001114 ALOGE("opendir %s failed: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001115 return;
1116 }
1117
1118 struct dirent* entry;
1119 while ((entry = readdir(dir))) {
1120 const char* name = entry->d_name;
1121
1122 // ignore "." and ".."
1123 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1124 continue;
1125 }
1126
1127 int nameLength = strlen(name);
1128 if (nameLength > pathRemaining) {
Steve Block29357bc2012-01-06 19:20:56 +00001129 ALOGE("path %s/%s too long\n", path, name);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001130 continue;
1131 }
1132 strcpy(fileSpot, name);
1133
Mike Lockwoodd3211492010-09-13 17:15:58 -04001134 if (entry->d_type == DT_DIR) {
1135 deleteRecursive(pathbuf);
1136 rmdir(pathbuf);
1137 } else {
1138 unlink(pathbuf);
1139 }
1140 }
Mike Lockwood7ce05cf2010-11-11 11:22:32 -05001141 closedir(dir);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001142}
1143
1144static void deletePath(const char* path) {
1145 struct stat statbuf;
1146 if (stat(path, &statbuf) == 0) {
1147 if (S_ISDIR(statbuf.st_mode)) {
1148 deleteRecursive(path);
1149 rmdir(path);
1150 } else {
1151 unlink(path);
1152 }
1153 } else {
Steve Block29357bc2012-01-06 19:20:56 +00001154 ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001155 }
1156}
1157
Mike Lockwood16864ba2010-05-11 17:16:59 -04001158MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001159 if (!hasStorage())
1160 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Marco Nelissenea9f2152015-01-23 10:55:25 -08001161 if (mRequest.getParameterCount() < 1)
Mike Lockwoodab063842014-11-12 14:20:06 -08001162 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001163 MtpObjectHandle handle = mRequest.getParameter(1);
Marco Nelissenea9f2152015-01-23 10:55:25 -08001164 MtpObjectFormat format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001165 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1166 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001167
1168 MtpString filePath;
1169 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001170 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001171 if (result == MTP_RESPONSE_OK) {
Steve Block3856b092011-10-20 11:56:00 +01001172 ALOGV("deleting %s", (const char *)filePath);
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001173 result = mDatabase->deleteFile(handle);
1174 // Don't delete the actual files unless the database deletion is allowed
1175 if (result == MTP_RESPONSE_OK) {
1176 deletePath((const char *)filePath);
1177 }
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001178 }
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001179
1180 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001181}
1182
1183MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001184 if (mRequest.getParameterCount() < 2)
1185 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001186 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001187 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001188 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001189 MtpDebug::getFormatCodeName(format));
1190 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001191 if (!property)
1192 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001193 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001194 delete property;
1195 return MTP_RESPONSE_OK;
1196}
1197
1198MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001199 if (mRequest.getParameterCount() < 1)
1200 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001201 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001202 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001203 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1204 if (!property)
1205 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1206 property->write(mData);
1207 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001208 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001209}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001210
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001211MtpResponseCode MtpServer::doSendPartialObject() {
1212 if (!hasStorage())
1213 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001214 if (mRequest.getParameterCount() < 4)
1215 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001216 MtpObjectHandle handle = mRequest.getParameter(1);
1217 uint64_t offset = mRequest.getParameter(2);
1218 uint64_t offset2 = mRequest.getParameter(3);
1219 offset = offset | (offset2 << 32);
1220 uint32_t length = mRequest.getParameter(4);
1221
1222 ObjectEdit* edit = getEditObject(handle);
1223 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001224 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001225 return MTP_RESPONSE_GENERAL_ERROR;
1226 }
1227
1228 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001229 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001230 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1231 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001232 return MTP_RESPONSE_GENERAL_ERROR;
1233 }
1234
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001235 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001236 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001237
Mike Lockwoodef441d92011-07-14 21:00:02 -04001238 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001239 int ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001240 if (ret < MTP_CONTAINER_HEADER_SIZE)
1241 return MTP_RESPONSE_GENERAL_ERROR;
1242 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1243
1244 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001245 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001246 offset += initialData;
1247 length -= initialData;
1248 }
1249
tao.pei07a9e542015-07-17 17:18:41 +08001250 bool isCanceled = false;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001251 if (ret < 0) {
1252 ALOGE("failed to write initial data");
1253 } else {
1254 if (length > 0) {
1255 mtp_file_range mfr;
1256 mfr.fd = edit->mFD;
1257 mfr.offset = offset;
1258 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001259
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001260 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -07001261 ret = sHandle->receiveFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +08001262 if ((ret < 0) && (errno == ECANCELED)) {
1263 isCanceled = true;
1264 }
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001265 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001266 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001267 if (ret < 0) {
1268 mResponse.setParameter(1, 0);
tao.pei07a9e542015-07-17 17:18:41 +08001269 if (isCanceled)
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001270 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1271 else
1272 return MTP_RESPONSE_GENERAL_ERROR;
1273 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001274
1275 // reset so we don't attempt to send this back
1276 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001277 mResponse.setParameter(1, length);
1278 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001279 if (end > edit->mSize) {
1280 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001281 }
1282 return MTP_RESPONSE_OK;
1283}
1284
1285MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001286 if (mRequest.getParameterCount() < 3)
1287 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001288 MtpObjectHandle handle = mRequest.getParameter(1);
1289 ObjectEdit* edit = getEditObject(handle);
1290 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001291 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001292 return MTP_RESPONSE_GENERAL_ERROR;
1293 }
1294
1295 uint64_t offset = mRequest.getParameter(2);
1296 uint64_t offset2 = mRequest.getParameter(3);
1297 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001298 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001299 return MTP_RESPONSE_GENERAL_ERROR;
1300 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001301 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001302 return MTP_RESPONSE_OK;
1303 }
1304}
1305
1306MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001307 if (mRequest.getParameterCount() < 1)
1308 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001309 MtpObjectHandle handle = mRequest.getParameter(1);
1310 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001311 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001312 return MTP_RESPONSE_GENERAL_ERROR;
1313 }
1314
1315 MtpString path;
1316 int64_t fileLength;
1317 MtpObjectFormat format;
1318 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1319 if (result != MTP_RESPONSE_OK)
1320 return result;
1321
1322 int fd = open((const char *)path, O_RDWR | O_EXCL);
1323 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001324 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001325 return MTP_RESPONSE_GENERAL_ERROR;
1326 }
1327
1328 addEditObject(handle, path, fileLength, format, fd);
1329 return MTP_RESPONSE_OK;
1330}
1331
1332MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001333 if (mRequest.getParameterCount() < 1)
1334 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001335 MtpObjectHandle handle = mRequest.getParameter(1);
1336 ObjectEdit* edit = getEditObject(handle);
1337 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001338 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001339 return MTP_RESPONSE_GENERAL_ERROR;
1340 }
1341
1342 commitEdit(edit);
1343 removeEditObject(handle);
1344 return MTP_RESPONSE_OK;
1345}
1346
Mike Lockwood7850ef92010-05-14 10:10:36 -04001347} // namespace android