blob: 90f1a77485bb04c732cd2cec1fee3b94380735e6 [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
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/types.h>
20#include <sys/ioctl.h>
21#include <sys/stat.h>
22#include <fcntl.h>
Mark Salyzyndb43b342014-04-04 14:47:28 -070023#include <inttypes.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040024#include <errno.h>
Mike Lockwoodd3211492010-09-13 17:15:58 -040025#include <sys/stat.h>
26#include <dirent.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040027
Mike Lockwoodc42aa122010-06-14 17:58:08 -070028#include <cutils/properties.h>
29
Mike Lockwooda881b442010-09-23 22:32:05 -040030#define LOG_TAG "MtpServer"
31
Mike Lockwood16864ba2010-05-11 17:16:59 -040032#include "MtpDebug.h"
Mike Lockwood7f53a192010-07-09 10:45:22 -040033#include "MtpDatabase.h"
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070034#include "MtpObjectInfo.h"
Mike Lockwood21ef7d02010-06-30 17:00:35 -040035#include "MtpProperty.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040036#include "MtpServer.h"
37#include "MtpStorage.h"
38#include "MtpStringBuffer.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040039
Mike Lockwood8065e202010-07-15 13:36:52 -040040#include <linux/usb/f_mtp.h>
Mike Lockwood16864ba2010-05-11 17:16:59 -040041
Mike Lockwood7850ef92010-05-14 10:10:36 -040042namespace android {
43
Mike Lockwood16864ba2010-05-11 17:16:59 -040044static const MtpOperationCode kSupportedOperationCodes[] = {
45 MTP_OPERATION_GET_DEVICE_INFO,
46 MTP_OPERATION_OPEN_SESSION,
47 MTP_OPERATION_CLOSE_SESSION,
48 MTP_OPERATION_GET_STORAGE_IDS,
49 MTP_OPERATION_GET_STORAGE_INFO,
50 MTP_OPERATION_GET_NUM_OBJECTS,
51 MTP_OPERATION_GET_OBJECT_HANDLES,
52 MTP_OPERATION_GET_OBJECT_INFO,
53 MTP_OPERATION_GET_OBJECT,
Mike Lockwood64000782011-04-24 18:40:17 -070054 MTP_OPERATION_GET_THUMB,
Mike Lockwood16864ba2010-05-11 17:16:59 -040055 MTP_OPERATION_DELETE_OBJECT,
56 MTP_OPERATION_SEND_OBJECT_INFO,
57 MTP_OPERATION_SEND_OBJECT,
58// MTP_OPERATION_INITIATE_CAPTURE,
59// MTP_OPERATION_FORMAT_STORE,
60// MTP_OPERATION_RESET_DEVICE,
61// MTP_OPERATION_SELF_TEST,
62// MTP_OPERATION_SET_OBJECT_PROTECTION,
63// MTP_OPERATION_POWER_DOWN,
Mike Lockwoode3e76c42010-09-02 14:57:30 -040064 MTP_OPERATION_GET_DEVICE_PROP_DESC,
Mike Lockwood8277cec2010-08-10 15:20:35 -040065 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
66 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
67 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
Mike Lockwood16864ba2010-05-11 17:16:59 -040068// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
69// MTP_OPERATION_MOVE_OBJECT,
70// MTP_OPERATION_COPY_OBJECT,
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -050071 MTP_OPERATION_GET_PARTIAL_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040072// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
73 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
Mike Lockwood8277cec2010-08-10 15:20:35 -040074 MTP_OPERATION_GET_OBJECT_PROP_DESC,
Mike Lockwood677f5702010-09-23 23:04:28 -040075 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
76 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
Mike Lockwoodb6da06e2010-10-14 18:03:25 -040077 MTP_OPERATION_GET_OBJECT_PROP_LIST,
78// MTP_OPERATION_SET_OBJECT_PROP_LIST,
79// MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
80// MTP_OPERATION_SEND_OBJECT_PROP_LIST,
Mike Lockwood438344f2010-08-03 15:30:09 -040081 MTP_OPERATION_GET_OBJECT_REFERENCES,
82 MTP_OPERATION_SET_OBJECT_REFERENCES,
Mike Lockwood16864ba2010-05-11 17:16:59 -040083// MTP_OPERATION_SKIP,
Mike Lockwood7d77dcf2011-04-21 17:05:55 -070084 // Android extension for direct file IO
85 MTP_OPERATION_GET_PARTIAL_OBJECT_64,
86 MTP_OPERATION_SEND_PARTIAL_OBJECT,
87 MTP_OPERATION_TRUNCATE_OBJECT,
88 MTP_OPERATION_BEGIN_EDIT_OBJECT,
89 MTP_OPERATION_END_EDIT_OBJECT,
Mike Lockwood16864ba2010-05-11 17:16:59 -040090};
91
Mike Lockwood873871f2010-07-12 18:54:16 -040092static const MtpEventCode kSupportedEventCodes[] = {
93 MTP_EVENT_OBJECT_ADDED,
94 MTP_EVENT_OBJECT_REMOVED,
Mike Lockwooda8494402011-02-18 09:07:14 -050095 MTP_EVENT_STORE_ADDED,
96 MTP_EVENT_STORE_REMOVED,
Mike Lockwood0fa848d2014-03-07 13:29:59 -080097 MTP_EVENT_DEVICE_PROP_CHANGED,
Mike Lockwood873871f2010-07-12 18:54:16 -040098};
99
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400100MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400101 int fileGroup, int filePerm, int directoryPerm)
Mike Lockwood16864ba2010-05-11 17:16:59 -0400102 : mFD(fd),
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400103 mDatabase(database),
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400104 mPtp(ptp),
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400105 mFileGroup(fileGroup),
106 mFilePermission(filePerm),
107 mDirectoryPermission(directoryPerm),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400108 mSessionID(0),
109 mSessionOpen(false),
110 mSendObjectHandle(kInvalidObjectHandle),
Mike Lockwood4714b072010-07-12 08:49:01 -0400111 mSendObjectFormat(0),
Mike Lockwood16864ba2010-05-11 17:16:59 -0400112 mSendObjectFileSize(0)
113{
Mike Lockwood16864ba2010-05-11 17:16:59 -0400114}
115
116MtpServer::~MtpServer() {
117}
118
Mike Lockwooda8494402011-02-18 09:07:14 -0500119void MtpServer::addStorage(MtpStorage* storage) {
120 Mutex::Autolock autoLock(mMutex);
121
122 mStorages.push(storage);
123 sendStoreAdded(storage->getStorageID());
124}
125
126void MtpServer::removeStorage(MtpStorage* storage) {
127 Mutex::Autolock autoLock(mMutex);
128
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700129 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500130 if (mStorages[i] == storage) {
131 mStorages.removeAt(i);
132 sendStoreRemoved(storage->getStorageID());
133 break;
134 }
135 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400136}
137
138MtpStorage* MtpServer::getStorage(MtpStorageID id) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800139 if (id == 0)
140 return mStorages[0];
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700141 for (size_t i = 0; i < mStorages.size(); i++) {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800142 MtpStorage* storage = mStorages[i];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400143 if (storage->getStorageID() == id)
144 return storage;
145 }
146 return NULL;
147}
148
Mike Lockwooda8494402011-02-18 09:07:14 -0500149bool MtpServer::hasStorage(MtpStorageID id) {
150 if (id == 0 || id == 0xFFFFFFFF)
151 return mStorages.size() > 0;
152 return (getStorage(id) != NULL);
153}
154
Mike Lockwood16864ba2010-05-11 17:16:59 -0400155void MtpServer::run() {
156 int fd = mFD;
157
Steve Block3856b092011-10-20 11:56:00 +0100158 ALOGV("MtpServer::run fd: %d\n", fd);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400159
160 while (1) {
161 int ret = mRequest.read(fd);
162 if (ret < 0) {
Steve Block3856b092011-10-20 11:56:00 +0100163 ALOGV("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400164 if (errno == ECANCELED) {
165 // return to top of loop and wait for next command
166 continue;
167 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400168 break;
169 }
170 MtpOperationCode operation = mRequest.getOperationCode();
171 MtpTransactionID transaction = mRequest.getTransactionID();
172
Steve Block3856b092011-10-20 11:56:00 +0100173 ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400174 mRequest.dump();
175
176 // FIXME need to generalize this
Mike Lockwood438344f2010-08-03 15:30:09 -0400177 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood8277cec2010-08-10 15:20:35 -0400178 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
179 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
180 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400181 if (dataIn) {
182 int ret = mData.read(fd);
183 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000184 ALOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400185 if (errno == ECANCELED) {
186 // return to top of loop and wait for next command
187 continue;
188 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400189 break;
190 }
Steve Block3856b092011-10-20 11:56:00 +0100191 ALOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400192 mData.dump();
193 } else {
194 mData.reset();
195 }
196
Mike Lockwood916076c2010-06-04 09:49:21 -0400197 if (handleRequest()) {
198 if (!dataIn && mData.hasData()) {
199 mData.setOperationCode(operation);
200 mData.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100201 ALOGV("sending data:");
Mike Lockwood23d20712010-10-11 17:31:44 -0400202 mData.dump();
Mike Lockwood916076c2010-06-04 09:49:21 -0400203 ret = mData.write(fd);
204 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000205 ALOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400206 if (errno == ECANCELED) {
207 // return to top of loop and wait for next command
208 continue;
209 }
210 break;
211 }
212 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400213
Mike Lockwood916076c2010-06-04 09:49:21 -0400214 mResponse.setTransactionID(transaction);
Steve Block3856b092011-10-20 11:56:00 +0100215 ALOGV("sending response %04X", mResponse.getResponseCode());
Mike Lockwood916076c2010-06-04 09:49:21 -0400216 ret = mResponse.write(fd);
tao.pei07a9e542015-07-17 17:18:41 +0800217 const int savedErrno = errno;
Mike Lockwood23d20712010-10-11 17:31:44 -0400218 mResponse.dump();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400219 if (ret < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000220 ALOGE("request write returned %d, errno: %d", ret, errno);
tao.pei07a9e542015-07-17 17:18:41 +0800221 if (savedErrno == ECANCELED) {
Mike Lockwood916076c2010-06-04 09:49:21 -0400222 // return to top of loop and wait for next command
223 continue;
224 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400225 break;
226 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400227 } else {
Steve Block3856b092011-10-20 11:56:00 +0100228 ALOGV("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400229 }
230 }
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400231
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700232 // commit any open edits
233 int count = mObjectEditList.size();
234 for (int i = 0; i < count; i++) {
235 ObjectEdit* edit = mObjectEditList[i];
236 commitEdit(edit);
237 delete edit;
238 }
239 mObjectEditList.clear();
240
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400241 if (mSessionOpen)
242 mDatabase->sessionEnded();
Mike Lockwooddec73882011-07-11 15:04:38 -0400243 close(fd);
244 mFD = -1;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400245}
246
Mike Lockwood873871f2010-07-12 18:54:16 -0400247void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100248 ALOGV("sendObjectAdded %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500249 sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
Mike Lockwood873871f2010-07-12 18:54:16 -0400250}
251
252void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Steve Block3856b092011-10-20 11:56:00 +0100253 ALOGV("sendObjectRemoved %d\n", handle);
Mike Lockwooda8494402011-02-18 09:07:14 -0500254 sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
255}
256
257void MtpServer::sendStoreAdded(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100258 ALOGV("sendStoreAdded %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500259 sendEvent(MTP_EVENT_STORE_ADDED, id);
260}
261
262void MtpServer::sendStoreRemoved(MtpStorageID id) {
Steve Block3856b092011-10-20 11:56:00 +0100263 ALOGV("sendStoreRemoved %08X\n", id);
Mike Lockwooda8494402011-02-18 09:07:14 -0500264 sendEvent(MTP_EVENT_STORE_REMOVED, id);
265}
266
Mike Lockwood0fa848d2014-03-07 13:29:59 -0800267void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
268 ALOGV("sendDevicePropertyChanged %d\n", property);
269 sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
270}
271
Mike Lockwooda8494402011-02-18 09:07:14 -0500272void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
Mike Lockwood73ecd232010-07-19 14:29:58 -0400273 if (mSessionOpen) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500274 mEvent.setEventCode(code);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400275 mEvent.setTransactionID(mRequest.getTransactionID());
Mike Lockwooda8494402011-02-18 09:07:14 -0500276 mEvent.setParameter(1, param1);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400277 int ret = mEvent.write(mFD);
Steve Block3856b092011-10-20 11:56:00 +0100278 ALOGV("mEvent.write returned %d\n", ret);
Mike Lockwood73ecd232010-07-19 14:29:58 -0400279 }
Mike Lockwood873871f2010-07-12 18:54:16 -0400280}
281
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700282void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
283 uint64_t size, MtpObjectFormat format, int fd) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700284 ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700285 mObjectEditList.add(edit);
286}
287
288MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
289 int count = mObjectEditList.size();
290 for (int i = 0; i < count; i++) {
291 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700292 if (edit->mHandle == handle) return edit;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700293 }
294 return NULL;
295}
296
297void MtpServer::removeEditObject(MtpObjectHandle handle) {
298 int count = mObjectEditList.size();
299 for (int i = 0; i < count; i++) {
300 ObjectEdit* edit = mObjectEditList[i];
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700301 if (edit->mHandle == handle) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700302 delete edit;
303 mObjectEditList.removeAt(i);
304 return;
305 }
306 }
Steve Block29357bc2012-01-06 19:20:56 +0000307 ALOGE("ObjectEdit not found in removeEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700308}
309
310void MtpServer::commitEdit(ObjectEdit* edit) {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700311 mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700312}
313
314
Mike Lockwood916076c2010-06-04 09:49:21 -0400315bool MtpServer::handleRequest() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500316 Mutex::Autolock autoLock(mMutex);
317
Mike Lockwood16864ba2010-05-11 17:16:59 -0400318 MtpOperationCode operation = mRequest.getOperationCode();
319 MtpResponseCode response;
320
321 mResponse.reset();
322
323 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
324 // FIXME - need to delete mSendObjectHandle from the database
Steve Block29357bc2012-01-06 19:20:56 +0000325 ALOGE("expected SendObject after SendObjectInfo");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400326 mSendObjectHandle = kInvalidObjectHandle;
327 }
328
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700329 int containertype = mRequest.getContainerType();
330 if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
331 ALOGE("wrong container type %d", containertype);
332 return false;
333 }
334
335 ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
336
Mike Lockwood16864ba2010-05-11 17:16:59 -0400337 switch (operation) {
338 case MTP_OPERATION_GET_DEVICE_INFO:
339 response = doGetDeviceInfo();
340 break;
341 case MTP_OPERATION_OPEN_SESSION:
342 response = doOpenSession();
343 break;
344 case MTP_OPERATION_CLOSE_SESSION:
345 response = doCloseSession();
346 break;
347 case MTP_OPERATION_GET_STORAGE_IDS:
348 response = doGetStorageIDs();
349 break;
350 case MTP_OPERATION_GET_STORAGE_INFO:
351 response = doGetStorageInfo();
352 break;
353 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
354 response = doGetObjectPropsSupported();
355 break;
356 case MTP_OPERATION_GET_OBJECT_HANDLES:
357 response = doGetObjectHandles();
358 break;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400359 case MTP_OPERATION_GET_NUM_OBJECTS:
360 response = doGetNumObjects();
361 break;
Mike Lockwood438344f2010-08-03 15:30:09 -0400362 case MTP_OPERATION_GET_OBJECT_REFERENCES:
363 response = doGetObjectReferences();
364 break;
365 case MTP_OPERATION_SET_OBJECT_REFERENCES:
366 response = doSetObjectReferences();
367 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400368 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
369 response = doGetObjectPropValue();
370 break;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400371 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
372 response = doSetObjectPropValue();
373 break;
374 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
375 response = doGetDevicePropValue();
376 break;
377 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
378 response = doSetDevicePropValue();
379 break;
380 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
381 response = doResetDevicePropValue();
382 break;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400383 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
384 response = doGetObjectPropList();
385 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400386 case MTP_OPERATION_GET_OBJECT_INFO:
387 response = doGetObjectInfo();
388 break;
389 case MTP_OPERATION_GET_OBJECT:
390 response = doGetObject();
391 break;
Mike Lockwood64000782011-04-24 18:40:17 -0700392 case MTP_OPERATION_GET_THUMB:
393 response = doGetThumb();
394 break;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500395 case MTP_OPERATION_GET_PARTIAL_OBJECT:
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700396 case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
397 response = doGetPartialObject(operation);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500398 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400399 case MTP_OPERATION_SEND_OBJECT_INFO:
400 response = doSendObjectInfo();
401 break;
402 case MTP_OPERATION_SEND_OBJECT:
403 response = doSendObject();
404 break;
405 case MTP_OPERATION_DELETE_OBJECT:
406 response = doDeleteObject();
407 break;
408 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood21ef7d02010-06-30 17:00:35 -0400409 response = doGetObjectPropDesc();
410 break;
Mike Lockwoode3e76c42010-09-02 14:57:30 -0400411 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
412 response = doGetDevicePropDesc();
413 break;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700414 case MTP_OPERATION_SEND_PARTIAL_OBJECT:
415 response = doSendPartialObject();
416 break;
417 case MTP_OPERATION_TRUNCATE_OBJECT:
418 response = doTruncateObject();
419 break;
420 case MTP_OPERATION_BEGIN_EDIT_OBJECT:
421 response = doBeginEditObject();
422 break;
423 case MTP_OPERATION_END_EDIT_OBJECT:
424 response = doEndEditObject();
425 break;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400426 default:
Marco Nelissendcd89ec2014-06-24 10:49:08 -0700427 ALOGE("got unsupported command %s (%x)",
428 MtpDebug::getOperationCodeName(operation), operation);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400429 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
430 break;
431 }
432
Mike Lockwood916076c2010-06-04 09:49:21 -0400433 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
434 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400435 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400436 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400437}
438
439MtpResponseCode MtpServer::doGetDeviceInfo() {
440 MtpStringBuffer string;
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700441 char prop_value[PROPERTY_VALUE_MAX];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400442
Mike Lockwood782aef12010-08-10 07:37:50 -0400443 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
444 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
445 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
446
Mike Lockwood16864ba2010-05-11 17:16:59 -0400447 // fill in device info
448 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400449 if (mPtp) {
450 mData.putUInt32(0);
451 } else {
452 // MTP Vendor Extension ID
453 mData.putUInt32(6);
454 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400455 mData.putUInt16(MTP_STANDARD_VERSION);
Mike Lockwood3d1d7762011-06-21 08:27:06 -0400456 if (mPtp) {
457 // no extensions
458 string.set("");
459 } else {
460 // MTP extensions
461 string.set("microsoft.com: 1.0; android.com: 1.0;");
462 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400463 mData.putString(string); // MTP Extensions
464 mData.putUInt16(0); //Functional Mode
465 mData.putAUInt16(kSupportedOperationCodes,
466 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwood873871f2010-07-12 18:54:16 -0400467 mData.putAUInt16(kSupportedEventCodes,
468 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood782aef12010-08-10 07:37:50 -0400469 mData.putAUInt16(deviceProperties); // Device Properties Supported
470 mData.putAUInt16(captureFormats); // Capture Formats
471 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood8d08c5a2011-01-31 16:44:44 -0500472
473 property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
474 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400475 mData.putString(string); // Manufacturer
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700476
477 property_get("ro.product.model", prop_value, "MTP Device");
478 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400479 mData.putString(string); // Model
480 string.set("1.0");
481 mData.putString(string); // Device Version
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700482
483 property_get("ro.serialno", prop_value, "????????");
484 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400485 mData.putString(string); // Serial Number
486
Mike Lockwood782aef12010-08-10 07:37:50 -0400487 delete playbackFormats;
488 delete captureFormats;
489 delete deviceProperties;
490
Mike Lockwood16864ba2010-05-11 17:16:59 -0400491 return MTP_RESPONSE_OK;
492}
493
494MtpResponseCode MtpServer::doOpenSession() {
495 if (mSessionOpen) {
496 mResponse.setParameter(1, mSessionID);
497 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
498 }
Mike Lockwoodab063842014-11-12 14:20:06 -0800499 if (mRequest.getParameterCount() < 1)
500 return MTP_RESPONSE_INVALID_PARAMETER;
501
Mike Lockwood16864ba2010-05-11 17:16:59 -0400502 mSessionID = mRequest.getParameter(1);
503 mSessionOpen = true;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400504
505 mDatabase->sessionStarted();
506
Mike Lockwood16864ba2010-05-11 17:16:59 -0400507 return MTP_RESPONSE_OK;
508}
509
510MtpResponseCode MtpServer::doCloseSession() {
511 if (!mSessionOpen)
512 return MTP_RESPONSE_SESSION_NOT_OPEN;
513 mSessionID = 0;
514 mSessionOpen = false;
Mike Lockwood6b3a9d12010-08-31 16:25:12 -0400515 mDatabase->sessionEnded();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400516 return MTP_RESPONSE_OK;
517}
518
519MtpResponseCode MtpServer::doGetStorageIDs() {
520 if (!mSessionOpen)
521 return MTP_RESPONSE_SESSION_NOT_OPEN;
522
523 int count = mStorages.size();
524 mData.putUInt32(count);
525 for (int i = 0; i < count; i++)
526 mData.putUInt32(mStorages[i]->getStorageID());
527
528 return MTP_RESPONSE_OK;
529}
530
531MtpResponseCode MtpServer::doGetStorageInfo() {
532 MtpStringBuffer string;
533
534 if (!mSessionOpen)
535 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800536 if (mRequest.getParameterCount() < 1)
537 return MTP_RESPONSE_INVALID_PARAMETER;
538
Mike Lockwood16864ba2010-05-11 17:16:59 -0400539 MtpStorageID id = mRequest.getParameter(1);
540 MtpStorage* storage = getStorage(id);
541 if (!storage)
542 return MTP_RESPONSE_INVALID_STORAGE_ID;
543
544 mData.putUInt16(storage->getType());
545 mData.putUInt16(storage->getFileSystemType());
546 mData.putUInt16(storage->getAccessCapability());
547 mData.putUInt64(storage->getMaxCapacity());
548 mData.putUInt64(storage->getFreeSpace());
549 mData.putUInt32(1024*1024*1024); // Free Space in Objects
550 string.set(storage->getDescription());
551 mData.putString(string);
552 mData.putEmptyString(); // Volume Identifier
553
554 return MTP_RESPONSE_OK;
555}
556
557MtpResponseCode MtpServer::doGetObjectPropsSupported() {
558 if (!mSessionOpen)
559 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800560 if (mRequest.getParameterCount() < 1)
561 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400562 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood2e09e282010-12-07 10:51:20 -0800563 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood782aef12010-08-10 07:37:50 -0400564 mData.putAUInt16(properties);
Mike Lockwoodbf9b2052010-08-10 15:11:32 -0400565 delete properties;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400566 return MTP_RESPONSE_OK;
567}
568
569MtpResponseCode MtpServer::doGetObjectHandles() {
570 if (!mSessionOpen)
571 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800572 if (mRequest.getParameterCount() < 3)
573 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400574 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400575 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400576 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400577 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500578
579 if (!hasStorage(storageID))
580 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400581
582 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
583 mData.putAUInt32(handles);
584 delete handles;
585 return MTP_RESPONSE_OK;
586}
587
Mike Lockwood343af4e2010-08-02 10:52:20 -0400588MtpResponseCode MtpServer::doGetNumObjects() {
589 if (!mSessionOpen)
590 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwoodab063842014-11-12 14:20:06 -0800591 if (mRequest.getParameterCount() < 3)
592 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400593 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
594 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
595 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
Mike Lockwooddc3185e2011-06-17 13:44:24 -0400596 // 0x00000000 for all objects
Mike Lockwooda8494402011-02-18 09:07:14 -0500597 if (!hasStorage(storageID))
598 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood343af4e2010-08-02 10:52:20 -0400599
600 int count = mDatabase->getNumObjects(storageID, format, parent);
601 if (count >= 0) {
602 mResponse.setParameter(1, count);
603 return MTP_RESPONSE_OK;
604 } else {
605 mResponse.setParameter(1, 0);
606 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
607 }
608}
609
Mike Lockwood438344f2010-08-03 15:30:09 -0400610MtpResponseCode MtpServer::doGetObjectReferences() {
611 if (!mSessionOpen)
612 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500613 if (!hasStorage())
614 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800615 if (mRequest.getParameterCount() < 1)
616 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwooda8494402011-02-18 09:07:14 -0500617 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400618
619 // FIXME - check for invalid object handle
Mike Lockwood438344f2010-08-03 15:30:09 -0400620 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400621 if (handles) {
622 mData.putAUInt32(handles);
623 delete handles;
624 } else {
Mike Lockwood438344f2010-08-03 15:30:09 -0400625 mData.putEmptyArray();
Mike Lockwood438344f2010-08-03 15:30:09 -0400626 }
Mike Lockwood438344f2010-08-03 15:30:09 -0400627 return MTP_RESPONSE_OK;
628}
629
630MtpResponseCode MtpServer::doSetObjectReferences() {
631 if (!mSessionOpen)
632 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwooda8494402011-02-18 09:07:14 -0500633 if (!hasStorage())
634 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800635 if (mRequest.getParameterCount() < 1)
636 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400637 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwooda8494402011-02-18 09:07:14 -0500638
Mike Lockwood438344f2010-08-03 15:30:09 -0400639 MtpObjectHandleList* references = mData.getAUInt32();
Mike Lockwoodab063842014-11-12 14:20:06 -0800640 if (!references)
641 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood438344f2010-08-03 15:30:09 -0400642 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
643 delete references;
644 return result;
645}
646
Mike Lockwood16864ba2010-05-11 17:16:59 -0400647MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500648 if (!hasStorage())
649 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800650 if (mRequest.getParameterCount() < 2)
651 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400652 MtpObjectHandle handle = mRequest.getParameter(1);
653 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100654 ALOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400655 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400656
Mike Lockwood8277cec2010-08-10 15:20:35 -0400657 return mDatabase->getObjectPropertyValue(handle, property, mData);
658}
659
660MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500661 if (!hasStorage())
662 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800663 if (mRequest.getParameterCount() < 2)
664 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400665 MtpObjectHandle handle = mRequest.getParameter(1);
666 MtpObjectProperty property = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +0100667 ALOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood8277cec2010-08-10 15:20:35 -0400668 MtpDebug::getObjectPropCodeName(property));
669
670 return mDatabase->setObjectPropertyValue(handle, property, mData);
671}
672
673MtpResponseCode MtpServer::doGetDevicePropValue() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800674 if (mRequest.getParameterCount() < 1)
675 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -0400676 MtpDeviceProperty property = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +0100677 ALOGV("GetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400678 MtpDebug::getDevicePropCodeName(property));
679
680 return mDatabase->getDevicePropertyValue(property, mData);
681}
682
683MtpResponseCode MtpServer::doSetDevicePropValue() {
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("SetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400688 MtpDebug::getDevicePropCodeName(property));
689
690 return mDatabase->setDevicePropertyValue(property, mData);
691}
692
693MtpResponseCode MtpServer::doResetDevicePropValue() {
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("ResetDevicePropValue %s\n",
Mike Lockwood8277cec2010-08-10 15:20:35 -0400698 MtpDebug::getDevicePropCodeName(property));
699
700 return mDatabase->resetDeviceProperty(property);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400701}
702
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400703MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500704 if (!hasStorage())
705 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800706 if (mRequest.getParameterCount() < 5)
707 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400708
709 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood40ce1f22010-12-01 18:46:23 -0500710 // use uint32_t so we can support 0xFFFFFFFF
711 uint32_t format = mRequest.getParameter(2);
712 uint32_t property = mRequest.getParameter(3);
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400713 int groupCode = mRequest.getParameter(4);
Mike Lockwoodf05ff072010-11-23 18:45:25 -0500714 int depth = mRequest.getParameter(5);
Steve Block3856b092011-10-20 11:56:00 +0100715 ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoodb6da06e2010-10-14 18:03:25 -0400716 handle, MtpDebug::getFormatCodeName(format),
717 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
718
719 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
720}
721
Mike Lockwood16864ba2010-05-11 17:16:59 -0400722MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500723 if (!hasStorage())
724 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800725 if (mRequest.getParameterCount() < 1)
726 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400727 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700728 MtpObjectInfo info(handle);
729 MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
730 if (result == MTP_RESPONSE_OK) {
731 char date[20];
732
733 mData.putUInt32(info.mStorageID);
734 mData.putUInt16(info.mFormat);
735 mData.putUInt16(info.mProtectionStatus);
736
737 // if object is being edited the database size may be out of date
738 uint32_t size = info.mCompressedSize;
739 ObjectEdit* edit = getEditObject(handle);
740 if (edit)
Mike Lockwoodc3f16e52011-04-25 12:56:21 -0700741 size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700742 mData.putUInt32(size);
743
744 mData.putUInt16(info.mThumbFormat);
745 mData.putUInt32(info.mThumbCompressedSize);
746 mData.putUInt32(info.mThumbPixWidth);
747 mData.putUInt32(info.mThumbPixHeight);
748 mData.putUInt32(info.mImagePixWidth);
749 mData.putUInt32(info.mImagePixHeight);
750 mData.putUInt32(info.mImagePixDepth);
751 mData.putUInt32(info.mParent);
752 mData.putUInt16(info.mAssociationType);
753 mData.putUInt32(info.mAssociationDesc);
754 mData.putUInt32(info.mSequenceNumber);
755 mData.putString(info.mName);
Mike Lockwoodec24fa42013-04-01 10:51:35 -0700756 formatDateTime(info.mDateCreated, date, sizeof(date));
757 mData.putString(date); // date created
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700758 formatDateTime(info.mDateModified, date, sizeof(date));
759 mData.putString(date); // date modified
760 mData.putEmptyString(); // keywords
761 }
762 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400763}
764
765MtpResponseCode MtpServer::doGetObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500766 if (!hasStorage())
767 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -0800768 if (mRequest.getParameterCount() < 1)
769 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400770 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400771 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400772 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800773 MtpObjectFormat format;
774 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400775 if (result != MTP_RESPONSE_OK)
776 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400777
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400778 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400779 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400780 mfr.fd = open(filePath, O_RDONLY);
781 if (mfr.fd < 0) {
782 return MTP_RESPONSE_GENERAL_ERROR;
783 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400784 mfr.offset = 0;
785 mfr.length = fileLength;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400786 mfr.command = mRequest.getOperationCode();
787 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400788
789 // then transfer the file
Mike Lockwoodef441d92011-07-14 21:00:02 -0400790 int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
tao.pei07a9e542015-07-17 17:18:41 +0800791 if (ret < 0) {
792 if (errno == ECANCELED) {
793 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
794 } else {
795 result = MTP_RESPONSE_GENERAL_ERROR;
796 }
797 } else {
798 result = MTP_RESPONSE_OK;
799 }
800
Steve Block3856b092011-10-20 11:56:00 +0100801 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400802 close(mfr.fd);
tao.pei07a9e542015-07-17 17:18:41 +0800803 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400804}
805
Mike Lockwood64000782011-04-24 18:40:17 -0700806MtpResponseCode MtpServer::doGetThumb() {
Mike Lockwoodab063842014-11-12 14:20:06 -0800807 if (mRequest.getParameterCount() < 1)
808 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood64000782011-04-24 18:40:17 -0700809 MtpObjectHandle handle = mRequest.getParameter(1);
810 size_t thumbSize;
811 void* thumb = mDatabase->getThumbnail(handle, thumbSize);
812 if (thumb) {
813 // send data
814 mData.setOperationCode(mRequest.getOperationCode());
815 mData.setTransactionID(mRequest.getTransactionID());
816 mData.writeData(mFD, thumb, thumbSize);
817 free(thumb);
818 return MTP_RESPONSE_OK;
819 } else {
820 return MTP_RESPONSE_GENERAL_ERROR;
821 }
822}
823
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700824MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
Mike Lockwooda8494402011-02-18 09:07:14 -0500825 if (!hasStorage())
826 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500827 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700828 uint64_t offset;
829 uint32_t length;
830 offset = mRequest.getParameter(2);
831 if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800832 // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
833 if (mRequest.getParameterCount() < 4)
834 return MTP_RESPONSE_INVALID_PARAMETER;
835
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700836 // android extension with 64 bit offset
837 uint64_t offset2 = mRequest.getParameter(3);
838 offset = offset | (offset2 << 32);
839 length = mRequest.getParameter(4);
840 } else {
Mike Lockwoode48cf5b2014-12-17 12:22:36 -0800841 // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
842 if (mRequest.getParameterCount() < 3)
843 return MTP_RESPONSE_INVALID_PARAMETER;
844
Mike Lockwood7d77dcf2011-04-21 17:05:55 -0700845 // standard GetPartialObject
846 length = mRequest.getParameter(3);
847 }
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500848 MtpString pathBuf;
849 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800850 MtpObjectFormat format;
851 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500852 if (result != MTP_RESPONSE_OK)
853 return result;
Mark Salyzynd239cb62014-06-18 16:32:27 -0700854 if (offset + length > (uint64_t)fileLength)
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500855 length = fileLength - offset;
856
857 const char* filePath = (const char *)pathBuf;
858 mtp_file_range mfr;
859 mfr.fd = open(filePath, O_RDONLY);
860 if (mfr.fd < 0) {
861 return MTP_RESPONSE_GENERAL_ERROR;
862 }
863 mfr.offset = offset;
864 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400865 mfr.command = mRequest.getOperationCode();
866 mfr.transaction_id = mRequest.getTransactionID();
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500867 mResponse.setParameter(1, length);
868
Mike Lockwoodef441d92011-07-14 21:00:02 -0400869 // transfer the file
870 int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
Steve Block3856b092011-10-20 11:56:00 +0100871 ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
tao.pei07a9e542015-07-17 17:18:41 +0800872 result = MTP_RESPONSE_OK;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500873 if (ret < 0) {
874 if (errno == ECANCELED)
tao.pei07a9e542015-07-17 17:18:41 +0800875 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500876 else
tao.pei07a9e542015-07-17 17:18:41 +0800877 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500878 }
tao.pei07a9e542015-07-17 17:18:41 +0800879 close(mfr.fd);
880 return result;
Mike Lockwoodd81ce3c2010-11-23 09:08:01 -0500881}
882
Mike Lockwood16864ba2010-05-11 17:16:59 -0400883MtpResponseCode MtpServer::doSendObjectInfo() {
884 MtpString path;
Mike Lockwoodab063842014-11-12 14:20:06 -0800885 uint16_t temp16;
886 uint32_t temp32;
887
888 if (mRequest.getParameterCount() < 2)
889 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400890 MtpStorageID storageID = mRequest.getParameter(1);
891 MtpStorage* storage = getStorage(storageID);
892 MtpObjectHandle parent = mRequest.getParameter(2);
893 if (!storage)
894 return MTP_RESPONSE_INVALID_STORAGE_ID;
895
896 // special case the root
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400897 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400898 path = storage->getPath();
Mike Lockwood1865a5d2010-07-03 00:44:05 -0400899 parent = 0;
900 } else {
Mike Lockwoodfd346262010-12-08 16:08:01 -0800901 int64_t length;
902 MtpObjectFormat format;
903 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -0400904 if (result != MTP_RESPONSE_OK)
905 return result;
Mike Lockwoodfd346262010-12-08 16:08:01 -0800906 if (format != MTP_FORMAT_ASSOCIATION)
907 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400908 }
909
910 // read only the fields we need
Mike Lockwoodab063842014-11-12 14:20:06 -0800911 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
912 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
913 MtpObjectFormat format = temp16;
914 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
915 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
916 mSendObjectFileSize = temp32;
917 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
918 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
919 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
920 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
921 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
922 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
923 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
924 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
925 if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800926 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwoodab063842014-11-12 14:20:06 -0800927 if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
Mike Lockwood16864ba2010-05-11 17:16:59 -0400928 MtpStringBuffer name, created, modified;
Mike Lockwoodab063842014-11-12 14:20:06 -0800929 if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
930 if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
931 if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
Mike Lockwood16864ba2010-05-11 17:16:59 -0400932 // keywords follow
933
Steve Block3856b092011-10-20 11:56:00 +0100934 ALOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400935 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400936 if (!parseDateTime(modified, modifiedTime))
937 modifiedTime = 0;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400938
939 if (path[path.size() - 1] != '/')
940 path += "/";
941 path += (const char *)name;
942
Mike Lockwood20c3be02010-12-12 12:17:43 -0800943 // check space first
944 if (mSendObjectFileSize > storage->getFreeSpace())
945 return MTP_RESPONSE_STORAGE_FULL;
Mike Lockwood9b88b722011-07-11 09:18:03 -0400946 uint64_t maxFileSize = storage->getMaxFileSize();
947 // check storage max file size
948 if (maxFileSize != 0) {
949 // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
950 // is >= 0xFFFFFFFF
951 if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
952 return MTP_RESPONSE_OBJECT_TOO_LARGE;
953 }
Mike Lockwood20c3be02010-12-12 12:17:43 -0800954
Steve Blockb8a80522011-12-20 16:23:08 +0000955 ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Mike Lockwood4714b072010-07-12 08:49:01 -0400956 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
957 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodfceef462010-05-14 15:35:17 -0400958 if (handle == kInvalidObjectHandle) {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400959 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400960 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400961
962 if (format == MTP_FORMAT_ASSOCIATION) {
963 mode_t mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400964 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400965 umask(mask);
966 if (ret && ret != -EEXIST)
967 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood8e2a2802010-07-02 15:15:07 -0400968 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwoodaa952402011-01-18 11:06:19 -0800969
970 // SendObject does not get sent for directories, so call endSendObject here instead
971 mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400972 } else {
973 mSendObjectFilePath = path;
974 // save the handle for the SendObject call, which should follow
975 mSendObjectHandle = handle;
Mike Lockwood4714b072010-07-12 08:49:01 -0400976 mSendObjectFormat = format;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400977 }
978
979 mResponse.setParameter(1, storageID);
Mike Lockwood8277cec2010-08-10 15:20:35 -0400980 mResponse.setParameter(2, parent);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400981 mResponse.setParameter(3, handle);
982
983 return MTP_RESPONSE_OK;
984}
985
986MtpResponseCode MtpServer::doSendObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -0500987 if (!hasStorage())
988 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood4714b072010-07-12 08:49:01 -0400989 MtpResponseCode result = MTP_RESPONSE_OK;
990 mode_t mask;
Mike Lockwoodef441d92011-07-14 21:00:02 -0400991 int ret, initialData;
tao.pei07a9e542015-07-17 17:18:41 +0800992 bool isCanceled = false;
Mike Lockwood4714b072010-07-12 08:49:01 -0400993
Mike Lockwood16864ba2010-05-11 17:16:59 -0400994 if (mSendObjectHandle == kInvalidObjectHandle) {
Steve Block29357bc2012-01-06 19:20:56 +0000995 ALOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood4714b072010-07-12 08:49:01 -0400996 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
997 goto done;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400998 }
999
Mike Lockwoodef441d92011-07-14 21:00:02 -04001000 // read the header, and possibly some data
1001 ret = mData.read(mFD);
1002 if (ret < MTP_CONTAINER_HEADER_SIZE) {
1003 result = MTP_RESPONSE_GENERAL_ERROR;
1004 goto done;
1005 }
1006 initialData = ret - MTP_CONTAINER_HEADER_SIZE;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001007
1008 mtp_file_range mfr;
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -07001009 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodc6588762010-06-22 15:03:53 -04001010 if (mfr.fd < 0) {
Mike Lockwood4714b072010-07-12 08:49:01 -04001011 result = MTP_RESPONSE_GENERAL_ERROR;
1012 goto done;
Mike Lockwoodc6588762010-06-22 15:03:53 -04001013 }
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001014 fchown(mfr.fd, getuid(), mFileGroup);
1015 // set permissions
Mike Lockwood4714b072010-07-12 08:49:01 -04001016 mask = umask(0);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001017 fchmod(mfr.fd, mFilePermission);
1018 umask(mask);
1019
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001020 if (initialData > 0) {
Mike Lockwoodef441d92011-07-14 21:00:02 -04001021 ret = write(mfr.fd, mData.getData(), initialData);
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001022 }
Mike Lockwood16864ba2010-05-11 17:16:59 -04001023
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001024 if (ret < 0) {
1025 ALOGE("failed to write initial data");
1026 result = MTP_RESPONSE_GENERAL_ERROR;
1027 } else {
1028 if (mSendObjectFileSize - initialData > 0) {
1029 mfr.offset = initialData;
1030 if (mSendObjectFileSize == 0xFFFFFFFF) {
1031 // tell driver to read until it receives a short packet
1032 mfr.length = 0xFFFFFFFF;
1033 } else {
1034 mfr.length = mSendObjectFileSize - initialData;
1035 }
1036
1037 ALOGV("receiving %s\n", (const char *)mSendObjectFilePath);
1038 // transfer the file
1039 ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
tao.pei07a9e542015-07-17 17:18:41 +08001040 if ((ret < 0) && (errno == ECANCELED)) {
1041 isCanceled = true;
1042 }
1043
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001044 ALOGV("MTP_RECEIVE_FILE returned %d\n", ret);
Mike Lockwood0cc79c62011-10-13 11:38:20 -04001045 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001046 }
Mike Lockwoodc6588762010-06-22 15:03:53 -04001047 close(mfr.fd);
Mike Lockwood8e2a2802010-07-02 15:15:07 -04001048
Mike Lockwood916076c2010-06-04 09:49:21 -04001049 if (ret < 0) {
1050 unlink(mSendObjectFilePath);
tao.pei07a9e542015-07-17 17:18:41 +08001051 if (isCanceled)
Mike Lockwood4714b072010-07-12 08:49:01 -04001052 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwood916076c2010-06-04 09:49:21 -04001053 else
Mike Lockwood4714b072010-07-12 08:49:01 -04001054 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwood916076c2010-06-04 09:49:21 -04001055 }
Mike Lockwood4714b072010-07-12 08:49:01 -04001056
1057done:
Mike Lockwoodef441d92011-07-14 21:00:02 -04001058 // reset so we don't attempt to send the data back
1059 mData.reset();
1060
Mike Lockwood4714b072010-07-12 08:49:01 -04001061 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
Mike Lockwoodaa952402011-01-18 11:06:19 -08001062 result == MTP_RESPONSE_OK);
Mike Lockwood4714b072010-07-12 08:49:01 -04001063 mSendObjectHandle = kInvalidObjectHandle;
1064 mSendObjectFormat = 0;
1065 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001066}
1067
Mike Lockwoodd3211492010-09-13 17:15:58 -04001068static void deleteRecursive(const char* path) {
1069 char pathbuf[PATH_MAX];
Mark Salyzynd239cb62014-06-18 16:32:27 -07001070 size_t pathLength = strlen(path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001071 if (pathLength >= sizeof(pathbuf) - 1) {
Steve Block29357bc2012-01-06 19:20:56 +00001072 ALOGE("path too long: %s\n", path);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001073 }
1074 strcpy(pathbuf, path);
1075 if (pathbuf[pathLength - 1] != '/') {
1076 pathbuf[pathLength++] = '/';
1077 }
1078 char* fileSpot = pathbuf + pathLength;
1079 int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1080
1081 DIR* dir = opendir(path);
1082 if (!dir) {
Steve Block29357bc2012-01-06 19:20:56 +00001083 ALOGE("opendir %s failed: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001084 return;
1085 }
1086
1087 struct dirent* entry;
1088 while ((entry = readdir(dir))) {
1089 const char* name = entry->d_name;
1090
1091 // ignore "." and ".."
1092 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1093 continue;
1094 }
1095
1096 int nameLength = strlen(name);
1097 if (nameLength > pathRemaining) {
Steve Block29357bc2012-01-06 19:20:56 +00001098 ALOGE("path %s/%s too long\n", path, name);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001099 continue;
1100 }
1101 strcpy(fileSpot, name);
1102
Mike Lockwoodd3211492010-09-13 17:15:58 -04001103 if (entry->d_type == DT_DIR) {
1104 deleteRecursive(pathbuf);
1105 rmdir(pathbuf);
1106 } else {
1107 unlink(pathbuf);
1108 }
1109 }
Mike Lockwood7ce05cf2010-11-11 11:22:32 -05001110 closedir(dir);
Mike Lockwoodd3211492010-09-13 17:15:58 -04001111}
1112
1113static void deletePath(const char* path) {
1114 struct stat statbuf;
1115 if (stat(path, &statbuf) == 0) {
1116 if (S_ISDIR(statbuf.st_mode)) {
1117 deleteRecursive(path);
1118 rmdir(path);
1119 } else {
1120 unlink(path);
1121 }
1122 } else {
Steve Block29357bc2012-01-06 19:20:56 +00001123 ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
Mike Lockwoodd3211492010-09-13 17:15:58 -04001124 }
1125}
1126
Mike Lockwood16864ba2010-05-11 17:16:59 -04001127MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwooda8494402011-02-18 09:07:14 -05001128 if (!hasStorage())
1129 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Marco Nelissenea9f2152015-01-23 10:55:25 -08001130 if (mRequest.getParameterCount() < 1)
Mike Lockwoodab063842014-11-12 14:20:06 -08001131 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001132 MtpObjectHandle handle = mRequest.getParameter(1);
Marco Nelissenea9f2152015-01-23 10:55:25 -08001133 MtpObjectFormat format;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001134 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1135 // FIXME - implement deleting objects by format
Mike Lockwood16864ba2010-05-11 17:16:59 -04001136
1137 MtpString filePath;
1138 int64_t fileLength;
Mike Lockwoodfd346262010-12-08 16:08:01 -08001139 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001140 if (result == MTP_RESPONSE_OK) {
Steve Block3856b092011-10-20 11:56:00 +01001141 ALOGV("deleting %s", (const char *)filePath);
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001142 result = mDatabase->deleteFile(handle);
1143 // Don't delete the actual files unless the database deletion is allowed
1144 if (result == MTP_RESPONSE_OK) {
1145 deletePath((const char *)filePath);
1146 }
Mike Lockwood9c04c4c2010-08-02 10:37:41 -04001147 }
Mike Lockwooda9a46c12011-12-01 16:58:41 -05001148
1149 return result;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001150}
1151
1152MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001153 if (mRequest.getParameterCount() < 2)
1154 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001155 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood16864ba2010-05-11 17:16:59 -04001156 MtpObjectFormat format = mRequest.getParameter(2);
Steve Block3856b092011-10-20 11:56:00 +01001157 ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood8277cec2010-08-10 15:20:35 -04001158 MtpDebug::getFormatCodeName(format));
1159 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001160 if (!property)
1161 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001162 property->write(mData);
Mike Lockwood8277cec2010-08-10 15:20:35 -04001163 delete property;
1164 return MTP_RESPONSE_OK;
1165}
1166
1167MtpResponseCode MtpServer::doGetDevicePropDesc() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001168 if (mRequest.getParameterCount() < 1)
1169 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood8277cec2010-08-10 15:20:35 -04001170 MtpDeviceProperty propCode = mRequest.getParameter(1);
Steve Block3856b092011-10-20 11:56:00 +01001171 ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood8277cec2010-08-10 15:20:35 -04001172 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1173 if (!property)
1174 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1175 property->write(mData);
1176 delete property;
Mike Lockwood21ef7d02010-06-30 17:00:35 -04001177 return MTP_RESPONSE_OK;
Mike Lockwood16864ba2010-05-11 17:16:59 -04001178}
Mike Lockwood7850ef92010-05-14 10:10:36 -04001179
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001180MtpResponseCode MtpServer::doSendPartialObject() {
1181 if (!hasStorage())
1182 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodab063842014-11-12 14:20:06 -08001183 if (mRequest.getParameterCount() < 4)
1184 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001185 MtpObjectHandle handle = mRequest.getParameter(1);
1186 uint64_t offset = mRequest.getParameter(2);
1187 uint64_t offset2 = mRequest.getParameter(3);
1188 offset = offset | (offset2 << 32);
1189 uint32_t length = mRequest.getParameter(4);
1190
1191 ObjectEdit* edit = getEditObject(handle);
1192 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001193 ALOGE("object not open for edit in doSendPartialObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001194 return MTP_RESPONSE_GENERAL_ERROR;
1195 }
1196
1197 // can't start writing past the end of the file
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001198 if (offset > edit->mSize) {
Mark Salyzynd239cb62014-06-18 16:32:27 -07001199 ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1200 offset, edit->mSize);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001201 return MTP_RESPONSE_GENERAL_ERROR;
1202 }
1203
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001204 const char* filePath = (const char *)edit->mPath;
Mark Salyzynd239cb62014-06-18 16:32:27 -07001205 ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001206
Mike Lockwoodef441d92011-07-14 21:00:02 -04001207 // read the header, and possibly some data
1208 int ret = mData.read(mFD);
1209 if (ret < MTP_CONTAINER_HEADER_SIZE)
1210 return MTP_RESPONSE_GENERAL_ERROR;
1211 int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1212
1213 if (initialData > 0) {
Mike Lockwoood0a694952013-02-08 13:25:01 -08001214 ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
Mike Lockwoodef441d92011-07-14 21:00:02 -04001215 offset += initialData;
1216 length -= initialData;
1217 }
1218
tao.pei07a9e542015-07-17 17:18:41 +08001219 bool isCanceled = false;
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001220 if (ret < 0) {
1221 ALOGE("failed to write initial data");
1222 } else {
1223 if (length > 0) {
1224 mtp_file_range mfr;
1225 mfr.fd = edit->mFD;
1226 mfr.offset = offset;
1227 mfr.length = length;
Mike Lockwoodef441d92011-07-14 21:00:02 -04001228
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001229 // transfer the file
1230 ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
tao.pei07a9e542015-07-17 17:18:41 +08001231 if ((ret < 0) && (errno == ECANCELED)) {
1232 isCanceled = true;
1233 }
Marco Nelissendcd89ec2014-06-24 10:49:08 -07001234 ALOGV("MTP_RECEIVE_FILE returned %d", ret);
1235 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001236 }
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001237 if (ret < 0) {
1238 mResponse.setParameter(1, 0);
tao.pei07a9e542015-07-17 17:18:41 +08001239 if (isCanceled)
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001240 return MTP_RESPONSE_TRANSACTION_CANCELLED;
1241 else
1242 return MTP_RESPONSE_GENERAL_ERROR;
1243 }
Mike Lockwoodef441d92011-07-14 21:00:02 -04001244
1245 // reset so we don't attempt to send this back
1246 mData.reset();
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001247 mResponse.setParameter(1, length);
1248 uint64_t end = offset + length;
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001249 if (end > edit->mSize) {
1250 edit->mSize = end;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001251 }
1252 return MTP_RESPONSE_OK;
1253}
1254
1255MtpResponseCode MtpServer::doTruncateObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001256 if (mRequest.getParameterCount() < 3)
1257 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001258 MtpObjectHandle handle = mRequest.getParameter(1);
1259 ObjectEdit* edit = getEditObject(handle);
1260 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001261 ALOGE("object not open for edit in doTruncateObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001262 return MTP_RESPONSE_GENERAL_ERROR;
1263 }
1264
1265 uint64_t offset = mRequest.getParameter(2);
1266 uint64_t offset2 = mRequest.getParameter(3);
1267 offset |= (offset2 << 32);
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001268 if (ftruncate(edit->mFD, offset) != 0) {
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001269 return MTP_RESPONSE_GENERAL_ERROR;
1270 } else {
Mike Lockwoodc3f16e52011-04-25 12:56:21 -07001271 edit->mSize = offset;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001272 return MTP_RESPONSE_OK;
1273 }
1274}
1275
1276MtpResponseCode MtpServer::doBeginEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001277 if (mRequest.getParameterCount() < 1)
1278 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001279 MtpObjectHandle handle = mRequest.getParameter(1);
1280 if (getEditObject(handle)) {
Steve Block29357bc2012-01-06 19:20:56 +00001281 ALOGE("object already open for edit in doBeginEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001282 return MTP_RESPONSE_GENERAL_ERROR;
1283 }
1284
1285 MtpString path;
1286 int64_t fileLength;
1287 MtpObjectFormat format;
1288 int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1289 if (result != MTP_RESPONSE_OK)
1290 return result;
1291
1292 int fd = open((const char *)path, O_RDWR | O_EXCL);
1293 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001294 ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001295 return MTP_RESPONSE_GENERAL_ERROR;
1296 }
1297
1298 addEditObject(handle, path, fileLength, format, fd);
1299 return MTP_RESPONSE_OK;
1300}
1301
1302MtpResponseCode MtpServer::doEndEditObject() {
Mike Lockwoodab063842014-11-12 14:20:06 -08001303 if (mRequest.getParameterCount() < 1)
1304 return MTP_RESPONSE_INVALID_PARAMETER;
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001305 MtpObjectHandle handle = mRequest.getParameter(1);
1306 ObjectEdit* edit = getEditObject(handle);
1307 if (!edit) {
Steve Block29357bc2012-01-06 19:20:56 +00001308 ALOGE("object not open for edit in doEndEditObject");
Mike Lockwood7d77dcf2011-04-21 17:05:55 -07001309 return MTP_RESPONSE_GENERAL_ERROR;
1310 }
1311
1312 commitEdit(edit);
1313 removeEditObject(handle);
1314 return MTP_RESPONSE_OK;
1315}
1316
Mike Lockwood7850ef92010-05-14 10:10:36 -04001317} // namespace android