12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460 |
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <algorithm>
- #include <android-base/logging.h>
- #include <android-base/properties.h>
- #include <chrono>
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <inttypes.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #define LOG_TAG "MtpServer"
- #include "MtpDebug.h"
- #include "IMtpDatabase.h"
- #include "MtpDescriptors.h"
- #include "MtpDevHandle.h"
- #include "MtpFfsCompatHandle.h"
- #include "MtpFfsHandle.h"
- #include "MtpObjectInfo.h"
- #include "MtpProperty.h"
- #include "MtpServer.h"
- #include "MtpStorage.h"
- #include "MtpStringBuffer.h"
- namespace android {
- static const MtpOperationCode kSupportedOperationCodes[] = {
- MTP_OPERATION_GET_DEVICE_INFO,
- MTP_OPERATION_OPEN_SESSION,
- MTP_OPERATION_CLOSE_SESSION,
- MTP_OPERATION_GET_STORAGE_IDS,
- MTP_OPERATION_GET_STORAGE_INFO,
- MTP_OPERATION_GET_NUM_OBJECTS,
- MTP_OPERATION_GET_OBJECT_HANDLES,
- MTP_OPERATION_GET_OBJECT_INFO,
- MTP_OPERATION_GET_OBJECT,
- MTP_OPERATION_GET_THUMB,
- MTP_OPERATION_DELETE_OBJECT,
- MTP_OPERATION_SEND_OBJECT_INFO,
- MTP_OPERATION_SEND_OBJECT,
- // MTP_OPERATION_INITIATE_CAPTURE,
- // MTP_OPERATION_FORMAT_STORE,
- MTP_OPERATION_RESET_DEVICE,
- // MTP_OPERATION_SELF_TEST,
- // MTP_OPERATION_SET_OBJECT_PROTECTION,
- // MTP_OPERATION_POWER_DOWN,
- MTP_OPERATION_GET_DEVICE_PROP_DESC,
- MTP_OPERATION_GET_DEVICE_PROP_VALUE,
- MTP_OPERATION_SET_DEVICE_PROP_VALUE,
- MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
- // MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
- MTP_OPERATION_MOVE_OBJECT,
- MTP_OPERATION_COPY_OBJECT,
- MTP_OPERATION_GET_PARTIAL_OBJECT,
- // MTP_OPERATION_INITIATE_OPEN_CAPTURE,
- MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
- MTP_OPERATION_GET_OBJECT_PROP_DESC,
- MTP_OPERATION_GET_OBJECT_PROP_VALUE,
- MTP_OPERATION_SET_OBJECT_PROP_VALUE,
- MTP_OPERATION_GET_OBJECT_PROP_LIST,
- // MTP_OPERATION_SET_OBJECT_PROP_LIST,
- // MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
- // MTP_OPERATION_SEND_OBJECT_PROP_LIST,
- MTP_OPERATION_GET_OBJECT_REFERENCES,
- MTP_OPERATION_SET_OBJECT_REFERENCES,
- // MTP_OPERATION_SKIP,
- // Android extension for direct file IO
- MTP_OPERATION_GET_PARTIAL_OBJECT_64,
- MTP_OPERATION_SEND_PARTIAL_OBJECT,
- MTP_OPERATION_TRUNCATE_OBJECT,
- MTP_OPERATION_BEGIN_EDIT_OBJECT,
- MTP_OPERATION_END_EDIT_OBJECT,
- };
- static const MtpEventCode kSupportedEventCodes[] = {
- MTP_EVENT_OBJECT_ADDED,
- MTP_EVENT_OBJECT_REMOVED,
- MTP_EVENT_STORE_ADDED,
- MTP_EVENT_STORE_REMOVED,
- MTP_EVENT_DEVICE_PROP_CHANGED,
- MTP_EVENT_OBJECT_INFO_CHANGED,
- };
- MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
- const char *deviceInfoManufacturer,
- const char *deviceInfoModel,
- const char *deviceInfoDeviceVersion,
- const char *deviceInfoSerialNumber)
- : mDatabase(database),
- mPtp(ptp),
- mDeviceInfoManufacturer(deviceInfoManufacturer),
- mDeviceInfoModel(deviceInfoModel),
- mDeviceInfoDeviceVersion(deviceInfoDeviceVersion),
- mDeviceInfoSerialNumber(deviceInfoSerialNumber),
- mSessionID(0),
- mSessionOpen(false),
- mSendObjectHandle(kInvalidObjectHandle),
- mSendObjectFormat(0),
- mSendObjectFileSize(0),
- mSendObjectModifiedTime(0)
- {
- bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
- if (ffs_ok) {
- bool aio_compat = android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false);
- mHandle = aio_compat ? new MtpFfsCompatHandle(controlFd) : new MtpFfsHandle(controlFd);
- } else {
- mHandle = new MtpDevHandle();
- }
- }
- MtpServer::~MtpServer() {
- }
- void MtpServer::addStorage(MtpStorage* storage) {
- std::lock_guard<std::mutex> lg(mMutex);
- mStorages.push_back(storage);
- sendStoreAdded(storage->getStorageID());
- }
- void MtpServer::removeStorage(MtpStorage* storage) {
- std::lock_guard<std::mutex> lg(mMutex);
- auto iter = std::find(mStorages.begin(), mStorages.end(), storage);
- if (iter != mStorages.end()) {
- sendStoreRemoved(storage->getStorageID());
- mStorages.erase(iter);
- }
- }
- MtpStorage* MtpServer::getStorage(MtpStorageID id) {
- if (id == 0)
- return mStorages[0];
- for (MtpStorage *storage : mStorages) {
- if (storage->getStorageID() == id)
- return storage;
- }
- return nullptr;
- }
- bool MtpServer::hasStorage(MtpStorageID id) {
- if (id == 0 || id == 0xFFFFFFFF)
- return mStorages.size() > 0;
- return (getStorage(id) != nullptr);
- }
- void MtpServer::run() {
- if (mHandle->start(mPtp)) {
- ALOGE("Failed to start usb driver!");
- mHandle->close();
- return;
- }
- while (1) {
- int ret = mRequest.read(mHandle);
- if (ret < 0) {
- ALOGE("request read returned %d, errno: %d", ret, errno);
- if (errno == ECANCELED) {
- // return to top of loop and wait for next command
- continue;
- }
- break;
- }
- MtpOperationCode operation = mRequest.getOperationCode();
- MtpTransactionID transaction = mRequest.getTransactionID();
- ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
- // FIXME need to generalize this
- bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
- || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
- || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
- || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
- if (dataIn) {
- int ret = mData.read(mHandle);
- if (ret < 0) {
- ALOGE("data read returned %d, errno: %d", ret, errno);
- if (errno == ECANCELED) {
- // return to top of loop and wait for next command
- continue;
- }
- break;
- }
- ALOGV("received data:");
- } else {
- mData.reset();
- }
- if (handleRequest()) {
- if (!dataIn && mData.hasData()) {
- mData.setOperationCode(operation);
- mData.setTransactionID(transaction);
- ALOGV("sending data:");
- ret = mData.write(mHandle);
- if (ret < 0) {
- ALOGE("request write returned %d, errno: %d", ret, errno);
- if (errno == ECANCELED) {
- // return to top of loop and wait for next command
- continue;
- }
- break;
- }
- }
- mResponse.setTransactionID(transaction);
- ALOGV("sending response %04X", mResponse.getResponseCode());
- ret = mResponse.write(mHandle);
- const int savedErrno = errno;
- if (ret < 0) {
- ALOGE("request write returned %d, errno: %d", ret, errno);
- if (savedErrno == ECANCELED) {
- // return to top of loop and wait for next command
- continue;
- }
- break;
- }
- } else {
- ALOGV("skipping response\n");
- }
- }
- // commit any open edits
- int count = mObjectEditList.size();
- for (int i = 0; i < count; i++) {
- ObjectEdit* edit = mObjectEditList[i];
- commitEdit(edit);
- delete edit;
- }
- mObjectEditList.clear();
- mHandle->close();
- }
- void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
- ALOGV("sendObjectAdded %d\n", handle);
- sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
- }
- void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
- ALOGV("sendObjectRemoved %d\n", handle);
- sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
- }
- void MtpServer::sendObjectInfoChanged(MtpObjectHandle handle) {
- ALOGV("sendObjectInfoChanged %d\n", handle);
- sendEvent(MTP_EVENT_OBJECT_INFO_CHANGED, handle);
- }
- void MtpServer::sendStoreAdded(MtpStorageID id) {
- ALOGV("sendStoreAdded %08X\n", id);
- sendEvent(MTP_EVENT_STORE_ADDED, id);
- }
- void MtpServer::sendStoreRemoved(MtpStorageID id) {
- ALOGV("sendStoreRemoved %08X\n", id);
- sendEvent(MTP_EVENT_STORE_REMOVED, id);
- }
- void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
- ALOGV("sendDevicePropertyChanged %d\n", property);
- sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
- }
- void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
- if (mSessionOpen) {
- mEvent.setEventCode(code);
- mEvent.setTransactionID(mRequest.getTransactionID());
- mEvent.setParameter(1, param1);
- if (mEvent.write(mHandle))
- ALOGE("Mtp send event failed: %s", strerror(errno));
- }
- }
- void MtpServer::addEditObject(MtpObjectHandle handle, MtpStringBuffer& path,
- uint64_t size, MtpObjectFormat format, int fd) {
- ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd);
- mObjectEditList.push_back(edit);
- }
- MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
- int count = mObjectEditList.size();
- for (int i = 0; i < count; i++) {
- ObjectEdit* edit = mObjectEditList[i];
- if (edit->mHandle == handle) return edit;
- }
- return nullptr;
- }
- void MtpServer::removeEditObject(MtpObjectHandle handle) {
- int count = mObjectEditList.size();
- for (int i = 0; i < count; i++) {
- ObjectEdit* edit = mObjectEditList[i];
- if (edit->mHandle == handle) {
- delete edit;
- mObjectEditList.erase(mObjectEditList.begin() + i);
- return;
- }
- }
- ALOGE("ObjectEdit not found in removeEditObject");
- }
- void MtpServer::commitEdit(ObjectEdit* edit) {
- mDatabase->rescanFile((const char *)edit->mPath, edit->mHandle, edit->mFormat);
- }
- bool MtpServer::handleRequest() {
- std::lock_guard<std::mutex> lg(mMutex);
- MtpOperationCode operation = mRequest.getOperationCode();
- MtpResponseCode response;
- mResponse.reset();
- if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
- mSendObjectHandle = kInvalidObjectHandle;
- mSendObjectFormat = 0;
- mSendObjectModifiedTime = 0;
- }
- int containertype = mRequest.getContainerType();
- if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
- ALOGE("wrong container type %d", containertype);
- return false;
- }
- ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
- switch (operation) {
- case MTP_OPERATION_GET_DEVICE_INFO:
- response = doGetDeviceInfo();
- break;
- case MTP_OPERATION_OPEN_SESSION:
- response = doOpenSession();
- break;
- case MTP_OPERATION_RESET_DEVICE:
- case MTP_OPERATION_CLOSE_SESSION:
- response = doCloseSession();
- break;
- case MTP_OPERATION_GET_STORAGE_IDS:
- response = doGetStorageIDs();
- break;
- case MTP_OPERATION_GET_STORAGE_INFO:
- response = doGetStorageInfo();
- break;
- case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
- response = doGetObjectPropsSupported();
- break;
- case MTP_OPERATION_GET_OBJECT_HANDLES:
- response = doGetObjectHandles();
- break;
- case MTP_OPERATION_GET_NUM_OBJECTS:
- response = doGetNumObjects();
- break;
- case MTP_OPERATION_GET_OBJECT_REFERENCES:
- response = doGetObjectReferences();
- break;
- case MTP_OPERATION_SET_OBJECT_REFERENCES:
- response = doSetObjectReferences();
- break;
- case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
- response = doGetObjectPropValue();
- break;
- case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
- response = doSetObjectPropValue();
- break;
- case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
- response = doGetDevicePropValue();
- break;
- case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
- response = doSetDevicePropValue();
- break;
- case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
- response = doResetDevicePropValue();
- break;
- case MTP_OPERATION_GET_OBJECT_PROP_LIST:
- response = doGetObjectPropList();
- break;
- case MTP_OPERATION_GET_OBJECT_INFO:
- response = doGetObjectInfo();
- break;
- case MTP_OPERATION_GET_OBJECT:
- response = doGetObject();
- break;
- case MTP_OPERATION_GET_THUMB:
- response = doGetThumb();
- break;
- case MTP_OPERATION_GET_PARTIAL_OBJECT:
- case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
- response = doGetPartialObject(operation);
- break;
- case MTP_OPERATION_SEND_OBJECT_INFO:
- response = doSendObjectInfo();
- break;
- case MTP_OPERATION_SEND_OBJECT:
- response = doSendObject();
- break;
- case MTP_OPERATION_DELETE_OBJECT:
- response = doDeleteObject();
- break;
- case MTP_OPERATION_COPY_OBJECT:
- response = doCopyObject();
- break;
- case MTP_OPERATION_MOVE_OBJECT:
- response = doMoveObject();
- break;
- case MTP_OPERATION_GET_OBJECT_PROP_DESC:
- response = doGetObjectPropDesc();
- break;
- case MTP_OPERATION_GET_DEVICE_PROP_DESC:
- response = doGetDevicePropDesc();
- break;
- case MTP_OPERATION_SEND_PARTIAL_OBJECT:
- response = doSendPartialObject();
- break;
- case MTP_OPERATION_TRUNCATE_OBJECT:
- response = doTruncateObject();
- break;
- case MTP_OPERATION_BEGIN_EDIT_OBJECT:
- response = doBeginEditObject();
- break;
- case MTP_OPERATION_END_EDIT_OBJECT:
- response = doEndEditObject();
- break;
- default:
- ALOGE("got unsupported command %s (%x)",
- MtpDebug::getOperationCodeName(operation), operation);
- response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
- break;
- }
- if (response != MTP_RESPONSE_OK)
- ALOGW("[MTP] got response 0x%X in command %s (%x)", response,
- MtpDebug::getOperationCodeName(operation), operation);
- if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
- return false;
- mResponse.setResponseCode(response);
- return true;
- }
- MtpResponseCode MtpServer::doGetDeviceInfo() {
- MtpStringBuffer string;
- MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
- MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
- MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
- // fill in device info
- mData.putUInt16(MTP_STANDARD_VERSION);
- if (mPtp) {
- mData.putUInt32(0);
- } else {
- // MTP Vendor Extension ID
- mData.putUInt32(6);
- }
- mData.putUInt16(MTP_STANDARD_VERSION);
- if (mPtp) {
- // no extensions
- string.set("");
- } else {
- // MTP extensions
- string.set("microsoft.com: 1.0; android.com: 1.0;");
- }
- mData.putString(string); // MTP Extensions
- mData.putUInt16(0); //Functional Mode
- mData.putAUInt16(kSupportedOperationCodes,
- sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
- mData.putAUInt16(kSupportedEventCodes,
- sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
- mData.putAUInt16(deviceProperties); // Device Properties Supported
- mData.putAUInt16(captureFormats); // Capture Formats
- mData.putAUInt16(playbackFormats); // Playback Formats
- mData.putString(mDeviceInfoManufacturer); // Manufacturer
- mData.putString(mDeviceInfoModel); // Model
- mData.putString(mDeviceInfoDeviceVersion); // Device Version
- mData.putString(mDeviceInfoSerialNumber); // Serial Number
- delete playbackFormats;
- delete captureFormats;
- delete deviceProperties;
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doOpenSession() {
- if (mSessionOpen) {
- mResponse.setParameter(1, mSessionID);
- return MTP_RESPONSE_SESSION_ALREADY_OPEN;
- }
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- mSessionID = mRequest.getParameter(1);
- mSessionOpen = true;
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doCloseSession() {
- if (!mSessionOpen)
- return MTP_RESPONSE_SESSION_NOT_OPEN;
- mSessionID = 0;
- mSessionOpen = false;
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doGetStorageIDs() {
- if (!mSessionOpen)
- return MTP_RESPONSE_SESSION_NOT_OPEN;
- int count = mStorages.size();
- mData.putUInt32(count);
- for (int i = 0; i < count; i++)
- mData.putUInt32(mStorages[i]->getStorageID());
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doGetStorageInfo() {
- MtpStringBuffer string;
- if (!mSessionOpen)
- return MTP_RESPONSE_SESSION_NOT_OPEN;
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpStorageID id = mRequest.getParameter(1);
- MtpStorage* storage = getStorage(id);
- if (!storage)
- return MTP_RESPONSE_INVALID_STORAGE_ID;
- mData.putUInt16(storage->getType());
- mData.putUInt16(storage->getFileSystemType());
- mData.putUInt16(storage->getAccessCapability());
- mData.putUInt64(storage->getMaxCapacity());
- mData.putUInt64(storage->getFreeSpace());
- mData.putUInt32(1024*1024*1024); // Free Space in Objects
- string.set(storage->getDescription());
- mData.putString(string);
- mData.putEmptyString(); // Volume Identifier
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doGetObjectPropsSupported() {
- if (!mSessionOpen)
- return MTP_RESPONSE_SESSION_NOT_OPEN;
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectFormat format = mRequest.getParameter(1);
- MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
- mData.putAUInt16(properties);
- delete properties;
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doGetObjectHandles() {
- if (!mSessionOpen)
- return MTP_RESPONSE_SESSION_NOT_OPEN;
- if (mRequest.getParameterCount() < 3)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
- MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
- MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
- // 0x00000000 for all objects
- if (!hasStorage(storageID))
- return MTP_RESPONSE_INVALID_STORAGE_ID;
- MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
- if (handles == NULL)
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- mData.putAUInt32(handles);
- delete handles;
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doGetNumObjects() {
- if (!mSessionOpen)
- return MTP_RESPONSE_SESSION_NOT_OPEN;
- if (mRequest.getParameterCount() < 3)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
- MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
- MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
- // 0x00000000 for all objects
- if (!hasStorage(storageID))
- return MTP_RESPONSE_INVALID_STORAGE_ID;
- int count = mDatabase->getNumObjects(storageID, format, parent);
- if (count >= 0) {
- mResponse.setParameter(1, count);
- return MTP_RESPONSE_OK;
- } else {
- mResponse.setParameter(1, 0);
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- }
- }
- MtpResponseCode MtpServer::doGetObjectReferences() {
- if (!mSessionOpen)
- return MTP_RESPONSE_SESSION_NOT_OPEN;
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- // FIXME - check for invalid object handle
- MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
- if (handles) {
- mData.putAUInt32(handles);
- delete handles;
- } else {
- mData.putEmptyArray();
- }
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doSetObjectReferences() {
- if (!mSessionOpen)
- return MTP_RESPONSE_SESSION_NOT_OPEN;
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpStorageID handle = mRequest.getParameter(1);
- MtpObjectHandleList* references = mData.getAUInt32();
- if (!references)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
- delete references;
- return result;
- }
- MtpResponseCode MtpServer::doGetObjectPropValue() {
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 2)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- MtpObjectProperty property = mRequest.getParameter(2);
- ALOGV("GetObjectPropValue %d %s (0x%04X)\n", handle,
- MtpDebug::getObjectPropCodeName(property), property);
- return mDatabase->getObjectPropertyValue(handle, property, mData);
- }
- MtpResponseCode MtpServer::doSetObjectPropValue() {
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 2)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- MtpObjectProperty property = mRequest.getParameter(2);
- ALOGV("SetObjectPropValue %d %s\n", handle,
- MtpDebug::getObjectPropCodeName(property));
- return mDatabase->setObjectPropertyValue(handle, property, mData);
- }
- MtpResponseCode MtpServer::doGetDevicePropValue() {
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpDeviceProperty property = mRequest.getParameter(1);
- ALOGV("GetDevicePropValue %s\n",
- MtpDebug::getDevicePropCodeName(property));
- return mDatabase->getDevicePropertyValue(property, mData);
- }
- MtpResponseCode MtpServer::doSetDevicePropValue() {
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpDeviceProperty property = mRequest.getParameter(1);
- ALOGV("SetDevicePropValue %s\n",
- MtpDebug::getDevicePropCodeName(property));
- return mDatabase->setDevicePropertyValue(property, mData);
- }
- MtpResponseCode MtpServer::doResetDevicePropValue() {
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpDeviceProperty property = mRequest.getParameter(1);
- ALOGV("ResetDevicePropValue %s\n",
- MtpDebug::getDevicePropCodeName(property));
- return mDatabase->resetDeviceProperty(property);
- }
- MtpResponseCode MtpServer::doGetObjectPropList() {
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 5)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- // use uint32_t so we can support 0xFFFFFFFF
- uint32_t format = mRequest.getParameter(2);
- uint32_t property = mRequest.getParameter(3);
- int groupCode = mRequest.getParameter(4);
- int depth = mRequest.getParameter(5);
- ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
- handle, MtpDebug::getFormatCodeName(format),
- MtpDebug::getObjectPropCodeName(property), groupCode, depth);
- return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
- }
- MtpResponseCode MtpServer::doGetObjectInfo() {
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- MtpObjectInfo info(handle);
- MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
- if (result == MTP_RESPONSE_OK) {
- char date[20];
- mData.putUInt32(info.mStorageID);
- mData.putUInt16(info.mFormat);
- mData.putUInt16(info.mProtectionStatus);
- // if object is being edited the database size may be out of date
- uint32_t size = info.mCompressedSize;
- ObjectEdit* edit = getEditObject(handle);
- if (edit)
- size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
- mData.putUInt32(size);
- mData.putUInt16(info.mThumbFormat);
- mData.putUInt32(info.mThumbCompressedSize);
- mData.putUInt32(info.mThumbPixWidth);
- mData.putUInt32(info.mThumbPixHeight);
- mData.putUInt32(info.mImagePixWidth);
- mData.putUInt32(info.mImagePixHeight);
- mData.putUInt32(info.mImagePixDepth);
- mData.putUInt32(info.mParent);
- mData.putUInt16(info.mAssociationType);
- mData.putUInt32(info.mAssociationDesc);
- mData.putUInt32(info.mSequenceNumber);
- mData.putString(info.mName);
- formatDateTime(info.mDateCreated, date, sizeof(date));
- mData.putString(date); // date created
- formatDateTime(info.mDateModified, date, sizeof(date));
- mData.putString(date); // date modified
- mData.putEmptyString(); // keywords
- }
- return result;
- }
- MtpResponseCode MtpServer::doGetObject() {
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- MtpStringBuffer pathBuf;
- int64_t fileLength;
- MtpObjectFormat format;
- int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
- if (result != MTP_RESPONSE_OK)
- return result;
- auto start = std::chrono::steady_clock::now();
- const char* filePath = (const char *)pathBuf;
- mtp_file_range mfr;
- mfr.fd = open(filePath, O_RDONLY);
- if (mfr.fd < 0) {
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- mfr.offset = 0;
- mfr.length = fileLength;
- mfr.command = mRequest.getOperationCode();
- mfr.transaction_id = mRequest.getTransactionID();
- // then transfer the file
- int ret = mHandle->sendFile(mfr);
- if (ret < 0) {
- ALOGE("Mtp send file got error %s", strerror(errno));
- if (errno == ECANCELED) {
- result = MTP_RESPONSE_TRANSACTION_CANCELLED;
- } else {
- result = MTP_RESPONSE_GENERAL_ERROR;
- }
- } else {
- result = MTP_RESPONSE_OK;
- }
- auto end = std::chrono::steady_clock::now();
- std::chrono::duration<double> diff = end - start;
- struct stat sstat;
- fstat(mfr.fd, &sstat);
- uint64_t finalsize = sstat.st_size;
- ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
- diff.count(), finalsize, ((double) finalsize) / diff.count());
- closeObjFd(mfr.fd, filePath);
- return result;
- }
- MtpResponseCode MtpServer::doGetThumb() {
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- size_t thumbSize;
- void* thumb = mDatabase->getThumbnail(handle, thumbSize);
- if (thumb) {
- // send data
- mData.setOperationCode(mRequest.getOperationCode());
- mData.setTransactionID(mRequest.getTransactionID());
- mData.writeData(mHandle, thumb, thumbSize);
- free(thumb);
- return MTP_RESPONSE_OK;
- } else {
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- }
- MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- MtpObjectHandle handle = mRequest.getParameter(1);
- uint64_t offset;
- uint32_t length;
- offset = mRequest.getParameter(2);
- if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
- // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
- if (mRequest.getParameterCount() < 4)
- return MTP_RESPONSE_INVALID_PARAMETER;
- // android extension with 64 bit offset
- uint64_t offset2 = mRequest.getParameter(3);
- offset = offset | (offset2 << 32);
- length = mRequest.getParameter(4);
- } else {
- // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
- if (mRequest.getParameterCount() < 3)
- return MTP_RESPONSE_INVALID_PARAMETER;
- // standard GetPartialObject
- length = mRequest.getParameter(3);
- }
- MtpStringBuffer pathBuf;
- int64_t fileLength;
- MtpObjectFormat format;
- int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
- if (result != MTP_RESPONSE_OK)
- return result;
- if (offset + length > (uint64_t)fileLength)
- length = fileLength - offset;
- const char* filePath = (const char *)pathBuf;
- ALOGV("sending partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
- mtp_file_range mfr;
- mfr.fd = open(filePath, O_RDONLY);
- if (mfr.fd < 0) {
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- mfr.offset = offset;
- mfr.length = length;
- mfr.command = mRequest.getOperationCode();
- mfr.transaction_id = mRequest.getTransactionID();
- mResponse.setParameter(1, length);
- // transfer the file
- int ret = mHandle->sendFile(mfr);
- ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
- result = MTP_RESPONSE_OK;
- if (ret < 0) {
- if (errno == ECANCELED)
- result = MTP_RESPONSE_TRANSACTION_CANCELLED;
- else
- result = MTP_RESPONSE_GENERAL_ERROR;
- }
- closeObjFd(mfr.fd, filePath);
- return result;
- }
- MtpResponseCode MtpServer::doSendObjectInfo() {
- MtpStringBuffer path;
- uint16_t temp16;
- uint32_t temp32;
- if (mRequest.getParameterCount() < 2)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpStorageID storageID = mRequest.getParameter(1);
- MtpStorage* storage = getStorage(storageID);
- MtpObjectHandle parent = mRequest.getParameter(2);
- if (!storage)
- return MTP_RESPONSE_INVALID_STORAGE_ID;
- // special case the root
- if (parent == MTP_PARENT_ROOT) {
- path.set(storage->getPath());
- parent = 0;
- } else {
- int64_t length;
- MtpObjectFormat format;
- int result = mDatabase->getObjectFilePath(parent, path, length, format);
- if (result != MTP_RESPONSE_OK)
- return result;
- if (format != MTP_FORMAT_ASSOCIATION)
- return MTP_RESPONSE_INVALID_PARENT_OBJECT;
- }
- // read only the fields we need
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // storage ID
- if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectFormat format = temp16;
- if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // protection status
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
- mSendObjectFileSize = temp32;
- if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb format
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb compressed size
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix width
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // thumb pix height
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix width
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image pix height
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // image bit depth
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // parent
- if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
- if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER; // sequence number
- MtpStringBuffer name, created, modified;
- if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER; // file name
- if (name.isEmpty()) {
- ALOGE("empty name");
- return MTP_RESPONSE_INVALID_PARAMETER;
- }
- if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER; // date created
- if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
- // keywords follow
- ALOGV("name: %s format: 0x%04X (%s)\n", (const char*)name, format,
- MtpDebug::getFormatCodeName(format));
- time_t modifiedTime;
- if (!parseDateTime(modified, modifiedTime))
- modifiedTime = 0;
- if (path[path.size() - 1] != '/')
- path.append("/");
- path.append(name);
- // check space first
- if (mSendObjectFileSize > storage->getFreeSpace())
- return MTP_RESPONSE_STORAGE_FULL;
- uint64_t maxFileSize = storage->getMaxFileSize();
- // check storage max file size
- if (maxFileSize != 0) {
- // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
- // is >= 0xFFFFFFFF
- if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
- return MTP_RESPONSE_OBJECT_TOO_LARGE;
- }
- ALOGV("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
- MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, format,
- parent, storageID);
- ALOGD("handle: %d, parent: %d, storageID: %08X", handle, parent, storageID);
- if (handle == kInvalidObjectHandle) {
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- if (format == MTP_FORMAT_ASSOCIATION) {
- int ret = makeFolder((const char *)path);
- if (ret)
- return MTP_RESPONSE_GENERAL_ERROR;
- // SendObject does not get sent for directories, so call endSendObject here instead
- mDatabase->endSendObject(handle, MTP_RESPONSE_OK);
- }
- mSendObjectFilePath = path;
- // save the handle for the SendObject call, which should follow
- mSendObjectHandle = handle;
- mSendObjectFormat = format;
- mSendObjectModifiedTime = modifiedTime;
- mResponse.setParameter(1, storageID);
- mResponse.setParameter(2, parent);
- mResponse.setParameter(3, handle);
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doMoveObject() {
- if (!hasStorage())
- return MTP_RESPONSE_GENERAL_ERROR;
- if (mRequest.getParameterCount() < 3)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle objectHandle = mRequest.getParameter(1);
- MtpStorageID storageID = mRequest.getParameter(2);
- MtpStorage* storage = getStorage(storageID);
- MtpObjectHandle parent = mRequest.getParameter(3);
- if (!storage)
- return MTP_RESPONSE_INVALID_STORAGE_ID;
- MtpStringBuffer path;
- MtpResponseCode result;
- MtpStringBuffer fromPath;
- int64_t fileLength;
- MtpObjectFormat format;
- MtpObjectInfo info(objectHandle);
- result = mDatabase->getObjectInfo(objectHandle, info);
- if (result != MTP_RESPONSE_OK)
- return result;
- result = mDatabase->getObjectFilePath(objectHandle, fromPath, fileLength, format);
- if (result != MTP_RESPONSE_OK)
- return result;
- // special case the root
- if (parent == 0) {
- path.set(storage->getPath());
- } else {
- int64_t parentLength;
- MtpObjectFormat parentFormat;
- result = mDatabase->getObjectFilePath(parent, path, parentLength, parentFormat);
- if (result != MTP_RESPONSE_OK)
- return result;
- if (parentFormat != MTP_FORMAT_ASSOCIATION)
- return MTP_RESPONSE_INVALID_PARENT_OBJECT;
- }
- if (path[path.size() - 1] != '/')
- path.append("/");
- path.append(info.mName);
- result = mDatabase->beginMoveObject(objectHandle, parent, storageID);
- if (result != MTP_RESPONSE_OK)
- return result;
- if (info.mStorageID == storageID) {
- ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
- if (renameTo(fromPath, path)) {
- PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path;
- result = MTP_RESPONSE_GENERAL_ERROR;
- }
- } else {
- ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path);
- if (format == MTP_FORMAT_ASSOCIATION) {
- int ret = makeFolder((const char *)path);
- ret += copyRecursive(fromPath, path);
- if (ret) {
- result = MTP_RESPONSE_GENERAL_ERROR;
- } else {
- deletePath(fromPath);
- }
- } else {
- if (copyFile(fromPath, path)) {
- result = MTP_RESPONSE_GENERAL_ERROR;
- } else {
- deletePath(fromPath);
- }
- }
- }
- // If the move failed, undo the database change
- mDatabase->endMoveObject(info.mParent, parent, info.mStorageID, storageID, objectHandle,
- result == MTP_RESPONSE_OK);
- return result;
- }
- MtpResponseCode MtpServer::doCopyObject() {
- if (!hasStorage())
- return MTP_RESPONSE_GENERAL_ERROR;
- MtpResponseCode result = MTP_RESPONSE_OK;
- if (mRequest.getParameterCount() < 3)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle objectHandle = mRequest.getParameter(1);
- MtpStorageID storageID = mRequest.getParameter(2);
- MtpStorage* storage = getStorage(storageID);
- MtpObjectHandle parent = mRequest.getParameter(3);
- if (!storage)
- return MTP_RESPONSE_INVALID_STORAGE_ID;
- MtpStringBuffer path;
- MtpStringBuffer fromPath;
- int64_t fileLength;
- MtpObjectFormat format;
- MtpObjectInfo info(objectHandle);
- result = mDatabase->getObjectInfo(objectHandle, info);
- if (result != MTP_RESPONSE_OK)
- return result;
- result = mDatabase->getObjectFilePath(objectHandle, fromPath, fileLength, format);
- if (result != MTP_RESPONSE_OK)
- return result;
- // special case the root
- if (parent == 0) {
- path.set(storage->getPath());
- } else {
- int64_t parentLength;
- MtpObjectFormat parentFormat;
- result = mDatabase->getObjectFilePath(parent, path, parentLength, parentFormat);
- if (result != MTP_RESPONSE_OK)
- return result;
- if (parentFormat != MTP_FORMAT_ASSOCIATION)
- return MTP_RESPONSE_INVALID_PARENT_OBJECT;
- }
- // check space first
- if ((uint64_t) fileLength > storage->getFreeSpace())
- return MTP_RESPONSE_STORAGE_FULL;
- if (path[path.size() - 1] != '/')
- path.append("/");
- path.append(info.mName);
- MtpObjectHandle handle = mDatabase->beginCopyObject(objectHandle, parent, storageID);
- if (handle == kInvalidObjectHandle) {
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path);
- if (format == MTP_FORMAT_ASSOCIATION) {
- int ret = makeFolder((const char *)path);
- ret += copyRecursive(fromPath, path);
- if (ret) {
- result = MTP_RESPONSE_GENERAL_ERROR;
- }
- } else {
- if (copyFile(fromPath, path)) {
- result = MTP_RESPONSE_GENERAL_ERROR;
- }
- }
- mDatabase->endCopyObject(handle, result);
- mResponse.setParameter(1, handle);
- return result;
- }
- MtpResponseCode MtpServer::doSendObject() {
- if (!hasStorage())
- return MTP_RESPONSE_GENERAL_ERROR;
- MtpResponseCode result = MTP_RESPONSE_OK;
- mode_t mask;
- int ret, initialData;
- bool isCanceled = false;
- struct stat sstat = {};
- auto start = std::chrono::steady_clock::now();
- if (mSendObjectHandle == kInvalidObjectHandle) {
- ALOGE("Expected SendObjectInfo before SendObject");
- result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
- goto done;
- }
- // read the header, and possibly some data
- ret = mData.read(mHandle);
- if (ret < MTP_CONTAINER_HEADER_SIZE) {
- result = MTP_RESPONSE_GENERAL_ERROR;
- goto done;
- }
- initialData = ret - MTP_CONTAINER_HEADER_SIZE;
- if (mSendObjectFormat == MTP_FORMAT_ASSOCIATION) {
- if (initialData != 0)
- ALOGE("Expected folder size to be 0!");
- mSendObjectHandle = kInvalidObjectHandle;
- mSendObjectFormat = 0;
- mSendObjectModifiedTime = 0;
- return result;
- }
- mtp_file_range mfr;
- mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
- if (mfr.fd < 0) {
- result = MTP_RESPONSE_GENERAL_ERROR;
- goto done;
- }
- fchown(mfr.fd, getuid(), FILE_GROUP);
- // set permissions
- mask = umask(0);
- fchmod(mfr.fd, FILE_PERM);
- umask(mask);
- if (initialData > 0) {
- ret = write(mfr.fd, mData.getData(), initialData);
- }
- if (ret < 0) {
- ALOGE("failed to write initial data");
- result = MTP_RESPONSE_GENERAL_ERROR;
- } else {
- mfr.offset = initialData;
- if (mSendObjectFileSize == 0xFFFFFFFF) {
- // tell driver to read until it receives a short packet
- mfr.length = 0xFFFFFFFF;
- } else {
- mfr.length = mSendObjectFileSize - initialData;
- }
- mfr.command = 0;
- mfr.transaction_id = 0;
- // transfer the file
- ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
- initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
- if ((ret < 0) && (errno == ECANCELED)) {
- isCanceled = true;
- }
- }
- if (mSendObjectModifiedTime) {
- struct timespec newTime[2];
- newTime[0].tv_nsec = UTIME_NOW;
- newTime[1].tv_sec = mSendObjectModifiedTime;
- newTime[1].tv_nsec = 0;
- if (futimens(mfr.fd, newTime) < 0) {
- ALOGW("changing modified time failed, %s", strerror(errno));
- }
- }
- fstat(mfr.fd, &sstat);
- closeObjFd(mfr.fd, mSendObjectFilePath);
- if (ret < 0) {
- ALOGE("Mtp receive file got error %s", strerror(errno));
- unlink(mSendObjectFilePath);
- if (isCanceled)
- result = MTP_RESPONSE_TRANSACTION_CANCELLED;
- else
- result = MTP_RESPONSE_GENERAL_ERROR;
- }
- done:
- // reset so we don't attempt to send the data back
- mData.reset();
- mDatabase->endSendObject(mSendObjectHandle, result == MTP_RESPONSE_OK);
- mSendObjectHandle = kInvalidObjectHandle;
- mSendObjectFormat = 0;
- mSendObjectModifiedTime = 0;
- auto end = std::chrono::steady_clock::now();
- std::chrono::duration<double> diff = end - start;
- uint64_t finalsize = sstat.st_size;
- ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
- diff.count(), finalsize, ((double) finalsize) / diff.count());
- return result;
- }
- MtpResponseCode MtpServer::doDeleteObject() {
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- MtpObjectFormat format;
- // FIXME - support deleting all objects if handle is 0xFFFFFFFF
- // FIXME - implement deleting objects by format
- MtpStringBuffer filePath;
- int64_t fileLength;
- int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
- if (result != MTP_RESPONSE_OK)
- return result;
- // Don't delete the actual files unless the database deletion is allowed
- result = mDatabase->beginDeleteObject(handle);
- if (result != MTP_RESPONSE_OK)
- return result;
- bool success = deletePath((const char *)filePath);
- mDatabase->endDeleteObject(handle, success);
- return success ? result : MTP_RESPONSE_PARTIAL_DELETION;
- }
- MtpResponseCode MtpServer::doGetObjectPropDesc() {
- if (mRequest.getParameterCount() < 2)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectProperty propCode = mRequest.getParameter(1);
- MtpObjectFormat format = mRequest.getParameter(2);
- ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
- MtpDebug::getFormatCodeName(format));
- MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
- if (!property)
- return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
- property->write(mData);
- delete property;
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doGetDevicePropDesc() {
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpDeviceProperty propCode = mRequest.getParameter(1);
- ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
- MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
- if (!property)
- return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
- property->write(mData);
- delete property;
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doSendPartialObject() {
- if (!hasStorage())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- if (mRequest.getParameterCount() < 4)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- uint64_t offset = mRequest.getParameter(2);
- uint64_t offset2 = mRequest.getParameter(3);
- offset = offset | (offset2 << 32);
- uint32_t length = mRequest.getParameter(4);
- ObjectEdit* edit = getEditObject(handle);
- if (!edit) {
- ALOGE("object not open for edit in doSendPartialObject");
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- // can't start writing past the end of the file
- if (offset > edit->mSize) {
- ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
- offset, edit->mSize);
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- const char* filePath = (const char *)edit->mPath;
- ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
- // read the header, and possibly some data
- int ret = mData.read(mHandle);
- if (ret < MTP_CONTAINER_HEADER_SIZE)
- return MTP_RESPONSE_GENERAL_ERROR;
- int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
- if (initialData > 0) {
- ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
- offset += initialData;
- length -= initialData;
- }
- bool isCanceled = false;
- if (ret < 0) {
- ALOGE("failed to write initial data");
- } else {
- mtp_file_range mfr;
- mfr.fd = edit->mFD;
- mfr.offset = offset;
- mfr.length = length;
- mfr.command = 0;
- mfr.transaction_id = 0;
- // transfer the file
- ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
- initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
- if ((ret < 0) && (errno == ECANCELED)) {
- isCanceled = true;
- }
- }
- if (ret < 0) {
- mResponse.setParameter(1, 0);
- if (isCanceled)
- return MTP_RESPONSE_TRANSACTION_CANCELLED;
- else
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- // reset so we don't attempt to send this back
- mData.reset();
- mResponse.setParameter(1, length);
- uint64_t end = offset + length;
- if (end > edit->mSize) {
- edit->mSize = end;
- }
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doTruncateObject() {
- if (mRequest.getParameterCount() < 3)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- ObjectEdit* edit = getEditObject(handle);
- if (!edit) {
- ALOGE("object not open for edit in doTruncateObject");
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- uint64_t offset = mRequest.getParameter(2);
- uint64_t offset2 = mRequest.getParameter(3);
- offset |= (offset2 << 32);
- if (ftruncate(edit->mFD, offset) != 0) {
- return MTP_RESPONSE_GENERAL_ERROR;
- } else {
- edit->mSize = offset;
- return MTP_RESPONSE_OK;
- }
- }
- MtpResponseCode MtpServer::doBeginEditObject() {
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- if (getEditObject(handle)) {
- ALOGE("object already open for edit in doBeginEditObject");
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- MtpStringBuffer path;
- int64_t fileLength;
- MtpObjectFormat format;
- int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
- if (result != MTP_RESPONSE_OK)
- return result;
- int fd = open((const char *)path, O_RDWR | O_EXCL);
- if (fd < 0) {
- ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- addEditObject(handle, path, fileLength, format, fd);
- return MTP_RESPONSE_OK;
- }
- MtpResponseCode MtpServer::doEndEditObject() {
- if (mRequest.getParameterCount() < 1)
- return MTP_RESPONSE_INVALID_PARAMETER;
- MtpObjectHandle handle = mRequest.getParameter(1);
- ObjectEdit* edit = getEditObject(handle);
- if (!edit) {
- ALOGE("object not open for edit in doEndEditObject");
- return MTP_RESPONSE_GENERAL_ERROR;
- }
- commitEdit(edit);
- removeEditObject(handle);
- return MTP_RESPONSE_OK;
- }
- } // namespace android
|