1 /*
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 <android-base/properties.h>
18 #include <chrono>
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/stat.h>
28 
29 #define LOG_TAG "MtpServer"
30 
31 #include "MtpDebug.h"
32 #include "MtpDatabase.h"
33 #include "MtpObjectInfo.h"
34 #include "MtpProperty.h"
35 #include "MtpServer.h"
36 #include "MtpStorage.h"
37 #include "MtpStringBuffer.h"
38 
39 namespace android {
40 
41 static const MtpOperationCode kSupportedOperationCodes[] = {
42     MTP_OPERATION_GET_DEVICE_INFO,
43     MTP_OPERATION_OPEN_SESSION,
44     MTP_OPERATION_CLOSE_SESSION,
45     MTP_OPERATION_GET_STORAGE_IDS,
46     MTP_OPERATION_GET_STORAGE_INFO,
47     MTP_OPERATION_GET_NUM_OBJECTS,
48     MTP_OPERATION_GET_OBJECT_HANDLES,
49     MTP_OPERATION_GET_OBJECT_INFO,
50     MTP_OPERATION_GET_OBJECT,
51     MTP_OPERATION_GET_THUMB,
52     MTP_OPERATION_DELETE_OBJECT,
53     MTP_OPERATION_SEND_OBJECT_INFO,
54     MTP_OPERATION_SEND_OBJECT,
55 //    MTP_OPERATION_INITIATE_CAPTURE,
56 //    MTP_OPERATION_FORMAT_STORE,
57     MTP_OPERATION_RESET_DEVICE,
58 //    MTP_OPERATION_SELF_TEST,
59 //    MTP_OPERATION_SET_OBJECT_PROTECTION,
60 //    MTP_OPERATION_POWER_DOWN,
61     MTP_OPERATION_GET_DEVICE_PROP_DESC,
62     MTP_OPERATION_GET_DEVICE_PROP_VALUE,
63     MTP_OPERATION_SET_DEVICE_PROP_VALUE,
64     MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
65 //    MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
66 //    MTP_OPERATION_MOVE_OBJECT,
67 //    MTP_OPERATION_COPY_OBJECT,
68     MTP_OPERATION_GET_PARTIAL_OBJECT,
69 //    MTP_OPERATION_INITIATE_OPEN_CAPTURE,
70     MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
71     MTP_OPERATION_GET_OBJECT_PROP_DESC,
72     MTP_OPERATION_GET_OBJECT_PROP_VALUE,
73     MTP_OPERATION_SET_OBJECT_PROP_VALUE,
74     MTP_OPERATION_GET_OBJECT_PROP_LIST,
75 //    MTP_OPERATION_SET_OBJECT_PROP_LIST,
76 //    MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
77 //    MTP_OPERATION_SEND_OBJECT_PROP_LIST,
78     MTP_OPERATION_GET_OBJECT_REFERENCES,
79     MTP_OPERATION_SET_OBJECT_REFERENCES,
80 //    MTP_OPERATION_SKIP,
81     // Android extension for direct file IO
82     MTP_OPERATION_GET_PARTIAL_OBJECT_64,
83     MTP_OPERATION_SEND_PARTIAL_OBJECT,
84     MTP_OPERATION_TRUNCATE_OBJECT,
85     MTP_OPERATION_BEGIN_EDIT_OBJECT,
86     MTP_OPERATION_END_EDIT_OBJECT,
87 };
88 
89 static const MtpEventCode kSupportedEventCodes[] = {
90     MTP_EVENT_OBJECT_ADDED,
91     MTP_EVENT_OBJECT_REMOVED,
92     MTP_EVENT_STORE_ADDED,
93     MTP_EVENT_STORE_REMOVED,
94     MTP_EVENT_DEVICE_PROP_CHANGED,
95 };
96 
MtpServer(MtpDatabase * database,bool ptp,int fileGroup,int filePerm,int directoryPerm,const MtpString & deviceInfoManufacturer,const MtpString & deviceInfoModel,const MtpString & deviceInfoDeviceVersion,const MtpString & deviceInfoSerialNumber)97 MtpServer::MtpServer(MtpDatabase* database, bool ptp,
98                     int fileGroup, int filePerm, int directoryPerm,
99                     const MtpString& deviceInfoManufacturer,
100                     const MtpString& deviceInfoModel,
101                     const MtpString& deviceInfoDeviceVersion,
102                     const MtpString& deviceInfoSerialNumber)
103     :   mDatabase(database),
104         mPtp(ptp),
105         mFileGroup(fileGroup),
106         mFilePermission(filePerm),
107         mDirectoryPermission(directoryPerm),
108         mDeviceInfoManufacturer(deviceInfoManufacturer),
109         mDeviceInfoModel(deviceInfoModel),
110         mDeviceInfoDeviceVersion(deviceInfoDeviceVersion),
111         mDeviceInfoSerialNumber(deviceInfoSerialNumber),
112         mSessionID(0),
113         mSessionOpen(false),
114         mSendObjectHandle(kInvalidObjectHandle),
115         mSendObjectFormat(0),
116         mSendObjectFileSize(0)
117 {
118 }
119 
~MtpServer()120 MtpServer::~MtpServer() {
121 }
122 
123 IMtpHandle* MtpServer::sHandle = nullptr;
124 
configure(bool usePtp)125 int MtpServer::configure(bool usePtp) {
126     if (sHandle == nullptr) {
127         bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
128         sHandle = ffs_ok ? get_ffs_handle() : get_mtp_handle();
129     }
130 
131     int ret = sHandle->configure(usePtp);
132     if (ret) ALOGE("Failed to configure MTP driver!");
133     else android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
134 
135     return ret;
136 }
137 
addStorage(MtpStorage * storage)138 void MtpServer::addStorage(MtpStorage* storage) {
139     Mutex::Autolock autoLock(mMutex);
140 
141     mStorages.push(storage);
142     sendStoreAdded(storage->getStorageID());
143 }
144 
removeStorage(MtpStorage * storage)145 void MtpServer::removeStorage(MtpStorage* storage) {
146     Mutex::Autolock autoLock(mMutex);
147 
148     for (size_t i = 0; i < mStorages.size(); i++) {
149         if (mStorages[i] == storage) {
150             mStorages.removeAt(i);
151             sendStoreRemoved(storage->getStorageID());
152             break;
153         }
154     }
155 }
156 
getStorage(MtpStorageID id)157 MtpStorage* MtpServer::getStorage(MtpStorageID id) {
158     if (id == 0)
159         return mStorages[0];
160     for (size_t i = 0; i < mStorages.size(); i++) {
161         MtpStorage* storage = mStorages[i];
162         if (storage->getStorageID() == id)
163             return storage;
164     }
165     return nullptr;
166 }
167 
hasStorage(MtpStorageID id)168 bool MtpServer::hasStorage(MtpStorageID id) {
169     if (id == 0 || id == 0xFFFFFFFF)
170         return mStorages.size() > 0;
171     return (getStorage(id) != nullptr);
172 }
173 
run()174 void MtpServer::run() {
175     if (!sHandle) {
176         ALOGE("MtpServer was never configured!");
177         return;
178     }
179 
180     if (sHandle->start()) {
181         ALOGE("Failed to start usb driver!");
182         sHandle->close();
183         return;
184     }
185 
186     while (1) {
187         int ret = mRequest.read(sHandle);
188         if (ret < 0) {
189             ALOGE("request read returned %d, errno: %d", ret, errno);
190             if (errno == ECANCELED) {
191                 // return to top of loop and wait for next command
192                 continue;
193             }
194             break;
195         }
196         MtpOperationCode operation = mRequest.getOperationCode();
197         MtpTransactionID transaction = mRequest.getTransactionID();
198 
199         ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
200         // FIXME need to generalize this
201         bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
202                     || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
203                     || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
204                     || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
205         if (dataIn) {
206             int ret = mData.read(sHandle);
207             if (ret < 0) {
208                 ALOGE("data read returned %d, errno: %d", ret, errno);
209                 if (errno == ECANCELED) {
210                     // return to top of loop and wait for next command
211                     continue;
212                 }
213                 break;
214             }
215             ALOGV("received data:");
216         } else {
217             mData.reset();
218         }
219 
220         if (handleRequest()) {
221             if (!dataIn && mData.hasData()) {
222                 mData.setOperationCode(operation);
223                 mData.setTransactionID(transaction);
224                 ALOGV("sending data:");
225                 ret = mData.write(sHandle);
226                 if (ret < 0) {
227                     ALOGE("request write returned %d, errno: %d", ret, errno);
228                     if (errno == ECANCELED) {
229                         // return to top of loop and wait for next command
230                         continue;
231                     }
232                     break;
233                 }
234             }
235 
236             mResponse.setTransactionID(transaction);
237             ALOGV("sending response %04X", mResponse.getResponseCode());
238             ret = mResponse.write(sHandle);
239             const int savedErrno = errno;
240             if (ret < 0) {
241                 ALOGE("request write returned %d, errno: %d", ret, errno);
242                 if (savedErrno == ECANCELED) {
243                     // return to top of loop and wait for next command
244                     continue;
245                 }
246                 break;
247             }
248         } else {
249             ALOGV("skipping response\n");
250         }
251     }
252 
253     // commit any open edits
254     int count = mObjectEditList.size();
255     for (int i = 0; i < count; i++) {
256         ObjectEdit* edit = mObjectEditList[i];
257         commitEdit(edit);
258         delete edit;
259     }
260     mObjectEditList.clear();
261 
262     if (mSessionOpen)
263         mDatabase->sessionEnded();
264 
265     sHandle->close();
266 }
267 
sendObjectAdded(MtpObjectHandle handle)268 void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
269     ALOGV("sendObjectAdded %d\n", handle);
270     sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
271 }
272 
sendObjectRemoved(MtpObjectHandle handle)273 void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
274     ALOGV("sendObjectRemoved %d\n", handle);
275     sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
276 }
277 
sendStoreAdded(MtpStorageID id)278 void MtpServer::sendStoreAdded(MtpStorageID id) {
279     ALOGV("sendStoreAdded %08X\n", id);
280     sendEvent(MTP_EVENT_STORE_ADDED, id);
281 }
282 
sendStoreRemoved(MtpStorageID id)283 void MtpServer::sendStoreRemoved(MtpStorageID id) {
284     ALOGV("sendStoreRemoved %08X\n", id);
285     sendEvent(MTP_EVENT_STORE_REMOVED, id);
286 }
287 
sendDevicePropertyChanged(MtpDeviceProperty property)288 void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
289     ALOGV("sendDevicePropertyChanged %d\n", property);
290     sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
291 }
292 
sendEvent(MtpEventCode code,uint32_t param1)293 void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
294     if (mSessionOpen) {
295         mEvent.setEventCode(code);
296         mEvent.setTransactionID(mRequest.getTransactionID());
297         mEvent.setParameter(1, param1);
298         if (mEvent.write(sHandle))
299             ALOGE("Mtp send event failed: %s", strerror(errno));
300     }
301 }
302 
addEditObject(MtpObjectHandle handle,MtpString & path,uint64_t size,MtpObjectFormat format,int fd)303 void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
304         uint64_t size, MtpObjectFormat format, int fd) {
305     ObjectEdit*  edit = new ObjectEdit(handle, path, size, format, fd);
306     mObjectEditList.add(edit);
307 }
308 
getEditObject(MtpObjectHandle handle)309 MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
310     int count = mObjectEditList.size();
311     for (int i = 0; i < count; i++) {
312         ObjectEdit* edit = mObjectEditList[i];
313         if (edit->mHandle == handle) return edit;
314     }
315     return nullptr;
316 }
317 
removeEditObject(MtpObjectHandle handle)318 void MtpServer::removeEditObject(MtpObjectHandle handle) {
319     int count = mObjectEditList.size();
320     for (int i = 0; i < count; i++) {
321         ObjectEdit* edit = mObjectEditList[i];
322         if (edit->mHandle == handle) {
323             delete edit;
324             mObjectEditList.removeAt(i);
325             return;
326         }
327     }
328     ALOGE("ObjectEdit not found in removeEditObject");
329 }
330 
commitEdit(ObjectEdit * edit)331 void MtpServer::commitEdit(ObjectEdit* edit) {
332     mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
333 }
334 
335 
handleRequest()336 bool MtpServer::handleRequest() {
337     Mutex::Autolock autoLock(mMutex);
338 
339     MtpOperationCode operation = mRequest.getOperationCode();
340     MtpResponseCode response;
341 
342     mResponse.reset();
343 
344     if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
345         // FIXME - need to delete mSendObjectHandle from the database
346         ALOGE("expected SendObject after SendObjectInfo");
347         mSendObjectHandle = kInvalidObjectHandle;
348     }
349 
350     int containertype = mRequest.getContainerType();
351     if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
352         ALOGE("wrong container type %d", containertype);
353         return false;
354     }
355 
356     ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
357 
358     switch (operation) {
359         case MTP_OPERATION_GET_DEVICE_INFO:
360             response = doGetDeviceInfo();
361             break;
362         case MTP_OPERATION_OPEN_SESSION:
363             response = doOpenSession();
364             break;
365         case MTP_OPERATION_RESET_DEVICE:
366         case MTP_OPERATION_CLOSE_SESSION:
367             response = doCloseSession();
368             break;
369         case MTP_OPERATION_GET_STORAGE_IDS:
370             response = doGetStorageIDs();
371             break;
372          case MTP_OPERATION_GET_STORAGE_INFO:
373             response = doGetStorageInfo();
374             break;
375         case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
376             response = doGetObjectPropsSupported();
377             break;
378         case MTP_OPERATION_GET_OBJECT_HANDLES:
379             response = doGetObjectHandles();
380             break;
381         case MTP_OPERATION_GET_NUM_OBJECTS:
382             response = doGetNumObjects();
383             break;
384         case MTP_OPERATION_GET_OBJECT_REFERENCES:
385             response = doGetObjectReferences();
386             break;
387         case MTP_OPERATION_SET_OBJECT_REFERENCES:
388             response = doSetObjectReferences();
389             break;
390         case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
391             response = doGetObjectPropValue();
392             break;
393         case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
394             response = doSetObjectPropValue();
395             break;
396         case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
397             response = doGetDevicePropValue();
398             break;
399         case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
400             response = doSetDevicePropValue();
401             break;
402         case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
403             response = doResetDevicePropValue();
404             break;
405         case MTP_OPERATION_GET_OBJECT_PROP_LIST:
406             response = doGetObjectPropList();
407             break;
408         case MTP_OPERATION_GET_OBJECT_INFO:
409             response = doGetObjectInfo();
410             break;
411         case MTP_OPERATION_GET_OBJECT:
412             response = doGetObject();
413             break;
414         case MTP_OPERATION_GET_THUMB:
415             response = doGetThumb();
416             break;
417         case MTP_OPERATION_GET_PARTIAL_OBJECT:
418         case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
419             response = doGetPartialObject(operation);
420             break;
421         case MTP_OPERATION_SEND_OBJECT_INFO:
422             response = doSendObjectInfo();
423             break;
424         case MTP_OPERATION_SEND_OBJECT:
425             response = doSendObject();
426             break;
427         case MTP_OPERATION_DELETE_OBJECT:
428             response = doDeleteObject();
429             break;
430         case MTP_OPERATION_GET_OBJECT_PROP_DESC:
431             response = doGetObjectPropDesc();
432             break;
433         case MTP_OPERATION_GET_DEVICE_PROP_DESC:
434             response = doGetDevicePropDesc();
435             break;
436         case MTP_OPERATION_SEND_PARTIAL_OBJECT:
437             response = doSendPartialObject();
438             break;
439         case MTP_OPERATION_TRUNCATE_OBJECT:
440             response = doTruncateObject();
441             break;
442         case MTP_OPERATION_BEGIN_EDIT_OBJECT:
443             response = doBeginEditObject();
444             break;
445         case MTP_OPERATION_END_EDIT_OBJECT:
446             response = doEndEditObject();
447             break;
448         default:
449             ALOGE("got unsupported command %s (%x)",
450                     MtpDebug::getOperationCodeName(operation), operation);
451             response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
452             break;
453     }
454 
455     if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
456         return false;
457     mResponse.setResponseCode(response);
458     return true;
459 }
460 
doGetDeviceInfo()461 MtpResponseCode MtpServer::doGetDeviceInfo() {
462     MtpStringBuffer   string;
463 
464     MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
465     MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
466     MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
467 
468     // fill in device info
469     mData.putUInt16(MTP_STANDARD_VERSION);
470     if (mPtp) {
471         mData.putUInt32(0);
472     } else {
473         // MTP Vendor Extension ID
474         mData.putUInt32(6);
475     }
476     mData.putUInt16(MTP_STANDARD_VERSION);
477     if (mPtp) {
478         // no extensions
479         string.set("");
480     } else {
481         // MTP extensions
482         string.set("microsoft.com: 1.0; android.com: 1.0;");
483     }
484     mData.putString(string); // MTP Extensions
485     mData.putUInt16(0); //Functional Mode
486     mData.putAUInt16(kSupportedOperationCodes,
487             sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
488     mData.putAUInt16(kSupportedEventCodes,
489             sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
490     mData.putAUInt16(deviceProperties); // Device Properties Supported
491     mData.putAUInt16(captureFormats); // Capture Formats
492     mData.putAUInt16(playbackFormats);  // Playback Formats
493 
494     mData.putString(mDeviceInfoManufacturer); // Manufacturer
495     mData.putString(mDeviceInfoModel); // Model
496     mData.putString(mDeviceInfoDeviceVersion); // Device Version
497     mData.putString(mDeviceInfoSerialNumber); // Serial Number
498 
499     delete playbackFormats;
500     delete captureFormats;
501     delete deviceProperties;
502 
503     return MTP_RESPONSE_OK;
504 }
505 
doOpenSession()506 MtpResponseCode MtpServer::doOpenSession() {
507     if (mSessionOpen) {
508         mResponse.setParameter(1, mSessionID);
509         return MTP_RESPONSE_SESSION_ALREADY_OPEN;
510     }
511     if (mRequest.getParameterCount() < 1)
512         return MTP_RESPONSE_INVALID_PARAMETER;
513 
514     mSessionID = mRequest.getParameter(1);
515     mSessionOpen = true;
516 
517     mDatabase->sessionStarted();
518 
519     return MTP_RESPONSE_OK;
520 }
521 
doCloseSession()522 MtpResponseCode MtpServer::doCloseSession() {
523     if (!mSessionOpen)
524         return MTP_RESPONSE_SESSION_NOT_OPEN;
525     mSessionID = 0;
526     mSessionOpen = false;
527     mDatabase->sessionEnded();
528     return MTP_RESPONSE_OK;
529 }
530 
doGetStorageIDs()531 MtpResponseCode MtpServer::doGetStorageIDs() {
532     if (!mSessionOpen)
533         return MTP_RESPONSE_SESSION_NOT_OPEN;
534 
535     int count = mStorages.size();
536     mData.putUInt32(count);
537     for (int i = 0; i < count; i++)
538         mData.putUInt32(mStorages[i]->getStorageID());
539 
540     return MTP_RESPONSE_OK;
541 }
542 
doGetStorageInfo()543 MtpResponseCode MtpServer::doGetStorageInfo() {
544     MtpStringBuffer   string;
545 
546     if (!mSessionOpen)
547         return MTP_RESPONSE_SESSION_NOT_OPEN;
548     if (mRequest.getParameterCount() < 1)
549         return MTP_RESPONSE_INVALID_PARAMETER;
550 
551     MtpStorageID id = mRequest.getParameter(1);
552     MtpStorage* storage = getStorage(id);
553     if (!storage)
554         return MTP_RESPONSE_INVALID_STORAGE_ID;
555 
556     mData.putUInt16(storage->getType());
557     mData.putUInt16(storage->getFileSystemType());
558     mData.putUInt16(storage->getAccessCapability());
559     mData.putUInt64(storage->getMaxCapacity());
560     mData.putUInt64(storage->getFreeSpace());
561     mData.putUInt32(1024*1024*1024); // Free Space in Objects
562     string.set(storage->getDescription());
563     mData.putString(string);
564     mData.putEmptyString();   // Volume Identifier
565 
566     return MTP_RESPONSE_OK;
567 }
568 
doGetObjectPropsSupported()569 MtpResponseCode MtpServer::doGetObjectPropsSupported() {
570     if (!mSessionOpen)
571         return MTP_RESPONSE_SESSION_NOT_OPEN;
572     if (mRequest.getParameterCount() < 1)
573         return MTP_RESPONSE_INVALID_PARAMETER;
574     MtpObjectFormat format = mRequest.getParameter(1);
575     MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
576     mData.putAUInt16(properties);
577     delete properties;
578     return MTP_RESPONSE_OK;
579 }
580 
doGetObjectHandles()581 MtpResponseCode MtpServer::doGetObjectHandles() {
582     if (!mSessionOpen)
583         return MTP_RESPONSE_SESSION_NOT_OPEN;
584     if (mRequest.getParameterCount() < 3)
585         return MTP_RESPONSE_INVALID_PARAMETER;
586     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
587     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
588     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
589                                                             // 0x00000000 for all objects
590 
591     if (!hasStorage(storageID))
592         return MTP_RESPONSE_INVALID_STORAGE_ID;
593 
594     MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
595     mData.putAUInt32(handles);
596     delete handles;
597     return MTP_RESPONSE_OK;
598 }
599 
doGetNumObjects()600 MtpResponseCode MtpServer::doGetNumObjects() {
601     if (!mSessionOpen)
602         return MTP_RESPONSE_SESSION_NOT_OPEN;
603     if (mRequest.getParameterCount() < 3)
604         return MTP_RESPONSE_INVALID_PARAMETER;
605     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
606     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
607     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
608                                                             // 0x00000000 for all objects
609     if (!hasStorage(storageID))
610         return MTP_RESPONSE_INVALID_STORAGE_ID;
611 
612     int count = mDatabase->getNumObjects(storageID, format, parent);
613     if (count >= 0) {
614         mResponse.setParameter(1, count);
615         return MTP_RESPONSE_OK;
616     } else {
617         mResponse.setParameter(1, 0);
618         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
619     }
620 }
621 
doGetObjectReferences()622 MtpResponseCode MtpServer::doGetObjectReferences() {
623     if (!mSessionOpen)
624         return MTP_RESPONSE_SESSION_NOT_OPEN;
625     if (!hasStorage())
626         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
627     if (mRequest.getParameterCount() < 1)
628         return MTP_RESPONSE_INVALID_PARAMETER;
629     MtpObjectHandle handle = mRequest.getParameter(1);
630 
631     // FIXME - check for invalid object handle
632     MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
633     if (handles) {
634         mData.putAUInt32(handles);
635         delete handles;
636     } else {
637         mData.putEmptyArray();
638     }
639     return MTP_RESPONSE_OK;
640 }
641 
doSetObjectReferences()642 MtpResponseCode MtpServer::doSetObjectReferences() {
643     if (!mSessionOpen)
644         return MTP_RESPONSE_SESSION_NOT_OPEN;
645     if (!hasStorage())
646         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
647     if (mRequest.getParameterCount() < 1)
648         return MTP_RESPONSE_INVALID_PARAMETER;
649     MtpStorageID handle = mRequest.getParameter(1);
650 
651     MtpObjectHandleList* references = mData.getAUInt32();
652     if (!references)
653         return MTP_RESPONSE_INVALID_PARAMETER;
654     MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
655     delete references;
656     return result;
657 }
658 
doGetObjectPropValue()659 MtpResponseCode MtpServer::doGetObjectPropValue() {
660     if (!hasStorage())
661         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
662     if (mRequest.getParameterCount() < 2)
663         return MTP_RESPONSE_INVALID_PARAMETER;
664     MtpObjectHandle handle = mRequest.getParameter(1);
665     MtpObjectProperty property = mRequest.getParameter(2);
666     ALOGV("GetObjectPropValue %d %s\n", handle,
667             MtpDebug::getObjectPropCodeName(property));
668 
669     return mDatabase->getObjectPropertyValue(handle, property, mData);
670 }
671 
doSetObjectPropValue()672 MtpResponseCode MtpServer::doSetObjectPropValue() {
673     if (!hasStorage())
674         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
675     if (mRequest.getParameterCount() < 2)
676         return MTP_RESPONSE_INVALID_PARAMETER;
677     MtpObjectHandle handle = mRequest.getParameter(1);
678     MtpObjectProperty property = mRequest.getParameter(2);
679     ALOGV("SetObjectPropValue %d %s\n", handle,
680             MtpDebug::getObjectPropCodeName(property));
681 
682     return mDatabase->setObjectPropertyValue(handle, property, mData);
683 }
684 
doGetDevicePropValue()685 MtpResponseCode MtpServer::doGetDevicePropValue() {
686     if (mRequest.getParameterCount() < 1)
687         return MTP_RESPONSE_INVALID_PARAMETER;
688     MtpDeviceProperty property = mRequest.getParameter(1);
689     ALOGV("GetDevicePropValue %s\n",
690             MtpDebug::getDevicePropCodeName(property));
691 
692     return mDatabase->getDevicePropertyValue(property, mData);
693 }
694 
doSetDevicePropValue()695 MtpResponseCode MtpServer::doSetDevicePropValue() {
696     if (mRequest.getParameterCount() < 1)
697         return MTP_RESPONSE_INVALID_PARAMETER;
698     MtpDeviceProperty property = mRequest.getParameter(1);
699     ALOGV("SetDevicePropValue %s\n",
700             MtpDebug::getDevicePropCodeName(property));
701 
702     return mDatabase->setDevicePropertyValue(property, mData);
703 }
704 
doResetDevicePropValue()705 MtpResponseCode MtpServer::doResetDevicePropValue() {
706     if (mRequest.getParameterCount() < 1)
707         return MTP_RESPONSE_INVALID_PARAMETER;
708     MtpDeviceProperty property = mRequest.getParameter(1);
709     ALOGV("ResetDevicePropValue %s\n",
710             MtpDebug::getDevicePropCodeName(property));
711 
712     return mDatabase->resetDeviceProperty(property);
713 }
714 
doGetObjectPropList()715 MtpResponseCode MtpServer::doGetObjectPropList() {
716     if (!hasStorage())
717         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
718     if (mRequest.getParameterCount() < 5)
719         return MTP_RESPONSE_INVALID_PARAMETER;
720 
721     MtpObjectHandle handle = mRequest.getParameter(1);
722     // use uint32_t so we can support 0xFFFFFFFF
723     uint32_t format = mRequest.getParameter(2);
724     uint32_t property = mRequest.getParameter(3);
725     int groupCode = mRequest.getParameter(4);
726     int depth = mRequest.getParameter(5);
727    ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
728             handle, MtpDebug::getFormatCodeName(format),
729             MtpDebug::getObjectPropCodeName(property), groupCode, depth);
730 
731     return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
732 }
733 
doGetObjectInfo()734 MtpResponseCode MtpServer::doGetObjectInfo() {
735     if (!hasStorage())
736         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
737     if (mRequest.getParameterCount() < 1)
738         return MTP_RESPONSE_INVALID_PARAMETER;
739     MtpObjectHandle handle = mRequest.getParameter(1);
740     MtpObjectInfo info(handle);
741     MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
742     if (result == MTP_RESPONSE_OK) {
743         char    date[20];
744 
745         mData.putUInt32(info.mStorageID);
746         mData.putUInt16(info.mFormat);
747         mData.putUInt16(info.mProtectionStatus);
748 
749         // if object is being edited the database size may be out of date
750         uint32_t size = info.mCompressedSize;
751         ObjectEdit* edit = getEditObject(handle);
752         if (edit)
753             size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
754         mData.putUInt32(size);
755 
756         mData.putUInt16(info.mThumbFormat);
757         mData.putUInt32(info.mThumbCompressedSize);
758         mData.putUInt32(info.mThumbPixWidth);
759         mData.putUInt32(info.mThumbPixHeight);
760         mData.putUInt32(info.mImagePixWidth);
761         mData.putUInt32(info.mImagePixHeight);
762         mData.putUInt32(info.mImagePixDepth);
763         mData.putUInt32(info.mParent);
764         mData.putUInt16(info.mAssociationType);
765         mData.putUInt32(info.mAssociationDesc);
766         mData.putUInt32(info.mSequenceNumber);
767         mData.putString(info.mName);
768         formatDateTime(info.mDateCreated, date, sizeof(date));
769         mData.putString(date);   // date created
770         formatDateTime(info.mDateModified, date, sizeof(date));
771         mData.putString(date);   // date modified
772         mData.putEmptyString();   // keywords
773     }
774     return result;
775 }
776 
doGetObject()777 MtpResponseCode MtpServer::doGetObject() {
778     if (!hasStorage())
779         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
780     if (mRequest.getParameterCount() < 1)
781         return MTP_RESPONSE_INVALID_PARAMETER;
782     MtpObjectHandle handle = mRequest.getParameter(1);
783     MtpString pathBuf;
784     int64_t fileLength;
785     MtpObjectFormat format;
786     int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
787     if (result != MTP_RESPONSE_OK)
788         return result;
789 
790     auto start = std::chrono::steady_clock::now();
791 
792     const char* filePath = (const char *)pathBuf;
793     mtp_file_range  mfr;
794     mfr.fd = open(filePath, O_RDONLY);
795     if (mfr.fd < 0) {
796         return MTP_RESPONSE_GENERAL_ERROR;
797     }
798     mfr.offset = 0;
799     mfr.length = fileLength;
800     mfr.command = mRequest.getOperationCode();
801     mfr.transaction_id = mRequest.getTransactionID();
802 
803     // then transfer the file
804     int ret = sHandle->sendFile(mfr);
805     if (ret < 0) {
806         ALOGE("Mtp send file got error %s", strerror(errno));
807         if (errno == ECANCELED) {
808             result = MTP_RESPONSE_TRANSACTION_CANCELLED;
809         } else {
810             result = MTP_RESPONSE_GENERAL_ERROR;
811         }
812     } else {
813         result = MTP_RESPONSE_OK;
814     }
815 
816     auto end = std::chrono::steady_clock::now();
817     std::chrono::duration<double> diff = end - start;
818     struct stat sstat;
819     fstat(mfr.fd, &sstat);
820     uint64_t finalsize = sstat.st_size;
821     ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
822             diff.count(), finalsize, ((double) finalsize) / diff.count());
823     close(mfr.fd);
824     return result;
825 }
826 
doGetThumb()827 MtpResponseCode MtpServer::doGetThumb() {
828     if (mRequest.getParameterCount() < 1)
829         return MTP_RESPONSE_INVALID_PARAMETER;
830     MtpObjectHandle handle = mRequest.getParameter(1);
831     size_t thumbSize;
832     void* thumb = mDatabase->getThumbnail(handle, thumbSize);
833     if (thumb) {
834         // send data
835         mData.setOperationCode(mRequest.getOperationCode());
836         mData.setTransactionID(mRequest.getTransactionID());
837         mData.writeData(sHandle, thumb, thumbSize);
838         free(thumb);
839         return MTP_RESPONSE_OK;
840     } else {
841         return MTP_RESPONSE_GENERAL_ERROR;
842     }
843 }
844 
doGetPartialObject(MtpOperationCode operation)845 MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
846     if (!hasStorage())
847         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
848     MtpObjectHandle handle = mRequest.getParameter(1);
849     uint64_t offset;
850     uint32_t length;
851     offset = mRequest.getParameter(2);
852     if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
853         // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
854         if (mRequest.getParameterCount() < 4)
855             return MTP_RESPONSE_INVALID_PARAMETER;
856 
857         // android extension with 64 bit offset
858         uint64_t offset2 = mRequest.getParameter(3);
859         offset = offset | (offset2 << 32);
860         length = mRequest.getParameter(4);
861     } else {
862         // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
863         if (mRequest.getParameterCount() < 3)
864             return MTP_RESPONSE_INVALID_PARAMETER;
865 
866         // standard GetPartialObject
867         length = mRequest.getParameter(3);
868     }
869     MtpString pathBuf;
870     int64_t fileLength;
871     MtpObjectFormat format;
872     int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
873     if (result != MTP_RESPONSE_OK)
874         return result;
875     if (offset + length > (uint64_t)fileLength)
876         length = fileLength - offset;
877 
878     const char* filePath = (const char *)pathBuf;
879     mtp_file_range  mfr;
880     mfr.fd = open(filePath, O_RDONLY);
881     if (mfr.fd < 0) {
882         return MTP_RESPONSE_GENERAL_ERROR;
883     }
884     mfr.offset = offset;
885     mfr.length = length;
886     mfr.command = mRequest.getOperationCode();
887     mfr.transaction_id = mRequest.getTransactionID();
888     mResponse.setParameter(1, length);
889 
890     // transfer the file
891     int ret = sHandle->sendFile(mfr);
892     ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
893     result = MTP_RESPONSE_OK;
894     if (ret < 0) {
895         if (errno == ECANCELED)
896             result = MTP_RESPONSE_TRANSACTION_CANCELLED;
897         else
898             result = MTP_RESPONSE_GENERAL_ERROR;
899     }
900     close(mfr.fd);
901     return result;
902 }
903 
doSendObjectInfo()904 MtpResponseCode MtpServer::doSendObjectInfo() {
905     MtpString path;
906     uint16_t temp16;
907     uint32_t temp32;
908 
909     if (mRequest.getParameterCount() < 2)
910         return MTP_RESPONSE_INVALID_PARAMETER;
911     MtpStorageID storageID = mRequest.getParameter(1);
912     MtpStorage* storage = getStorage(storageID);
913     MtpObjectHandle parent = mRequest.getParameter(2);
914     if (!storage)
915         return MTP_RESPONSE_INVALID_STORAGE_ID;
916 
917     // special case the root
918     if (parent == MTP_PARENT_ROOT) {
919         path = storage->getPath();
920         parent = 0;
921     } else {
922         int64_t length;
923         MtpObjectFormat format;
924         int result = mDatabase->getObjectFilePath(parent, path, length, format);
925         if (result != MTP_RESPONSE_OK)
926             return result;
927         if (format != MTP_FORMAT_ASSOCIATION)
928             return MTP_RESPONSE_INVALID_PARENT_OBJECT;
929     }
930 
931     // read only the fields we need
932     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // storage ID
933     if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
934     MtpObjectFormat format = temp16;
935     if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;  // protection status
936     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
937     mSendObjectFileSize = temp32;
938     if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb format
939     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb compressed size
940     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb pix width
941     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb pix height
942     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image pix width
943     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image pix height
944     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image bit depth
945     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // parent
946     if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
947     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
948     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // sequence number
949     MtpStringBuffer name, created, modified;
950     if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER;    // file name
951     if (name.getCharCount() == 0) {
952         ALOGE("empty name");
953         return MTP_RESPONSE_INVALID_PARAMETER;
954     }
955     if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER;      // date created
956     if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER;     // date modified
957     // keywords follow
958 
959     ALOGV("name: %s format: %04X\n", (const char *)name, format);
960     time_t modifiedTime;
961     if (!parseDateTime(modified, modifiedTime))
962         modifiedTime = 0;
963 
964     if (path[path.size() - 1] != '/')
965         path += "/";
966     path += (const char *)name;
967 
968     // check space first
969     if (mSendObjectFileSize > storage->getFreeSpace())
970         return MTP_RESPONSE_STORAGE_FULL;
971     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     }
979 
980     ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
981     MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
982             format, parent, storageID, mSendObjectFileSize, modifiedTime);
983     if (handle == kInvalidObjectHandle) {
984         return MTP_RESPONSE_GENERAL_ERROR;
985     }
986 
987   if (format == MTP_FORMAT_ASSOCIATION) {
988         mode_t mask = umask(0);
989         int ret = mkdir((const char *)path, mDirectoryPermission);
990         umask(mask);
991         if (ret && ret != -EEXIST)
992             return MTP_RESPONSE_GENERAL_ERROR;
993         chown((const char *)path, getuid(), mFileGroup);
994 
995         // SendObject does not get sent for directories, so call endSendObject here instead
996         mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
997     } else {
998         mSendObjectFilePath = path;
999         // save the handle for the SendObject call, which should follow
1000         mSendObjectHandle = handle;
1001         mSendObjectFormat = format;
1002     }
1003 
1004     mResponse.setParameter(1, storageID);
1005     mResponse.setParameter(2, parent);
1006     mResponse.setParameter(3, handle);
1007 
1008     return MTP_RESPONSE_OK;
1009 }
1010 
doSendObject()1011 MtpResponseCode MtpServer::doSendObject() {
1012     if (!hasStorage())
1013         return MTP_RESPONSE_GENERAL_ERROR;
1014     MtpResponseCode result = MTP_RESPONSE_OK;
1015     mode_t mask;
1016     int ret, initialData;
1017     bool isCanceled = false;
1018 
1019     auto start = std::chrono::steady_clock::now();
1020 
1021     if (mSendObjectHandle == kInvalidObjectHandle) {
1022         ALOGE("Expected SendObjectInfo before SendObject");
1023         result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
1024         goto done;
1025     }
1026 
1027     // read the header, and possibly some data
1028     ret = mData.read(sHandle);
1029     if (ret < MTP_CONTAINER_HEADER_SIZE) {
1030         result = MTP_RESPONSE_GENERAL_ERROR;
1031         goto done;
1032     }
1033     initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1034 
1035     mtp_file_range  mfr;
1036     mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
1037     if (mfr.fd < 0) {
1038         result = MTP_RESPONSE_GENERAL_ERROR;
1039         goto done;
1040     }
1041     fchown(mfr.fd, getuid(), mFileGroup);
1042     // set permissions
1043     mask = umask(0);
1044     fchmod(mfr.fd, mFilePermission);
1045     umask(mask);
1046 
1047     if (initialData > 0) {
1048         ret = write(mfr.fd, mData.getData(), initialData);
1049     }
1050 
1051     if (ret < 0) {
1052         ALOGE("failed to write initial data");
1053         result = MTP_RESPONSE_GENERAL_ERROR;
1054     } else {
1055         mfr.offset = initialData;
1056         if (mSendObjectFileSize == 0xFFFFFFFF) {
1057             // tell driver to read until it receives a short packet
1058             mfr.length = 0xFFFFFFFF;
1059         } else {
1060             mfr.length = mSendObjectFileSize - initialData;
1061         }
1062 
1063         mfr.command = 0;
1064         mfr.transaction_id = 0;
1065 
1066         // transfer the file
1067         ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
1068                 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1069         if ((ret < 0) && (errno == ECANCELED)) {
1070             isCanceled = true;
1071         }
1072     }
1073     struct stat sstat;
1074     fstat(mfr.fd, &sstat);
1075     close(mfr.fd);
1076 
1077     if (ret < 0) {
1078         ALOGE("Mtp receive file got error %s", strerror(errno));
1079         unlink(mSendObjectFilePath);
1080         if (isCanceled)
1081             result = MTP_RESPONSE_TRANSACTION_CANCELLED;
1082         else
1083             result = MTP_RESPONSE_GENERAL_ERROR;
1084     }
1085 
1086 done:
1087     // reset so we don't attempt to send the data back
1088     mData.reset();
1089 
1090     mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
1091             result == MTP_RESPONSE_OK);
1092     mSendObjectHandle = kInvalidObjectHandle;
1093     mSendObjectFormat = 0;
1094 
1095     auto end = std::chrono::steady_clock::now();
1096     std::chrono::duration<double> diff = end - start;
1097     uint64_t finalsize = sstat.st_size;
1098     ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
1099             diff.count(), finalsize, ((double) finalsize) / diff.count());
1100     return result;
1101 }
1102 
deleteRecursive(const char * path)1103 static void deleteRecursive(const char* path) {
1104     char pathbuf[PATH_MAX];
1105     size_t pathLength = strlen(path);
1106     if (pathLength >= sizeof(pathbuf) - 1) {
1107         ALOGE("path too long: %s\n", path);
1108     }
1109     strcpy(pathbuf, path);
1110     if (pathbuf[pathLength - 1] != '/') {
1111         pathbuf[pathLength++] = '/';
1112     }
1113     char* fileSpot = pathbuf + pathLength;
1114     int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1115 
1116     DIR* dir = opendir(path);
1117     if (!dir) {
1118         ALOGE("opendir %s failed: %s", path, strerror(errno));
1119         return;
1120     }
1121 
1122     struct dirent* entry;
1123     while ((entry = readdir(dir))) {
1124         const char* name = entry->d_name;
1125 
1126         // ignore "." and ".."
1127         if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1128             continue;
1129         }
1130 
1131         int nameLength = strlen(name);
1132         if (nameLength > pathRemaining) {
1133             ALOGE("path %s/%s too long\n", path, name);
1134             continue;
1135         }
1136         strcpy(fileSpot, name);
1137 
1138         if (entry->d_type == DT_DIR) {
1139             deleteRecursive(pathbuf);
1140             rmdir(pathbuf);
1141         } else {
1142             unlink(pathbuf);
1143         }
1144     }
1145     closedir(dir);
1146 }
1147 
deletePath(const char * path)1148 static void deletePath(const char* path) {
1149     struct stat statbuf;
1150     if (stat(path, &statbuf) == 0) {
1151         if (S_ISDIR(statbuf.st_mode)) {
1152             deleteRecursive(path);
1153             rmdir(path);
1154         } else {
1155             unlink(path);
1156         }
1157     } else {
1158         ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
1159     }
1160 }
1161 
doDeleteObject()1162 MtpResponseCode MtpServer::doDeleteObject() {
1163     if (!hasStorage())
1164         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
1165     if (mRequest.getParameterCount() < 1)
1166         return MTP_RESPONSE_INVALID_PARAMETER;
1167     MtpObjectHandle handle = mRequest.getParameter(1);
1168     MtpObjectFormat format;
1169     // FIXME - support deleting all objects if handle is 0xFFFFFFFF
1170     // FIXME - implement deleting objects by format
1171 
1172     MtpString filePath;
1173     int64_t fileLength;
1174     int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
1175     if (result == MTP_RESPONSE_OK) {
1176         ALOGV("deleting %s", (const char *)filePath);
1177         result = mDatabase->deleteFile(handle);
1178         // Don't delete the actual files unless the database deletion is allowed
1179         if (result == MTP_RESPONSE_OK) {
1180             deletePath((const char *)filePath);
1181         }
1182     }
1183 
1184     return result;
1185 }
1186 
doGetObjectPropDesc()1187 MtpResponseCode MtpServer::doGetObjectPropDesc() {
1188     if (mRequest.getParameterCount() < 2)
1189         return MTP_RESPONSE_INVALID_PARAMETER;
1190     MtpObjectProperty propCode = mRequest.getParameter(1);
1191     MtpObjectFormat format = mRequest.getParameter(2);
1192     ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
1193                                         MtpDebug::getFormatCodeName(format));
1194     MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
1195     if (!property)
1196         return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
1197     property->write(mData);
1198     delete property;
1199     return MTP_RESPONSE_OK;
1200 }
1201 
doGetDevicePropDesc()1202 MtpResponseCode MtpServer::doGetDevicePropDesc() {
1203     if (mRequest.getParameterCount() < 1)
1204         return MTP_RESPONSE_INVALID_PARAMETER;
1205     MtpDeviceProperty propCode = mRequest.getParameter(1);
1206     ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
1207     MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
1208     if (!property)
1209         return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
1210     property->write(mData);
1211     delete property;
1212     return MTP_RESPONSE_OK;
1213 }
1214 
doSendPartialObject()1215 MtpResponseCode MtpServer::doSendPartialObject() {
1216     if (!hasStorage())
1217         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
1218     if (mRequest.getParameterCount() < 4)
1219         return MTP_RESPONSE_INVALID_PARAMETER;
1220     MtpObjectHandle handle = mRequest.getParameter(1);
1221     uint64_t offset = mRequest.getParameter(2);
1222     uint64_t offset2 = mRequest.getParameter(3);
1223     offset = offset | (offset2 << 32);
1224     uint32_t length = mRequest.getParameter(4);
1225 
1226     ObjectEdit* edit = getEditObject(handle);
1227     if (!edit) {
1228         ALOGE("object not open for edit in doSendPartialObject");
1229         return MTP_RESPONSE_GENERAL_ERROR;
1230     }
1231 
1232     // can't start writing past the end of the file
1233     if (offset > edit->mSize) {
1234         ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1235             offset, edit->mSize);
1236         return MTP_RESPONSE_GENERAL_ERROR;
1237     }
1238 
1239     const char* filePath = (const char *)edit->mPath;
1240     ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
1241 
1242     // read the header, and possibly some data
1243     int ret = mData.read(sHandle);
1244     if (ret < MTP_CONTAINER_HEADER_SIZE)
1245         return MTP_RESPONSE_GENERAL_ERROR;
1246     int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
1247 
1248     if (initialData > 0) {
1249         ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
1250         offset += initialData;
1251         length -= initialData;
1252     }
1253 
1254     bool isCanceled = false;
1255     if (ret < 0) {
1256         ALOGE("failed to write initial data");
1257     } else {
1258         mtp_file_range  mfr;
1259         mfr.fd = edit->mFD;
1260         mfr.offset = offset;
1261         mfr.length = length;
1262         mfr.command = 0;
1263         mfr.transaction_id = 0;
1264 
1265         // transfer the file
1266         ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
1267                 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
1268         if ((ret < 0) && (errno == ECANCELED)) {
1269             isCanceled = true;
1270         }
1271     }
1272     if (ret < 0) {
1273         mResponse.setParameter(1, 0);
1274         if (isCanceled)
1275             return MTP_RESPONSE_TRANSACTION_CANCELLED;
1276         else
1277             return MTP_RESPONSE_GENERAL_ERROR;
1278     }
1279 
1280     // reset so we don't attempt to send this back
1281     mData.reset();
1282     mResponse.setParameter(1, length);
1283     uint64_t end = offset + length;
1284     if (end > edit->mSize) {
1285         edit->mSize = end;
1286     }
1287     return MTP_RESPONSE_OK;
1288 }
1289 
doTruncateObject()1290 MtpResponseCode MtpServer::doTruncateObject() {
1291     if (mRequest.getParameterCount() < 3)
1292         return MTP_RESPONSE_INVALID_PARAMETER;
1293     MtpObjectHandle handle = mRequest.getParameter(1);
1294     ObjectEdit* edit = getEditObject(handle);
1295     if (!edit) {
1296         ALOGE("object not open for edit in doTruncateObject");
1297         return MTP_RESPONSE_GENERAL_ERROR;
1298     }
1299 
1300     uint64_t offset = mRequest.getParameter(2);
1301     uint64_t offset2 = mRequest.getParameter(3);
1302     offset |= (offset2 << 32);
1303     if (ftruncate(edit->mFD, offset) != 0) {
1304         return MTP_RESPONSE_GENERAL_ERROR;
1305     } else {
1306         edit->mSize = offset;
1307         return MTP_RESPONSE_OK;
1308     }
1309 }
1310 
doBeginEditObject()1311 MtpResponseCode MtpServer::doBeginEditObject() {
1312     if (mRequest.getParameterCount() < 1)
1313         return MTP_RESPONSE_INVALID_PARAMETER;
1314     MtpObjectHandle handle = mRequest.getParameter(1);
1315     if (getEditObject(handle)) {
1316         ALOGE("object already open for edit in doBeginEditObject");
1317         return MTP_RESPONSE_GENERAL_ERROR;
1318     }
1319 
1320     MtpString path;
1321     int64_t fileLength;
1322     MtpObjectFormat format;
1323     int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
1324     if (result != MTP_RESPONSE_OK)
1325         return result;
1326 
1327     int fd = open((const char *)path, O_RDWR | O_EXCL);
1328     if (fd < 0) {
1329         ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
1330         return MTP_RESPONSE_GENERAL_ERROR;
1331     }
1332 
1333     addEditObject(handle, path, fileLength, format, fd);
1334     return MTP_RESPONSE_OK;
1335 }
1336 
doEndEditObject()1337 MtpResponseCode MtpServer::doEndEditObject() {
1338     if (mRequest.getParameterCount() < 1)
1339         return MTP_RESPONSE_INVALID_PARAMETER;
1340     MtpObjectHandle handle = mRequest.getParameter(1);
1341     ObjectEdit* edit = getEditObject(handle);
1342     if (!edit) {
1343         ALOGE("object not open for edit in doEndEditObject");
1344         return MTP_RESPONSE_GENERAL_ERROR;
1345     }
1346 
1347     commitEdit(edit);
1348     removeEditObject(handle);
1349     return MTP_RESPONSE_OK;
1350 }
1351 
1352 }  // namespace android
1353