blob: ca8cb785e9a1e2e78136a7da73867e43cb4ce41f [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
James Weiba389222018-09-27 19:22:55 +0800451 if (response != MTP_RESPONSE_OK)
452 ALOGW("[MTP] got response 0x%X in command %s (%x)", response,
453 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood916076c2010-06-04 09:49:21 -0400454 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
455 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400456 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400457 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400458}
459
460MtpResponseCode MtpServer::doGetDeviceInfo() {
461 MtpStringBuffer string;
462
Mike Lockwood782aef12010-08-10 07:37:50 -0400463 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
464 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
465 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
466
Mike Lockwood16864ba2010-05-11 17:16:59 -0400467 // fill in device info
468 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400469 if (mPtp) {
470 mData.putUInt32(0);
471 } else {
472 // MTP Vendor Extension ID
473 mData.putUInt32(6);
474 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400475 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400476 if (mPtp) {
477 // no extensions
478 string.set("");
479 } else {
480 // MTP extensions
481 string.set("microsoft.com: 1.0; android.com: 1.0;");
482 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400483 mData.putString(string); // MTP Extensions
484 mData.putUInt16(0); //Functional Mode
485 mData.putAUInt16(kSupportedOperationCodes,
486 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400487 mData.putAUInt16(kSupportedEventCodes,
488 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400489 mData.putAUInt16(deviceProperties); // Device Properties Supported
490 mData.putAUInt16(captureFormats); // Capture Formats
491 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500492
Alex Klyubin792298f2016-12-21 11:20:22 -0800493 mData.putString(mDeviceInfoManufacturer); // Manufacturer
494 mData.putString(mDeviceInfoModel); // Model
495 mData.putString(mDeviceInfoDeviceVersion); // Device Version
496 mData.putString(mDeviceInfoSerialNumber); // Serial Number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400497
Mike Lockwood782aef12010-08-10 07:37:50 -0400498 delete playbackFormats;
499 delete captureFormats;
500 delete deviceProperties;
501
Mike Lockwood16864ba2010-05-11 17:16:59 -0400502 return MTP_RESPONSE_OK;
503}
504
505MtpResponseCode MtpServer::doOpenSession() {
506 if (mSessionOpen) {
507 mResponse.setParameter(1, mSessionID);
508 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
509 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800510 if (mRequest.getParameterCount() < 1)
511 return MTP_RESPONSE_INVALID_PARAMETER;
512
Mike Lockwood16864ba2010-05-11 17:16:59 -0400513 mSessionID = mRequest.getParameter(1);
514 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400515
Mike Lockwood16864ba2010-05-11 17:16:59 -0400516 return MTP_RESPONSE_OK;
517}
518
519MtpResponseCode MtpServer::doCloseSession() {
520 if (!mSessionOpen)
521 return MTP_RESPONSE_SESSION_NOT_OPEN;
522 mSessionID = 0;
523 mSessionOpen = false;
524 return MTP_RESPONSE_OK;
525}
526
527MtpResponseCode MtpServer::doGetStorageIDs() {
528 if (!mSessionOpen)
529 return MTP_RESPONSE_SESSION_NOT_OPEN;
530
531 int count = mStorages.size();
532 mData.putUInt32(count);
533 for (int i = 0; i < count; i++)
534 mData.putUInt32(mStorages[i]->getStorageID());
535
536 return MTP_RESPONSE_OK;
537}
538
539MtpResponseCode MtpServer::doGetStorageInfo() {
540 MtpStringBuffer string;
541
542 if (!mSessionOpen)
543 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800544 if (mRequest.getParameterCount() < 1)
545 return MTP_RESPONSE_INVALID_PARAMETER;
546
Mike Lockwood16864ba2010-05-11 17:16:59 -0400547 MtpStorageID id = mRequest.getParameter(1);
548 MtpStorage* storage = getStorage(id);
549 if (!storage)
550 return MTP_RESPONSE_INVALID_STORAGE_ID;
551
552 mData.putUInt16(storage->getType());
553 mData.putUInt16(storage->getFileSystemType());
554 mData.putUInt16(storage->getAccessCapability());
555 mData.putUInt64(storage->getMaxCapacity());
556 mData.putUInt64(storage->getFreeSpace());
557 mData.putUInt32(1024*1024*1024); // Free Space in Objects
558 string.set(storage->getDescription());
559 mData.putString(string);
560 mData.putEmptyString(); // Volume Identifier
561
562 return MTP_RESPONSE_OK;
563}
564
565MtpResponseCode MtpServer::doGetObjectPropsSupported() {
566 if (!mSessionOpen)
567 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800568 if (mRequest.getParameterCount() < 1)
569 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400570 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800571 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400572 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400573 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400574 return MTP_RESPONSE_OK;
575}
576
577MtpResponseCode MtpServer::doGetObjectHandles() {
578 if (!mSessionOpen)
579 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800580 if (mRequest.getParameterCount() < 3)
581 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400582 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400583 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400584 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400585 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500586
587 if (!hasStorage(storageID))
588 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400589
590 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700591 if (handles == NULL)
592 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400593 mData.putAUInt32(handles);
594 delete handles;
595 return MTP_RESPONSE_OK;
596}
597
Mike Lockwood343af4e2010-08-02 10:52:20 -0400598MtpResponseCode MtpServer::doGetNumObjects() {
599 if (!mSessionOpen)
600 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800601 if (mRequest.getParameterCount() < 3)
602 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400603 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
604 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
605 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400606 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500607 if (!hasStorage(storageID))
608 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400609
610 int count = mDatabase->getNumObjects(storageID, format, parent);
611 if (count >= 0) {
612 mResponse.setParameter(1, count);
613 return MTP_RESPONSE_OK;
614 } else {
615 mResponse.setParameter(1, 0);
616 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
617 }
618}
619
Mike Lockwood438344f2010-08-03 15:30:09 -0400620MtpResponseCode MtpServer::doGetObjectReferences() {
621 if (!mSessionOpen)
622 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500623 if (!hasStorage())
624 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800625 if (mRequest.getParameterCount() < 1)
626 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500627 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400628
629 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400630 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400631 if (handles) {
632 mData.putAUInt32(handles);
633 delete handles;
634 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400635 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400636 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400637 return MTP_RESPONSE_OK;
638}
639
640MtpResponseCode MtpServer::doSetObjectReferences() {
641 if (!mSessionOpen)
642 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500643 if (!hasStorage())
644 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800645 if (mRequest.getParameterCount() < 1)
646 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400647 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500648
Mike Lockwood438344f2010-08-03 15:30:09 -0400649 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800650 if (!references)
651 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400652 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
653 delete references;
654 return result;
655}
656
Mike Lockwood16864ba2010-05-11 17:16:59 -0400657MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500658 if (!hasStorage())
659 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800660 if (mRequest.getParameterCount() < 2)
661 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400662 MtpObjectHandle handle = mRequest.getParameter(1);
663 MtpObjectProperty property = mRequest.getParameter(2);
James Weiba389222018-09-27 19:22:55 +0800664 ALOGV("GetObjectPropValue %d %s (0x%04X)\n", handle,
665 MtpDebug::getObjectPropCodeName(property), property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400666
Mike Lockwood8277cec2010-08-10 15:20:35 -0400667 return mDatabase->getObjectPropertyValue(handle, property, mData);
668}
669
670MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500671 if (!hasStorage())
672 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800673 if (mRequest.getParameterCount() < 2)
674 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400675 MtpObjectHandle handle = mRequest.getParameter(1);
676 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100677 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400678 MtpDebug::getObjectPropCodeName(property));
679
680 return mDatabase->setObjectPropertyValue(handle, property, mData);
681}
682
683MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800684 if (mRequest.getParameterCount() < 1)
685 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400686 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100687 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400688 MtpDebug::getDevicePropCodeName(property));
689
690 return mDatabase->getDevicePropertyValue(property, mData);
691}
692
693MtpResponseCode MtpServer::doSetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800694 if (mRequest.getParameterCount() < 1)
695 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400696 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100697 ALOGV("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400698 MtpDebug::getDevicePropCodeName(property));
699
700 return mDatabase->setDevicePropertyValue(property, mData);
701}
702
703MtpResponseCode MtpServer::doResetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800704 if (mRequest.getParameterCount() < 1)
705 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400706 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100707 ALOGV("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400708 MtpDebug::getDevicePropCodeName(property));
709
710 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400711}
712
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400713MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500714 if (!hasStorage())
715 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800716 if (mRequest.getParameterCount() < 5)
717 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400718
719 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500720 // use uint32_t so we can support 0xFFFFFFFF
721 uint32_t format = mRequest.getParameter(2);
722 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400723 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500724 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100725 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400726 handle, MtpDebug::getFormatCodeName(format),
727 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
728
729 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
730}
731
Mike Lockwood16864ba2010-05-11 17:16:59 -0400732MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500733 if (!hasStorage())
734 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800735 if (mRequest.getParameterCount() < 1)
736 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400737 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700738 MtpObjectInfo info(handle);
739 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
740 if (result == MTP_RESPONSE_OK) {
741 char date[20];
742
743 mData.putUInt32(info.mStorageID);
744 mData.putUInt16(info.mFormat);
745 mData.putUInt16(info.mProtectionStatus);
746
747 // if object is being edited the database size may be out of date
748 uint32_t size = info.mCompressedSize;
749 ObjectEdit* edit = getEditObject(handle);
750 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700751 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700752 mData.putUInt32(size);
753
754 mData.putUInt16(info.mThumbFormat);
755 mData.putUInt32(info.mThumbCompressedSize);
756 mData.putUInt32(info.mThumbPixWidth);
757 mData.putUInt32(info.mThumbPixHeight);
758 mData.putUInt32(info.mImagePixWidth);
759 mData.putUInt32(info.mImagePixHeight);
760 mData.putUInt32(info.mImagePixDepth);
761 mData.putUInt32(info.mParent);
762 mData.putUInt16(info.mAssociationType);
763 mData.putUInt32(info.mAssociationDesc);
764 mData.putUInt32(info.mSequenceNumber);
765 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700766 formatDateTime(info.mDateCreated, date, sizeof(date));
767 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700768 formatDateTime(info.mDateModified, date, sizeof(date));
769 mData.putString(date); // date modified
770 mData.putEmptyString(); // keywords
771 }
772 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400773}
774
775MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500776 if (!hasStorage())
777 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800778 if (mRequest.getParameterCount() < 1)
779 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400780 MtpObjectHandle handle = mRequest.getParameter(1);
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700781 MtpStringBuffer pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400782 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800783 MtpObjectFormat format;
784 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400785 if (result != MTP_RESPONSE_OK)
786 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400787
Jerry Zhang487be612016-10-24 12:10:41 -0700788 auto start = std::chrono::steady_clock::now();
789
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400790 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400791 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400792 mfr.fd = open(filePath, O_RDONLY);
793 if (mfr.fd < 0) {
794 return MTP_RESPONSE_GENERAL_ERROR;
795 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400796 mfr.offset = 0;
797 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400798 mfr.command = mRequest.getOperationCode();
799 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400800
801 // then transfer the file
Jerry Zhang63dac452017-12-06 15:19:36 -0800802 int ret = mHandle->sendFile(mfr);
tao.pei07a9e542015-07-17 17:18:41 +0800803 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -0700804 ALOGE("Mtp send file got error %s", strerror(errno));
tao.pei07a9e542015-07-17 17:18:41 +0800805 if (errno == ECANCELED) {
806 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
807 } else {
808 result = MTP_RESPONSE_GENERAL_ERROR;
809 }
810 } else {
811 result = MTP_RESPONSE_OK;
812 }
813
Jerry Zhang487be612016-10-24 12:10:41 -0700814 auto end = std::chrono::steady_clock::now();
815 std::chrono::duration<double> diff = end - start;
816 struct stat sstat;
817 fstat(mfr.fd, &sstat);
818 uint64_t finalsize = sstat.st_size;
819 ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
820 diff.count(), finalsize, ((double) finalsize) / diff.count());
Jerry Zhangdc148de2018-05-14 12:07:16 -0700821 closeObjFd(mfr.fd, filePath);
tao.pei07a9e542015-07-17 17:18:41 +0800822 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400823}
824
Mike Lockwood64000782011-04-24 18:40:17 -0700825MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800826 if (mRequest.getParameterCount() < 1)
827 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700828 MtpObjectHandle handle = mRequest.getParameter(1);
829 size_t thumbSize;
830 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
831 if (thumb) {
832 // send data
833 mData.setOperationCode(mRequest.getOperationCode());
834 mData.setTransactionID(mRequest.getTransactionID());
Jerry Zhang63dac452017-12-06 15:19:36 -0800835 mData.writeData(mHandle, thumb, thumbSize);
Mike Lockwood64000782011-04-24 18:40:17 -0700836 free(thumb);
837 return MTP_RESPONSE_OK;
838 } else {
839 return MTP_RESPONSE_GENERAL_ERROR;
840 }
841}
842
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700843MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500844 if (!hasStorage())
845 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500846 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700847 uint64_t offset;
848 uint32_t length;
849 offset = mRequest.getParameter(2);
850 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800851 // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
852 if (mRequest.getParameterCount() < 4)
853 return MTP_RESPONSE_INVALID_PARAMETER;
854
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700855 // android extension with 64 bit offset
856 uint64_t offset2 = mRequest.getParameter(3);
857 offset = offset | (offset2 << 32);
858 length = mRequest.getParameter(4);
859 } else {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800860 // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
861 if (mRequest.getParameterCount() < 3)
862 return MTP_RESPONSE_INVALID_PARAMETER;
863
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700864 // standard GetPartialObject
865 length = mRequest.getParameter(3);
866 }
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700867 MtpStringBuffer pathBuf;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500868 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800869 MtpObjectFormat format;
870 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500871 if (result != MTP_RESPONSE_OK)
872 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700873 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500874 length = fileLength - offset;
875
876 const char* filePath = (const char *)pathBuf;
Jerry Zhangdf69dd32017-05-03 17:17:49 -0700877 ALOGV("sending partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500878 mtp_file_range mfr;
879 mfr.fd = open(filePath, O_RDONLY);
880 if (mfr.fd < 0) {
881 return MTP_RESPONSE_GENERAL_ERROR;
882 }
883 mfr.offset = offset;
884 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400885 mfr.command = mRequest.getOperationCode();
886 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500887 mResponse.setParameter(1, length);
888
Mike Lockwoodef441d92011-07-14 21:00:02 -0400889 // transfer the file
Jerry Zhang63dac452017-12-06 15:19:36 -0800890 int ret = mHandle->sendFile(mfr);
Steve Block3856b092011-10-20 11:56:00 +0100891 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
tao.pei07a9e542015-07-17 17:18:41 +0800892 result = MTP_RESPONSE_OK;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500893 if (ret < 0) {
894 if (errno == ECANCELED)
tao.pei07a9e542015-07-17 17:18:41 +0800895 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500896 else
tao.pei07a9e542015-07-17 17:18:41 +0800897 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500898 }
Jerry Zhangdc148de2018-05-14 12:07:16 -0700899 closeObjFd(mfr.fd, filePath);
tao.pei07a9e542015-07-17 17:18:41 +0800900 return result;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500901}
902
Mike Lockwood16864ba2010-05-11 17:16:59 -0400903MtpResponseCode MtpServer::doSendObjectInfo() {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700904 MtpStringBuffer path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800905 uint16_t temp16;
906 uint32_t temp32;
907
908 if (mRequest.getParameterCount() < 2)
909 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400910 MtpStorageID storageID = mRequest.getParameter(1);
911 MtpStorage* storage = getStorage(storageID);
912 MtpObjectHandle parent = mRequest.getParameter(2);
913 if (!storage)
914 return MTP_RESPONSE_INVALID_STORAGE_ID;
915
916 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400917 if (parent == MTP_PARENT_ROOT) {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700918 path.set(storage->getPath());
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400919 parent = 0;
920 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800921 int64_t length;
922 MtpObjectFormat format;
923 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400924 if (result != MTP_RESPONSE_OK)
925 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800926 if (format != MTP_FORMAT_ASSOCIATION)
927 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400928 }
929
930 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800931 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
932 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
933 MtpObjectFormat format = temp16;
934 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
935 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
936 mSendObjectFileSize = temp32;
937 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
938 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
939 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
940 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
941 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
942 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
943 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
944 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
945 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800946 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800947 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400948 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800949 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700950 if (name.isEmpty()) {
Marco Nelissen7ea72dc2016-09-19 14:08:16 -0700951 ALOGE("empty name");
952 return MTP_RESPONSE_INVALID_PARAMETER;
953 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800954 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
955 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400956 // keywords follow
957
James Weiba389222018-09-27 19:22:55 +0800958 ALOGV("name: %s format: 0x%04X (%s)\n", (const char*)name, format,
959 MtpDebug::getFormatCodeName(format));
Mike Lockwoodfceef462010-05-14 15:35:17 -0400960 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400961 if (!parseDateTime(modified, modifiedTime))
962 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400963
964 if (path[path.size() - 1] != '/')
Jerry Zhangbc1d4b42018-03-27 15:25:03 -0700965 path.append("/");
966 path.append(name);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400967
Mike Lockwood20c3be02010-12-12 12:17:43 -0800968 // check space first
969 if (mSendObjectFileSize > storage->getFreeSpace())
970 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400971 uint64_t maxFileSize = storage->getMaxFileSize();
972 // check storage max file size
973 if (maxFileSize != 0) {
974 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
975 // is >= 0xFFFFFFFF
976 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
977 return MTP_RESPONSE_OBJECT_TOO_LARGE;
978 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800979
James Weiba389222018-09-27 19:22:55 +0800980 ALOGV("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700981 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, format,
982 parent, storageID);
James Weiba389222018-09-27 19:22:55 +0800983 ALOGD("handle: %d, parent: %d, storageID: %08X", handle, parent, storageID);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400984 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400985 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400986 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400987
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700988 if (format == MTP_FORMAT_ASSOCIATION) {
Jerry Zhange242f122017-10-16 14:54:08 -0700989 int ret = makeFolder((const char *)path);
990 if (ret)
Mike Lockwood16864ba2010-05-11 17:16:59 -0400991 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodaa952402011-01-18 11:06:19 -0800992
993 // SendObject does not get sent for directories, so call endSendObject here instead
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700994 mDatabase->endSendObject(handle, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400995 }
Jerry Zhange5aa05d2017-10-13 12:14:42 -0700996 mSendObjectFilePath = path;
997 // save the handle for the SendObject call, which should follow
998 mSendObjectHandle = handle;
999 mSendObjectFormat = format;
1000 mSendObjectModifiedTime = modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001001
1002 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001003 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001004 mResponse.setParameter(3, handle);
1005
1006 return MTP_RESPONSE_OK;
1007}
1008
Jerry Zhang708b3e02017-09-26 17:53:39 -07001009MtpResponseCode MtpServer::doMoveObject() {
1010 if (!hasStorage())
1011 return MTP_RESPONSE_GENERAL_ERROR;
1012 if (mRequest.getParameterCount() < 3)
1013 return MTP_RESPONSE_INVALID_PARAMETER;
1014 MtpObjectHandle objectHandle = mRequest.getParameter(1);
1015 MtpStorageID storageID = mRequest.getParameter(2);
1016 MtpStorage* storage = getStorage(storageID);
1017 MtpObjectHandle parent = mRequest.getParameter(3);
1018 if (!storage)
1019 return MTP_RESPONSE_INVALID_STORAGE_ID;
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001020 MtpStringBuffer path;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001021 MtpResponseCode result;
1022
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001023 MtpStringBuffer fromPath;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001024 int64_t fileLength;
1025 MtpObjectFormat format;
1026 MtpObjectInfo info(objectHandle);
1027 result = mDatabase->getObjectInfo(objectHandle, info);
1028 if (result != MTP_RESPONSE_OK)
1029 return result;
1030 result = mDatabase->getObjectFilePath(objectHandle, fromPath, fileLength, format);
1031 if (result != MTP_RESPONSE_OK)
1032 return result;
1033
1034 // special case the root
1035 if (parent == 0) {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001036 path.set(storage->getPath());
Jerry Zhang708b3e02017-09-26 17:53:39 -07001037 } else {
1038 int64_t parentLength;
1039 MtpObjectFormat parentFormat;
1040 result = mDatabase->getObjectFilePath(parent, path, parentLength, parentFormat);
1041 if (result != MTP_RESPONSE_OK)
1042 return result;
1043 if (parentFormat != MTP_FORMAT_ASSOCIATION)
1044 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
1045 }
1046
1047 if (path[path.size() - 1] != '/')
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001048 path.append("/");
1049 path.append(info.mName);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001050
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001051 result = mDatabase->beginMoveObject(objectHandle, parent, storageID);
1052 if (result != MTP_RESPONSE_OK)
1053 return result;
1054
Jerry Zhang708b3e02017-09-26 17:53:39 -07001055 if (info.mStorageID == storageID) {
1056 ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
Jerry Zhangdc148de2018-05-14 12:07:16 -07001057 if (renameTo(fromPath, path)) {
Jerry Zhange242f122017-10-16 14:54:08 -07001058 PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001059 result = MTP_RESPONSE_GENERAL_ERROR;
1060 }
1061 } else {
1062 ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path);
Jerry Zhange242f122017-10-16 14:54:08 -07001063 if (format == MTP_FORMAT_ASSOCIATION) {
1064 int ret = makeFolder((const char *)path);
1065 ret += copyRecursive(fromPath, path);
1066 if (ret) {
1067 result = MTP_RESPONSE_GENERAL_ERROR;
1068 } else {
1069 deletePath(fromPath);
1070 }
Jerry Zhang708b3e02017-09-26 17:53:39 -07001071 } else {
Jerry Zhange242f122017-10-16 14:54:08 -07001072 if (copyFile(fromPath, path)) {
1073 result = MTP_RESPONSE_GENERAL_ERROR;
1074 } else {
1075 deletePath(fromPath);
1076 }
Jerry Zhang708b3e02017-09-26 17:53:39 -07001077 }
1078 }
1079
1080 // If the move failed, undo the database change
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001081 mDatabase->endMoveObject(info.mParent, parent, info.mStorageID, storageID, objectHandle,
1082 result == MTP_RESPONSE_OK);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001083
1084 return result;
1085}
1086
1087MtpResponseCode MtpServer::doCopyObject() {
1088 if (!hasStorage())
1089 return MTP_RESPONSE_GENERAL_ERROR;
1090 MtpResponseCode result = MTP_RESPONSE_OK;
1091 if (mRequest.getParameterCount() < 3)
1092 return MTP_RESPONSE_INVALID_PARAMETER;
1093 MtpObjectHandle objectHandle = mRequest.getParameter(1);
1094 MtpStorageID storageID = mRequest.getParameter(2);
1095 MtpStorage* storage = getStorage(storageID);
1096 MtpObjectHandle parent = mRequest.getParameter(3);
1097 if (!storage)
1098 return MTP_RESPONSE_INVALID_STORAGE_ID;
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001099 MtpStringBuffer path;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001100
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001101 MtpStringBuffer fromPath;
Jerry Zhang708b3e02017-09-26 17:53:39 -07001102 int64_t fileLength;
1103 MtpObjectFormat format;
1104 MtpObjectInfo info(objectHandle);
1105 result = mDatabase->getObjectInfo(objectHandle, info);
1106 if (result != MTP_RESPONSE_OK)
1107 return result;
1108 result = mDatabase->getObjectFilePath(objectHandle, fromPath, fileLength, format);
1109 if (result != MTP_RESPONSE_OK)
1110 return result;
1111
1112 // special case the root
1113 if (parent == 0) {
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001114 path.set(storage->getPath());
Jerry Zhang708b3e02017-09-26 17:53:39 -07001115 } else {
1116 int64_t parentLength;
1117 MtpObjectFormat parentFormat;
1118 result = mDatabase->getObjectFilePath(parent, path, parentLength, parentFormat);
1119 if (result != MTP_RESPONSE_OK)
1120 return result;
1121 if (parentFormat != MTP_FORMAT_ASSOCIATION)
1122 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
1123 }
1124
1125 // check space first
1126 if ((uint64_t) fileLength > storage->getFreeSpace())
1127 return MTP_RESPONSE_STORAGE_FULL;
1128
1129 if (path[path.size() - 1] != '/')
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001130 path.append("/");
1131 path.append(info.mName);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001132
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001133 MtpObjectHandle handle = mDatabase->beginCopyObject(objectHandle, parent, storageID);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001134 if (handle == kInvalidObjectHandle) {
1135 return MTP_RESPONSE_GENERAL_ERROR;
1136 }
1137
1138 ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path);
Jerry Zhange242f122017-10-16 14:54:08 -07001139 if (format == MTP_FORMAT_ASSOCIATION) {
1140 int ret = makeFolder((const char *)path);
kyle_tso6de16602017-11-22 18:14:51 +08001141 ret += copyRecursive(fromPath, path);
Jerry Zhange242f122017-10-16 14:54:08 -07001142 if (ret) {
1143 result = MTP_RESPONSE_GENERAL_ERROR;
1144 }
1145 } else {
1146 if (copyFile(fromPath, path)) {
1147 result = MTP_RESPONSE_GENERAL_ERROR;
1148 }
Jerry Zhang708b3e02017-09-26 17:53:39 -07001149 }
1150
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001151 mDatabase->endCopyObject(handle, result);
Jerry Zhang708b3e02017-09-26 17:53:39 -07001152 mResponse.setParameter(1, handle);
1153 return result;
1154}
1155
Mike Lockwood16864ba2010-05-11 17:16:59 -04001156MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001157 if (!hasStorage())
1158 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -04001159 MtpResponseCode result = MTP_RESPONSE_OK;
1160 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001161 int ret, initialData;
tao.pei07a9e542015-07-17 17:18:41 +08001162 bool isCanceled = false;
Manoj Gupta33587d12017-04-18 16:41:09 -07001163 struct stat sstat = {};
Mike Lockwood4714b072010-07-12 08:49:01 -04001164
Jerry Zhang487be612016-10-24 12:10:41 -07001165 auto start = std::chrono::steady_clock::now();
1166
Mike Lockwood16864ba2010-05-11 17:16:59 -04001167 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +00001168 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -04001169 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
1170 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001171 }
1172
Mike Lockwoodef441d92011-07-14 21:00:02 -04001173 // read the header, and possibly some data
Jerry Zhang63dac452017-12-06 15:19:36 -08001174 ret = mData.read(mHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001175 if (ret < MTP_CONTAINER_HEADER_SIZE) {
1176 result = MTP_RESPONSE_GENERAL_ERROR;
1177 goto done;
1178 }
1179 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001180
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001181 if (mSendObjectFormat == MTP_FORMAT_ASSOCIATION) {
1182 if (initialData != 0)
1183 ALOGE("Expected folder size to be 0!");
1184 mSendObjectHandle = kInvalidObjectHandle;
1185 mSendObjectFormat = 0;
1186 mSendObjectModifiedTime = 0;
1187 return result;
1188 }
1189
Mike Lockwood16864ba2010-05-11 17:16:59 -04001190 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -07001191 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001192 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001193 result = MTP_RESPONSE_GENERAL_ERROR;
1194 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001195 }
Jerry Zhange242f122017-10-16 14:54:08 -07001196 fchown(mfr.fd, getuid(), FILE_GROUP);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001197 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001198 mask = umask(0);
Jerry Zhange242f122017-10-16 14:54:08 -07001199 fchmod(mfr.fd, FILE_PERM);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001200 umask(mask);
1201
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001202 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001203 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001204 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001205
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001206 if (ret < 0) {
1207 ALOGE("failed to write initial data");
1208 result = MTP_RESPONSE_GENERAL_ERROR;
1209 } else {
Jerry Zhang54107562017-05-15 11:54:19 -07001210 mfr.offset = initialData;
1211 if (mSendObjectFileSize == 0xFFFFFFFF) {
1212 // tell driver to read until it receives a short packet
1213 mfr.length = 0xFFFFFFFF;
1214 } else {
1215 mfr.length = mSendObjectFileSize - initialData;
1216 }
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001217
Jerry Zhang54107562017-05-15 11:54:19 -07001218 mfr.command = 0;
1219 mfr.transaction_id = 0;
Yunlian Jiang8ddc3522017-02-21 15:58:09 -08001220
Jerry Zhang54107562017-05-15 11:54:19 -07001221 // transfer the file
Jerry Zhang63dac452017-12-06 15:19:36 -08001222 ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
Jerry Zhang54107562017-05-15 11:54:19 -07001223 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1224 if ((ret < 0) && (errno == ECANCELED)) {
1225 isCanceled = true;
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001226 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001227 }
caozhiyuan854cb172017-04-26 16:52:30 +08001228
1229 if (mSendObjectModifiedTime) {
1230 struct timespec newTime[2];
1231 newTime[0].tv_nsec = UTIME_NOW;
1232 newTime[1].tv_sec = mSendObjectModifiedTime;
1233 newTime[1].tv_nsec = 0;
1234 if (futimens(mfr.fd, newTime) < 0) {
1235 ALOGW("changing modified time failed, %s", strerror(errno));
1236 }
1237 }
1238
Jerry Zhang487be612016-10-24 12:10:41 -07001239 fstat(mfr.fd, &sstat);
Jerry Zhangdc148de2018-05-14 12:07:16 -07001240 closeObjFd(mfr.fd, mSendObjectFilePath);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001241
Mike Lockwood916076c2010-06-04 09:49:21 -04001242 if (ret < 0) {
Jerry Zhang487be612016-10-24 12:10:41 -07001243 ALOGE("Mtp receive file got error %s", strerror(errno));
Mike Lockwood916076c2010-06-04 09:49:21 -04001244 unlink(mSendObjectFilePath);
tao.pei07a9e542015-07-17 17:18:41 +08001245 if (isCanceled)
Mike Lockwood4714b072010-07-12 08:49:01 -04001246 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001247 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001248 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001249 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001250
1251done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001252 // reset so we don't attempt to send the data back
1253 mData.reset();
1254
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001255 mDatabase->endSendObject(mSendObjectHandle, result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001256 mSendObjectHandle = kInvalidObjectHandle;
1257 mSendObjectFormat = 0;
caozhiyuan854cb172017-04-26 16:52:30 +08001258 mSendObjectModifiedTime = 0;
Jerry Zhang487be612016-10-24 12:10:41 -07001259
1260 auto end = std::chrono::steady_clock::now();
1261 std::chrono::duration<double> diff = end - start;
1262 uint64_t finalsize = sstat.st_size;
1263 ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
1264 diff.count(), finalsize, ((double) finalsize) / diff.count());
Mike Lockwood4714b072010-07-12 08:49:01 -04001265 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001266}
1267
1268MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001269 if (!hasStorage())
1270 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Marco Nelissenea9f2152015-01-23 10:55:25 -08001271 if (mRequest.getParameterCount() < 1)
Mike Lockwoodab063842014-11-12 14:20:06 -08001272 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001273 MtpObjectHandle handle = mRequest.getParameter(1);
Marco Nelissenea9f2152015-01-23 10:55:25 -08001274 MtpObjectFormat format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001275 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1276 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001277
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001278 MtpStringBuffer filePath;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001279 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001280 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001281 if (result != MTP_RESPONSE_OK)
1282 return result;
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001283
Jerry Zhange5aa05d2017-10-13 12:14:42 -07001284 // Don't delete the actual files unless the database deletion is allowed
1285 result = mDatabase->beginDeleteObject(handle);
1286 if (result != MTP_RESPONSE_OK)
1287 return result;
1288
1289 bool success = deletePath((const char *)filePath);
1290
1291 mDatabase->endDeleteObject(handle, success);
1292 return success ? result : MTP_RESPONSE_PARTIAL_DELETION;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001293}
1294
1295MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001296 if (mRequest.getParameterCount() < 2)
1297 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001298 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001299 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001300 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001301 MtpDebug::getFormatCodeName(format));
1302 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001303 if (!property)
1304 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001305 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001306 delete property;
1307 return MTP_RESPONSE_OK;
1308}
1309
1310MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001311 if (mRequest.getParameterCount() < 1)
1312 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001313 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001314 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001315 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1316 if (!property)
1317 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1318 property->write(mData);
1319 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001320 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001321}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001322
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001323MtpResponseCode MtpServer::doSendPartialObject() {
1324 if (!hasStorage())
1325 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001326 if (mRequest.getParameterCount() < 4)
1327 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001328 MtpObjectHandle handle = mRequest.getParameter(1);
1329 uint64_t offset = mRequest.getParameter(2);
1330 uint64_t offset2 = mRequest.getParameter(3);
1331 offset = offset | (offset2 << 32);
1332 uint32_t length = mRequest.getParameter(4);
1333
1334 ObjectEdit* edit = getEditObject(handle);
1335 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001336 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001337 return MTP_RESPONSE_GENERAL_ERROR;
1338 }
1339
1340 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001341 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001342 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1343 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001344 return MTP_RESPONSE_GENERAL_ERROR;
1345 }
1346
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001347 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001348 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001349
Mike Lockwoodef441d92011-07-14 21:00:02 -04001350 // read the header, and possibly some data
Jerry Zhang63dac452017-12-06 15:19:36 -08001351 int ret = mData.read(mHandle);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001352 if (ret < MTP_CONTAINER_HEADER_SIZE)
1353 return MTP_RESPONSE_GENERAL_ERROR;
1354 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1355
1356 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001357 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001358 offset += initialData;
1359 length -= initialData;
1360 }
1361
tao.pei07a9e542015-07-17 17:18:41 +08001362 bool isCanceled = false;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001363 if (ret < 0) {
1364 ALOGE("failed to write initial data");
1365 } else {
Jerry Zhang54107562017-05-15 11:54:19 -07001366 mtp_file_range mfr;
1367 mfr.fd = edit->mFD;
1368 mfr.offset = offset;
1369 mfr.length = length;
1370 mfr.command = 0;
1371 mfr.transaction_id = 0;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001372
Jerry Zhang54107562017-05-15 11:54:19 -07001373 // transfer the file
Jerry Zhang63dac452017-12-06 15:19:36 -08001374 ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
Jerry Zhang54107562017-05-15 11:54:19 -07001375 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1376 if ((ret < 0) && (errno == ECANCELED)) {
1377 isCanceled = true;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001378 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001379 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001380 if (ret < 0) {
1381 mResponse.setParameter(1, 0);
tao.pei07a9e542015-07-17 17:18:41 +08001382 if (isCanceled)
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001383 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1384 else
1385 return MTP_RESPONSE_GENERAL_ERROR;
1386 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001387
1388 // reset so we don't attempt to send this back
1389 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001390 mResponse.setParameter(1, length);
1391 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001392 if (end > edit->mSize) {
1393 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001394 }
1395 return MTP_RESPONSE_OK;
1396}
1397
1398MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001399 if (mRequest.getParameterCount() < 3)
1400 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001401 MtpObjectHandle handle = mRequest.getParameter(1);
1402 ObjectEdit* edit = getEditObject(handle);
1403 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001404 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001405 return MTP_RESPONSE_GENERAL_ERROR;
1406 }
1407
1408 uint64_t offset = mRequest.getParameter(2);
1409 uint64_t offset2 = mRequest.getParameter(3);
1410 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001411 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001412 return MTP_RESPONSE_GENERAL_ERROR;
1413 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001414 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001415 return MTP_RESPONSE_OK;
1416 }
1417}
1418
1419MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001420 if (mRequest.getParameterCount() < 1)
1421 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001422 MtpObjectHandle handle = mRequest.getParameter(1);
1423 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001424 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001425 return MTP_RESPONSE_GENERAL_ERROR;
1426 }
1427
Jerry Zhangbc1d4b42018-03-27 15:25:03 -07001428 MtpStringBuffer path;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001429 int64_t fileLength;
1430 MtpObjectFormat format;
1431 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1432 if (result != MTP_RESPONSE_OK)
1433 return result;
1434
1435 int fd = open((const char *)path, O_RDWR | O_EXCL);
1436 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001437 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001438 return MTP_RESPONSE_GENERAL_ERROR;
1439 }
1440
1441 addEditObject(handle, path, fileLength, format, fd);
1442 return MTP_RESPONSE_OK;
1443}
1444
1445MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001446 if (mRequest.getParameterCount() < 1)
1447 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001448 MtpObjectHandle handle = mRequest.getParameter(1);
1449 ObjectEdit* edit = getEditObject(handle);
1450 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001451 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001452 return MTP_RESPONSE_GENERAL_ERROR;
1453 }
1454
1455 commitEdit(edit);
1456 removeEditObject(handle);
1457 return MTP_RESPONSE_OK;
1458}
1459
Mike Lockwood7850ef92010-05-14 10:10:36 -04001460} // namespace android