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