MtpServer.cpp 49 KB

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