blob: 5c332656664224232e3e6e2a488cbb20a270fce8 [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,
Jerry Zhang6dafecc2017-02-23 16:39:30 -080057 MTP_OPERATION_RESET_DEVICE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040058// 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!");
Jerry Zhangcc9d0fd2017-01-27 10:29:59 -0800182 sHandle->close();
Jerry Zhang487be612016-10-24 12:10:41 -0700183 return;
184 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400185
186 while (1) {
Jerry Zhang487be612016-10-24 12:10:41 -0700187 int ret = mRequest.read(sHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400188 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700189 ALOGE("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400190 if (errno == ECANCELED) {
191 // return to top of loop and wait for next command
192 continue;
193 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400194 break;
195 }
196 MtpOperationCode operation = mRequest.getOperationCode();
197 MtpTransactionID transaction = mRequest.getTransactionID();
198
Steve Block3856b092011-10-20 11:56:00 +0100199 ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400200 // FIXME need to generalize this
Mike Lockwood438344f2010-08-03 15:30:09 -0400201 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood8277cec2010-08-10 15:20:35 -0400202 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
203 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
204 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400205 if (dataIn) {
Jerry Zhang487be612016-10-24 12:10:41 -0700206 int ret = mData.read(sHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400207 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000208 ALOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400209 if (errno == ECANCELED) {
210 // return to top of loop and wait for next command
211 continue;
212 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400213 break;
214 }
Steve Block3856b092011-10-20 11:56:00 +0100215 ALOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400216 } else {
217 mData.reset();
218 }
219
Mike Lockwood916076c2010-06-04 09:49:21 -0400220 if (handleRequest()) {
221 if (!dataIn && mData.hasData()) {
222 mData.setOperationCode(operation);
223 mData.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100224 ALOGV("sending data:");
Jerry Zhang487be612016-10-24 12:10:41 -0700225 ret = mData.write(sHandle);
Mike Lockwood916076c2010-06-04 09:49:21 -0400226 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000227 ALOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400228 if (errno == ECANCELED) {
229 // return to top of loop and wait for next command
230 continue;
231 }
232 break;
233 }
234 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400235
Mike Lockwood916076c2010-06-04 09:49:21 -0400236 mResponse.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100237 ALOGV("sending response %04X", mResponse.getResponseCode());
Jerry Zhang487be612016-10-24 12:10:41 -0700238 ret = mResponse.write(sHandle);
tao.pei07a9e542015-07-17 17:18:41 +0800239 const int savedErrno = errno;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400240 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000241 ALOGE("request write returned %d, errno: %d", ret, errno);
tao.pei07a9e542015-07-17 17:18:41 +0800242 if (savedErrno == ECANCELED) {
Mike Lockwood916076c2010-06-04 09:49:21 -0400243 // return to top of loop and wait for next command
244 continue;
245 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400246 break;
247 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400248 } else {
Steve Block3856b092011-10-20 11:56:00 +0100249 ALOGV("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400250 }
251 }
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400252
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700253 // commit any open edits
254 int count = mObjectEditList.size();
255 for (int i = 0; i < count; i++) {
256 ObjectEdit* edit = mObjectEditList[i];
257 commitEdit(edit);
258 delete edit;
259 }
260 mObjectEditList.clear();
261
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400262 if (mSessionOpen)
263 mDatabase->sessionEnded();
Jerry Zhang487be612016-10-24 12:10:41 -0700264
265 sHandle->close();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400266}
267
Mike Lockwood873871f2010-07-12 18:54:16 -0400268void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100269 ALOGV("sendObjectAdded %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500270 sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
Mike Lockwood873871f2010-07-12 18:54:16 -0400271}
272
273void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100274 ALOGV("sendObjectRemoved %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500275 sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
276}
277
278void MtpServer::sendStoreAdded(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100279 ALOGV("sendStoreAdded %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500280 sendEvent(MTP_EVENT_STORE_ADDED, id);
281}
282
283void MtpServer::sendStoreRemoved(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100284 ALOGV("sendStoreRemoved %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500285 sendEvent(MTP_EVENT_STORE_REMOVED, id);
286}
287
Mike Lockwood0fa848d2014-03-07 13:29:59 -0800288void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
289 ALOGV("sendDevicePropertyChanged %d\n", property);
290 sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
291}
292
Mike Lockwooda8494402011-02-18 09:07:14 -0500293void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400294 if (mSessionOpen) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500295 mEvent.setEventCode(code);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400296 mEvent.setTransactionID(mRequest.getTransactionID());
Mike Lockwooda8494402011-02-18 09:07:14 -0500297 mEvent.setParameter(1, param1);
Jerry Zhang487be612016-10-24 12:10:41 -0700298 if (mEvent.write(sHandle))
299 ALOGE("Mtp send event failed: %s", strerror(errno));
Mike Lockwood73ecd232010-07-19 14:29:58 -0400300 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400301}
302
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700303void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
304 uint64_t size, MtpObjectFormat format, int fd) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700305 ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700306 mObjectEditList.add(edit);
307}
308
309MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
310 int count = mObjectEditList.size();
311 for (int i = 0; i < count; i++) {
312 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700313 if (edit->mHandle == handle) return edit;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700314 }
Jerry Zhang487be612016-10-24 12:10:41 -0700315 return nullptr;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700316}
317
318void MtpServer::removeEditObject(MtpObjectHandle handle) {
319 int count = mObjectEditList.size();
320 for (int i = 0; i < count; i++) {
321 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700322 if (edit->mHandle == handle) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700323 delete edit;
324 mObjectEditList.removeAt(i);
325 return;
326 }
327 }
Steve Block29357bc2012-01-06 19:20:56 +0000328 ALOGE("ObjectEdit not found in removeEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700329}
330
331void MtpServer::commitEdit(ObjectEdit* edit) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700332 mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700333}
334
335
Mike Lockwood916076c2010-06-04 09:49:21 -0400336bool MtpServer::handleRequest() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500337 Mutex::Autolock autoLock(mMutex);
338
Mike Lockwood16864ba2010-05-11 17:16:59 -0400339 MtpOperationCode operation = mRequest.getOperationCode();
340 MtpResponseCode response;
341
342 mResponse.reset();
343
344 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
345 // FIXME - need to delete mSendObjectHandle from the database
Steve Block29357bc2012-01-06 19:20:56 +0000346 ALOGE("expected SendObject after SendObjectInfo");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400347 mSendObjectHandle = kInvalidObjectHandle;
348 }
349
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700350 int containertype = mRequest.getContainerType();
351 if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
352 ALOGE("wrong container type %d", containertype);
353 return false;
354 }
355
356 ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
357
Mike Lockwood16864ba2010-05-11 17:16:59 -0400358 switch (operation) {
359 case MTP_OPERATION_GET_DEVICE_INFO:
360 response = doGetDeviceInfo();
361 break;
362 case MTP_OPERATION_OPEN_SESSION:
363 response = doOpenSession();
364 break;
Jerry Zhang6dafecc2017-02-23 16:39:30 -0800365 case MTP_OPERATION_RESET_DEVICE:
Mike Lockwood16864ba2010-05-11 17:16:59 -0400366 case MTP_OPERATION_CLOSE_SESSION:
367 response = doCloseSession();
368 break;
369 case MTP_OPERATION_GET_STORAGE_IDS:
370 response = doGetStorageIDs();
371 break;
372 case MTP_OPERATION_GET_STORAGE_INFO:
373 response = doGetStorageInfo();
374 break;
375 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
376 response = doGetObjectPropsSupported();
377 break;
378 case MTP_OPERATION_GET_OBJECT_HANDLES:
379 response = doGetObjectHandles();
380 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400381 case MTP_OPERATION_GET_NUM_OBJECTS:
382 response = doGetNumObjects();
383 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400384 case MTP_OPERATION_GET_OBJECT_REFERENCES:
385 response = doGetObjectReferences();
386 break;
387 case MTP_OPERATION_SET_OBJECT_REFERENCES:
388 response = doSetObjectReferences();
389 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400390 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
391 response = doGetObjectPropValue();
392 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400393 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
394 response = doSetObjectPropValue();
395 break;
396 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
397 response = doGetDevicePropValue();
398 break;
399 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
400 response = doSetDevicePropValue();
401 break;
402 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
403 response = doResetDevicePropValue();
404 break;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400405 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
406 response = doGetObjectPropList();
407 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400408 case MTP_OPERATION_GET_OBJECT_INFO:
409 response = doGetObjectInfo();
410 break;
411 case MTP_OPERATION_GET_OBJECT:
412 response = doGetObject();
413 break;
Mike Lockwood64000782011-04-24 18:40:17 -0700414 case MTP_OPERATION_GET_THUMB:
415 response = doGetThumb();
416 break;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500417 case MTP_OPERATION_GET_PARTIAL_OBJECT:
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700418 case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
419 response = doGetPartialObject(operation);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500420 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400421 case MTP_OPERATION_SEND_OBJECT_INFO:
422 response = doSendObjectInfo();
423 break;
424 case MTP_OPERATION_SEND_OBJECT:
425 response = doSendObject();
426 break;
427 case MTP_OPERATION_DELETE_OBJECT:
428 response = doDeleteObject();
429 break;
430 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400431 response = doGetObjectPropDesc();
432 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400433 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
434 response = doGetDevicePropDesc();
435 break;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700436 case MTP_OPERATION_SEND_PARTIAL_OBJECT:
437 response = doSendPartialObject();
438 break;
439 case MTP_OPERATION_TRUNCATE_OBJECT:
440 response = doTruncateObject();
441 break;
442 case MTP_OPERATION_BEGIN_EDIT_OBJECT:
443 response = doBeginEditObject();
444 break;
445 case MTP_OPERATION_END_EDIT_OBJECT:
446 response = doEndEditObject();
447 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400448 default:
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700449 ALOGE("got unsupported command %s (%x)",
450 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400451 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
452 break;
453 }
454
Mike Lockwood916076c2010-06-04 09:49:21 -0400455 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
456 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400457 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400458 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400459}
460
461MtpResponseCode MtpServer::doGetDeviceInfo() {
462 MtpStringBuffer string;
463
Mike Lockwood782aef12010-08-10 07:37:50 -0400464 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
465 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
466 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
467
Mike Lockwood16864ba2010-05-11 17:16:59 -0400468 // fill in device info
469 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400470 if (mPtp) {
471 mData.putUInt32(0);
472 } else {
473 // MTP Vendor Extension ID
474 mData.putUInt32(6);
475 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400476 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400477 if (mPtp) {
478 // no extensions
479 string.set("");
480 } else {
481 // MTP extensions
482 string.set("microsoft.com: 1.0; android.com: 1.0;");
483 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400484 mData.putString(string); // MTP Extensions
485 mData.putUInt16(0); //Functional Mode
486 mData.putAUInt16(kSupportedOperationCodes,
487 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400488 mData.putAUInt16(kSupportedEventCodes,
489 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400490 mData.putAUInt16(deviceProperties); // Device Properties Supported
491 mData.putAUInt16(captureFormats); // Capture Formats
492 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500493
Alex Klyubin792298f2016-12-21 11:20:22 -0800494 mData.putString(mDeviceInfoManufacturer); // Manufacturer
495 mData.putString(mDeviceInfoModel); // Model
496 mData.putString(mDeviceInfoDeviceVersion); // Device Version
497 mData.putString(mDeviceInfoSerialNumber); // Serial Number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400498
Mike Lockwood782aef12010-08-10 07:37:50 -0400499 delete playbackFormats;
500 delete captureFormats;
501 delete deviceProperties;
502
Mike Lockwood16864ba2010-05-11 17:16:59 -0400503 return MTP_RESPONSE_OK;
504}
505
506MtpResponseCode MtpServer::doOpenSession() {
507 if (mSessionOpen) {
508 mResponse.setParameter(1, mSessionID);
509 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
510 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800511 if (mRequest.getParameterCount() < 1)
512 return MTP_RESPONSE_INVALID_PARAMETER;
513
Mike Lockwood16864ba2010-05-11 17:16:59 -0400514 mSessionID = mRequest.getParameter(1);
515 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400516
517 mDatabase->sessionStarted();
518
Mike Lockwood16864ba2010-05-11 17:16:59 -0400519 return MTP_RESPONSE_OK;
520}
521
522MtpResponseCode MtpServer::doCloseSession() {
523 if (!mSessionOpen)
524 return MTP_RESPONSE_SESSION_NOT_OPEN;
525 mSessionID = 0;
526 mSessionOpen = false;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400527 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400528 return MTP_RESPONSE_OK;
529}
530
531MtpResponseCode MtpServer::doGetStorageIDs() {
532 if (!mSessionOpen)
533 return MTP_RESPONSE_SESSION_NOT_OPEN;
534
535 int count = mStorages.size();
536 mData.putUInt32(count);
537 for (int i = 0; i < count; i++)
538 mData.putUInt32(mStorages[i]->getStorageID());
539
540 return MTP_RESPONSE_OK;
541}
542
543MtpResponseCode MtpServer::doGetStorageInfo() {
544 MtpStringBuffer string;
545
546 if (!mSessionOpen)
547 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800548 if (mRequest.getParameterCount() < 1)
549 return MTP_RESPONSE_INVALID_PARAMETER;
550
Mike Lockwood16864ba2010-05-11 17:16:59 -0400551 MtpStorageID id = mRequest.getParameter(1);
552 MtpStorage* storage = getStorage(id);
553 if (!storage)
554 return MTP_RESPONSE_INVALID_STORAGE_ID;
555
556 mData.putUInt16(storage->getType());
557 mData.putUInt16(storage->getFileSystemType());
558 mData.putUInt16(storage->getAccessCapability());
559 mData.putUInt64(storage->getMaxCapacity());
560 mData.putUInt64(storage->getFreeSpace());
561 mData.putUInt32(1024*1024*1024); // Free Space in Objects
562 string.set(storage->getDescription());
563 mData.putString(string);
564 mData.putEmptyString(); // Volume Identifier
565
566 return MTP_RESPONSE_OK;
567}
568
569MtpResponseCode MtpServer::doGetObjectPropsSupported() {
570 if (!mSessionOpen)
571 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800572 if (mRequest.getParameterCount() < 1)
573 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400574 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800575 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400576 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400577 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400578 return MTP_RESPONSE_OK;
579}
580
581MtpResponseCode MtpServer::doGetObjectHandles() {
582 if (!mSessionOpen)
583 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800584 if (mRequest.getParameterCount() < 3)
585 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400586 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400587 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400588 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400589 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500590
591 if (!hasStorage(storageID))
592 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400593
594 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
595 mData.putAUInt32(handles);
596 delete handles;
597 return MTP_RESPONSE_OK;
598}
599
Mike Lockwood343af4e2010-08-02 10:52:20 -0400600MtpResponseCode MtpServer::doGetNumObjects() {
601 if (!mSessionOpen)
602 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800603 if (mRequest.getParameterCount() < 3)
604 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400605 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
606 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
607 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400608 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500609 if (!hasStorage(storageID))
610 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400611
612 int count = mDatabase->getNumObjects(storageID, format, parent);
613 if (count >= 0) {
614 mResponse.setParameter(1, count);
615 return MTP_RESPONSE_OK;
616 } else {
617 mResponse.setParameter(1, 0);
618 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
619 }
620}
621
Mike Lockwood438344f2010-08-03 15:30:09 -0400622MtpResponseCode MtpServer::doGetObjectReferences() {
623 if (!mSessionOpen)
624 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500625 if (!hasStorage())
626 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800627 if (mRequest.getParameterCount() < 1)
628 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500629 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400630
631 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400632 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400633 if (handles) {
634 mData.putAUInt32(handles);
635 delete handles;
636 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400637 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400638 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400639 return MTP_RESPONSE_OK;
640}
641
642MtpResponseCode MtpServer::doSetObjectReferences() {
643 if (!mSessionOpen)
644 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500645 if (!hasStorage())
646 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800647 if (mRequest.getParameterCount() < 1)
648 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400649 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500650
Mike Lockwood438344f2010-08-03 15:30:09 -0400651 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800652 if (!references)
653 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400654 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
655 delete references;
656 return result;
657}
658
Mike Lockwood16864ba2010-05-11 17:16:59 -0400659MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500660 if (!hasStorage())
661 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800662 if (mRequest.getParameterCount() < 2)
663 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400664 MtpObjectHandle handle = mRequest.getParameter(1);
665 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100666 ALOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400667 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400668
Mike Lockwood8277cec2010-08-10 15:20:35 -0400669 return mDatabase->getObjectPropertyValue(handle, property, mData);
670}
671
672MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500673 if (!hasStorage())
674 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800675 if (mRequest.getParameterCount() < 2)
676 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400677 MtpObjectHandle handle = mRequest.getParameter(1);
678 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100679 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400680 MtpDebug::getObjectPropCodeName(property));
681
682 return mDatabase->setObjectPropertyValue(handle, property, mData);
683}
684
685MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800686 if (mRequest.getParameterCount() < 1)
687 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400688 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100689 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400690 MtpDebug::getDevicePropCodeName(property));
691
692 return mDatabase->getDevicePropertyValue(property, mData);
693}
694
695MtpResponseCode MtpServer::doSetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800696 if (mRequest.getParameterCount() < 1)
697 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400698 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100699 ALOGV("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400700 MtpDebug::getDevicePropCodeName(property));
701
702 return mDatabase->setDevicePropertyValue(property, mData);
703}
704
705MtpResponseCode MtpServer::doResetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800706 if (mRequest.getParameterCount() < 1)
707 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400708 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100709 ALOGV("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400710 MtpDebug::getDevicePropCodeName(property));
711
712 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400713}
714
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400715MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500716 if (!hasStorage())
717 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800718 if (mRequest.getParameterCount() < 5)
719 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400720
721 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500722 // use uint32_t so we can support 0xFFFFFFFF
723 uint32_t format = mRequest.getParameter(2);
724 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400725 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500726 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100727 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400728 handle, MtpDebug::getFormatCodeName(format),
729 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
730
731 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
732}
733
Mike Lockwood16864ba2010-05-11 17:16:59 -0400734MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500735 if (!hasStorage())
736 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800737 if (mRequest.getParameterCount() < 1)
738 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400739 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700740 MtpObjectInfo info(handle);
741 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
742 if (result == MTP_RESPONSE_OK) {
743 char date[20];
744
745 mData.putUInt32(info.mStorageID);
746 mData.putUInt16(info.mFormat);
747 mData.putUInt16(info.mProtectionStatus);
748
749 // if object is being edited the database size may be out of date
750 uint32_t size = info.mCompressedSize;
751 ObjectEdit* edit = getEditObject(handle);
752 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700753 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700754 mData.putUInt32(size);
755
756 mData.putUInt16(info.mThumbFormat);
757 mData.putUInt32(info.mThumbCompressedSize);
758 mData.putUInt32(info.mThumbPixWidth);
759 mData.putUInt32(info.mThumbPixHeight);
760 mData.putUInt32(info.mImagePixWidth);
761 mData.putUInt32(info.mImagePixHeight);
762 mData.putUInt32(info.mImagePixDepth);
763 mData.putUInt32(info.mParent);
764 mData.putUInt16(info.mAssociationType);
765 mData.putUInt32(info.mAssociationDesc);
766 mData.putUInt32(info.mSequenceNumber);
767 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700768 formatDateTime(info.mDateCreated, date, sizeof(date));
769 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700770 formatDateTime(info.mDateModified, date, sizeof(date));
771 mData.putString(date); // date modified
772 mData.putEmptyString(); // keywords
773 }
774 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400775}
776
777MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500778 if (!hasStorage())
779 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800780 if (mRequest.getParameterCount() < 1)
781 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400782 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400783 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400784 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800785 MtpObjectFormat format;
786 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400787 if (result != MTP_RESPONSE_OK)
788 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400789
Jerry Zhang487be612016-10-24 12:10:41 -0700790 auto start = std::chrono::steady_clock::now();
791
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400792 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400793 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400794 mfr.fd = open(filePath, O_RDONLY);
795 if (mfr.fd < 0) {
796 return MTP_RESPONSE_GENERAL_ERROR;
797 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400798 mfr.offset = 0;
799 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400800 mfr.command = mRequest.getOperationCode();
801 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400802
803 // then transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700804 int ret = sHandle->sendFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +0800805 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700806 ALOGE("Mtp send file got error %s", strerror(errno));
tao.pei07a9e542015-07-17 17:18:41 +0800807 if (errno == ECANCELED) {
808 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
809 } else {
810 result = MTP_RESPONSE_GENERAL_ERROR;
811 }
812 } else {
813 result = MTP_RESPONSE_OK;
814 }
815
Jerry Zhang487be612016-10-24 12:10:41 -0700816 auto end = std::chrono::steady_clock::now();
817 std::chrono::duration<double> diff = end - start;
818 struct stat sstat;
819 fstat(mfr.fd, &sstat);
820 uint64_t finalsize = sstat.st_size;
821 ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
822 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwoodc6588762010-06-22 15:03:53 -0400823 close(mfr.fd);
tao.pei07a9e542015-07-17 17:18:41 +0800824 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400825}
826
Mike Lockwood64000782011-04-24 18:40:17 -0700827MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800828 if (mRequest.getParameterCount() < 1)
829 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700830 MtpObjectHandle handle = mRequest.getParameter(1);
831 size_t thumbSize;
832 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
833 if (thumb) {
834 // send data
835 mData.setOperationCode(mRequest.getOperationCode());
836 mData.setTransactionID(mRequest.getTransactionID());
Jerry Zhang487be612016-10-24 12:10:41 -0700837 mData.writeData(sHandle, thumb, thumbSize);
Mike Lockwood64000782011-04-24 18:40:17 -0700838 free(thumb);
839 return MTP_RESPONSE_OK;
840 } else {
841 return MTP_RESPONSE_GENERAL_ERROR;
842 }
843}
844
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700845MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500846 if (!hasStorage())
847 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500848 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700849 uint64_t offset;
850 uint32_t length;
851 offset = mRequest.getParameter(2);
852 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800853 // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
854 if (mRequest.getParameterCount() < 4)
855 return MTP_RESPONSE_INVALID_PARAMETER;
856
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700857 // android extension with 64 bit offset
858 uint64_t offset2 = mRequest.getParameter(3);
859 offset = offset | (offset2 << 32);
860 length = mRequest.getParameter(4);
861 } else {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800862 // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
863 if (mRequest.getParameterCount() < 3)
864 return MTP_RESPONSE_INVALID_PARAMETER;
865
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700866 // standard GetPartialObject
867 length = mRequest.getParameter(3);
868 }
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500869 MtpString pathBuf;
870 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800871 MtpObjectFormat format;
872 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500873 if (result != MTP_RESPONSE_OK)
874 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700875 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500876 length = fileLength - offset;
877
878 const char* filePath = (const char *)pathBuf;
879 mtp_file_range mfr;
880 mfr.fd = open(filePath, O_RDONLY);
881 if (mfr.fd < 0) {
882 return MTP_RESPONSE_GENERAL_ERROR;
883 }
884 mfr.offset = offset;
885 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400886 mfr.command = mRequest.getOperationCode();
887 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500888 mResponse.setParameter(1, length);
889
Mike Lockwoodef441d92011-07-14 21:00:02 -0400890 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700891 int ret = sHandle->sendFile(mfr);
Steve Block3856b092011-10-20 11:56:00 +0100892 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
tao.pei07a9e542015-07-17 17:18:41 +0800893 result = MTP_RESPONSE_OK;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500894 if (ret < 0) {
895 if (errno == ECANCELED)
tao.pei07a9e542015-07-17 17:18:41 +0800896 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500897 else
tao.pei07a9e542015-07-17 17:18:41 +0800898 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500899 }
tao.pei07a9e542015-07-17 17:18:41 +0800900 close(mfr.fd);
901 return result;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500902}
903
Mike Lockwood16864ba2010-05-11 17:16:59 -0400904MtpResponseCode MtpServer::doSendObjectInfo() {
905 MtpString path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800906 uint16_t temp16;
907 uint32_t temp32;
908
909 if (mRequest.getParameterCount() < 2)
910 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400911 MtpStorageID storageID = mRequest.getParameter(1);
912 MtpStorage* storage = getStorage(storageID);
913 MtpObjectHandle parent = mRequest.getParameter(2);
914 if (!storage)
915 return MTP_RESPONSE_INVALID_STORAGE_ID;
916
917 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400918 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400919 path = storage->getPath();
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400920 parent = 0;
921 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800922 int64_t length;
923 MtpObjectFormat format;
924 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400925 if (result != MTP_RESPONSE_OK)
926 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800927 if (format != MTP_FORMAT_ASSOCIATION)
928 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400929 }
930
931 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800932 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
933 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
934 MtpObjectFormat format = temp16;
935 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
936 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
937 mSendObjectFileSize = temp32;
938 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
939 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
940 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
941 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
942 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
943 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
944 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
945 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
946 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800947 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800948 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400949 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800950 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
Marco Nelissen7ea72dc2016-09-19 14:08:16 -0700951 if (name.getCharCount() == 0) {
952 ALOGE("empty name");
953 return MTP_RESPONSE_INVALID_PARAMETER;
954 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800955 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
956 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400957 // keywords follow
958
Steve Block3856b092011-10-20 11:56:00 +0100959 ALOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400960 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400961 if (!parseDateTime(modified, modifiedTime))
962 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400963
964 if (path[path.size() - 1] != '/')
965 path += "/";
966 path += (const char *)name;
967
Mike Lockwood20c3be02010-12-12 12:17:43 -0800968 // check space first
969 if (mSendObjectFileSize > storage->getFreeSpace())
970 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400971 uint64_t maxFileSize = storage->getMaxFileSize();
972 // check storage max file size
973 if (maxFileSize != 0) {
974 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
975 // is >= 0xFFFFFFFF
976 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
977 return MTP_RESPONSE_OBJECT_TOO_LARGE;
978 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800979
Steve Blockb8a80522011-12-20 16:23:08 +0000980 ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Mike Lockwood4714b072010-07-12 08:49:01 -0400981 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
982 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400983 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400984 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400985 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400986
987 if (format == MTP_FORMAT_ASSOCIATION) {
988 mode_t mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400989 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400990 umask(mask);
991 if (ret && ret != -EEXIST)
992 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400993 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwoodaa952402011-01-18 11:06:19 -0800994
995 // SendObject does not get sent for directories, so call endSendObject here instead
996 mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400997 } else {
998 mSendObjectFilePath = path;
999 // save the handle for the SendObject call, which should follow
1000 mSendObjectHandle = handle;
Mike Lockwood4714b072010-07-12 08:49:01 -04001001 mSendObjectFormat = format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001002 }
1003
1004 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001005 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001006 mResponse.setParameter(3, handle);
1007
1008 return MTP_RESPONSE_OK;
1009}
1010
1011MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001012 if (!hasStorage())
1013 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -04001014 MtpResponseCode result = MTP_RESPONSE_OK;
1015 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001016 int ret, initialData;
tao.pei07a9e542015-07-17 17:18:41 +08001017 bool isCanceled = false;
Mike Lockwood4714b072010-07-12 08:49:01 -04001018
Jerry Zhang487be612016-10-24 12:10:41 -07001019 auto start = std::chrono::steady_clock::now();
1020
Mike Lockwood16864ba2010-05-11 17:16:59 -04001021 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +00001022 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -04001023 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
1024 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001025 }
1026
Mike Lockwoodef441d92011-07-14 21:00:02 -04001027 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001028 ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001029 if (ret < MTP_CONTAINER_HEADER_SIZE) {
1030 result = MTP_RESPONSE_GENERAL_ERROR;
1031 goto done;
1032 }
1033 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001034
1035 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -07001036 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001037 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001038 result = MTP_RESPONSE_GENERAL_ERROR;
1039 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001040 }
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001041 fchown(mfr.fd, getuid(), mFileGroup);
1042 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001043 mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001044 fchmod(mfr.fd, mFilePermission);
1045 umask(mask);
1046
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001047 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001048 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001049 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001050
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001051 if (ret < 0) {
1052 ALOGE("failed to write initial data");
1053 result = MTP_RESPONSE_GENERAL_ERROR;
1054 } else {
Jerry Zhang54107562017-05-15 11:54:19 -07001055 mfr.offset = initialData;
1056 if (mSendObjectFileSize == 0xFFFFFFFF) {
1057 // tell driver to read until it receives a short packet
1058 mfr.length = 0xFFFFFFFF;
1059 } else {
1060 mfr.length = mSendObjectFileSize - initialData;
1061 }
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001062
Jerry Zhang54107562017-05-15 11:54:19 -07001063 mfr.command = 0;
1064 mfr.transaction_id = 0;
Yunlian Jiang8ddc3522017-02-21 15:58:09 -08001065
Jerry Zhang54107562017-05-15 11:54:19 -07001066 // transfer the file
1067 ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
1068 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1069 if ((ret < 0) && (errno == ECANCELED)) {
1070 isCanceled = true;
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001071 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001072 }
Jerry Zhang487be612016-10-24 12:10:41 -07001073 struct stat sstat;
1074 fstat(mfr.fd, &sstat);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001075 close(mfr.fd);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001076
Mike Lockwood916076c2010-06-04 09:49:21 -04001077 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -07001078 ALOGE("Mtp receive file got error %s", strerror(errno));
Mike Lockwood916076c2010-06-04 09:49:21 -04001079 unlink(mSendObjectFilePath);
tao.pei07a9e542015-07-17 17:18:41 +08001080 if (isCanceled)
Mike Lockwood4714b072010-07-12 08:49:01 -04001081 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001082 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001083 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001084 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001085
1086done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001087 // reset so we don't attempt to send the data back
1088 mData.reset();
1089
Mike Lockwood4714b072010-07-12 08:49:01 -04001090 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
Mike Lockwoodaa952402011-01-18 11:06:19 -08001091 result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001092 mSendObjectHandle = kInvalidObjectHandle;
1093 mSendObjectFormat = 0;
Jerry Zhang487be612016-10-24 12:10:41 -07001094
1095 auto end = std::chrono::steady_clock::now();
1096 std::chrono::duration<double> diff = end - start;
1097 uint64_t finalsize = sstat.st_size;
1098 ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
1099 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwood4714b072010-07-12 08:49:01 -04001100 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001101}
1102
Mike Lockwoodd3211492010-09-13 17:15:58 -04001103static void deleteRecursive(const char* path) {
1104 char pathbuf[PATH_MAX];
Mark Salyzynd239cb62014-06-18 16:32:27 -07001105 size_t pathLength = strlen(path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001106 if (pathLength >= sizeof(pathbuf) - 1) {
Steve Block29357bc2012-01-06 19:20:56 +00001107 ALOGE("path too long: %s\n", path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001108 }
1109 strcpy(pathbuf, path);
1110 if (pathbuf[pathLength - 1] != '/') {
1111 pathbuf[pathLength++] = '/';
1112 }
1113 char* fileSpot = pathbuf + pathLength;
1114 int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1115
1116 DIR* dir = opendir(path);
1117 if (!dir) {
Steve Block29357bc2012-01-06 19:20:56 +00001118 ALOGE("opendir %s failed: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001119 return;
1120 }
1121
1122 struct dirent* entry;
1123 while ((entry = readdir(dir))) {
1124 const char* name = entry->d_name;
1125
1126 // ignore "." and ".."
1127 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1128 continue;
1129 }
1130
1131 int nameLength = strlen(name);
1132 if (nameLength > pathRemaining) {
Steve Block29357bc2012-01-06 19:20:56 +00001133 ALOGE("path %s/%s too long\n", path, name);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001134 continue;
1135 }
1136 strcpy(fileSpot, name);
1137
Mike Lockwoodd3211492010-09-13 17:15:58 -04001138 if (entry->d_type == DT_DIR) {
1139 deleteRecursive(pathbuf);
1140 rmdir(pathbuf);
1141 } else {
1142 unlink(pathbuf);
1143 }
1144 }
Mike Lockwood7ce05cf2010-11-11 11:22:32 -05001145 closedir(dir);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001146}
1147
1148static void deletePath(const char* path) {
1149 struct stat statbuf;
1150 if (stat(path, &statbuf) == 0) {
1151 if (S_ISDIR(statbuf.st_mode)) {
1152 deleteRecursive(path);
1153 rmdir(path);
1154 } else {
1155 unlink(path);
1156 }
1157 } else {
Steve Block29357bc2012-01-06 19:20:56 +00001158 ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001159 }
1160}
1161
Mike Lockwood16864ba2010-05-11 17:16:59 -04001162MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001163 if (!hasStorage())
1164 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Marco Nelissenea9f2152015-01-23 10:55:25 -08001165 if (mRequest.getParameterCount() < 1)
Mike Lockwoodab063842014-11-12 14:20:06 -08001166 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001167 MtpObjectHandle handle = mRequest.getParameter(1);
Marco Nelissenea9f2152015-01-23 10:55:25 -08001168 MtpObjectFormat format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001169 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1170 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001171
1172 MtpString filePath;
1173 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001174 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001175 if (result == MTP_RESPONSE_OK) {
Steve Block3856b092011-10-20 11:56:00 +01001176 ALOGV("deleting %s", (const char *)filePath);
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001177 result = mDatabase->deleteFile(handle);
1178 // Don't delete the actual files unless the database deletion is allowed
1179 if (result == MTP_RESPONSE_OK) {
1180 deletePath((const char *)filePath);
1181 }
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001182 }
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001183
1184 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001185}
1186
1187MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001188 if (mRequest.getParameterCount() < 2)
1189 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001190 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001191 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001192 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001193 MtpDebug::getFormatCodeName(format));
1194 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001195 if (!property)
1196 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001197 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001198 delete property;
1199 return MTP_RESPONSE_OK;
1200}
1201
1202MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001203 if (mRequest.getParameterCount() < 1)
1204 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001205 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001206 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001207 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1208 if (!property)
1209 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1210 property->write(mData);
1211 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001212 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001213}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001214
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001215MtpResponseCode MtpServer::doSendPartialObject() {
1216 if (!hasStorage())
1217 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001218 if (mRequest.getParameterCount() < 4)
1219 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001220 MtpObjectHandle handle = mRequest.getParameter(1);
1221 uint64_t offset = mRequest.getParameter(2);
1222 uint64_t offset2 = mRequest.getParameter(3);
1223 offset = offset | (offset2 << 32);
1224 uint32_t length = mRequest.getParameter(4);
1225
1226 ObjectEdit* edit = getEditObject(handle);
1227 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001228 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001229 return MTP_RESPONSE_GENERAL_ERROR;
1230 }
1231
1232 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001233 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001234 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1235 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001236 return MTP_RESPONSE_GENERAL_ERROR;
1237 }
1238
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001239 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001240 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001241
Mike Lockwoodef441d92011-07-14 21:00:02 -04001242 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001243 int ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001244 if (ret < MTP_CONTAINER_HEADER_SIZE)
1245 return MTP_RESPONSE_GENERAL_ERROR;
1246 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1247
1248 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001249 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001250 offset += initialData;
1251 length -= initialData;
1252 }
1253
tao.pei07a9e542015-07-17 17:18:41 +08001254 bool isCanceled = false;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001255 if (ret < 0) {
1256 ALOGE("failed to write initial data");
1257 } else {
Jerry Zhang54107562017-05-15 11:54:19 -07001258 mtp_file_range mfr;
1259 mfr.fd = edit->mFD;
1260 mfr.offset = offset;
1261 mfr.length = length;
1262 mfr.command = 0;
1263 mfr.transaction_id = 0;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001264
Jerry Zhang54107562017-05-15 11:54:19 -07001265 // transfer the file
1266 ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
1267 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1268 if ((ret < 0) && (errno == ECANCELED)) {
1269 isCanceled = true;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001270 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001271 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001272 if (ret < 0) {
1273 mResponse.setParameter(1, 0);
tao.pei07a9e542015-07-17 17:18:41 +08001274 if (isCanceled)
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001275 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1276 else
1277 return MTP_RESPONSE_GENERAL_ERROR;
1278 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001279
1280 // reset so we don't attempt to send this back
1281 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001282 mResponse.setParameter(1, length);
1283 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001284 if (end > edit->mSize) {
1285 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001286 }
1287 return MTP_RESPONSE_OK;
1288}
1289
1290MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001291 if (mRequest.getParameterCount() < 3)
1292 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001293 MtpObjectHandle handle = mRequest.getParameter(1);
1294 ObjectEdit* edit = getEditObject(handle);
1295 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001296 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001297 return MTP_RESPONSE_GENERAL_ERROR;
1298 }
1299
1300 uint64_t offset = mRequest.getParameter(2);
1301 uint64_t offset2 = mRequest.getParameter(3);
1302 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001303 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001304 return MTP_RESPONSE_GENERAL_ERROR;
1305 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001306 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001307 return MTP_RESPONSE_OK;
1308 }
1309}
1310
1311MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001312 if (mRequest.getParameterCount() < 1)
1313 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001314 MtpObjectHandle handle = mRequest.getParameter(1);
1315 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001316 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001317 return MTP_RESPONSE_GENERAL_ERROR;
1318 }
1319
1320 MtpString path;
1321 int64_t fileLength;
1322 MtpObjectFormat format;
1323 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1324 if (result != MTP_RESPONSE_OK)
1325 return result;
1326
1327 int fd = open((const char *)path, O_RDWR | O_EXCL);
1328 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001329 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001330 return MTP_RESPONSE_GENERAL_ERROR;
1331 }
1332
1333 addEditObject(handle, path, fileLength, format, fd);
1334 return MTP_RESPONSE_OK;
1335}
1336
1337MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001338 if (mRequest.getParameterCount() < 1)
1339 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001340 MtpObjectHandle handle = mRequest.getParameter(1);
1341 ObjectEdit* edit = getEditObject(handle);
1342 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001343 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001344 return MTP_RESPONSE_GENERAL_ERROR;
1345 }
1346
1347 commitEdit(edit);
1348 removeEditObject(handle);
1349 return MTP_RESPONSE_OK;
1350}
1351
Mike Lockwood7850ef92010-05-14 10:10:36 -04001352} // namespace android