blob: cff28039a992770394c96268ec72677eccd59b14 [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 Zhange5aa05d2017-10-13 12:14:42 -070017#include <algorithm>
Jerry Zhange242f122017-10-16 14:54:08 -070018#include <android-base/logging.h>
Jerry Zhang487be612016-10-24 12:10:41 -070019#include <android-base/properties.h>
20#include <chrono>
Jerry Zhang487be612016-10-24 12:10:41 -070021#include <dirent.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <inttypes.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040025#include <stdio.h>
26#include <stdlib.h>
27#include <sys/types.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040028#include <sys/stat.h>
Mike Lockwoodd3211492010-09-13 17:15:58 -040029#include <sys/stat.h>
caozhiyuan854cb172017-04-26 16:52:30 +080030#include <sys/time.h>
Mike Lockwoodc42aa122010-06-14 17:58:08 -070031
Mike Lockwooda881b442010-09-23 22:32:05 -040032#define LOG_TAG "MtpServer"
33
Mike Lockwood16864ba2010-05-11 17:16:59 -040034#include "MtpDebug.h"
Jerry Zhange5aa05d2017-10-13 12:14:42 -070035#include "IMtpDatabase.h"
Jerry Zhang63dac452017-12-06 15:19:36 -080036#include "MtpDescriptors.h"
Jerry Zhangdf69dd32017-05-03 17:17:49 -070037#include "MtpDevHandle.h"
38#include "MtpFfsCompatHandle.h"
39#include "MtpFfsHandle.h"
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070040#include "MtpObjectInfo.h"
Mike Lockwood21ef7d02010-06-30 17:00:35 -040041#include "MtpProperty.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040042#include "MtpServer.h"
43#include "MtpStorage.h"
44#include "MtpStringBuffer.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040045
Mike Lockwood7850ef92010-05-14 10:10:36 -040046namespace android {
47
Mike Lockwood16864ba2010-05-11 17:16:59 -040048static const MtpOperationCode kSupportedOperationCodes[] = {
49 MTP_OPERATION_GET_DEVICE_INFO,
50 MTP_OPERATION_OPEN_SESSION,
51 MTP_OPERATION_CLOSE_SESSION,
52 MTP_OPERATION_GET_STORAGE_IDS,
53 MTP_OPERATION_GET_STORAGE_INFO,
54 MTP_OPERATION_GET_NUM_OBJECTS,
55 MTP_OPERATION_GET_OBJECT_HANDLES,
56 MTP_OPERATION_GET_OBJECT_INFO,
57 MTP_OPERATION_GET_OBJECT,
Mike Lockwood64000782011-04-24 18:40:17 -070058 MTP_OPERATION_GET_THUMB,
Mike Lockwood16864ba2010-05-11 17:16:59 -040059 MTP_OPERATION_DELETE_OBJECT,
60 MTP_OPERATION_SEND_OBJECT_INFO,
61 MTP_OPERATION_SEND_OBJECT,
62// MTP_OPERATION_INITIATE_CAPTURE,
63// MTP_OPERATION_FORMAT_STORE,
Jerry Zhang6dafecc2017-02-23 16:39:30 -080064 MTP_OPERATION_RESET_DEVICE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040065// MTP_OPERATION_SELF_TEST,
66// MTP_OPERATION_SET_OBJECT_PROTECTION,
67// MTP_OPERATION_POWER_DOWN,
Mike Lockwoode3e76c42010-09-02 14:57:30 -040068 MTP_OPERATION_GET_DEVICE_PROP_DESC,
Mike Lockwood8277cec2010-08-10 15:20:35 -040069 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
70 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
71 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040072// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
Jerry Zhang708b3e02017-09-26 17:53:39 -070073 MTP_OPERATION_MOVE_OBJECT,
74 MTP_OPERATION_COPY_OBJECT,
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -050075 MTP_OPERATION_GET_PARTIAL_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040076// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
77 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
Mike Lockwood8277cec2010-08-10 15:20:35 -040078 MTP_OPERATION_GET_OBJECT_PROP_DESC,
Mike Lockwood677f5702010-09-23 23:04:28 -040079 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
80 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
Mike Lockwoodb6da06e2010-10-14 18:03:25 -040081 MTP_OPERATION_GET_OBJECT_PROP_LIST,
82// MTP_OPERATION_SET_OBJECT_PROP_LIST,
83// MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
84// MTP_OPERATION_SEND_OBJECT_PROP_LIST,
Mike Lockwood438344f2010-08-03 15:30:09 -040085 MTP_OPERATION_GET_OBJECT_REFERENCES,
86 MTP_OPERATION_SET_OBJECT_REFERENCES,
Mike Lockwood16864ba2010-05-11 17:16:59 -040087// MTP_OPERATION_SKIP,
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070088 // Android extension for direct file IO
89 MTP_OPERATION_GET_PARTIAL_OBJECT_64,
90 MTP_OPERATION_SEND_PARTIAL_OBJECT,
91 MTP_OPERATION_TRUNCATE_OBJECT,
92 MTP_OPERATION_BEGIN_EDIT_OBJECT,
93 MTP_OPERATION_END_EDIT_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040094};
95
Mike Lockwood873871f2010-07-12 18:54:16 -040096static const MtpEventCode kSupportedEventCodes[] = {
97 MTP_EVENT_OBJECT_ADDED,
98 MTP_EVENT_OBJECT_REMOVED,
Mike Lockwooda8494402011-02-18 09:07:14 -050099 MTP_EVENT_STORE_ADDED,
100 MTP_EVENT_STORE_REMOVED,
Mike Lockwood0fa848d2014-03-07 13:29:59 -0800101 MTP_EVENT_DEVICE_PROP_CHANGED,
James55138432018-07-02 18:07:30 +0800102 MTP_EVENT_OBJECT_INFO_CHANGED,
Mike Lockwood873871f2010-07-12 18:54:16 -0400103};
104
Jerry Zhang63dac452017-12-06 15:19:36 -0800105MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700106 const char *deviceInfoManufacturer,
107 const char *deviceInfoModel,
108 const char *deviceInfoDeviceVersion,
109 const char *deviceInfoSerialNumber)
Jerry Zhang487be612016-10-24 12:10:41 -0700110 : mDatabase(database),
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400111 mPtp(ptp),
Alex Klyubin792298f2016-12-21 11:20:22 -0800112 mDeviceInfoManufacturer(deviceInfoManufacturer),
113 mDeviceInfoModel(deviceInfoModel),
114 mDeviceInfoDeviceVersion(deviceInfoDeviceVersion),
115 mDeviceInfoSerialNumber(deviceInfoSerialNumber),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400116 mSessionID(0),
117 mSessionOpen(false),
118 mSendObjectHandle(kInvalidObjectHandle),
Mike Lockwood4714b072010-07-12 08:49:01 -0400119 mSendObjectFormat(0),
caozhiyuan854cb172017-04-26 16:52:30 +0800120 mSendObjectFileSize(0),
121 mSendObjectModifiedTime(0)
Mike Lockwood16864ba2010-05-11 17:16:59 -0400122{
Jerry Zhang63dac452017-12-06 15:19:36 -0800123 bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
124 if (ffs_ok) {
125 bool aio_compat = android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false);
126 mHandle = aio_compat ? new MtpFfsCompatHandle(controlFd) : new MtpFfsHandle(controlFd);
127 } else {
128 mHandle = new MtpDevHandle();
129 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400130}
131
132MtpServer::~MtpServer() {
133}
134
Mike Lockwooda8494402011-02-18 09:07:14 -0500135void MtpServer::addStorage(MtpStorage* storage) {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700136 std::lock_guard<std::mutex> lg(mMutex);
Mike Lockwooda8494402011-02-18 09:07:14 -0500137
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700138 mStorages.push_back(storage);
Mike Lockwooda8494402011-02-18 09:07:14 -0500139 sendStoreAdded(storage->getStorageID());
140}
141
142void MtpServer::removeStorage(MtpStorage* storage) {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700143 std::lock_guard<std::mutex> lg(mMutex);
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700144 auto iter = std::find(mStorages.begin(), mStorages.end(), storage);
145 if (iter != mStorages.end()) {
146 sendStoreRemoved(storage->getStorageID());
147 mStorages.erase(iter);
Mike Lockwooda8494402011-02-18 09:07:14 -0500148 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400149}
150
151MtpStorage* MtpServer::getStorage(MtpStorageID id) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800152 if (id == 0)
153 return mStorages[0];
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700154 for (MtpStorage *storage : mStorages) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400155 if (storage->getStorageID() == id)
156 return storage;
157 }
Jerry Zhang487be612016-10-24 12:10:41 -0700158 return nullptr;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400159}
160
Mike Lockwooda8494402011-02-18 09:07:14 -0500161bool MtpServer::hasStorage(MtpStorageID id) {
162 if (id == 0 || id == 0xFFFFFFFF)
163 return mStorages.size() > 0;
Jerry Zhang487be612016-10-24 12:10:41 -0700164 return (getStorage(id) != nullptr);
Mike Lockwooda8494402011-02-18 09:07:14 -0500165}
166
Mike Lockwood16864ba2010-05-11 17:16:59 -0400167void MtpServer::run() {
Jerry Zhang63dac452017-12-06 15:19:36 -0800168 if (mHandle->start(mPtp)) {
Jerry Zhang487be612016-10-24 12:10:41 -0700169 ALOGE("Failed to start usb driver!");
Jerry Zhang63dac452017-12-06 15:19:36 -0800170 mHandle->close();
Jerry Zhang487be612016-10-24 12:10:41 -0700171 return;
172 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400173
174 while (1) {
Jerry Zhang63dac452017-12-06 15:19:36 -0800175 int ret = mRequest.read(mHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400176 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700177 ALOGE("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400178 if (errno == ECANCELED) {
179 // return to top of loop and wait for next command
180 continue;
181 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400182 break;
183 }
184 MtpOperationCode operation = mRequest.getOperationCode();
185 MtpTransactionID transaction = mRequest.getTransactionID();
186
Steve Block3856b092011-10-20 11:56:00 +0100187 ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400188 // FIXME need to generalize this
Mike Lockwood438344f2010-08-03 15:30:09 -0400189 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood8277cec2010-08-10 15:20:35 -0400190 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
191 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
192 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400193 if (dataIn) {
Jerry Zhang63dac452017-12-06 15:19:36 -0800194 int ret = mData.read(mHandle);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400195 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000196 ALOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400197 if (errno == ECANCELED) {
198 // return to top of loop and wait for next command
199 continue;
200 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400201 break;
202 }
Steve Block3856b092011-10-20 11:56:00 +0100203 ALOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400204 } else {
205 mData.reset();
206 }
207
Mike Lockwood916076c2010-06-04 09:49:21 -0400208 if (handleRequest()) {
209 if (!dataIn && mData.hasData()) {
210 mData.setOperationCode(operation);
211 mData.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100212 ALOGV("sending data:");
Jerry Zhang63dac452017-12-06 15:19:36 -0800213 ret = mData.write(mHandle);
Mike Lockwood916076c2010-06-04 09:49:21 -0400214 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000215 ALOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400216 if (errno == ECANCELED) {
217 // return to top of loop and wait for next command
218 continue;
219 }
220 break;
221 }
222 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400223
Mike Lockwood916076c2010-06-04 09:49:21 -0400224 mResponse.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100225 ALOGV("sending response %04X", mResponse.getResponseCode());
Jerry Zhang63dac452017-12-06 15:19:36 -0800226 ret = mResponse.write(mHandle);
tao.pei07a9e542015-07-17 17:18:41 +0800227 const int savedErrno = errno;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400228 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000229 ALOGE("request write returned %d, errno: %d", ret, errno);
tao.pei07a9e542015-07-17 17:18:41 +0800230 if (savedErrno == ECANCELED) {
Mike Lockwood916076c2010-06-04 09:49:21 -0400231 // return to top of loop and wait for next command
232 continue;
233 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400234 break;
235 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400236 } else {
Steve Block3856b092011-10-20 11:56:00 +0100237 ALOGV("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400238 }
239 }
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400240
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700241 // commit any open edits
242 int count = mObjectEditList.size();
243 for (int i = 0; i < count; i++) {
244 ObjectEdit* edit = mObjectEditList[i];
245 commitEdit(edit);
246 delete edit;
247 }
248 mObjectEditList.clear();
249
Jerry Zhang63dac452017-12-06 15:19:36 -0800250 mHandle->close();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400251}
252
Mike Lockwood873871f2010-07-12 18:54:16 -0400253void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100254 ALOGV("sendObjectAdded %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500255 sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
Mike Lockwood873871f2010-07-12 18:54:16 -0400256}
257
258void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100259 ALOGV("sendObjectRemoved %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500260 sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
261}
262
James55138432018-07-02 18:07:30 +0800263void MtpServer::sendObjectInfoChanged(MtpObjectHandle handle) {
264 ALOGV("sendObjectInfoChanged %d\n", handle);
265 sendEvent(MTP_EVENT_OBJECT_INFO_CHANGED, handle);
266}
267
Mike Lockwooda8494402011-02-18 09:07:14 -0500268void MtpServer::sendStoreAdded(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100269 ALOGV("sendStoreAdded %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500270 sendEvent(MTP_EVENT_STORE_ADDED, id);
271}
272
273void MtpServer::sendStoreRemoved(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100274 ALOGV("sendStoreRemoved %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500275 sendEvent(MTP_EVENT_STORE_REMOVED, id);
276}
277
Mike Lockwood0fa848d2014-03-07 13:29:59 -0800278void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
279 ALOGV("sendDevicePropertyChanged %d\n", property);
280 sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
281}
282
Mike Lockwooda8494402011-02-18 09:07:14 -0500283void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400284 if (mSessionOpen) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500285 mEvent.setEventCode(code);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400286 mEvent.setTransactionID(mRequest.getTransactionID());
Mike Lockwooda8494402011-02-18 09:07:14 -0500287 mEvent.setParameter(1, param1);
Jerry Zhang63dac452017-12-06 15:19:36 -0800288 if (mEvent.write(mHandle))
Jerry Zhang487be612016-10-24 12:10:41 -0700289 ALOGE("Mtp send event failed: %s", strerror(errno));
Mike Lockwood73ecd232010-07-19 14:29:58 -0400290 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400291}
292
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700293void MtpServer::addEditObject(MtpObjectHandle handle, MtpStringBuffer& path,
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700294 uint64_t size, MtpObjectFormat format, int fd) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700295 ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700296 mObjectEditList.push_back(edit);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700297}
298
299MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
300 int count = mObjectEditList.size();
301 for (int i = 0; i < count; i++) {
302 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700303 if (edit->mHandle == handle) return edit;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700304 }
Jerry Zhang487be612016-10-24 12:10:41 -0700305 return nullptr;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700306}
307
308void MtpServer::removeEditObject(MtpObjectHandle handle) {
309 int count = mObjectEditList.size();
310 for (int i = 0; i < count; i++) {
311 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700312 if (edit->mHandle == handle) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700313 delete edit;
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700314 mObjectEditList.erase(mObjectEditList.begin() + i);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700315 return;
316 }
317 }
Steve Block29357bc2012-01-06 19:20:56 +0000318 ALOGE("ObjectEdit not found in removeEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700319}
320
321void MtpServer::commitEdit(ObjectEdit* edit) {
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700322 mDatabase->rescanFile((const char *)edit->mPath, edit->mHandle, edit->mFormat);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700323}
324
325
Mike Lockwood916076c2010-06-04 09:49:21 -0400326bool MtpServer::handleRequest() {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700327 std::lock_guard<std::mutex> lg(mMutex);
Mike Lockwooda8494402011-02-18 09:07:14 -0500328
Mike Lockwood16864ba2010-05-11 17:16:59 -0400329 MtpOperationCode operation = mRequest.getOperationCode();
330 MtpResponseCode response;
331
332 mResponse.reset();
333
334 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400335 mSendObjectHandle = kInvalidObjectHandle;
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700336 mSendObjectFormat = 0;
337 mSendObjectModifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400338 }
339
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700340 int containertype = mRequest.getContainerType();
341 if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
342 ALOGE("wrong container type %d", containertype);
343 return false;
344 }
345
346 ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
347
Mike Lockwood16864ba2010-05-11 17:16:59 -0400348 switch (operation) {
349 case MTP_OPERATION_GET_DEVICE_INFO:
350 response = doGetDeviceInfo();
351 break;
352 case MTP_OPERATION_OPEN_SESSION:
353 response = doOpenSession();
354 break;
Jerry Zhang6dafecc2017-02-23 16:39:30 -0800355 case MTP_OPERATION_RESET_DEVICE:
Mike Lockwood16864ba2010-05-11 17:16:59 -0400356 case MTP_OPERATION_CLOSE_SESSION:
357 response = doCloseSession();
358 break;
359 case MTP_OPERATION_GET_STORAGE_IDS:
360 response = doGetStorageIDs();
361 break;
362 case MTP_OPERATION_GET_STORAGE_INFO:
363 response = doGetStorageInfo();
364 break;
365 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
366 response = doGetObjectPropsSupported();
367 break;
368 case MTP_OPERATION_GET_OBJECT_HANDLES:
369 response = doGetObjectHandles();
370 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400371 case MTP_OPERATION_GET_NUM_OBJECTS:
372 response = doGetNumObjects();
373 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400374 case MTP_OPERATION_GET_OBJECT_REFERENCES:
375 response = doGetObjectReferences();
376 break;
377 case MTP_OPERATION_SET_OBJECT_REFERENCES:
378 response = doSetObjectReferences();
379 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400380 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
381 response = doGetObjectPropValue();
382 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400383 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
384 response = doSetObjectPropValue();
385 break;
386 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
387 response = doGetDevicePropValue();
388 break;
389 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
390 response = doSetDevicePropValue();
391 break;
392 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
393 response = doResetDevicePropValue();
394 break;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400395 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
396 response = doGetObjectPropList();
397 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400398 case MTP_OPERATION_GET_OBJECT_INFO:
399 response = doGetObjectInfo();
400 break;
401 case MTP_OPERATION_GET_OBJECT:
402 response = doGetObject();
403 break;
Mike Lockwood64000782011-04-24 18:40:17 -0700404 case MTP_OPERATION_GET_THUMB:
405 response = doGetThumb();
406 break;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500407 case MTP_OPERATION_GET_PARTIAL_OBJECT:
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700408 case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
409 response = doGetPartialObject(operation);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500410 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400411 case MTP_OPERATION_SEND_OBJECT_INFO:
412 response = doSendObjectInfo();
413 break;
414 case MTP_OPERATION_SEND_OBJECT:
415 response = doSendObject();
416 break;
417 case MTP_OPERATION_DELETE_OBJECT:
418 response = doDeleteObject();
419 break;
Jerry Zhang708b3e02017-09-26 17:53:39 -0700420 case MTP_OPERATION_COPY_OBJECT:
421 response = doCopyObject();
422 break;
423 case MTP_OPERATION_MOVE_OBJECT:
424 response = doMoveObject();
425 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400426 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400427 response = doGetObjectPropDesc();
428 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400429 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
430 response = doGetDevicePropDesc();
431 break;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700432 case MTP_OPERATION_SEND_PARTIAL_OBJECT:
433 response = doSendPartialObject();
434 break;
435 case MTP_OPERATION_TRUNCATE_OBJECT:
436 response = doTruncateObject();
437 break;
438 case MTP_OPERATION_BEGIN_EDIT_OBJECT:
439 response = doBeginEditObject();
440 break;
441 case MTP_OPERATION_END_EDIT_OBJECT:
442 response = doEndEditObject();
443 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400444 default:
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700445 ALOGE("got unsupported command %s (%x)",
446 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400447 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
448 break;
449 }
450
Mike Lockwood916076c2010-06-04 09:49:21 -0400451 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
452 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400453 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400454 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400455}
456
457MtpResponseCode MtpServer::doGetDeviceInfo() {
458 MtpStringBuffer string;
459
Mike Lockwood782aef12010-08-10 07:37:50 -0400460 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
461 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
462 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
463
Mike Lockwood16864ba2010-05-11 17:16:59 -0400464 // fill in device info
465 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400466 if (mPtp) {
467 mData.putUInt32(0);
468 } else {
469 // MTP Vendor Extension ID
470 mData.putUInt32(6);
471 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400472 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400473 if (mPtp) {
474 // no extensions
475 string.set("");
476 } else {
477 // MTP extensions
478 string.set("microsoft.com: 1.0; android.com: 1.0;");
479 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400480 mData.putString(string); // MTP Extensions
481 mData.putUInt16(0); //Functional Mode
482 mData.putAUInt16(kSupportedOperationCodes,
483 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400484 mData.putAUInt16(kSupportedEventCodes,
485 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400486 mData.putAUInt16(deviceProperties); // Device Properties Supported
487 mData.putAUInt16(captureFormats); // Capture Formats
488 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500489
Alex Klyubin792298f2016-12-21 11:20:22 -0800490 mData.putString(mDeviceInfoManufacturer); // Manufacturer
491 mData.putString(mDeviceInfoModel); // Model
492 mData.putString(mDeviceInfoDeviceVersion); // Device Version
493 mData.putString(mDeviceInfoSerialNumber); // Serial Number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400494
Mike Lockwood782aef12010-08-10 07:37:50 -0400495 delete playbackFormats;
496 delete captureFormats;
497 delete deviceProperties;
498
Mike Lockwood16864ba2010-05-11 17:16:59 -0400499 return MTP_RESPONSE_OK;
500}
501
502MtpResponseCode MtpServer::doOpenSession() {
503 if (mSessionOpen) {
504 mResponse.setParameter(1, mSessionID);
505 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
506 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800507 if (mRequest.getParameterCount() < 1)
508 return MTP_RESPONSE_INVALID_PARAMETER;
509
Mike Lockwood16864ba2010-05-11 17:16:59 -0400510 mSessionID = mRequest.getParameter(1);
511 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400512
Mike Lockwood16864ba2010-05-11 17:16:59 -0400513 return MTP_RESPONSE_OK;
514}
515
516MtpResponseCode MtpServer::doCloseSession() {
517 if (!mSessionOpen)
518 return MTP_RESPONSE_SESSION_NOT_OPEN;
519 mSessionID = 0;
520 mSessionOpen = false;
521 return MTP_RESPONSE_OK;
522}
523
524MtpResponseCode MtpServer::doGetStorageIDs() {
525 if (!mSessionOpen)
526 return MTP_RESPONSE_SESSION_NOT_OPEN;
527
528 int count = mStorages.size();
529 mData.putUInt32(count);
530 for (int i = 0; i < count; i++)
531 mData.putUInt32(mStorages[i]->getStorageID());
532
533 return MTP_RESPONSE_OK;
534}
535
536MtpResponseCode MtpServer::doGetStorageInfo() {
537 MtpStringBuffer string;
538
539 if (!mSessionOpen)
540 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800541 if (mRequest.getParameterCount() < 1)
542 return MTP_RESPONSE_INVALID_PARAMETER;
543
Mike Lockwood16864ba2010-05-11 17:16:59 -0400544 MtpStorageID id = mRequest.getParameter(1);
545 MtpStorage* storage = getStorage(id);
546 if (!storage)
547 return MTP_RESPONSE_INVALID_STORAGE_ID;
548
549 mData.putUInt16(storage->getType());
550 mData.putUInt16(storage->getFileSystemType());
551 mData.putUInt16(storage->getAccessCapability());
552 mData.putUInt64(storage->getMaxCapacity());
553 mData.putUInt64(storage->getFreeSpace());
554 mData.putUInt32(1024*1024*1024); // Free Space in Objects
555 string.set(storage->getDescription());
556 mData.putString(string);
557 mData.putEmptyString(); // Volume Identifier
558
559 return MTP_RESPONSE_OK;
560}
561
562MtpResponseCode MtpServer::doGetObjectPropsSupported() {
563 if (!mSessionOpen)
564 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800565 if (mRequest.getParameterCount() < 1)
566 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400567 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800568 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400569 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400570 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400571 return MTP_RESPONSE_OK;
572}
573
574MtpResponseCode MtpServer::doGetObjectHandles() {
575 if (!mSessionOpen)
576 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800577 if (mRequest.getParameterCount() < 3)
578 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400579 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400580 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400581 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400582 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500583
584 if (!hasStorage(storageID))
585 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400586
587 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700588 if (handles == NULL)
589 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400590 mData.putAUInt32(handles);
591 delete handles;
592 return MTP_RESPONSE_OK;
593}
594
Mike Lockwood343af4e2010-08-02 10:52:20 -0400595MtpResponseCode MtpServer::doGetNumObjects() {
596 if (!mSessionOpen)
597 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800598 if (mRequest.getParameterCount() < 3)
599 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400600 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
601 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
602 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400603 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500604 if (!hasStorage(storageID))
605 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400606
607 int count = mDatabase->getNumObjects(storageID, format, parent);
608 if (count >= 0) {
609 mResponse.setParameter(1, count);
610 return MTP_RESPONSE_OK;
611 } else {
612 mResponse.setParameter(1, 0);
613 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
614 }
615}
616
Mike Lockwood438344f2010-08-03 15:30:09 -0400617MtpResponseCode MtpServer::doGetObjectReferences() {
618 if (!mSessionOpen)
619 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500620 if (!hasStorage())
621 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800622 if (mRequest.getParameterCount() < 1)
623 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500624 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400625
626 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400627 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400628 if (handles) {
629 mData.putAUInt32(handles);
630 delete handles;
631 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400632 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400633 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400634 return MTP_RESPONSE_OK;
635}
636
637MtpResponseCode MtpServer::doSetObjectReferences() {
638 if (!mSessionOpen)
639 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500640 if (!hasStorage())
641 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800642 if (mRequest.getParameterCount() < 1)
643 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400644 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500645
Mike Lockwood438344f2010-08-03 15:30:09 -0400646 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800647 if (!references)
648 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400649 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
650 delete references;
651 return result;
652}
653
Mike Lockwood16864ba2010-05-11 17:16:59 -0400654MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500655 if (!hasStorage())
656 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800657 if (mRequest.getParameterCount() < 2)
658 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400659 MtpObjectHandle handle = mRequest.getParameter(1);
660 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100661 ALOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400662 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400663
Mike Lockwood8277cec2010-08-10 15:20:35 -0400664 return mDatabase->getObjectPropertyValue(handle, property, mData);
665}
666
667MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500668 if (!hasStorage())
669 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800670 if (mRequest.getParameterCount() < 2)
671 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400672 MtpObjectHandle handle = mRequest.getParameter(1);
673 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100674 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400675 MtpDebug::getObjectPropCodeName(property));
676
677 return mDatabase->setObjectPropertyValue(handle, property, mData);
678}
679
680MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800681 if (mRequest.getParameterCount() < 1)
682 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400683 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100684 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400685 MtpDebug::getDevicePropCodeName(property));
686
687 return mDatabase->getDevicePropertyValue(property, mData);
688}
689
690MtpResponseCode MtpServer::doSetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800691 if (mRequest.getParameterCount() < 1)
692 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400693 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100694 ALOGV("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400695 MtpDebug::getDevicePropCodeName(property));
696
697 return mDatabase->setDevicePropertyValue(property, mData);
698}
699
700MtpResponseCode MtpServer::doResetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800701 if (mRequest.getParameterCount() < 1)
702 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400703 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100704 ALOGV("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400705 MtpDebug::getDevicePropCodeName(property));
706
707 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400708}
709
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400710MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500711 if (!hasStorage())
712 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800713 if (mRequest.getParameterCount() < 5)
714 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400715
716 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500717 // use uint32_t so we can support 0xFFFFFFFF
718 uint32_t format = mRequest.getParameter(2);
719 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400720 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500721 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100722 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400723 handle, MtpDebug::getFormatCodeName(format),
724 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
725
726 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
727}
728
Mike Lockwood16864ba2010-05-11 17:16:59 -0400729MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500730 if (!hasStorage())
731 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800732 if (mRequest.getParameterCount() < 1)
733 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400734 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700735 MtpObjectInfo info(handle);
736 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
737 if (result == MTP_RESPONSE_OK) {
738 char date[20];
739
740 mData.putUInt32(info.mStorageID);
741 mData.putUInt16(info.mFormat);
742 mData.putUInt16(info.mProtectionStatus);
743
744 // if object is being edited the database size may be out of date
745 uint32_t size = info.mCompressedSize;
746 ObjectEdit* edit = getEditObject(handle);
747 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700748 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700749 mData.putUInt32(size);
750
751 mData.putUInt16(info.mThumbFormat);
752 mData.putUInt32(info.mThumbCompressedSize);
753 mData.putUInt32(info.mThumbPixWidth);
754 mData.putUInt32(info.mThumbPixHeight);
755 mData.putUInt32(info.mImagePixWidth);
756 mData.putUInt32(info.mImagePixHeight);
757 mData.putUInt32(info.mImagePixDepth);
758 mData.putUInt32(info.mParent);
759 mData.putUInt16(info.mAssociationType);
760 mData.putUInt32(info.mAssociationDesc);
761 mData.putUInt32(info.mSequenceNumber);
762 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700763 formatDateTime(info.mDateCreated, date, sizeof(date));
764 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700765 formatDateTime(info.mDateModified, date, sizeof(date));
766 mData.putString(date); // date modified
767 mData.putEmptyString(); // keywords
768 }
769 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400770}
771
772MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500773 if (!hasStorage())
774 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800775 if (mRequest.getParameterCount() < 1)
776 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400777 MtpObjectHandle handle = mRequest.getParameter(1);
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700778 MtpStringBuffer pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400779 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800780 MtpObjectFormat format;
781 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400782 if (result != MTP_RESPONSE_OK)
783 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400784
Jerry Zhang487be612016-10-24 12:10:41 -0700785 auto start = std::chrono::steady_clock::now();
786
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400787 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400788 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400789 mfr.fd = open(filePath, O_RDONLY);
790 if (mfr.fd < 0) {
791 return MTP_RESPONSE_GENERAL_ERROR;
792 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400793 mfr.offset = 0;
794 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400795 mfr.command = mRequest.getOperationCode();
796 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400797
798 // then transfer the file
Jerry Zhang63dac452017-12-06 15:19:36 -0800799 int ret = mHandle->sendFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +0800800 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700801 ALOGE("Mtp send file got error %s", strerror(errno));
tao.pei07a9e542015-07-17 17:18:41 +0800802 if (errno == ECANCELED) {
803 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
804 } else {
805 result = MTP_RESPONSE_GENERAL_ERROR;
806 }
807 } else {
808 result = MTP_RESPONSE_OK;
809 }
810
Jerry Zhang487be612016-10-24 12:10:41 -0700811 auto end = std::chrono::steady_clock::now();
812 std::chrono::duration<double> diff = end - start;
813 struct stat sstat;
814 fstat(mfr.fd, &sstat);
815 uint64_t finalsize = sstat.st_size;
816 ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
817 diff.count(), finalsize, ((double) finalsize) / diff.count());
Jerry Zhangdc148de2018-05-14 12:07:16 -0700818 closeObjFd(mfr.fd, filePath);
tao.pei07a9e542015-07-17 17:18:41 +0800819 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400820}
821
Mike Lockwood64000782011-04-24 18:40:17 -0700822MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800823 if (mRequest.getParameterCount() < 1)
824 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700825 MtpObjectHandle handle = mRequest.getParameter(1);
826 size_t thumbSize;
827 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
828 if (thumb) {
829 // send data
830 mData.setOperationCode(mRequest.getOperationCode());
831 mData.setTransactionID(mRequest.getTransactionID());
Jerry Zhang63dac452017-12-06 15:19:36 -0800832 mData.writeData(mHandle, thumb, thumbSize);
Mike Lockwood64000782011-04-24 18:40:17 -0700833 free(thumb);
834 return MTP_RESPONSE_OK;
835 } else {
836 return MTP_RESPONSE_GENERAL_ERROR;
837 }
838}
839
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700840MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500841 if (!hasStorage())
842 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500843 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700844 uint64_t offset;
845 uint32_t length;
846 offset = mRequest.getParameter(2);
847 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800848 // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
849 if (mRequest.getParameterCount() < 4)
850 return MTP_RESPONSE_INVALID_PARAMETER;
851
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700852 // android extension with 64 bit offset
853 uint64_t offset2 = mRequest.getParameter(3);
854 offset = offset | (offset2 << 32);
855 length = mRequest.getParameter(4);
856 } else {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800857 // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
858 if (mRequest.getParameterCount() < 3)
859 return MTP_RESPONSE_INVALID_PARAMETER;
860
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700861 // standard GetPartialObject
862 length = mRequest.getParameter(3);
863 }
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700864 MtpStringBuffer pathBuf;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500865 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800866 MtpObjectFormat format;
867 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500868 if (result != MTP_RESPONSE_OK)
869 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700870 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500871 length = fileLength - offset;
872
873 const char* filePath = (const char *)pathBuf;
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700874 ALOGV("sending partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500875 mtp_file_range mfr;
876 mfr.fd = open(filePath, O_RDONLY);
877 if (mfr.fd < 0) {
878 return MTP_RESPONSE_GENERAL_ERROR;
879 }
880 mfr.offset = offset;
881 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400882 mfr.command = mRequest.getOperationCode();
883 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500884 mResponse.setParameter(1, length);
885
Mike Lockwoodef441d92011-07-14 21:00:02 -0400886 // transfer the file
Jerry Zhang63dac452017-12-06 15:19:36 -0800887 int ret = mHandle->sendFile(mfr);
Steve Block3856b092011-10-20 11:56:00 +0100888 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
tao.pei07a9e542015-07-17 17:18:41 +0800889 result = MTP_RESPONSE_OK;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500890 if (ret < 0) {
891 if (errno == ECANCELED)
tao.pei07a9e542015-07-17 17:18:41 +0800892 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500893 else
tao.pei07a9e542015-07-17 17:18:41 +0800894 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500895 }
Jerry Zhangdc148de2018-05-14 12:07:16 -0700896 closeObjFd(mfr.fd, filePath);
tao.pei07a9e542015-07-17 17:18:41 +0800897 return result;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500898}
899
Mike Lockwood16864ba2010-05-11 17:16:59 -0400900MtpResponseCode MtpServer::doSendObjectInfo() {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700901 MtpStringBuffer path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800902 uint16_t temp16;
903 uint32_t temp32;
904
905 if (mRequest.getParameterCount() < 2)
906 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400907 MtpStorageID storageID = mRequest.getParameter(1);
908 MtpStorage* storage = getStorage(storageID);
909 MtpObjectHandle parent = mRequest.getParameter(2);
910 if (!storage)
911 return MTP_RESPONSE_INVALID_STORAGE_ID;
912
913 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400914 if (parent == MTP_PARENT_ROOT) {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700915 path.set(storage->getPath());
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400916 parent = 0;
917 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800918 int64_t length;
919 MtpObjectFormat format;
920 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400921 if (result != MTP_RESPONSE_OK)
922 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800923 if (format != MTP_FORMAT_ASSOCIATION)
924 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400925 }
926
927 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800928 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
929 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
930 MtpObjectFormat format = temp16;
931 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
932 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
933 mSendObjectFileSize = temp32;
934 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
935 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
936 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
937 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
938 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
939 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
940 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
941 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
942 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800943 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800944 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400945 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800946 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700947 if (name.isEmpty()) {
Marco Nelissen7ea72dc2016-09-19 14:08:16 -0700948 ALOGE("empty name");
949 return MTP_RESPONSE_INVALID_PARAMETER;
950 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800951 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
952 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400953 // keywords follow
954
Steve Block3856b092011-10-20 11:56:00 +0100955 ALOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400956 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400957 if (!parseDateTime(modified, modifiedTime))
958 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400959
960 if (path[path.size() - 1] != '/')
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700961 path.append("/");
962 path.append(name);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400963
Mike Lockwood20c3be02010-12-12 12:17:43 -0800964 // check space first
965 if (mSendObjectFileSize > storage->getFreeSpace())
966 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400967 uint64_t maxFileSize = storage->getMaxFileSize();
968 // check storage max file size
969 if (maxFileSize != 0) {
970 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
971 // is >= 0xFFFFFFFF
972 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
973 return MTP_RESPONSE_OBJECT_TOO_LARGE;
974 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800975
Steve Blockb8a80522011-12-20 16:23:08 +0000976 ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700977 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, format,
978 parent, storageID);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400979 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400980 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400981 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400982
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700983 if (format == MTP_FORMAT_ASSOCIATION) {
Jerry Zhange242f122017-10-16 14:54:08 -0700984 int ret = makeFolder((const char *)path);
985 if (ret)
Mike Lockwood16864ba2010-05-11 17:16:59 -0400986 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodaa952402011-01-18 11:06:19 -0800987
988 // SendObject does not get sent for directories, so call endSendObject here instead
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700989 mDatabase->endSendObject(handle, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400990 }
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700991 mSendObjectFilePath = path;
992 // save the handle for the SendObject call, which should follow
993 mSendObjectHandle = handle;
994 mSendObjectFormat = format;
995 mSendObjectModifiedTime = modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400996
997 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400998 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400999 mResponse.setParameter(3, handle);
1000
1001 return MTP_RESPONSE_OK;
1002}
1003
Jerry Zhang708b3e02017-09-26 17:53:39 -07001004MtpResponseCode MtpServer::doMoveObject() {
1005 if (!hasStorage())
1006 return MTP_RESPONSE_GENERAL_ERROR;
1007 if (mRequest.getParameterCount() < 3)
1008 return MTP_RESPONSE_INVALID_PARAMETER;
1009 MtpObjectHandle objectHandle = mRequest.getParameter(1);
1010 MtpStorageID storageID = mRequest.getParameter(2);
1011 MtpStorage* storage = getStorage(storageID);
1012 MtpObjectHandle parent = mRequest.getParameter(3);
1013 if (!storage)
1014 return MTP_RESPONSE_INVALID_STORAGE_ID;
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001015 MtpStringBuffer path;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001016 MtpResponseCode result;
1017
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001018 MtpStringBuffer fromPath;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001019 int64_t fileLength;
1020 MtpObjectFormat format;
1021 MtpObjectInfo info(objectHandle);
1022 result = mDatabase->getObjectInfo(objectHandle, info);
1023 if (result != MTP_RESPONSE_OK)
1024 return result;
1025 result = mDatabase->getObjectFilePath(objectHandle, fromPath, fileLength, format);
1026 if (result != MTP_RESPONSE_OK)
1027 return result;
1028
1029 // special case the root
1030 if (parent == 0) {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001031 path.set(storage->getPath());
Jerry Zhang708b3e02017-09-26 17:53:39 -07001032 } else {
1033 int64_t parentLength;
1034 MtpObjectFormat parentFormat;
1035 result = mDatabase->getObjectFilePath(parent, path, parentLength, parentFormat);
1036 if (result != MTP_RESPONSE_OK)
1037 return result;
1038 if (parentFormat != MTP_FORMAT_ASSOCIATION)
1039 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
1040 }
1041
1042 if (path[path.size() - 1] != '/')
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001043 path.append("/");
1044 path.append(info.mName);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001045
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001046 result = mDatabase->beginMoveObject(objectHandle, parent, storageID);
1047 if (result != MTP_RESPONSE_OK)
1048 return result;
1049
Jerry Zhang708b3e02017-09-26 17:53:39 -07001050 if (info.mStorageID == storageID) {
1051 ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
Jerry Zhangdc148de2018-05-14 12:07:16 -07001052 if (renameTo(fromPath, path)) {
Jerry Zhange242f122017-10-16 14:54:08 -07001053 PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001054 result = MTP_RESPONSE_GENERAL_ERROR;
1055 }
1056 } else {
1057 ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path);
Jerry Zhange242f122017-10-16 14:54:08 -07001058 if (format == MTP_FORMAT_ASSOCIATION) {
1059 int ret = makeFolder((const char *)path);
1060 ret += copyRecursive(fromPath, path);
1061 if (ret) {
1062 result = MTP_RESPONSE_GENERAL_ERROR;
1063 } else {
1064 deletePath(fromPath);
1065 }
Jerry Zhang708b3e02017-09-26 17:53:39 -07001066 } else {
Jerry Zhange242f122017-10-16 14:54:08 -07001067 if (copyFile(fromPath, path)) {
1068 result = MTP_RESPONSE_GENERAL_ERROR;
1069 } else {
1070 deletePath(fromPath);
1071 }
Jerry Zhang708b3e02017-09-26 17:53:39 -07001072 }
1073 }
1074
1075 // If the move failed, undo the database change
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001076 mDatabase->endMoveObject(info.mParent, parent, info.mStorageID, storageID, objectHandle,
1077 result == MTP_RESPONSE_OK);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001078
1079 return result;
1080}
1081
1082MtpResponseCode MtpServer::doCopyObject() {
1083 if (!hasStorage())
1084 return MTP_RESPONSE_GENERAL_ERROR;
1085 MtpResponseCode result = MTP_RESPONSE_OK;
1086 if (mRequest.getParameterCount() < 3)
1087 return MTP_RESPONSE_INVALID_PARAMETER;
1088 MtpObjectHandle objectHandle = mRequest.getParameter(1);
1089 MtpStorageID storageID = mRequest.getParameter(2);
1090 MtpStorage* storage = getStorage(storageID);
1091 MtpObjectHandle parent = mRequest.getParameter(3);
1092 if (!storage)
1093 return MTP_RESPONSE_INVALID_STORAGE_ID;
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001094 MtpStringBuffer path;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001095
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001096 MtpStringBuffer fromPath;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001097 int64_t fileLength;
1098 MtpObjectFormat format;
1099 MtpObjectInfo info(objectHandle);
1100 result = mDatabase->getObjectInfo(objectHandle, info);
1101 if (result != MTP_RESPONSE_OK)
1102 return result;
1103 result = mDatabase->getObjectFilePath(objectHandle, fromPath, fileLength, format);
1104 if (result != MTP_RESPONSE_OK)
1105 return result;
1106
1107 // special case the root
1108 if (parent == 0) {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001109 path.set(storage->getPath());
Jerry Zhang708b3e02017-09-26 17:53:39 -07001110 } else {
1111 int64_t parentLength;
1112 MtpObjectFormat parentFormat;
1113 result = mDatabase->getObjectFilePath(parent, path, parentLength, parentFormat);
1114 if (result != MTP_RESPONSE_OK)
1115 return result;
1116 if (parentFormat != MTP_FORMAT_ASSOCIATION)
1117 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
1118 }
1119
1120 // check space first
1121 if ((uint64_t) fileLength > storage->getFreeSpace())
1122 return MTP_RESPONSE_STORAGE_FULL;
1123
1124 if (path[path.size() - 1] != '/')
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001125 path.append("/");
1126 path.append(info.mName);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001127
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001128 MtpObjectHandle handle = mDatabase->beginCopyObject(objectHandle, parent, storageID);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001129 if (handle == kInvalidObjectHandle) {
1130 return MTP_RESPONSE_GENERAL_ERROR;
1131 }
1132
1133 ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path);
Jerry Zhange242f122017-10-16 14:54:08 -07001134 if (format == MTP_FORMAT_ASSOCIATION) {
1135 int ret = makeFolder((const char *)path);
kyle_tso6de16602017-11-22 18:14:51 +08001136 ret += copyRecursive(fromPath, path);
Jerry Zhange242f122017-10-16 14:54:08 -07001137 if (ret) {
1138 result = MTP_RESPONSE_GENERAL_ERROR;
1139 }
1140 } else {
1141 if (copyFile(fromPath, path)) {
1142 result = MTP_RESPONSE_GENERAL_ERROR;
1143 }
Jerry Zhang708b3e02017-09-26 17:53:39 -07001144 }
1145
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001146 mDatabase->endCopyObject(handle, result);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001147 mResponse.setParameter(1, handle);
1148 return result;
1149}
1150
Mike Lockwood16864ba2010-05-11 17:16:59 -04001151MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001152 if (!hasStorage())
1153 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -04001154 MtpResponseCode result = MTP_RESPONSE_OK;
1155 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001156 int ret, initialData;
tao.pei07a9e542015-07-17 17:18:41 +08001157 bool isCanceled = false;
Manoj Gupta33587d12017-04-18 16:41:09 -07001158 struct stat sstat = {};
Mike Lockwood4714b072010-07-12 08:49:01 -04001159
Jerry Zhang487be612016-10-24 12:10:41 -07001160 auto start = std::chrono::steady_clock::now();
1161
Mike Lockwood16864ba2010-05-11 17:16:59 -04001162 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +00001163 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -04001164 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
1165 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001166 }
1167
Mike Lockwoodef441d92011-07-14 21:00:02 -04001168 // read the header, and possibly some data
Jerry Zhang63dac452017-12-06 15:19:36 -08001169 ret = mData.read(mHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001170 if (ret < MTP_CONTAINER_HEADER_SIZE) {
1171 result = MTP_RESPONSE_GENERAL_ERROR;
1172 goto done;
1173 }
1174 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001175
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001176 if (mSendObjectFormat == MTP_FORMAT_ASSOCIATION) {
1177 if (initialData != 0)
1178 ALOGE("Expected folder size to be 0!");
1179 mSendObjectHandle = kInvalidObjectHandle;
1180 mSendObjectFormat = 0;
1181 mSendObjectModifiedTime = 0;
1182 return result;
1183 }
1184
Mike Lockwood16864ba2010-05-11 17:16:59 -04001185 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -07001186 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001187 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001188 result = MTP_RESPONSE_GENERAL_ERROR;
1189 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001190 }
Jerry Zhange242f122017-10-16 14:54:08 -07001191 fchown(mfr.fd, getuid(), FILE_GROUP);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001192 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001193 mask = umask(0);
Jerry Zhange242f122017-10-16 14:54:08 -07001194 fchmod(mfr.fd, FILE_PERM);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001195 umask(mask);
1196
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001197 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001198 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001199 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001200
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001201 if (ret < 0) {
1202 ALOGE("failed to write initial data");
1203 result = MTP_RESPONSE_GENERAL_ERROR;
1204 } else {
Jerry Zhang54107562017-05-15 11:54:19 -07001205 mfr.offset = initialData;
1206 if (mSendObjectFileSize == 0xFFFFFFFF) {
1207 // tell driver to read until it receives a short packet
1208 mfr.length = 0xFFFFFFFF;
1209 } else {
1210 mfr.length = mSendObjectFileSize - initialData;
1211 }
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001212
Jerry Zhang54107562017-05-15 11:54:19 -07001213 mfr.command = 0;
1214 mfr.transaction_id = 0;
Yunlian Jiang8ddc3522017-02-21 15:58:09 -08001215
Jerry Zhang54107562017-05-15 11:54:19 -07001216 // transfer the file
Jerry Zhang63dac452017-12-06 15:19:36 -08001217 ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
Jerry Zhang54107562017-05-15 11:54:19 -07001218 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1219 if ((ret < 0) && (errno == ECANCELED)) {
1220 isCanceled = true;
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001221 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001222 }
caozhiyuan854cb172017-04-26 16:52:30 +08001223
1224 if (mSendObjectModifiedTime) {
1225 struct timespec newTime[2];
1226 newTime[0].tv_nsec = UTIME_NOW;
1227 newTime[1].tv_sec = mSendObjectModifiedTime;
1228 newTime[1].tv_nsec = 0;
1229 if (futimens(mfr.fd, newTime) < 0) {
1230 ALOGW("changing modified time failed, %s", strerror(errno));
1231 }
1232 }
1233
Jerry Zhang487be612016-10-24 12:10:41 -07001234 fstat(mfr.fd, &sstat);
Jerry Zhangdc148de2018-05-14 12:07:16 -07001235 closeObjFd(mfr.fd, mSendObjectFilePath);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001236
Mike Lockwood916076c2010-06-04 09:49:21 -04001237 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -07001238 ALOGE("Mtp receive file got error %s", strerror(errno));
Mike Lockwood916076c2010-06-04 09:49:21 -04001239 unlink(mSendObjectFilePath);
tao.pei07a9e542015-07-17 17:18:41 +08001240 if (isCanceled)
Mike Lockwood4714b072010-07-12 08:49:01 -04001241 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001242 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001243 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001244 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001245
1246done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001247 // reset so we don't attempt to send the data back
1248 mData.reset();
1249
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001250 mDatabase->endSendObject(mSendObjectHandle, result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001251 mSendObjectHandle = kInvalidObjectHandle;
1252 mSendObjectFormat = 0;
caozhiyuan854cb172017-04-26 16:52:30 +08001253 mSendObjectModifiedTime = 0;
Jerry Zhang487be612016-10-24 12:10:41 -07001254
1255 auto end = std::chrono::steady_clock::now();
1256 std::chrono::duration<double> diff = end - start;
1257 uint64_t finalsize = sstat.st_size;
1258 ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
1259 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwood4714b072010-07-12 08:49:01 -04001260 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001261}
1262
1263MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001264 if (!hasStorage())
1265 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Marco Nelissenea9f2152015-01-23 10:55:25 -08001266 if (mRequest.getParameterCount() < 1)
Mike Lockwoodab063842014-11-12 14:20:06 -08001267 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001268 MtpObjectHandle handle = mRequest.getParameter(1);
Marco Nelissenea9f2152015-01-23 10:55:25 -08001269 MtpObjectFormat format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001270 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1271 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001272
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001273 MtpStringBuffer filePath;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001274 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001275 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001276 if (result != MTP_RESPONSE_OK)
1277 return result;
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001278
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001279 // Don't delete the actual files unless the database deletion is allowed
1280 result = mDatabase->beginDeleteObject(handle);
1281 if (result != MTP_RESPONSE_OK)
1282 return result;
1283
1284 bool success = deletePath((const char *)filePath);
1285
1286 mDatabase->endDeleteObject(handle, success);
1287 return success ? result : MTP_RESPONSE_PARTIAL_DELETION;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001288}
1289
1290MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001291 if (mRequest.getParameterCount() < 2)
1292 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001293 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001294 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001295 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001296 MtpDebug::getFormatCodeName(format));
1297 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001298 if (!property)
1299 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001300 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001301 delete property;
1302 return MTP_RESPONSE_OK;
1303}
1304
1305MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001306 if (mRequest.getParameterCount() < 1)
1307 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001308 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001309 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001310 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1311 if (!property)
1312 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1313 property->write(mData);
1314 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001315 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001316}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001317
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001318MtpResponseCode MtpServer::doSendPartialObject() {
1319 if (!hasStorage())
1320 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001321 if (mRequest.getParameterCount() < 4)
1322 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001323 MtpObjectHandle handle = mRequest.getParameter(1);
1324 uint64_t offset = mRequest.getParameter(2);
1325 uint64_t offset2 = mRequest.getParameter(3);
1326 offset = offset | (offset2 << 32);
1327 uint32_t length = mRequest.getParameter(4);
1328
1329 ObjectEdit* edit = getEditObject(handle);
1330 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001331 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001332 return MTP_RESPONSE_GENERAL_ERROR;
1333 }
1334
1335 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001336 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001337 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1338 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001339 return MTP_RESPONSE_GENERAL_ERROR;
1340 }
1341
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001342 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001343 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001344
Mike Lockwoodef441d92011-07-14 21:00:02 -04001345 // read the header, and possibly some data
Jerry Zhang63dac452017-12-06 15:19:36 -08001346 int ret = mData.read(mHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001347 if (ret < MTP_CONTAINER_HEADER_SIZE)
1348 return MTP_RESPONSE_GENERAL_ERROR;
1349 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1350
1351 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001352 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001353 offset += initialData;
1354 length -= initialData;
1355 }
1356
tao.pei07a9e542015-07-17 17:18:41 +08001357 bool isCanceled = false;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001358 if (ret < 0) {
1359 ALOGE("failed to write initial data");
1360 } else {
Jerry Zhang54107562017-05-15 11:54:19 -07001361 mtp_file_range mfr;
1362 mfr.fd = edit->mFD;
1363 mfr.offset = offset;
1364 mfr.length = length;
1365 mfr.command = 0;
1366 mfr.transaction_id = 0;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001367
Jerry Zhang54107562017-05-15 11:54:19 -07001368 // transfer the file
Jerry Zhang63dac452017-12-06 15:19:36 -08001369 ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
Jerry Zhang54107562017-05-15 11:54:19 -07001370 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1371 if ((ret < 0) && (errno == ECANCELED)) {
1372 isCanceled = true;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001373 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001374 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001375 if (ret < 0) {
1376 mResponse.setParameter(1, 0);
tao.pei07a9e542015-07-17 17:18:41 +08001377 if (isCanceled)
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001378 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1379 else
1380 return MTP_RESPONSE_GENERAL_ERROR;
1381 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001382
1383 // reset so we don't attempt to send this back
1384 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001385 mResponse.setParameter(1, length);
1386 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001387 if (end > edit->mSize) {
1388 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001389 }
1390 return MTP_RESPONSE_OK;
1391}
1392
1393MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001394 if (mRequest.getParameterCount() < 3)
1395 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001396 MtpObjectHandle handle = mRequest.getParameter(1);
1397 ObjectEdit* edit = getEditObject(handle);
1398 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001399 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001400 return MTP_RESPONSE_GENERAL_ERROR;
1401 }
1402
1403 uint64_t offset = mRequest.getParameter(2);
1404 uint64_t offset2 = mRequest.getParameter(3);
1405 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001406 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001407 return MTP_RESPONSE_GENERAL_ERROR;
1408 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001409 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001410 return MTP_RESPONSE_OK;
1411 }
1412}
1413
1414MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001415 if (mRequest.getParameterCount() < 1)
1416 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001417 MtpObjectHandle handle = mRequest.getParameter(1);
1418 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001419 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001420 return MTP_RESPONSE_GENERAL_ERROR;
1421 }
1422
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001423 MtpStringBuffer path;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001424 int64_t fileLength;
1425 MtpObjectFormat format;
1426 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1427 if (result != MTP_RESPONSE_OK)
1428 return result;
1429
1430 int fd = open((const char *)path, O_RDWR | O_EXCL);
1431 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001432 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001433 return MTP_RESPONSE_GENERAL_ERROR;
1434 }
1435
1436 addEditObject(handle, path, fileLength, format, fd);
1437 return MTP_RESPONSE_OK;
1438}
1439
1440MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001441 if (mRequest.getParameterCount() < 1)
1442 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001443 MtpObjectHandle handle = mRequest.getParameter(1);
1444 ObjectEdit* edit = getEditObject(handle);
1445 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001446 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001447 return MTP_RESPONSE_GENERAL_ERROR;
1448 }
1449
1450 commitEdit(edit);
1451 removeEditObject(handle);
1452 return MTP_RESPONSE_OK;
1453}
1454
Mike Lockwood7850ef92010-05-14 10:10:36 -04001455} // namespace android