blob: 753d833f6fe6afde9bc7315ec6b1e547062fc8f8 [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!");
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;
365 case MTP_OPERATION_CLOSE_SESSION:
366 response = doCloseSession();
367 break;
368 case MTP_OPERATION_GET_STORAGE_IDS:
369 response = doGetStorageIDs();
370 break;
371 case MTP_OPERATION_GET_STORAGE_INFO:
372 response = doGetStorageInfo();
373 break;
374 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
375 response = doGetObjectPropsSupported();
376 break;
377 case MTP_OPERATION_GET_OBJECT_HANDLES:
378 response = doGetObjectHandles();
379 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400380 case MTP_OPERATION_GET_NUM_OBJECTS:
381 response = doGetNumObjects();
382 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400383 case MTP_OPERATION_GET_OBJECT_REFERENCES:
384 response = doGetObjectReferences();
385 break;
386 case MTP_OPERATION_SET_OBJECT_REFERENCES:
387 response = doSetObjectReferences();
388 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400389 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
390 response = doGetObjectPropValue();
391 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400392 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
393 response = doSetObjectPropValue();
394 break;
395 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
396 response = doGetDevicePropValue();
397 break;
398 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
399 response = doSetDevicePropValue();
400 break;
401 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
402 response = doResetDevicePropValue();
403 break;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400404 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
405 response = doGetObjectPropList();
406 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400407 case MTP_OPERATION_GET_OBJECT_INFO:
408 response = doGetObjectInfo();
409 break;
410 case MTP_OPERATION_GET_OBJECT:
411 response = doGetObject();
412 break;
Mike Lockwood64000782011-04-24 18:40:17 -0700413 case MTP_OPERATION_GET_THUMB:
414 response = doGetThumb();
415 break;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500416 case MTP_OPERATION_GET_PARTIAL_OBJECT:
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700417 case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
418 response = doGetPartialObject(operation);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500419 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400420 case MTP_OPERATION_SEND_OBJECT_INFO:
421 response = doSendObjectInfo();
422 break;
423 case MTP_OPERATION_SEND_OBJECT:
424 response = doSendObject();
425 break;
426 case MTP_OPERATION_DELETE_OBJECT:
427 response = doDeleteObject();
428 break;
429 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400430 response = doGetObjectPropDesc();
431 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400432 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
433 response = doGetDevicePropDesc();
434 break;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700435 case MTP_OPERATION_SEND_PARTIAL_OBJECT:
436 response = doSendPartialObject();
437 break;
438 case MTP_OPERATION_TRUNCATE_OBJECT:
439 response = doTruncateObject();
440 break;
441 case MTP_OPERATION_BEGIN_EDIT_OBJECT:
442 response = doBeginEditObject();
443 break;
444 case MTP_OPERATION_END_EDIT_OBJECT:
445 response = doEndEditObject();
446 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400447 default:
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700448 ALOGE("got unsupported command %s (%x)",
449 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400450 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
451 break;
452 }
453
Mike Lockwood916076c2010-06-04 09:49:21 -0400454 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
455 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400456 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400457 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400458}
459
460MtpResponseCode MtpServer::doGetDeviceInfo() {
461 MtpStringBuffer string;
462
Mike Lockwood782aef12010-08-10 07:37:50 -0400463 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
464 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
465 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
466
Mike Lockwood16864ba2010-05-11 17:16:59 -0400467 // fill in device info
468 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400469 if (mPtp) {
470 mData.putUInt32(0);
471 } else {
472 // MTP Vendor Extension ID
473 mData.putUInt32(6);
474 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400475 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400476 if (mPtp) {
477 // no extensions
478 string.set("");
479 } else {
480 // MTP extensions
481 string.set("microsoft.com: 1.0; android.com: 1.0;");
482 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400483 mData.putString(string); // MTP Extensions
484 mData.putUInt16(0); //Functional Mode
485 mData.putAUInt16(kSupportedOperationCodes,
486 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400487 mData.putAUInt16(kSupportedEventCodes,
488 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400489 mData.putAUInt16(deviceProperties); // Device Properties Supported
490 mData.putAUInt16(captureFormats); // Capture Formats
491 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500492
Alex Klyubin792298f2016-12-21 11:20:22 -0800493 mData.putString(mDeviceInfoManufacturer); // Manufacturer
494 mData.putString(mDeviceInfoModel); // Model
495 mData.putString(mDeviceInfoDeviceVersion); // Device Version
496 mData.putString(mDeviceInfoSerialNumber); // Serial Number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400497
Mike Lockwood782aef12010-08-10 07:37:50 -0400498 delete playbackFormats;
499 delete captureFormats;
500 delete deviceProperties;
501
Mike Lockwood16864ba2010-05-11 17:16:59 -0400502 return MTP_RESPONSE_OK;
503}
504
505MtpResponseCode MtpServer::doOpenSession() {
506 if (mSessionOpen) {
507 mResponse.setParameter(1, mSessionID);
508 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
509 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800510 if (mRequest.getParameterCount() < 1)
511 return MTP_RESPONSE_INVALID_PARAMETER;
512
Mike Lockwood16864ba2010-05-11 17:16:59 -0400513 mSessionID = mRequest.getParameter(1);
514 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400515
516 mDatabase->sessionStarted();
517
Mike Lockwood16864ba2010-05-11 17:16:59 -0400518 return MTP_RESPONSE_OK;
519}
520
521MtpResponseCode MtpServer::doCloseSession() {
522 if (!mSessionOpen)
523 return MTP_RESPONSE_SESSION_NOT_OPEN;
524 mSessionID = 0;
525 mSessionOpen = false;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400526 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400527 return MTP_RESPONSE_OK;
528}
529
530MtpResponseCode MtpServer::doGetStorageIDs() {
531 if (!mSessionOpen)
532 return MTP_RESPONSE_SESSION_NOT_OPEN;
533
534 int count = mStorages.size();
535 mData.putUInt32(count);
536 for (int i = 0; i < count; i++)
537 mData.putUInt32(mStorages[i]->getStorageID());
538
539 return MTP_RESPONSE_OK;
540}
541
542MtpResponseCode MtpServer::doGetStorageInfo() {
543 MtpStringBuffer string;
544
545 if (!mSessionOpen)
546 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800547 if (mRequest.getParameterCount() < 1)
548 return MTP_RESPONSE_INVALID_PARAMETER;
549
Mike Lockwood16864ba2010-05-11 17:16:59 -0400550 MtpStorageID id = mRequest.getParameter(1);
551 MtpStorage* storage = getStorage(id);
552 if (!storage)
553 return MTP_RESPONSE_INVALID_STORAGE_ID;
554
555 mData.putUInt16(storage->getType());
556 mData.putUInt16(storage->getFileSystemType());
557 mData.putUInt16(storage->getAccessCapability());
558 mData.putUInt64(storage->getMaxCapacity());
559 mData.putUInt64(storage->getFreeSpace());
560 mData.putUInt32(1024*1024*1024); // Free Space in Objects
561 string.set(storage->getDescription());
562 mData.putString(string);
563 mData.putEmptyString(); // Volume Identifier
564
565 return MTP_RESPONSE_OK;
566}
567
568MtpResponseCode MtpServer::doGetObjectPropsSupported() {
569 if (!mSessionOpen)
570 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800571 if (mRequest.getParameterCount() < 1)
572 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400573 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800574 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400575 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400576 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400577 return MTP_RESPONSE_OK;
578}
579
580MtpResponseCode MtpServer::doGetObjectHandles() {
581 if (!mSessionOpen)
582 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800583 if (mRequest.getParameterCount() < 3)
584 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400585 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400586 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400587 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400588 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500589
590 if (!hasStorage(storageID))
591 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400592
593 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
594 mData.putAUInt32(handles);
595 delete handles;
596 return MTP_RESPONSE_OK;
597}
598
Mike Lockwood343af4e2010-08-02 10:52:20 -0400599MtpResponseCode MtpServer::doGetNumObjects() {
600 if (!mSessionOpen)
601 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800602 if (mRequest.getParameterCount() < 3)
603 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400604 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
605 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
606 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400607 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500608 if (!hasStorage(storageID))
609 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400610
611 int count = mDatabase->getNumObjects(storageID, format, parent);
612 if (count >= 0) {
613 mResponse.setParameter(1, count);
614 return MTP_RESPONSE_OK;
615 } else {
616 mResponse.setParameter(1, 0);
617 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
618 }
619}
620
Mike Lockwood438344f2010-08-03 15:30:09 -0400621MtpResponseCode MtpServer::doGetObjectReferences() {
622 if (!mSessionOpen)
623 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500624 if (!hasStorage())
625 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800626 if (mRequest.getParameterCount() < 1)
627 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500628 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400629
630 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400631 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400632 if (handles) {
633 mData.putAUInt32(handles);
634 delete handles;
635 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400636 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400637 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400638 return MTP_RESPONSE_OK;
639}
640
641MtpResponseCode MtpServer::doSetObjectReferences() {
642 if (!mSessionOpen)
643 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500644 if (!hasStorage())
645 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800646 if (mRequest.getParameterCount() < 1)
647 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400648 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500649
Mike Lockwood438344f2010-08-03 15:30:09 -0400650 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800651 if (!references)
652 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400653 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
654 delete references;
655 return result;
656}
657
Mike Lockwood16864ba2010-05-11 17:16:59 -0400658MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500659 if (!hasStorage())
660 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800661 if (mRequest.getParameterCount() < 2)
662 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400663 MtpObjectHandle handle = mRequest.getParameter(1);
664 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100665 ALOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400666 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400667
Mike Lockwood8277cec2010-08-10 15:20:35 -0400668 return mDatabase->getObjectPropertyValue(handle, property, mData);
669}
670
671MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500672 if (!hasStorage())
673 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800674 if (mRequest.getParameterCount() < 2)
675 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400676 MtpObjectHandle handle = mRequest.getParameter(1);
677 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100678 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400679 MtpDebug::getObjectPropCodeName(property));
680
681 return mDatabase->setObjectPropertyValue(handle, property, mData);
682}
683
684MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800685 if (mRequest.getParameterCount() < 1)
686 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400687 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100688 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400689 MtpDebug::getDevicePropCodeName(property));
690
691 return mDatabase->getDevicePropertyValue(property, mData);
692}
693
694MtpResponseCode MtpServer::doSetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800695 if (mRequest.getParameterCount() < 1)
696 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400697 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100698 ALOGV("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400699 MtpDebug::getDevicePropCodeName(property));
700
701 return mDatabase->setDevicePropertyValue(property, mData);
702}
703
704MtpResponseCode MtpServer::doResetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800705 if (mRequest.getParameterCount() < 1)
706 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400707 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100708 ALOGV("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400709 MtpDebug::getDevicePropCodeName(property));
710
711 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400712}
713
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400714MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500715 if (!hasStorage())
716 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800717 if (mRequest.getParameterCount() < 5)
718 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400719
720 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500721 // use uint32_t so we can support 0xFFFFFFFF
722 uint32_t format = mRequest.getParameter(2);
723 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400724 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500725 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100726 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400727 handle, MtpDebug::getFormatCodeName(format),
728 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
729
730 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
731}
732
Mike Lockwood16864ba2010-05-11 17:16:59 -0400733MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500734 if (!hasStorage())
735 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800736 if (mRequest.getParameterCount() < 1)
737 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400738 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700739 MtpObjectInfo info(handle);
740 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
741 if (result == MTP_RESPONSE_OK) {
742 char date[20];
743
744 mData.putUInt32(info.mStorageID);
745 mData.putUInt16(info.mFormat);
746 mData.putUInt16(info.mProtectionStatus);
747
748 // if object is being edited the database size may be out of date
749 uint32_t size = info.mCompressedSize;
750 ObjectEdit* edit = getEditObject(handle);
751 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700752 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700753 mData.putUInt32(size);
754
755 mData.putUInt16(info.mThumbFormat);
756 mData.putUInt32(info.mThumbCompressedSize);
757 mData.putUInt32(info.mThumbPixWidth);
758 mData.putUInt32(info.mThumbPixHeight);
759 mData.putUInt32(info.mImagePixWidth);
760 mData.putUInt32(info.mImagePixHeight);
761 mData.putUInt32(info.mImagePixDepth);
762 mData.putUInt32(info.mParent);
763 mData.putUInt16(info.mAssociationType);
764 mData.putUInt32(info.mAssociationDesc);
765 mData.putUInt32(info.mSequenceNumber);
766 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700767 formatDateTime(info.mDateCreated, date, sizeof(date));
768 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700769 formatDateTime(info.mDateModified, date, sizeof(date));
770 mData.putString(date); // date modified
771 mData.putEmptyString(); // keywords
772 }
773 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400774}
775
776MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500777 if (!hasStorage())
778 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800779 if (mRequest.getParameterCount() < 1)
780 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400781 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400782 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400783 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800784 MtpObjectFormat format;
785 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400786 if (result != MTP_RESPONSE_OK)
787 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400788
Jerry Zhang487be612016-10-24 12:10:41 -0700789 auto start = std::chrono::steady_clock::now();
790
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400791 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400792 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400793 mfr.fd = open(filePath, O_RDONLY);
794 if (mfr.fd < 0) {
795 return MTP_RESPONSE_GENERAL_ERROR;
796 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400797 mfr.offset = 0;
798 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400799 mfr.command = mRequest.getOperationCode();
800 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400801
802 // then transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700803 int ret = sHandle->sendFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +0800804 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700805 ALOGE("Mtp send file got error %s", strerror(errno));
tao.pei07a9e542015-07-17 17:18:41 +0800806 if (errno == ECANCELED) {
807 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
808 } else {
809 result = MTP_RESPONSE_GENERAL_ERROR;
810 }
811 } else {
812 result = MTP_RESPONSE_OK;
813 }
814
Jerry Zhang487be612016-10-24 12:10:41 -0700815 auto end = std::chrono::steady_clock::now();
816 std::chrono::duration<double> diff = end - start;
817 struct stat sstat;
818 fstat(mfr.fd, &sstat);
819 uint64_t finalsize = sstat.st_size;
820 ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
821 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwoodc6588762010-06-22 15:03:53 -0400822 close(mfr.fd);
tao.pei07a9e542015-07-17 17:18:41 +0800823 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400824}
825
Mike Lockwood64000782011-04-24 18:40:17 -0700826MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800827 if (mRequest.getParameterCount() < 1)
828 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700829 MtpObjectHandle handle = mRequest.getParameter(1);
830 size_t thumbSize;
831 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
832 if (thumb) {
833 // send data
834 mData.setOperationCode(mRequest.getOperationCode());
835 mData.setTransactionID(mRequest.getTransactionID());
Jerry Zhang487be612016-10-24 12:10:41 -0700836 mData.writeData(sHandle, thumb, thumbSize);
Mike Lockwood64000782011-04-24 18:40:17 -0700837 free(thumb);
838 return MTP_RESPONSE_OK;
839 } else {
840 return MTP_RESPONSE_GENERAL_ERROR;
841 }
842}
843
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700844MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500845 if (!hasStorage())
846 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500847 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700848 uint64_t offset;
849 uint32_t length;
850 offset = mRequest.getParameter(2);
851 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800852 // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
853 if (mRequest.getParameterCount() < 4)
854 return MTP_RESPONSE_INVALID_PARAMETER;
855
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700856 // android extension with 64 bit offset
857 uint64_t offset2 = mRequest.getParameter(3);
858 offset = offset | (offset2 << 32);
859 length = mRequest.getParameter(4);
860 } else {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800861 // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
862 if (mRequest.getParameterCount() < 3)
863 return MTP_RESPONSE_INVALID_PARAMETER;
864
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700865 // standard GetPartialObject
866 length = mRequest.getParameter(3);
867 }
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500868 MtpString pathBuf;
869 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800870 MtpObjectFormat format;
871 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500872 if (result != MTP_RESPONSE_OK)
873 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700874 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500875 length = fileLength - offset;
876
877 const char* filePath = (const char *)pathBuf;
878 mtp_file_range mfr;
879 mfr.fd = open(filePath, O_RDONLY);
880 if (mfr.fd < 0) {
881 return MTP_RESPONSE_GENERAL_ERROR;
882 }
883 mfr.offset = offset;
884 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400885 mfr.command = mRequest.getOperationCode();
886 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500887 mResponse.setParameter(1, length);
888
Mike Lockwoodef441d92011-07-14 21:00:02 -0400889 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700890 int ret = sHandle->sendFile(mfr);
Steve Block3856b092011-10-20 11:56:00 +0100891 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
tao.pei07a9e542015-07-17 17:18:41 +0800892 result = MTP_RESPONSE_OK;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500893 if (ret < 0) {
894 if (errno == ECANCELED)
tao.pei07a9e542015-07-17 17:18:41 +0800895 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500896 else
tao.pei07a9e542015-07-17 17:18:41 +0800897 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500898 }
tao.pei07a9e542015-07-17 17:18:41 +0800899 close(mfr.fd);
900 return result;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500901}
902
Mike Lockwood16864ba2010-05-11 17:16:59 -0400903MtpResponseCode MtpServer::doSendObjectInfo() {
904 MtpString path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800905 uint16_t temp16;
906 uint32_t temp32;
907
908 if (mRequest.getParameterCount() < 2)
909 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400910 MtpStorageID storageID = mRequest.getParameter(1);
911 MtpStorage* storage = getStorage(storageID);
912 MtpObjectHandle parent = mRequest.getParameter(2);
913 if (!storage)
914 return MTP_RESPONSE_INVALID_STORAGE_ID;
915
916 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400917 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400918 path = storage->getPath();
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400919 parent = 0;
920 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800921 int64_t length;
922 MtpObjectFormat format;
923 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400924 if (result != MTP_RESPONSE_OK)
925 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800926 if (format != MTP_FORMAT_ASSOCIATION)
927 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400928 }
929
930 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800931 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
932 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
933 MtpObjectFormat format = temp16;
934 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
935 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
936 mSendObjectFileSize = temp32;
937 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
938 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
939 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
940 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
941 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
942 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
943 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
944 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
945 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800946 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800947 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400948 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800949 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
Marco Nelissen7ea72dc2016-09-19 14:08:16 -0700950 if (name.getCharCount() == 0) {
951 ALOGE("empty name");
952 return MTP_RESPONSE_INVALID_PARAMETER;
953 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800954 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
955 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400956 // keywords follow
957
Steve Block3856b092011-10-20 11:56:00 +0100958 ALOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400959 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400960 if (!parseDateTime(modified, modifiedTime))
961 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400962
963 if (path[path.size() - 1] != '/')
964 path += "/";
965 path += (const char *)name;
966
Mike Lockwood20c3be02010-12-12 12:17:43 -0800967 // check space first
968 if (mSendObjectFileSize > storage->getFreeSpace())
969 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400970 uint64_t maxFileSize = storage->getMaxFileSize();
971 // check storage max file size
972 if (maxFileSize != 0) {
973 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
974 // is >= 0xFFFFFFFF
975 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
976 return MTP_RESPONSE_OBJECT_TOO_LARGE;
977 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800978
Steve Blockb8a80522011-12-20 16:23:08 +0000979 ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Mike Lockwood4714b072010-07-12 08:49:01 -0400980 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
981 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400982 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400983 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400984 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400985
986 if (format == MTP_FORMAT_ASSOCIATION) {
987 mode_t mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400988 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400989 umask(mask);
990 if (ret && ret != -EEXIST)
991 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400992 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwoodaa952402011-01-18 11:06:19 -0800993
994 // SendObject does not get sent for directories, so call endSendObject here instead
995 mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400996 } else {
997 mSendObjectFilePath = path;
998 // save the handle for the SendObject call, which should follow
999 mSendObjectHandle = handle;
Mike Lockwood4714b072010-07-12 08:49:01 -04001000 mSendObjectFormat = format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001001 }
1002
1003 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001004 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001005 mResponse.setParameter(3, handle);
1006
1007 return MTP_RESPONSE_OK;
1008}
1009
1010MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001011 if (!hasStorage())
1012 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -04001013 MtpResponseCode result = MTP_RESPONSE_OK;
1014 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001015 int ret, initialData;
tao.pei07a9e542015-07-17 17:18:41 +08001016 bool isCanceled = false;
Mike Lockwood4714b072010-07-12 08:49:01 -04001017
Jerry Zhang487be612016-10-24 12:10:41 -07001018 auto start = std::chrono::steady_clock::now();
1019
Mike Lockwood16864ba2010-05-11 17:16:59 -04001020 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +00001021 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -04001022 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
1023 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001024 }
1025
Mike Lockwoodef441d92011-07-14 21:00:02 -04001026 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001027 ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001028 if (ret < MTP_CONTAINER_HEADER_SIZE) {
1029 result = MTP_RESPONSE_GENERAL_ERROR;
1030 goto done;
1031 }
1032 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001033
1034 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -07001035 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001036 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001037 result = MTP_RESPONSE_GENERAL_ERROR;
1038 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001039 }
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001040 fchown(mfr.fd, getuid(), mFileGroup);
1041 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001042 mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001043 fchmod(mfr.fd, mFilePermission);
1044 umask(mask);
1045
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001046 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001047 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001048 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001049
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001050 if (ret < 0) {
1051 ALOGE("failed to write initial data");
1052 result = MTP_RESPONSE_GENERAL_ERROR;
1053 } else {
1054 if (mSendObjectFileSize - initialData > 0) {
1055 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 }
1062
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001063 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -07001064 ret = sHandle->receiveFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +08001065 if ((ret < 0) && (errno == ECANCELED)) {
1066 isCanceled = true;
1067 }
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001068 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001069 }
Jerry Zhang487be612016-10-24 12:10:41 -07001070 struct stat sstat;
1071 fstat(mfr.fd, &sstat);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001072 close(mfr.fd);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001073
Mike Lockwood916076c2010-06-04 09:49:21 -04001074 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -07001075 ALOGE("Mtp receive file got error %s", strerror(errno));
Mike Lockwood916076c2010-06-04 09:49:21 -04001076 unlink(mSendObjectFilePath);
tao.pei07a9e542015-07-17 17:18:41 +08001077 if (isCanceled)
Mike Lockwood4714b072010-07-12 08:49:01 -04001078 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001079 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001080 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001081 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001082
1083done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001084 // reset so we don't attempt to send the data back
1085 mData.reset();
1086
Mike Lockwood4714b072010-07-12 08:49:01 -04001087 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
Mike Lockwoodaa952402011-01-18 11:06:19 -08001088 result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001089 mSendObjectHandle = kInvalidObjectHandle;
1090 mSendObjectFormat = 0;
Jerry Zhang487be612016-10-24 12:10:41 -07001091
1092 auto end = std::chrono::steady_clock::now();
1093 std::chrono::duration<double> diff = end - start;
1094 uint64_t finalsize = sstat.st_size;
1095 ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
1096 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwood4714b072010-07-12 08:49:01 -04001097 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001098}
1099
Mike Lockwoodd3211492010-09-13 17:15:58 -04001100static void deleteRecursive(const char* path) {
1101 char pathbuf[PATH_MAX];
Mark Salyzynd239cb62014-06-18 16:32:27 -07001102 size_t pathLength = strlen(path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001103 if (pathLength >= sizeof(pathbuf) - 1) {
Steve Block29357bc2012-01-06 19:20:56 +00001104 ALOGE("path too long: %s\n", path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001105 }
1106 strcpy(pathbuf, path);
1107 if (pathbuf[pathLength - 1] != '/') {
1108 pathbuf[pathLength++] = '/';
1109 }
1110 char* fileSpot = pathbuf + pathLength;
1111 int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1112
1113 DIR* dir = opendir(path);
1114 if (!dir) {
Steve Block29357bc2012-01-06 19:20:56 +00001115 ALOGE("opendir %s failed: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001116 return;
1117 }
1118
1119 struct dirent* entry;
1120 while ((entry = readdir(dir))) {
1121 const char* name = entry->d_name;
1122
1123 // ignore "." and ".."
1124 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1125 continue;
1126 }
1127
1128 int nameLength = strlen(name);
1129 if (nameLength > pathRemaining) {
Steve Block29357bc2012-01-06 19:20:56 +00001130 ALOGE("path %s/%s too long\n", path, name);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001131 continue;
1132 }
1133 strcpy(fileSpot, name);
1134
Mike Lockwoodd3211492010-09-13 17:15:58 -04001135 if (entry->d_type == DT_DIR) {
1136 deleteRecursive(pathbuf);
1137 rmdir(pathbuf);
1138 } else {
1139 unlink(pathbuf);
1140 }
1141 }
Mike Lockwood7ce05cf2010-11-11 11:22:32 -05001142 closedir(dir);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001143}
1144
1145static void deletePath(const char* path) {
1146 struct stat statbuf;
1147 if (stat(path, &statbuf) == 0) {
1148 if (S_ISDIR(statbuf.st_mode)) {
1149 deleteRecursive(path);
1150 rmdir(path);
1151 } else {
1152 unlink(path);
1153 }
1154 } else {
Steve Block29357bc2012-01-06 19:20:56 +00001155 ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001156 }
1157}
1158
Mike Lockwood16864ba2010-05-11 17:16:59 -04001159MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001160 if (!hasStorage())
1161 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Marco Nelissenea9f2152015-01-23 10:55:25 -08001162 if (mRequest.getParameterCount() < 1)
Mike Lockwoodab063842014-11-12 14:20:06 -08001163 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001164 MtpObjectHandle handle = mRequest.getParameter(1);
Marco Nelissenea9f2152015-01-23 10:55:25 -08001165 MtpObjectFormat format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001166 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1167 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001168
1169 MtpString filePath;
1170 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001171 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001172 if (result == MTP_RESPONSE_OK) {
Steve Block3856b092011-10-20 11:56:00 +01001173 ALOGV("deleting %s", (const char *)filePath);
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001174 result = mDatabase->deleteFile(handle);
1175 // Don't delete the actual files unless the database deletion is allowed
1176 if (result == MTP_RESPONSE_OK) {
1177 deletePath((const char *)filePath);
1178 }
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001179 }
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001180
1181 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001182}
1183
1184MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001185 if (mRequest.getParameterCount() < 2)
1186 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001187 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001188 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001189 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001190 MtpDebug::getFormatCodeName(format));
1191 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001192 if (!property)
1193 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001194 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001195 delete property;
1196 return MTP_RESPONSE_OK;
1197}
1198
1199MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001200 if (mRequest.getParameterCount() < 1)
1201 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001202 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001203 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001204 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1205 if (!property)
1206 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1207 property->write(mData);
1208 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001209 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001210}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001211
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001212MtpResponseCode MtpServer::doSendPartialObject() {
1213 if (!hasStorage())
1214 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001215 if (mRequest.getParameterCount() < 4)
1216 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001217 MtpObjectHandle handle = mRequest.getParameter(1);
1218 uint64_t offset = mRequest.getParameter(2);
1219 uint64_t offset2 = mRequest.getParameter(3);
1220 offset = offset | (offset2 << 32);
1221 uint32_t length = mRequest.getParameter(4);
1222
1223 ObjectEdit* edit = getEditObject(handle);
1224 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001225 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001226 return MTP_RESPONSE_GENERAL_ERROR;
1227 }
1228
1229 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001230 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001231 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1232 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001233 return MTP_RESPONSE_GENERAL_ERROR;
1234 }
1235
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001236 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001237 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001238
Mike Lockwoodef441d92011-07-14 21:00:02 -04001239 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001240 int ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001241 if (ret < MTP_CONTAINER_HEADER_SIZE)
1242 return MTP_RESPONSE_GENERAL_ERROR;
1243 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1244
1245 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001246 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001247 offset += initialData;
1248 length -= initialData;
1249 }
1250
tao.pei07a9e542015-07-17 17:18:41 +08001251 bool isCanceled = false;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001252 if (ret < 0) {
1253 ALOGE("failed to write initial data");
1254 } else {
1255 if (length > 0) {
1256 mtp_file_range mfr;
1257 mfr.fd = edit->mFD;
1258 mfr.offset = offset;
1259 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001260
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001261 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -07001262 ret = sHandle->receiveFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +08001263 if ((ret < 0) && (errno == ECANCELED)) {
1264 isCanceled = true;
1265 }
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001266 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001267 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001268 if (ret < 0) {
1269 mResponse.setParameter(1, 0);
tao.pei07a9e542015-07-17 17:18:41 +08001270 if (isCanceled)
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001271 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1272 else
1273 return MTP_RESPONSE_GENERAL_ERROR;
1274 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001275
1276 // reset so we don't attempt to send this back
1277 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001278 mResponse.setParameter(1, length);
1279 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001280 if (end > edit->mSize) {
1281 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001282 }
1283 return MTP_RESPONSE_OK;
1284}
1285
1286MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001287 if (mRequest.getParameterCount() < 3)
1288 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001289 MtpObjectHandle handle = mRequest.getParameter(1);
1290 ObjectEdit* edit = getEditObject(handle);
1291 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001292 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001293 return MTP_RESPONSE_GENERAL_ERROR;
1294 }
1295
1296 uint64_t offset = mRequest.getParameter(2);
1297 uint64_t offset2 = mRequest.getParameter(3);
1298 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001299 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001300 return MTP_RESPONSE_GENERAL_ERROR;
1301 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001302 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001303 return MTP_RESPONSE_OK;
1304 }
1305}
1306
1307MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001308 if (mRequest.getParameterCount() < 1)
1309 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001310 MtpObjectHandle handle = mRequest.getParameter(1);
1311 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001312 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001313 return MTP_RESPONSE_GENERAL_ERROR;
1314 }
1315
1316 MtpString path;
1317 int64_t fileLength;
1318 MtpObjectFormat format;
1319 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1320 if (result != MTP_RESPONSE_OK)
1321 return result;
1322
1323 int fd = open((const char *)path, O_RDWR | O_EXCL);
1324 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001325 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001326 return MTP_RESPONSE_GENERAL_ERROR;
1327 }
1328
1329 addEditObject(handle, path, fileLength, format, fd);
1330 return MTP_RESPONSE_OK;
1331}
1332
1333MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001334 if (mRequest.getParameterCount() < 1)
1335 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001336 MtpObjectHandle handle = mRequest.getParameter(1);
1337 ObjectEdit* edit = getEditObject(handle);
1338 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001339 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001340 return MTP_RESPONSE_GENERAL_ERROR;
1341 }
1342
1343 commitEdit(edit);
1344 removeEditObject(handle);
1345 return MTP_RESPONSE_OK;
1346}
1347
Mike Lockwood7850ef92010-05-14 10:10:36 -04001348} // namespace android