blob: 2180462e87ed0ecb1f029f417c73a84a0dd65256 [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>
caozhiyuan854cb172017-04-26 16:52:30 +080028#include <sys/time.h>
Mike Lockwoodc42aa122010-06-14 17:58:08 -070029
Mike Lockwooda881b442010-09-23 22:32:05 -040030#define LOG_TAG "MtpServer"
31
Mike Lockwood16864ba2010-05-11 17:16:59 -040032#include "MtpDebug.h"
Mike Lockwood7f53a192010-07-09 10:45:22 -040033#include "MtpDatabase.h"
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070034#include "MtpObjectInfo.h"
Mike Lockwood21ef7d02010-06-30 17:00:35 -040035#include "MtpProperty.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040036#include "MtpServer.h"
37#include "MtpStorage.h"
38#include "MtpStringBuffer.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040039
Mike Lockwood7850ef92010-05-14 10:10:36 -040040namespace android {
41
Mike Lockwood16864ba2010-05-11 17:16:59 -040042static const MtpOperationCode kSupportedOperationCodes[] = {
43 MTP_OPERATION_GET_DEVICE_INFO,
44 MTP_OPERATION_OPEN_SESSION,
45 MTP_OPERATION_CLOSE_SESSION,
46 MTP_OPERATION_GET_STORAGE_IDS,
47 MTP_OPERATION_GET_STORAGE_INFO,
48 MTP_OPERATION_GET_NUM_OBJECTS,
49 MTP_OPERATION_GET_OBJECT_HANDLES,
50 MTP_OPERATION_GET_OBJECT_INFO,
51 MTP_OPERATION_GET_OBJECT,
Mike Lockwood64000782011-04-24 18:40:17 -070052 MTP_OPERATION_GET_THUMB,
Mike Lockwood16864ba2010-05-11 17:16:59 -040053 MTP_OPERATION_DELETE_OBJECT,
54 MTP_OPERATION_SEND_OBJECT_INFO,
55 MTP_OPERATION_SEND_OBJECT,
56// MTP_OPERATION_INITIATE_CAPTURE,
57// MTP_OPERATION_FORMAT_STORE,
Jerry Zhang6dafecc2017-02-23 16:39:30 -080058 MTP_OPERATION_RESET_DEVICE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040059// MTP_OPERATION_SELF_TEST,
60// MTP_OPERATION_SET_OBJECT_PROTECTION,
61// MTP_OPERATION_POWER_DOWN,
Mike Lockwoode3e76c42010-09-02 14:57:30 -040062 MTP_OPERATION_GET_DEVICE_PROP_DESC,
Mike Lockwood8277cec2010-08-10 15:20:35 -040063 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
64 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
65 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040066// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
67// MTP_OPERATION_MOVE_OBJECT,
68// MTP_OPERATION_COPY_OBJECT,
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -050069 MTP_OPERATION_GET_PARTIAL_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040070// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
71 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
Mike Lockwood8277cec2010-08-10 15:20:35 -040072 MTP_OPERATION_GET_OBJECT_PROP_DESC,
Mike Lockwood677f5702010-09-23 23:04:28 -040073 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
74 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
Mike Lockwoodb6da06e2010-10-14 18:03:25 -040075 MTP_OPERATION_GET_OBJECT_PROP_LIST,
76// MTP_OPERATION_SET_OBJECT_PROP_LIST,
77// MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
78// MTP_OPERATION_SEND_OBJECT_PROP_LIST,
Mike Lockwood438344f2010-08-03 15:30:09 -040079 MTP_OPERATION_GET_OBJECT_REFERENCES,
80 MTP_OPERATION_SET_OBJECT_REFERENCES,
Mike Lockwood16864ba2010-05-11 17:16:59 -040081// MTP_OPERATION_SKIP,
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070082 // Android extension for direct file IO
83 MTP_OPERATION_GET_PARTIAL_OBJECT_64,
84 MTP_OPERATION_SEND_PARTIAL_OBJECT,
85 MTP_OPERATION_TRUNCATE_OBJECT,
86 MTP_OPERATION_BEGIN_EDIT_OBJECT,
87 MTP_OPERATION_END_EDIT_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040088};
89
Mike Lockwood873871f2010-07-12 18:54:16 -040090static const MtpEventCode kSupportedEventCodes[] = {
91 MTP_EVENT_OBJECT_ADDED,
92 MTP_EVENT_OBJECT_REMOVED,
Mike Lockwooda8494402011-02-18 09:07:14 -050093 MTP_EVENT_STORE_ADDED,
94 MTP_EVENT_STORE_REMOVED,
Mike Lockwood0fa848d2014-03-07 13:29:59 -080095 MTP_EVENT_DEVICE_PROP_CHANGED,
Mike Lockwood873871f2010-07-12 18:54:16 -040096};
97
Jerry Zhang487be612016-10-24 12:10:41 -070098MtpServer::MtpServer(MtpDatabase* database, bool ptp,
Alex Klyubin792298f2016-12-21 11:20:22 -080099 int fileGroup, int filePerm, int directoryPerm,
100 const MtpString& deviceInfoManufacturer,
101 const MtpString& deviceInfoModel,
102 const MtpString& deviceInfoDeviceVersion,
103 const MtpString& deviceInfoSerialNumber)
Jerry Zhang487be612016-10-24 12:10:41 -0700104 : mDatabase(database),
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400105 mPtp(ptp),
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400106 mFileGroup(fileGroup),
107 mFilePermission(filePerm),
108 mDirectoryPermission(directoryPerm),
Alex Klyubin792298f2016-12-21 11:20:22 -0800109 mDeviceInfoManufacturer(deviceInfoManufacturer),
110 mDeviceInfoModel(deviceInfoModel),
111 mDeviceInfoDeviceVersion(deviceInfoDeviceVersion),
112 mDeviceInfoSerialNumber(deviceInfoSerialNumber),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400113 mSessionID(0),
114 mSessionOpen(false),
115 mSendObjectHandle(kInvalidObjectHandle),
Mike Lockwood4714b072010-07-12 08:49:01 -0400116 mSendObjectFormat(0),
caozhiyuan854cb172017-04-26 16:52:30 +0800117 mSendObjectFileSize(0),
118 mSendObjectModifiedTime(0)
Mike Lockwood16864ba2010-05-11 17:16:59 -0400119{
Mike Lockwood16864ba2010-05-11 17:16:59 -0400120}
121
122MtpServer::~MtpServer() {
123}
124
Jerry Zhang487be612016-10-24 12:10:41 -0700125IMtpHandle* MtpServer::sHandle = nullptr;
126
127int MtpServer::configure(bool usePtp) {
128 if (sHandle == nullptr) {
129 bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
130 sHandle = ffs_ok ? get_ffs_handle() : get_mtp_handle();
131 }
132
133 int ret = sHandle->configure(usePtp);
134 if (ret) ALOGE("Failed to configure MTP driver!");
135 else android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
136
137 return ret;
138}
139
Mike Lockwooda8494402011-02-18 09:07:14 -0500140void MtpServer::addStorage(MtpStorage* storage) {
141 Mutex::Autolock autoLock(mMutex);
142
143 mStorages.push(storage);
144 sendStoreAdded(storage->getStorageID());
145}
146
147void MtpServer::removeStorage(MtpStorage* storage) {
148 Mutex::Autolock autoLock(mMutex);
149
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700150 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500151 if (mStorages[i] == storage) {
152 mStorages.removeAt(i);
153 sendStoreRemoved(storage->getStorageID());
154 break;
155 }
156 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400157}
158
159MtpStorage* MtpServer::getStorage(MtpStorageID id) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800160 if (id == 0)
161 return mStorages[0];
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700162 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800163 MtpStorage* storage = mStorages[i];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400164 if (storage->getStorageID() == id)
165 return storage;
166 }
Jerry Zhang487be612016-10-24 12:10:41 -0700167 return nullptr;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400168}
169
Mike Lockwooda8494402011-02-18 09:07:14 -0500170bool MtpServer::hasStorage(MtpStorageID id) {
171 if (id == 0 || id == 0xFFFFFFFF)
172 return mStorages.size() > 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700173 return (getStorage(id) != nullptr);
Mike Lockwooda8494402011-02-18 09:07:14 -0500174}
175
Mike Lockwood16864ba2010-05-11 17:16:59 -0400176void MtpServer::run() {
Jerry Zhang487be612016-10-24 12:10:41 -0700177 if (!sHandle) {
178 ALOGE("MtpServer was never configured!");
179 return;
180 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400181
Jerry Zhang487be612016-10-24 12:10:41 -0700182 if (sHandle->start()) {
183 ALOGE("Failed to start usb driver!");
Jerry Zhangcc9d0fd2017-01-27 10:29:59 -0800184 sHandle->close();
Jerry Zhang487be612016-10-24 12:10:41 -0700185 return;
186 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400187
188 while (1) {
Jerry Zhang487be612016-10-24 12:10:41 -0700189 int ret = mRequest.read(sHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400190 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700191 ALOGE("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400192 if (errno == ECANCELED) {
193 // return to top of loop and wait for next command
194 continue;
195 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400196 break;
197 }
198 MtpOperationCode operation = mRequest.getOperationCode();
199 MtpTransactionID transaction = mRequest.getTransactionID();
200
Steve Block3856b092011-10-20 11:56:00 +0100201 ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400202 // FIXME need to generalize this
Mike Lockwood438344f2010-08-03 15:30:09 -0400203 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood8277cec2010-08-10 15:20:35 -0400204 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
205 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
206 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400207 if (dataIn) {
Jerry Zhang487be612016-10-24 12:10:41 -0700208 int ret = mData.read(sHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400209 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000210 ALOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400211 if (errno == ECANCELED) {
212 // return to top of loop and wait for next command
213 continue;
214 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400215 break;
216 }
Steve Block3856b092011-10-20 11:56:00 +0100217 ALOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400218 } else {
219 mData.reset();
220 }
221
Mike Lockwood916076c2010-06-04 09:49:21 -0400222 if (handleRequest()) {
223 if (!dataIn && mData.hasData()) {
224 mData.setOperationCode(operation);
225 mData.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100226 ALOGV("sending data:");
Jerry Zhang487be612016-10-24 12:10:41 -0700227 ret = mData.write(sHandle);
Mike Lockwood916076c2010-06-04 09:49:21 -0400228 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000229 ALOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400230 if (errno == ECANCELED) {
231 // return to top of loop and wait for next command
232 continue;
233 }
234 break;
235 }
236 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400237
Mike Lockwood916076c2010-06-04 09:49:21 -0400238 mResponse.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100239 ALOGV("sending response %04X", mResponse.getResponseCode());
Jerry Zhang487be612016-10-24 12:10:41 -0700240 ret = mResponse.write(sHandle);
tao.pei07a9e542015-07-17 17:18:41 +0800241 const int savedErrno = errno;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400242 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000243 ALOGE("request write returned %d, errno: %d", ret, errno);
tao.pei07a9e542015-07-17 17:18:41 +0800244 if (savedErrno == ECANCELED) {
Mike Lockwood916076c2010-06-04 09:49:21 -0400245 // return to top of loop and wait for next command
246 continue;
247 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400248 break;
249 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400250 } else {
Steve Block3856b092011-10-20 11:56:00 +0100251 ALOGV("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400252 }
253 }
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400254
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700255 // commit any open edits
256 int count = mObjectEditList.size();
257 for (int i = 0; i < count; i++) {
258 ObjectEdit* edit = mObjectEditList[i];
259 commitEdit(edit);
260 delete edit;
261 }
262 mObjectEditList.clear();
263
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400264 if (mSessionOpen)
265 mDatabase->sessionEnded();
Jerry Zhang487be612016-10-24 12:10:41 -0700266
267 sHandle->close();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400268}
269
Mike Lockwood873871f2010-07-12 18:54:16 -0400270void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100271 ALOGV("sendObjectAdded %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500272 sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
Mike Lockwood873871f2010-07-12 18:54:16 -0400273}
274
275void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100276 ALOGV("sendObjectRemoved %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500277 sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
278}
279
280void MtpServer::sendStoreAdded(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100281 ALOGV("sendStoreAdded %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500282 sendEvent(MTP_EVENT_STORE_ADDED, id);
283}
284
285void MtpServer::sendStoreRemoved(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100286 ALOGV("sendStoreRemoved %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500287 sendEvent(MTP_EVENT_STORE_REMOVED, id);
288}
289
Mike Lockwood0fa848d2014-03-07 13:29:59 -0800290void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
291 ALOGV("sendDevicePropertyChanged %d\n", property);
292 sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
293}
294
Mike Lockwooda8494402011-02-18 09:07:14 -0500295void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400296 if (mSessionOpen) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500297 mEvent.setEventCode(code);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400298 mEvent.setTransactionID(mRequest.getTransactionID());
Mike Lockwooda8494402011-02-18 09:07:14 -0500299 mEvent.setParameter(1, param1);
Jerry Zhang487be612016-10-24 12:10:41 -0700300 if (mEvent.write(sHandle))
301 ALOGE("Mtp send event failed: %s", strerror(errno));
Mike Lockwood73ecd232010-07-19 14:29:58 -0400302 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400303}
304
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700305void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
306 uint64_t size, MtpObjectFormat format, int fd) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700307 ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700308 mObjectEditList.add(edit);
309}
310
311MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
312 int count = mObjectEditList.size();
313 for (int i = 0; i < count; i++) {
314 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700315 if (edit->mHandle == handle) return edit;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700316 }
Jerry Zhang487be612016-10-24 12:10:41 -0700317 return nullptr;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700318}
319
320void MtpServer::removeEditObject(MtpObjectHandle handle) {
321 int count = mObjectEditList.size();
322 for (int i = 0; i < count; i++) {
323 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700324 if (edit->mHandle == handle) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700325 delete edit;
326 mObjectEditList.removeAt(i);
327 return;
328 }
329 }
Steve Block29357bc2012-01-06 19:20:56 +0000330 ALOGE("ObjectEdit not found in removeEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700331}
332
333void MtpServer::commitEdit(ObjectEdit* edit) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700334 mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700335}
336
337
Mike Lockwood916076c2010-06-04 09:49:21 -0400338bool MtpServer::handleRequest() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500339 Mutex::Autolock autoLock(mMutex);
340
Mike Lockwood16864ba2010-05-11 17:16:59 -0400341 MtpOperationCode operation = mRequest.getOperationCode();
342 MtpResponseCode response;
343
344 mResponse.reset();
345
346 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
347 // FIXME - need to delete mSendObjectHandle from the database
Steve Block29357bc2012-01-06 19:20:56 +0000348 ALOGE("expected SendObject after SendObjectInfo");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400349 mSendObjectHandle = kInvalidObjectHandle;
350 }
351
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700352 int containertype = mRequest.getContainerType();
353 if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
354 ALOGE("wrong container type %d", containertype);
355 return false;
356 }
357
358 ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
359
Mike Lockwood16864ba2010-05-11 17:16:59 -0400360 switch (operation) {
361 case MTP_OPERATION_GET_DEVICE_INFO:
362 response = doGetDeviceInfo();
363 break;
364 case MTP_OPERATION_OPEN_SESSION:
365 response = doOpenSession();
366 break;
Jerry Zhang6dafecc2017-02-23 16:39:30 -0800367 case MTP_OPERATION_RESET_DEVICE:
Mike Lockwood16864ba2010-05-11 17:16:59 -0400368 case MTP_OPERATION_CLOSE_SESSION:
369 response = doCloseSession();
370 break;
371 case MTP_OPERATION_GET_STORAGE_IDS:
372 response = doGetStorageIDs();
373 break;
374 case MTP_OPERATION_GET_STORAGE_INFO:
375 response = doGetStorageInfo();
376 break;
377 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
378 response = doGetObjectPropsSupported();
379 break;
380 case MTP_OPERATION_GET_OBJECT_HANDLES:
381 response = doGetObjectHandles();
382 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400383 case MTP_OPERATION_GET_NUM_OBJECTS:
384 response = doGetNumObjects();
385 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400386 case MTP_OPERATION_GET_OBJECT_REFERENCES:
387 response = doGetObjectReferences();
388 break;
389 case MTP_OPERATION_SET_OBJECT_REFERENCES:
390 response = doSetObjectReferences();
391 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400392 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
393 response = doGetObjectPropValue();
394 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400395 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
396 response = doSetObjectPropValue();
397 break;
398 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
399 response = doGetDevicePropValue();
400 break;
401 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
402 response = doSetDevicePropValue();
403 break;
404 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
405 response = doResetDevicePropValue();
406 break;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400407 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
408 response = doGetObjectPropList();
409 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400410 case MTP_OPERATION_GET_OBJECT_INFO:
411 response = doGetObjectInfo();
412 break;
413 case MTP_OPERATION_GET_OBJECT:
414 response = doGetObject();
415 break;
Mike Lockwood64000782011-04-24 18:40:17 -0700416 case MTP_OPERATION_GET_THUMB:
417 response = doGetThumb();
418 break;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500419 case MTP_OPERATION_GET_PARTIAL_OBJECT:
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700420 case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
421 response = doGetPartialObject(operation);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500422 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400423 case MTP_OPERATION_SEND_OBJECT_INFO:
424 response = doSendObjectInfo();
425 break;
426 case MTP_OPERATION_SEND_OBJECT:
427 response = doSendObject();
428 break;
429 case MTP_OPERATION_DELETE_OBJECT:
430 response = doDeleteObject();
431 break;
432 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400433 response = doGetObjectPropDesc();
434 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400435 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
436 response = doGetDevicePropDesc();
437 break;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700438 case MTP_OPERATION_SEND_PARTIAL_OBJECT:
439 response = doSendPartialObject();
440 break;
441 case MTP_OPERATION_TRUNCATE_OBJECT:
442 response = doTruncateObject();
443 break;
444 case MTP_OPERATION_BEGIN_EDIT_OBJECT:
445 response = doBeginEditObject();
446 break;
447 case MTP_OPERATION_END_EDIT_OBJECT:
448 response = doEndEditObject();
449 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400450 default:
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700451 ALOGE("got unsupported command %s (%x)",
452 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400453 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
454 break;
455 }
456
Mike Lockwood916076c2010-06-04 09:49:21 -0400457 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
458 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400459 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400460 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400461}
462
463MtpResponseCode MtpServer::doGetDeviceInfo() {
464 MtpStringBuffer string;
465
Mike Lockwood782aef12010-08-10 07:37:50 -0400466 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
467 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
468 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
469
Mike Lockwood16864ba2010-05-11 17:16:59 -0400470 // fill in device info
471 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400472 if (mPtp) {
473 mData.putUInt32(0);
474 } else {
475 // MTP Vendor Extension ID
476 mData.putUInt32(6);
477 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400478 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400479 if (mPtp) {
480 // no extensions
481 string.set("");
482 } else {
483 // MTP extensions
484 string.set("microsoft.com: 1.0; android.com: 1.0;");
485 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400486 mData.putString(string); // MTP Extensions
487 mData.putUInt16(0); //Functional Mode
488 mData.putAUInt16(kSupportedOperationCodes,
489 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400490 mData.putAUInt16(kSupportedEventCodes,
491 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400492 mData.putAUInt16(deviceProperties); // Device Properties Supported
493 mData.putAUInt16(captureFormats); // Capture Formats
494 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500495
Alex Klyubin792298f2016-12-21 11:20:22 -0800496 mData.putString(mDeviceInfoManufacturer); // Manufacturer
497 mData.putString(mDeviceInfoModel); // Model
498 mData.putString(mDeviceInfoDeviceVersion); // Device Version
499 mData.putString(mDeviceInfoSerialNumber); // Serial Number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400500
Mike Lockwood782aef12010-08-10 07:37:50 -0400501 delete playbackFormats;
502 delete captureFormats;
503 delete deviceProperties;
504
Mike Lockwood16864ba2010-05-11 17:16:59 -0400505 return MTP_RESPONSE_OK;
506}
507
508MtpResponseCode MtpServer::doOpenSession() {
509 if (mSessionOpen) {
510 mResponse.setParameter(1, mSessionID);
511 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
512 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800513 if (mRequest.getParameterCount() < 1)
514 return MTP_RESPONSE_INVALID_PARAMETER;
515
Mike Lockwood16864ba2010-05-11 17:16:59 -0400516 mSessionID = mRequest.getParameter(1);
517 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400518
519 mDatabase->sessionStarted();
520
Mike Lockwood16864ba2010-05-11 17:16:59 -0400521 return MTP_RESPONSE_OK;
522}
523
524MtpResponseCode MtpServer::doCloseSession() {
525 if (!mSessionOpen)
526 return MTP_RESPONSE_SESSION_NOT_OPEN;
527 mSessionID = 0;
528 mSessionOpen = false;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400529 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400530 return MTP_RESPONSE_OK;
531}
532
533MtpResponseCode MtpServer::doGetStorageIDs() {
534 if (!mSessionOpen)
535 return MTP_RESPONSE_SESSION_NOT_OPEN;
536
537 int count = mStorages.size();
538 mData.putUInt32(count);
539 for (int i = 0; i < count; i++)
540 mData.putUInt32(mStorages[i]->getStorageID());
541
542 return MTP_RESPONSE_OK;
543}
544
545MtpResponseCode MtpServer::doGetStorageInfo() {
546 MtpStringBuffer string;
547
548 if (!mSessionOpen)
549 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800550 if (mRequest.getParameterCount() < 1)
551 return MTP_RESPONSE_INVALID_PARAMETER;
552
Mike Lockwood16864ba2010-05-11 17:16:59 -0400553 MtpStorageID id = mRequest.getParameter(1);
554 MtpStorage* storage = getStorage(id);
555 if (!storage)
556 return MTP_RESPONSE_INVALID_STORAGE_ID;
557
558 mData.putUInt16(storage->getType());
559 mData.putUInt16(storage->getFileSystemType());
560 mData.putUInt16(storage->getAccessCapability());
561 mData.putUInt64(storage->getMaxCapacity());
562 mData.putUInt64(storage->getFreeSpace());
563 mData.putUInt32(1024*1024*1024); // Free Space in Objects
564 string.set(storage->getDescription());
565 mData.putString(string);
566 mData.putEmptyString(); // Volume Identifier
567
568 return MTP_RESPONSE_OK;
569}
570
571MtpResponseCode MtpServer::doGetObjectPropsSupported() {
572 if (!mSessionOpen)
573 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800574 if (mRequest.getParameterCount() < 1)
575 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400576 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800577 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400578 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400579 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400580 return MTP_RESPONSE_OK;
581}
582
583MtpResponseCode MtpServer::doGetObjectHandles() {
584 if (!mSessionOpen)
585 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800586 if (mRequest.getParameterCount() < 3)
587 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400588 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400589 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400590 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400591 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500592
593 if (!hasStorage(storageID))
594 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400595
596 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
597 mData.putAUInt32(handles);
598 delete handles;
599 return MTP_RESPONSE_OK;
600}
601
Mike Lockwood343af4e2010-08-02 10:52:20 -0400602MtpResponseCode MtpServer::doGetNumObjects() {
603 if (!mSessionOpen)
604 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800605 if (mRequest.getParameterCount() < 3)
606 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400607 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
608 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
609 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400610 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500611 if (!hasStorage(storageID))
612 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400613
614 int count = mDatabase->getNumObjects(storageID, format, parent);
615 if (count >= 0) {
616 mResponse.setParameter(1, count);
617 return MTP_RESPONSE_OK;
618 } else {
619 mResponse.setParameter(1, 0);
620 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
621 }
622}
623
Mike Lockwood438344f2010-08-03 15:30:09 -0400624MtpResponseCode MtpServer::doGetObjectReferences() {
625 if (!mSessionOpen)
626 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500627 if (!hasStorage())
628 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800629 if (mRequest.getParameterCount() < 1)
630 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500631 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400632
633 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400634 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400635 if (handles) {
636 mData.putAUInt32(handles);
637 delete handles;
638 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400639 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400640 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400641 return MTP_RESPONSE_OK;
642}
643
644MtpResponseCode MtpServer::doSetObjectReferences() {
645 if (!mSessionOpen)
646 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500647 if (!hasStorage())
648 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800649 if (mRequest.getParameterCount() < 1)
650 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400651 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500652
Mike Lockwood438344f2010-08-03 15:30:09 -0400653 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800654 if (!references)
655 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400656 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
657 delete references;
658 return result;
659}
660
Mike Lockwood16864ba2010-05-11 17:16:59 -0400661MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500662 if (!hasStorage())
663 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800664 if (mRequest.getParameterCount() < 2)
665 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400666 MtpObjectHandle handle = mRequest.getParameter(1);
667 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100668 ALOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400669 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400670
Mike Lockwood8277cec2010-08-10 15:20:35 -0400671 return mDatabase->getObjectPropertyValue(handle, property, mData);
672}
673
674MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500675 if (!hasStorage())
676 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800677 if (mRequest.getParameterCount() < 2)
678 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400679 MtpObjectHandle handle = mRequest.getParameter(1);
680 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100681 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400682 MtpDebug::getObjectPropCodeName(property));
683
684 return mDatabase->setObjectPropertyValue(handle, property, mData);
685}
686
687MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800688 if (mRequest.getParameterCount() < 1)
689 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400690 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100691 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400692 MtpDebug::getDevicePropCodeName(property));
693
694 return mDatabase->getDevicePropertyValue(property, mData);
695}
696
697MtpResponseCode MtpServer::doSetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800698 if (mRequest.getParameterCount() < 1)
699 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400700 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100701 ALOGV("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400702 MtpDebug::getDevicePropCodeName(property));
703
704 return mDatabase->setDevicePropertyValue(property, mData);
705}
706
707MtpResponseCode MtpServer::doResetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800708 if (mRequest.getParameterCount() < 1)
709 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400710 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100711 ALOGV("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400712 MtpDebug::getDevicePropCodeName(property));
713
714 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400715}
716
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400717MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500718 if (!hasStorage())
719 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800720 if (mRequest.getParameterCount() < 5)
721 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400722
723 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500724 // use uint32_t so we can support 0xFFFFFFFF
725 uint32_t format = mRequest.getParameter(2);
726 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400727 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500728 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100729 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400730 handle, MtpDebug::getFormatCodeName(format),
731 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
732
733 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
734}
735
Mike Lockwood16864ba2010-05-11 17:16:59 -0400736MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500737 if (!hasStorage())
738 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800739 if (mRequest.getParameterCount() < 1)
740 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400741 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700742 MtpObjectInfo info(handle);
743 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
744 if (result == MTP_RESPONSE_OK) {
745 char date[20];
746
747 mData.putUInt32(info.mStorageID);
748 mData.putUInt16(info.mFormat);
749 mData.putUInt16(info.mProtectionStatus);
750
751 // if object is being edited the database size may be out of date
752 uint32_t size = info.mCompressedSize;
753 ObjectEdit* edit = getEditObject(handle);
754 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700755 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700756 mData.putUInt32(size);
757
758 mData.putUInt16(info.mThumbFormat);
759 mData.putUInt32(info.mThumbCompressedSize);
760 mData.putUInt32(info.mThumbPixWidth);
761 mData.putUInt32(info.mThumbPixHeight);
762 mData.putUInt32(info.mImagePixWidth);
763 mData.putUInt32(info.mImagePixHeight);
764 mData.putUInt32(info.mImagePixDepth);
765 mData.putUInt32(info.mParent);
766 mData.putUInt16(info.mAssociationType);
767 mData.putUInt32(info.mAssociationDesc);
768 mData.putUInt32(info.mSequenceNumber);
769 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700770 formatDateTime(info.mDateCreated, date, sizeof(date));
771 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700772 formatDateTime(info.mDateModified, date, sizeof(date));
773 mData.putString(date); // date modified
774 mData.putEmptyString(); // keywords
775 }
776 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400777}
778
779MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500780 if (!hasStorage())
781 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800782 if (mRequest.getParameterCount() < 1)
783 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400784 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400785 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400786 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800787 MtpObjectFormat format;
788 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400789 if (result != MTP_RESPONSE_OK)
790 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400791
Jerry Zhang487be612016-10-24 12:10:41 -0700792 auto start = std::chrono::steady_clock::now();
793
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400794 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400795 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400796 mfr.fd = open(filePath, O_RDONLY);
797 if (mfr.fd < 0) {
798 return MTP_RESPONSE_GENERAL_ERROR;
799 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400800 mfr.offset = 0;
801 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400802 mfr.command = mRequest.getOperationCode();
803 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400804
805 // then transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700806 int ret = sHandle->sendFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +0800807 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700808 ALOGE("Mtp send file got error %s", strerror(errno));
tao.pei07a9e542015-07-17 17:18:41 +0800809 if (errno == ECANCELED) {
810 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
811 } else {
812 result = MTP_RESPONSE_GENERAL_ERROR;
813 }
814 } else {
815 result = MTP_RESPONSE_OK;
816 }
817
Jerry Zhang487be612016-10-24 12:10:41 -0700818 auto end = std::chrono::steady_clock::now();
819 std::chrono::duration<double> diff = end - start;
820 struct stat sstat;
821 fstat(mfr.fd, &sstat);
822 uint64_t finalsize = sstat.st_size;
823 ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
824 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwoodc6588762010-06-22 15:03:53 -0400825 close(mfr.fd);
tao.pei07a9e542015-07-17 17:18:41 +0800826 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400827}
828
Mike Lockwood64000782011-04-24 18:40:17 -0700829MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800830 if (mRequest.getParameterCount() < 1)
831 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700832 MtpObjectHandle handle = mRequest.getParameter(1);
833 size_t thumbSize;
834 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
835 if (thumb) {
836 // send data
837 mData.setOperationCode(mRequest.getOperationCode());
838 mData.setTransactionID(mRequest.getTransactionID());
Jerry Zhang487be612016-10-24 12:10:41 -0700839 mData.writeData(sHandle, thumb, thumbSize);
Mike Lockwood64000782011-04-24 18:40:17 -0700840 free(thumb);
841 return MTP_RESPONSE_OK;
842 } else {
843 return MTP_RESPONSE_GENERAL_ERROR;
844 }
845}
846
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700847MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500848 if (!hasStorage())
849 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500850 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700851 uint64_t offset;
852 uint32_t length;
853 offset = mRequest.getParameter(2);
854 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800855 // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
856 if (mRequest.getParameterCount() < 4)
857 return MTP_RESPONSE_INVALID_PARAMETER;
858
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700859 // android extension with 64 bit offset
860 uint64_t offset2 = mRequest.getParameter(3);
861 offset = offset | (offset2 << 32);
862 length = mRequest.getParameter(4);
863 } else {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800864 // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
865 if (mRequest.getParameterCount() < 3)
866 return MTP_RESPONSE_INVALID_PARAMETER;
867
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700868 // standard GetPartialObject
869 length = mRequest.getParameter(3);
870 }
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500871 MtpString pathBuf;
872 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800873 MtpObjectFormat format;
874 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500875 if (result != MTP_RESPONSE_OK)
876 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700877 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500878 length = fileLength - offset;
879
880 const char* filePath = (const char *)pathBuf;
881 mtp_file_range mfr;
882 mfr.fd = open(filePath, O_RDONLY);
883 if (mfr.fd < 0) {
884 return MTP_RESPONSE_GENERAL_ERROR;
885 }
886 mfr.offset = offset;
887 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400888 mfr.command = mRequest.getOperationCode();
889 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500890 mResponse.setParameter(1, length);
891
Mike Lockwoodef441d92011-07-14 21:00:02 -0400892 // transfer the file
Jerry Zhang487be612016-10-24 12:10:41 -0700893 int ret = sHandle->sendFile(mfr);
Steve Block3856b092011-10-20 11:56:00 +0100894 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
tao.pei07a9e542015-07-17 17:18:41 +0800895 result = MTP_RESPONSE_OK;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500896 if (ret < 0) {
897 if (errno == ECANCELED)
tao.pei07a9e542015-07-17 17:18:41 +0800898 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500899 else
tao.pei07a9e542015-07-17 17:18:41 +0800900 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500901 }
tao.pei07a9e542015-07-17 17:18:41 +0800902 close(mfr.fd);
903 return result;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500904}
905
Mike Lockwood16864ba2010-05-11 17:16:59 -0400906MtpResponseCode MtpServer::doSendObjectInfo() {
907 MtpString path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800908 uint16_t temp16;
909 uint32_t temp32;
910
911 if (mRequest.getParameterCount() < 2)
912 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400913 MtpStorageID storageID = mRequest.getParameter(1);
914 MtpStorage* storage = getStorage(storageID);
915 MtpObjectHandle parent = mRequest.getParameter(2);
916 if (!storage)
917 return MTP_RESPONSE_INVALID_STORAGE_ID;
918
919 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400920 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400921 path = storage->getPath();
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400922 parent = 0;
923 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800924 int64_t length;
925 MtpObjectFormat format;
926 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400927 if (result != MTP_RESPONSE_OK)
928 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800929 if (format != MTP_FORMAT_ASSOCIATION)
930 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400931 }
932
933 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800934 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
935 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
936 MtpObjectFormat format = temp16;
937 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
938 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
939 mSendObjectFileSize = temp32;
940 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
941 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
942 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
943 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
944 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
945 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
946 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
947 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
948 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800949 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800950 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400951 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800952 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
Marco Nelissen7ea72dc2016-09-19 14:08:16 -0700953 if (name.getCharCount() == 0) {
954 ALOGE("empty name");
955 return MTP_RESPONSE_INVALID_PARAMETER;
956 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800957 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
958 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400959 // keywords follow
960
Steve Block3856b092011-10-20 11:56:00 +0100961 ALOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400962 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400963 if (!parseDateTime(modified, modifiedTime))
964 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400965
966 if (path[path.size() - 1] != '/')
967 path += "/";
968 path += (const char *)name;
969
Mike Lockwood20c3be02010-12-12 12:17:43 -0800970 // check space first
971 if (mSendObjectFileSize > storage->getFreeSpace())
972 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400973 uint64_t maxFileSize = storage->getMaxFileSize();
974 // check storage max file size
975 if (maxFileSize != 0) {
976 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
977 // is >= 0xFFFFFFFF
978 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
979 return MTP_RESPONSE_OBJECT_TOO_LARGE;
980 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800981
Steve Blockb8a80522011-12-20 16:23:08 +0000982 ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Mike Lockwood4714b072010-07-12 08:49:01 -0400983 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
984 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400985 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400986 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400987 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400988
989 if (format == MTP_FORMAT_ASSOCIATION) {
990 mode_t mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400991 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400992 umask(mask);
993 if (ret && ret != -EEXIST)
994 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400995 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwoodaa952402011-01-18 11:06:19 -0800996
997 // SendObject does not get sent for directories, so call endSendObject here instead
998 mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400999 } else {
1000 mSendObjectFilePath = path;
1001 // save the handle for the SendObject call, which should follow
1002 mSendObjectHandle = handle;
Mike Lockwood4714b072010-07-12 08:49:01 -04001003 mSendObjectFormat = format;
caozhiyuan854cb172017-04-26 16:52:30 +08001004 mSendObjectModifiedTime = modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001005 }
1006
1007 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001008 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001009 mResponse.setParameter(3, handle);
1010
1011 return MTP_RESPONSE_OK;
1012}
1013
1014MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001015 if (!hasStorage())
1016 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -04001017 MtpResponseCode result = MTP_RESPONSE_OK;
1018 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001019 int ret, initialData;
tao.pei07a9e542015-07-17 17:18:41 +08001020 bool isCanceled = false;
Manoj Gupta33587d12017-04-18 16:41:09 -07001021 struct stat sstat = {};
Mike Lockwood4714b072010-07-12 08:49:01 -04001022
Jerry Zhang487be612016-10-24 12:10:41 -07001023 auto start = std::chrono::steady_clock::now();
1024
Mike Lockwood16864ba2010-05-11 17:16:59 -04001025 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +00001026 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -04001027 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
1028 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001029 }
1030
Mike Lockwoodef441d92011-07-14 21:00:02 -04001031 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001032 ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001033 if (ret < MTP_CONTAINER_HEADER_SIZE) {
1034 result = MTP_RESPONSE_GENERAL_ERROR;
1035 goto done;
1036 }
1037 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001038
1039 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -07001040 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001041 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001042 result = MTP_RESPONSE_GENERAL_ERROR;
1043 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001044 }
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001045 fchown(mfr.fd, getuid(), mFileGroup);
1046 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001047 mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001048 fchmod(mfr.fd, mFilePermission);
1049 umask(mask);
1050
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001051 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001052 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001053 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001054
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001055 if (ret < 0) {
1056 ALOGE("failed to write initial data");
1057 result = MTP_RESPONSE_GENERAL_ERROR;
1058 } else {
Jerry Zhang54107562017-05-15 11:54:19 -07001059 mfr.offset = initialData;
1060 if (mSendObjectFileSize == 0xFFFFFFFF) {
1061 // tell driver to read until it receives a short packet
1062 mfr.length = 0xFFFFFFFF;
1063 } else {
1064 mfr.length = mSendObjectFileSize - initialData;
1065 }
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001066
Jerry Zhang54107562017-05-15 11:54:19 -07001067 mfr.command = 0;
1068 mfr.transaction_id = 0;
Yunlian Jiang8ddc3522017-02-21 15:58:09 -08001069
Jerry Zhang54107562017-05-15 11:54:19 -07001070 // transfer the file
1071 ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
1072 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1073 if ((ret < 0) && (errno == ECANCELED)) {
1074 isCanceled = true;
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001075 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001076 }
caozhiyuan854cb172017-04-26 16:52:30 +08001077
1078 if (mSendObjectModifiedTime) {
1079 struct timespec newTime[2];
1080 newTime[0].tv_nsec = UTIME_NOW;
1081 newTime[1].tv_sec = mSendObjectModifiedTime;
1082 newTime[1].tv_nsec = 0;
1083 if (futimens(mfr.fd, newTime) < 0) {
1084 ALOGW("changing modified time failed, %s", strerror(errno));
1085 }
1086 }
1087
Jerry Zhang487be612016-10-24 12:10:41 -07001088 fstat(mfr.fd, &sstat);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001089 close(mfr.fd);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001090
Mike Lockwood916076c2010-06-04 09:49:21 -04001091 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -07001092 ALOGE("Mtp receive file got error %s", strerror(errno));
Mike Lockwood916076c2010-06-04 09:49:21 -04001093 unlink(mSendObjectFilePath);
tao.pei07a9e542015-07-17 17:18:41 +08001094 if (isCanceled)
Mike Lockwood4714b072010-07-12 08:49:01 -04001095 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001096 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001097 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001098 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001099
1100done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001101 // reset so we don't attempt to send the data back
1102 mData.reset();
1103
Mike Lockwood4714b072010-07-12 08:49:01 -04001104 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
Mike Lockwoodaa952402011-01-18 11:06:19 -08001105 result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001106 mSendObjectHandle = kInvalidObjectHandle;
1107 mSendObjectFormat = 0;
caozhiyuan854cb172017-04-26 16:52:30 +08001108 mSendObjectModifiedTime = 0;
Jerry Zhang487be612016-10-24 12:10:41 -07001109
1110 auto end = std::chrono::steady_clock::now();
1111 std::chrono::duration<double> diff = end - start;
1112 uint64_t finalsize = sstat.st_size;
1113 ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
1114 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwood4714b072010-07-12 08:49:01 -04001115 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001116}
1117
Mike Lockwoodd3211492010-09-13 17:15:58 -04001118static void deleteRecursive(const char* path) {
1119 char pathbuf[PATH_MAX];
Mark Salyzynd239cb62014-06-18 16:32:27 -07001120 size_t pathLength = strlen(path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001121 if (pathLength >= sizeof(pathbuf) - 1) {
Steve Block29357bc2012-01-06 19:20:56 +00001122 ALOGE("path too long: %s\n", path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001123 }
1124 strcpy(pathbuf, path);
1125 if (pathbuf[pathLength - 1] != '/') {
1126 pathbuf[pathLength++] = '/';
1127 }
1128 char* fileSpot = pathbuf + pathLength;
1129 int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1130
1131 DIR* dir = opendir(path);
1132 if (!dir) {
Steve Block29357bc2012-01-06 19:20:56 +00001133 ALOGE("opendir %s failed: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001134 return;
1135 }
1136
1137 struct dirent* entry;
1138 while ((entry = readdir(dir))) {
1139 const char* name = entry->d_name;
1140
1141 // ignore "." and ".."
1142 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1143 continue;
1144 }
1145
1146 int nameLength = strlen(name);
1147 if (nameLength > pathRemaining) {
Steve Block29357bc2012-01-06 19:20:56 +00001148 ALOGE("path %s/%s too long\n", path, name);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001149 continue;
1150 }
1151 strcpy(fileSpot, name);
1152
Mike Lockwoodd3211492010-09-13 17:15:58 -04001153 if (entry->d_type == DT_DIR) {
1154 deleteRecursive(pathbuf);
1155 rmdir(pathbuf);
1156 } else {
1157 unlink(pathbuf);
1158 }
1159 }
Mike Lockwood7ce05cf2010-11-11 11:22:32 -05001160 closedir(dir);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001161}
1162
1163static void deletePath(const char* path) {
1164 struct stat statbuf;
1165 if (stat(path, &statbuf) == 0) {
1166 if (S_ISDIR(statbuf.st_mode)) {
1167 deleteRecursive(path);
1168 rmdir(path);
1169 } else {
1170 unlink(path);
1171 }
1172 } else {
Steve Block29357bc2012-01-06 19:20:56 +00001173 ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001174 }
1175}
1176
Mike Lockwood16864ba2010-05-11 17:16:59 -04001177MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001178 if (!hasStorage())
1179 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Marco Nelissenea9f2152015-01-23 10:55:25 -08001180 if (mRequest.getParameterCount() < 1)
Mike Lockwoodab063842014-11-12 14:20:06 -08001181 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001182 MtpObjectHandle handle = mRequest.getParameter(1);
Marco Nelissenea9f2152015-01-23 10:55:25 -08001183 MtpObjectFormat format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001184 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1185 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001186
1187 MtpString filePath;
1188 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001189 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001190 if (result == MTP_RESPONSE_OK) {
Steve Block3856b092011-10-20 11:56:00 +01001191 ALOGV("deleting %s", (const char *)filePath);
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001192 result = mDatabase->deleteFile(handle);
1193 // Don't delete the actual files unless the database deletion is allowed
1194 if (result == MTP_RESPONSE_OK) {
1195 deletePath((const char *)filePath);
1196 }
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001197 }
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001198
1199 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001200}
1201
1202MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001203 if (mRequest.getParameterCount() < 2)
1204 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001205 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001206 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001207 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001208 MtpDebug::getFormatCodeName(format));
1209 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001210 if (!property)
1211 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001212 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001213 delete property;
1214 return MTP_RESPONSE_OK;
1215}
1216
1217MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001218 if (mRequest.getParameterCount() < 1)
1219 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001220 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001221 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001222 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1223 if (!property)
1224 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1225 property->write(mData);
1226 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001227 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001228}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001229
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001230MtpResponseCode MtpServer::doSendPartialObject() {
1231 if (!hasStorage())
1232 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001233 if (mRequest.getParameterCount() < 4)
1234 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001235 MtpObjectHandle handle = mRequest.getParameter(1);
1236 uint64_t offset = mRequest.getParameter(2);
1237 uint64_t offset2 = mRequest.getParameter(3);
1238 offset = offset | (offset2 << 32);
1239 uint32_t length = mRequest.getParameter(4);
1240
1241 ObjectEdit* edit = getEditObject(handle);
1242 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001243 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001244 return MTP_RESPONSE_GENERAL_ERROR;
1245 }
1246
1247 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001248 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001249 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1250 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001251 return MTP_RESPONSE_GENERAL_ERROR;
1252 }
1253
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001254 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001255 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001256
Mike Lockwoodef441d92011-07-14 21:00:02 -04001257 // read the header, and possibly some data
Jerry Zhang487be612016-10-24 12:10:41 -07001258 int ret = mData.read(sHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001259 if (ret < MTP_CONTAINER_HEADER_SIZE)
1260 return MTP_RESPONSE_GENERAL_ERROR;
1261 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1262
1263 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001264 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001265 offset += initialData;
1266 length -= initialData;
1267 }
1268
tao.pei07a9e542015-07-17 17:18:41 +08001269 bool isCanceled = false;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001270 if (ret < 0) {
1271 ALOGE("failed to write initial data");
1272 } else {
Jerry Zhang54107562017-05-15 11:54:19 -07001273 mtp_file_range mfr;
1274 mfr.fd = edit->mFD;
1275 mfr.offset = offset;
1276 mfr.length = length;
1277 mfr.command = 0;
1278 mfr.transaction_id = 0;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001279
Jerry Zhang54107562017-05-15 11:54:19 -07001280 // transfer the file
1281 ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
1282 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1283 if ((ret < 0) && (errno == ECANCELED)) {
1284 isCanceled = true;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001285 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001286 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001287 if (ret < 0) {
1288 mResponse.setParameter(1, 0);
tao.pei07a9e542015-07-17 17:18:41 +08001289 if (isCanceled)
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001290 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1291 else
1292 return MTP_RESPONSE_GENERAL_ERROR;
1293 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001294
1295 // reset so we don't attempt to send this back
1296 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001297 mResponse.setParameter(1, length);
1298 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001299 if (end > edit->mSize) {
1300 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001301 }
1302 return MTP_RESPONSE_OK;
1303}
1304
1305MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001306 if (mRequest.getParameterCount() < 3)
1307 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001308 MtpObjectHandle handle = mRequest.getParameter(1);
1309 ObjectEdit* edit = getEditObject(handle);
1310 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001311 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001312 return MTP_RESPONSE_GENERAL_ERROR;
1313 }
1314
1315 uint64_t offset = mRequest.getParameter(2);
1316 uint64_t offset2 = mRequest.getParameter(3);
1317 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001318 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001319 return MTP_RESPONSE_GENERAL_ERROR;
1320 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001321 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001322 return MTP_RESPONSE_OK;
1323 }
1324}
1325
1326MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001327 if (mRequest.getParameterCount() < 1)
1328 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001329 MtpObjectHandle handle = mRequest.getParameter(1);
1330 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001331 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001332 return MTP_RESPONSE_GENERAL_ERROR;
1333 }
1334
1335 MtpString path;
1336 int64_t fileLength;
1337 MtpObjectFormat format;
1338 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1339 if (result != MTP_RESPONSE_OK)
1340 return result;
1341
1342 int fd = open((const char *)path, O_RDWR | O_EXCL);
1343 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001344 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001345 return MTP_RESPONSE_GENERAL_ERROR;
1346 }
1347
1348 addEditObject(handle, path, fileLength, format, fd);
1349 return MTP_RESPONSE_OK;
1350}
1351
1352MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001353 if (mRequest.getParameterCount() < 1)
1354 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001355 MtpObjectHandle handle = mRequest.getParameter(1);
1356 ObjectEdit* edit = getEditObject(handle);
1357 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001358 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001359 return MTP_RESPONSE_GENERAL_ERROR;
1360 }
1361
1362 commitEdit(edit);
1363 removeEditObject(handle);
1364 return MTP_RESPONSE_OK;
1365}
1366
Mike Lockwood7850ef92010-05-14 10:10:36 -04001367} // namespace android