diff options
Diffstat (limited to 'mtp/MtpServer.cpp')
-rw-r--r-- | mtp/MtpServer.cpp | 1379 |
1 files changed, 0 insertions, 1379 deletions
diff --git a/mtp/MtpServer.cpp b/mtp/MtpServer.cpp deleted file mode 100644 index 11eca86bc..000000000 --- a/mtp/MtpServer.cpp +++ /dev/null @@ -1,1379 +0,0 @@ -/* - * Copyright (C) 2017 TeamWin - * 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 <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/stat.h> -#include <dirent.h> -#include "../twcommon.h" -#include "../set_metadata.h" -#include <cutils/properties.h> - -#include "MtpTypes.h" -#include "MtpDebug.h" -#include "MtpDatabase.h" -#include "MtpObjectInfo.h" -#include "MtpProperty.h" -#include "MtpServer.h" -#include "MtpStorage.h" -#include "MtpStringBuffer.h" - -#include <linux/usb/f_mtp.h> - -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_OBJECT_PROP_CHANGED, -}; - -MtpServer::MtpServer(MtpDatabase* database, bool ptp, - int fileGroup, int filePerm, int directoryPerm) - : mDatabase(database), - mPtp(ptp), - mFileGroup(fileGroup), - mFilePermission(filePerm), - mDirectoryPermission(directoryPerm), - mSessionID(0), - mSessionOpen(false), - mSendObjectHandle(kInvalidObjectHandle), - mSendObjectFormat(0), - mSendObjectFileSize(0) -{ - mFD = -1; -} - -MtpServer::~MtpServer() { -} - -void MtpServer::addStorage(MtpStorage* storage) { - android::Mutex::Autolock autoLock(mMutex); - MTPD("addStorage(): storage: %x\n", storage); - if (getStorage(storage->getStorageID()) != NULL) { - MTPE("MtpServer::addStorage Storage for storage ID %i already exists.\n", storage->getStorageID()); - return; - } - mDatabase->createDB(storage, storage->getStorageID()); - mStorages.push(storage); - sendStoreAdded(storage->getStorageID()); -} - -void MtpServer::removeStorage(MtpStorage* storage) { - android::Mutex::Autolock autoLock(mMutex); - - for (size_t i = 0; i < mStorages.size(); i++) { - if (mStorages[i] == storage) { - MTPD("MtpServer::removeStorage calling sendStoreRemoved\n"); - // First lock the mutex so that the inotify thread and main - // thread do not do anything while we remove the storage - // item, and to make sure we don't remove the item while an - // operation is in progress - mDatabase->lockMutex(); - // Grab the storage ID before we delete the item from the - // database - MtpStorageID storageID = storage->getStorageID(); - // Remove the item from the mStorages from the vector. At - // this point the main thread will no longer be able to find - // this storage item anymore. - mStorages.removeAt(i); - // Destroy the storage item, free up all the memory, kill - // the inotify thread. - mDatabase->destroyDB(storageID); - // Tell the host OS that the storage item is gone. - sendStoreRemoved(storageID); - // Unlock any remaining mutexes on other storage devices. - // If no storage devices exist anymore this will do nothing. - mDatabase->unlockMutex(); - break; - } - } - MTPD("MtpServer::removeStorage DONE\n"); -} - -MtpStorage* MtpServer::getStorage(MtpStorageID id) { - MTPD("getStorage\n"); - if (id == 0) { - MTPD("mStorages\n"); - return mStorages[0]; - } - for (size_t i = 0; i < mStorages.size(); i++) { - MtpStorage* storage = mStorages[i]; - MTPD("id: %d\n", id); - MTPD("storage: %d\n", storage->getStorageID()); - if (storage->getStorageID() == id) { - return storage; - } - } - return NULL; -} - -bool MtpServer::hasStorage(MtpStorageID id) { - MTPD("in hasStorage\n"); - if (id == 0 || id == 0xFFFFFFFF) - return mStorages.size() > 0; - return (getStorage(id) != NULL); -} - -void MtpServer::run(int fd) { - if (fd < 0) - return; - - mFD = fd; - MTPI("MtpServer::run fd: %d\n", fd); - - while (1) { - MTPD("About to read device...\n"); - int ret = mRequest.read(fd); - if (ret < 0) { - if (errno == ECANCELED) { - // return to top of loop and wait for next command - MTPD("request read returned %d ECANCELED, starting over\n", ret); - continue; - } - MTPE("request read returned %d, errno: %d, exiting MtpServer::run loop\n", ret, errno); - break; - } - MtpOperationCode operation = mRequest.getOperationCode(); - MtpTransactionID transaction = mRequest.getTransactionID(); - - MTPD("operation: %s", MtpDebug::getOperationCodeName(operation)); - mRequest.dump(); - - // 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(fd); - if (ret < 0) { - if (errno == ECANCELED) { - // return to top of loop and wait for next command - MTPD("data read returned %d ECANCELED, starting over\n", ret); - continue; - } - MTPD("data read returned %d, errno: %d, exiting MtpServer::run loop\n", ret, errno); - break; - } - MTPD("received data:"); - mData.dump(); - } else { - mData.reset(); - } - - if (handleRequest()) { - if (!dataIn && mData.hasData()) { - mData.setOperationCode(operation); - mData.setTransactionID(transaction); - MTPD("sending data:"); - mData.dump(); - ret = mData.write(fd); - if (ret < 0) { - if (errno == ECANCELED) { - // return to top of loop and wait for next command - MTPD("data write returned %d ECANCELED, starting over\n", ret); - continue; - } - MTPE("data write returned %d, errno: %d, exiting MtpServer::run loop\n", ret, errno); - break; - } - } - - mResponse.setTransactionID(transaction); - MTPD("sending response %04X\n", mResponse.getResponseCode()); - ret = mResponse.write(fd); - MTPD("ret: %d\n", ret); - mResponse.dump(); - if (ret < 0) { - if (errno == ECANCELED) { - // return to top of loop and wait for next command - MTPD("response write returned %d ECANCELED, starting over\n", ret); - continue; - } - MTPE("response write returned %d, errno: %d, exiting MtpServer::run loop\n", ret, errno); - break; - } - } else { - MTPD("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(); - - if (mSessionOpen) - mDatabase->sessionEnded(); // This doesn't actually do anything but was carry over from AOSP - close(fd); - mFD = -1; -} - -void MtpServer::sendObjectAdded(MtpObjectHandle handle) { - MTPD("sendObjectAdded %d\n", handle); - sendEvent(MTP_EVENT_OBJECT_ADDED, handle); -} - -void MtpServer::sendObjectRemoved(MtpObjectHandle handle) { - MTPD("sendObjectRemoved %d\n", handle); - sendEvent(MTP_EVENT_OBJECT_REMOVED, handle); -} - -void MtpServer::sendObjectUpdated(MtpObjectHandle handle) { - MTPD("sendObjectUpdated %d\n", handle); - sendEvent(MTP_EVENT_OBJECT_PROP_CHANGED, handle); -} - -void MtpServer::sendStoreAdded(MtpStorageID id) { - MTPD("sendStoreAdded %08X\n", id); - sendEvent(MTP_EVENT_STORE_ADDED, id); -} - -void MtpServer::sendStoreRemoved(MtpStorageID id) { - MTPD("sendStoreRemoved %08X\n", id); - sendEvent(MTP_EVENT_STORE_REMOVED, id); - MTPD("MtpServer::sendStoreRemoved done\n"); -} - -void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) { - MTPD("MtpServer::sendEvent sending event code: %x\n", code); - if (mSessionOpen) { - mEvent.setEventCode(code); - mEvent.setTransactionID(mRequest.getTransactionID()); - mEvent.setParameter(1, param1); - int ret = mEvent.write(mFD); - MTPD("mEvent.write returned %d\n", ret); - } -} - -void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path, - uint64_t size, MtpObjectFormat format, int fd) { - ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd); - mObjectEditList.add(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 NULL; -} - -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.removeAt(i); - return; - } - } - MTPE("ObjectEdit not found in removeEditObject"); -} - -void MtpServer::commitEdit(ObjectEdit* edit) { - mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true); -} - - -bool MtpServer::handleRequest() { - android::Mutex::Autolock autoLock(mMutex); - - MtpOperationCode operation = mRequest.getOperationCode(); - MtpResponseCode response; - - mResponse.reset(); - - if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) { - // FIXME - need to delete mSendObjectHandle from the database - MTPE("expected SendObject after SendObjectInfo"); - mSendObjectHandle = kInvalidObjectHandle; - } - - switch (operation) { - case MTP_OPERATION_GET_DEVICE_INFO: - MTPD("doGetDeviceInfo()\n"); - response = doGetDeviceInfo(); - break; - case MTP_OPERATION_OPEN_SESSION: - MTPD("doOpenSesion()\n"); - response = doOpenSession(); - break; - case MTP_OPERATION_CLOSE_SESSION: - MTPD("doCloseSession()\n"); - response = doCloseSession(); - break; - case MTP_OPERATION_GET_STORAGE_IDS: - MTPD("doGetStorageIDs()\n"); - response = doGetStorageIDs(); - break; - case MTP_OPERATION_GET_STORAGE_INFO: - MTPD("about to call doGetStorageInfo()\n"); - response = doGetStorageInfo(); - break; - case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED: - MTPD("about to call doGetObjectPropsSupported()\n"); - response = doGetObjectPropsSupported(); - break; - case MTP_OPERATION_GET_OBJECT_HANDLES: - MTPD("about to call doGetObjectHandles()\n"); - response = doGetObjectHandles(); - break; - case MTP_OPERATION_GET_NUM_OBJECTS: - MTPD("about to call doGetNumbObjects()\n"); - response = doGetNumObjects(); - break; - case MTP_OPERATION_GET_OBJECT_REFERENCES: - MTPD("about to call doGetObjectReferences()\n"); - response = doGetObjectReferences(); - break; - case MTP_OPERATION_SET_OBJECT_REFERENCES: - MTPD("about to call doSetObjectReferences()\n"); - response = doSetObjectReferences(); - break; - case MTP_OPERATION_GET_OBJECT_PROP_VALUE: - MTPD("about to call doGetObjectPropValue()\n"); - response = doGetObjectPropValue(); - break; - case MTP_OPERATION_SET_OBJECT_PROP_VALUE: - MTPD("about to call doSetObjectPropValue()\n"); - response = doSetObjectPropValue(); - break; - case MTP_OPERATION_GET_DEVICE_PROP_VALUE: - MTPD("about to call doGetDevicPropValue()\n"); - response = doGetDevicePropValue(); - break; - case MTP_OPERATION_SET_DEVICE_PROP_VALUE: - MTPD("about to call doSetDevicePropVaue()\n"); - response = doSetDevicePropValue(); - break; - case MTP_OPERATION_RESET_DEVICE_PROP_VALUE: - MTPD("about to call doResetDevicePropValue()\n"); - response = doResetDevicePropValue(); - break; - case MTP_OPERATION_GET_OBJECT_PROP_LIST: - MTPD("calling doGetObjectPropList()\n"); - response = doGetObjectPropList(); - break; - case MTP_OPERATION_GET_OBJECT_INFO: - MTPD("calling doGetObjectInfo()\n"); - response = doGetObjectInfo(); - break; - case MTP_OPERATION_GET_OBJECT: - MTPD("about to call doGetObject()\n"); - 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: - MTPD("about to call doSendObjectInfo()\n"); - response = doSendObjectInfo(); - break; - case MTP_OPERATION_SEND_OBJECT: - MTPD("about to call doSendObject()\n"); - response = doSendObject(); - break; - case MTP_OPERATION_DELETE_OBJECT: - response = doDeleteObject(); - break; - case MTP_OPERATION_GET_OBJECT_PROP_DESC: - MTPD("about to call doGetObjectPropDesc()\n"); - response = doGetObjectPropDesc(); - break; - case MTP_OPERATION_GET_DEVICE_PROP_DESC: - MTPD("about to call doGetDevicePropDesc()\n"); - 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: - MTPE("got unsupported command %s", MtpDebug::getOperationCodeName(operation)); - response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; - break; - } - - if (response == MTP_RESPONSE_TRANSACTION_CANCELLED) - return false; - mResponse.setResponseCode(response); - return true; -} - -MtpResponseCode MtpServer::doGetDeviceInfo() { - MtpStringBuffer string; - char prop_value[PROPERTY_VALUE_MAX]; - - MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats(); - MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats(); - MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties(); - - // fill in device info - mData.putUInt16(MTP_STANDARD_VERSION); - if (mPtp) { - MTPD("doGetDeviceInfo putting 0\n"); - mData.putUInt32(0); - } else { - // MTP Vendor Extension ID - MTPD("doGetDeviceInfo putting 6\n"); - mData.putUInt32(6); - } - mData.putUInt16(MTP_STANDARD_VERSION); - if (mPtp) { - // no extensions - MTPD("doGetDeviceInfo no extensions\n"); - string.set(""); - } else { - // MTP extensions - MTPD("doGetDeviceInfo microsoft.com: 1.0; android.com: 1.0;\n"); - string.set("microsoft.com: 1.0; android.com: 1.0;"); - } - mData.putString(string); // MTP Extensions - mData.putUInt16(0); //Functional Mode - MTPD("doGetDeviceInfo opcodes, %i\n", sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); - MTPD("doGetDeviceInfo eventcodes, %i\n", sizeof(kSupportedEventCodes) / sizeof(uint16_t)); - 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 - - property_get("ro.product.manufacturer", prop_value, "unknown manufacturer"); - MTPD("prop: %s\n", prop_value); - string.set(prop_value); - mData.putString(string); // Manufacturer - - property_get("ro.product.model", prop_value, "MTP Device"); - string.set(prop_value); - mData.putString(string); // Model - string.set("1.0"); - mData.putString(string); // Device Version - - property_get("ro.serialno", prop_value, "????????"); - MTPD("sn: %s\n", prop_value); - string.set(prop_value); - mData.putString(string); // 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; - } - mSessionID = mRequest.getParameter(1); - mSessionOpen = true; - - mDatabase->sessionStarted(); - - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doCloseSession() { - if (!mSessionOpen) - return MTP_RESPONSE_SESSION_NOT_OPEN; - mSessionID = 0; - mSessionOpen = false; - mDatabase->sessionEnded(); - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doGetStorageIDs() { - MTPD("doGetStorageIDs()\n"); - if (!mSessionOpen) - return MTP_RESPONSE_SESSION_NOT_OPEN; - int count = mStorages.size(); - mData.putUInt32(count); - for (int i = 0; i < count; i++) { - MTPD("getting storageid %d\n", mStorages[i]->getStorageID()); - mData.putUInt32(mStorages[i]->getStorageID()); - } - - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doGetStorageInfo() { - MtpStringBuffer string; - MTPD("doGetStorageInfo()\n"); - if (!mSessionOpen) - return MTP_RESPONSE_SESSION_NOT_OPEN; - MtpStorageID id = mRequest.getParameter(1); - MtpStorage* storage = getStorage(id); - if (!storage) { - MTPE("invalid storage id\n"); - 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() { - MTPD("doGetObjectPropsSupported()\n"); - if (!mSessionOpen) - return MTP_RESPONSE_SESSION_NOT_OPEN; - MtpObjectFormat format = mRequest.getParameter(1); - mDatabase->lockMutex(); - MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format); - mData.putAUInt16(properties); - delete properties; - mDatabase->unlockMutex(); - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doGetObjectHandles() { - if (!mSessionOpen) - return MTP_RESPONSE_SESSION_NOT_OPEN; - 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; - - MTPD("calling MtpDatabase->getObjectList()\n"); - mDatabase->lockMutex(); - MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent); - mData.putAUInt32(handles); - delete handles; - mDatabase->unlockMutex(); - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doGetNumObjects() { - if (!mSessionOpen) - return MTP_RESPONSE_SESSION_NOT_OPEN; - 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; - - mDatabase->lockMutex(); - int count = mDatabase->getNumObjects(storageID, format, parent); - mDatabase->unlockMutex(); - 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; - MtpObjectHandle handle = mRequest.getParameter(1); - - // FIXME - check for invalid object handle - mDatabase->lockMutex(); - MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle); - if (handles) { - mData.putAUInt32(handles); - delete handles; - } else { - MTPD("MtpServer::doGetObjectReferences putEmptyArray\n"); - mData.putEmptyArray(); - } - mDatabase->unlockMutex(); - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doSetObjectReferences() { - if (!mSessionOpen) - return MTP_RESPONSE_SESSION_NOT_OPEN; - if (!hasStorage()) - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - MtpStorageID handle = mRequest.getParameter(1); - - MtpObjectHandleList* references = mData.getAUInt32(); - mDatabase->lockMutex(); - MtpResponseCode result = mDatabase->setObjectReferences(handle, references); - mDatabase->unlockMutex(); - delete references; - return result; -} - -MtpResponseCode MtpServer::doGetObjectPropValue() { - if (!hasStorage()) - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - MtpObjectHandle handle = mRequest.getParameter(1); - MtpObjectProperty property = mRequest.getParameter(2); - MTPD("GetObjectPropValue %d %s\n", handle, - MtpDebug::getObjectPropCodeName(property)); - - mDatabase->lockMutex(); - MtpResponseCode res = mDatabase->getObjectPropertyValue(handle, property, mData); - mDatabase->unlockMutex(); - return res; -} - -MtpResponseCode MtpServer::doSetObjectPropValue() { - if (!hasStorage()) - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - MtpObjectHandle handle = mRequest.getParameter(1); - MtpObjectProperty property = mRequest.getParameter(2); - MTPD("SetObjectPropValue %d %s\n", handle, - MtpDebug::getObjectPropCodeName(property)); - - mDatabase->lockMutex(); - MtpResponseCode res = mDatabase->setObjectPropertyValue(handle, property, mData); - mDatabase->unlockMutex(); - return res; -} - -MtpResponseCode MtpServer::doGetDevicePropValue() { - MtpDeviceProperty property = mRequest.getParameter(1); - MTPD("GetDevicePropValue %s\n", - MtpDebug::getDevicePropCodeName(property)); - - mDatabase->lockMutex(); - MtpResponseCode res = mDatabase->getDevicePropertyValue(property, mData); - mDatabase->unlockMutex(); - return res; -} - -MtpResponseCode MtpServer::doSetDevicePropValue() { - MtpDeviceProperty property = mRequest.getParameter(1); - MTPD("SetDevicePropValue %s\n", - MtpDebug::getDevicePropCodeName(property)); - - mDatabase->lockMutex(); - MtpResponseCode res = mDatabase->setDevicePropertyValue(property, mData); - mDatabase->unlockMutex(); - return res; -} - -MtpResponseCode MtpServer::doResetDevicePropValue() { - MtpDeviceProperty property = mRequest.getParameter(1); - MTPD("ResetDevicePropValue %s\n", - MtpDebug::getDevicePropCodeName(property)); - - mDatabase->lockMutex(); - MtpResponseCode res = mDatabase->resetDeviceProperty(property); - mDatabase->unlockMutex(); - return res; -} - -MtpResponseCode MtpServer::doGetObjectPropList() { - if (!hasStorage()) - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - - 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); - MTPD("GetObjectPropList %d format: %s property: %x group: %d depth: %d\n", - handle, MtpDebug::getFormatCodeName(format), - property, groupCode, depth); - - mDatabase->lockMutex(); - MtpResponseCode res = mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData); - mDatabase->unlockMutex(); - return res; -} - -MtpResponseCode MtpServer::doGetObjectInfo() { - MTPD("inside doGetObjectInfo()\n"); - if (!hasStorage()) - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - MtpObjectHandle handle = mRequest.getParameter(1); - MtpObjectInfo info(handle); - MTPD("calling mtpdatabase getObjectInfo()\n"); - mDatabase->lockMutex(); - MtpResponseCode result = mDatabase->getObjectInfo(handle, info); - mDatabase->unlockMutex(); - 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); - MTPD("info.mName: %s\n", info.mName); - mData.putString(info.mName); - mData.putEmptyString(); // 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; - MtpObjectHandle handle = mRequest.getParameter(1); - MtpString pathBuf; - int64_t fileLength; - MtpObjectFormat format; - MTPD("MtpServer::doGetObject calling getObjectFilePath\n"); - mDatabase->lockMutex(); - int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format); - mDatabase->unlockMutex(); - if (result != MTP_RESPONSE_OK) - return result; - - const char* filePath = (const char *)pathBuf; - MTPD("filePath: %s\n", filePath); - 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; - MTPD("mfr.length: %lld\n", mfr.length); - mfr.command = mRequest.getOperationCode(); - mfr.transaction_id = mRequest.getTransactionID(); - - // then transfer the file - int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr); - MTPD("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret); - close(mfr.fd); - if (ret < 0) { - if (errno == ECANCELED) - return MTP_RESPONSE_TRANSACTION_CANCELLED; - else - return MTP_RESPONSE_GENERAL_ERROR; - } - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doGetThumb() { - MtpObjectHandle handle = mRequest.getParameter(1); - size_t thumbSize; - mDatabase->lockMutex(); - void* thumb = mDatabase->getThumbnail(handle, thumbSize); - mDatabase->unlockMutex(); - if (thumb) { - // send data - mData.setOperationCode(mRequest.getOperationCode()); - mData.setTransactionID(mRequest.getTransactionID()); - mData.writeData(mFD, 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) { - // android extension with 64 bit offset - uint64_t offset2 = mRequest.getParameter(3); - offset = offset | (offset2 << 32); - length = mRequest.getParameter(4); - } else { - // standard GetPartialObject - length = mRequest.getParameter(3); - } - MtpString pathBuf; - int64_t fileLength; - MtpObjectFormat format; - MTPD("MtpServer::doGetPartialObject calling getObjectFilePath\n"); - mDatabase->lockMutex(); - int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format); - mDatabase->unlockMutex(); - if (result != MTP_RESPONSE_OK) { - return result; - } - if (offset + length > (uint64_t)fileLength) - length = fileLength - offset; - - 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 = offset; - mfr.length = length; - mfr.command = mRequest.getOperationCode(); - mfr.transaction_id = mRequest.getTransactionID(); - mResponse.setParameter(1, length); - - // transfer the file - int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr); - MTPD("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret); - close(mfr.fd); - if (ret < 0) { - if (errno == ECANCELED) - return MTP_RESPONSE_TRANSACTION_CANCELLED; - else - return MTP_RESPONSE_GENERAL_ERROR; - } - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doSendObjectInfo() { - MTPD("MtpServer::doSendObjectInfo starting\n"); - MtpString path; - 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) { - MTPD("MtpServer::doSendObjectInfo special case root\n"); - path = storage->getPath(); - parent = 0; - } else { - int64_t length; - MtpObjectFormat format; - MTPD("MtpServer::doSendObjectInfo calling getObjectFilePath\n"); - mDatabase->lockMutex(); - int result = mDatabase->getObjectFilePath(parent, path, length, format); - mDatabase->unlockMutex(); - if (result != MTP_RESPONSE_OK) { - return result; - } - if (format != MTP_FORMAT_ASSOCIATION) - return MTP_RESPONSE_INVALID_PARENT_OBJECT; - } - - // read only the fields we need - mData.getUInt32(); // storage ID - MtpObjectFormat format = mData.getUInt16(); - mData.getUInt16(); // protection status - mSendObjectFileSize = mData.getUInt32(); - mData.getUInt16(); // thumb format - mData.getUInt32(); // thumb compressed size - mData.getUInt32(); // thumb pix width - mData.getUInt32(); // thumb pix height - mData.getUInt32(); // image pix width - mData.getUInt32(); // image pix height - mData.getUInt32(); // image bit depth - mData.getUInt32(); // parent - uint16_t associationType = mData.getUInt16(); - uint32_t associationDesc = mData.getUInt32(); // association desc - mData.getUInt32(); // sequence number - MtpStringBuffer name, created, modified; - mData.getString(name); // file name - mData.getString(created); // date created - mData.getString(modified); // date modified - // keywords follow - - MTPD("name: %s format: %04X\n", (const char *)name, format); - time_t modifiedTime; - if (!parseDateTime(modified, modifiedTime)) { - modifiedTime = 0; - } - if (path[path.size() - 1] != '/') { - path += "/"; - } - path += (const char *)name; - - // check space first - if (mSendObjectFileSize > storage->getFreeSpace()) - return MTP_RESPONSE_STORAGE_FULL; - uint64_t maxFileSize = storage->getMaxFileSize(); - // check storage max file size - MTPD("maxFileSize: %ld\n", maxFileSize); - 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; - } - - MTPD("MtpServer::doSendObjectInfo path: %s parent: %d storageID: %08X\n", (const char*)path, parent, storageID); - mDatabase->lockMutex(); - MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, - format, parent, storageID, mSendObjectFileSize, modifiedTime); - mDatabase->unlockMutex(); - if (handle == kInvalidObjectHandle) { - MTPE("MtpServer::doSendObjectInfo returning MTP_RESPONSE_GENERAL_ERROR, handle == kInvalidObjectHandle\n"); - return MTP_RESPONSE_GENERAL_ERROR; - } - - if (format == MTP_FORMAT_ASSOCIATION) { - mode_t mask = umask(0); - MTPD("MtpServer::doSendObjectInfo mkdir '%s'\n", (const char *)path); - int ret = mkdir((const char *)path, mDirectoryPermission); - umask(mask); - if (ret && ret != -EEXIST) { - MTPE("MtpServer::doSendObjectInfo returning MTP_RESPONSE_GENERAL_ERROR, ret && ret != -EEXIST\n"); - return MTP_RESPONSE_GENERAL_ERROR; - } - chown((const char *)path, getuid(), mFileGroup); - tw_set_default_metadata((const char *)path); - - // SendObject does not get sent for directories, so call endSendObject here instead - mDatabase->lockMutex(); - mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK); - mDatabase->unlockMutex(); - } else { - mSendObjectFilePath = path; - // save the handle for the SendObject call, which should follow - mSendObjectHandle = handle; - mSendObjectFormat = format; - } - - mResponse.setParameter(1, storageID); - mResponse.setParameter(2, parent); - mResponse.setParameter(3, handle); - MTPD("MtpServer::doSendObjectInfo returning MTP_RESPONSE_OK\n"); - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doSendObject() { - if (!hasStorage()) - return MTP_RESPONSE_GENERAL_ERROR; - MtpResponseCode result = MTP_RESPONSE_OK; - mode_t mask; - int ret = 0, initialData; - - if (mSendObjectHandle == kInvalidObjectHandle) { - MTPE("Expected SendObjectInfo before SendObject"); - result = MTP_RESPONSE_NO_VALID_OBJECT_INFO; - goto done; - } - - // read the header, and possibly some data - ret = mData.read(mFD); - if (ret < MTP_CONTAINER_HEADER_SIZE) { - MTPE("MTP_RESPONSE_GENERAL_ERROR\n"); - result = MTP_RESPONSE_GENERAL_ERROR; - goto done; - } - initialData = ret - MTP_CONTAINER_HEADER_SIZE; - - mtp_file_range mfr; - mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, 0640); - if (mfr.fd < 0) { - result = MTP_RESPONSE_GENERAL_ERROR; - MTPE("fd error\n"); - goto done; - } - fchown(mfr.fd, getuid(), mFileGroup); - // set permissions - mask = umask(0); - fchmod(mfr.fd, mFilePermission); - umask(mask); - - if (initialData > 0) - ret = write(mfr.fd, mData.getData(), initialData); - - if (mSendObjectFileSize - initialData > 0) { - mfr.offset = initialData; - if (mSendObjectFileSize == 0xFFFFFFFF) { - // tell driver to read until it receives a short packet - mfr.length = 0xFFFFFFFF; - } else { - mfr.length = mSendObjectFileSize - initialData; - } - - MTPD("receiving %s\n", (const char *)mSendObjectFilePath); - // transfer the file - ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); - } - close(mfr.fd); - tw_set_default_metadata((const char *)mSendObjectFilePath); - - if (ret < 0) { - unlink(mSendObjectFilePath); - if (errno == ECANCELED) - result = MTP_RESPONSE_TRANSACTION_CANCELLED; - else { - MTPD("errno: %d\n", errno); - result = MTP_RESPONSE_GENERAL_ERROR; - } - } - -done: - // reset so we don't attempt to send the data back - MTPD("MTP_RECEIVE_FILE returned %d\n", ret); - mData.reset(); - mDatabase->lockMutex(); - mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat, - result == MTP_RESPONSE_OK); - mDatabase->unlockMutex(); - mSendObjectHandle = kInvalidObjectHandle; - MTPD("result: %d\n", result); - mSendObjectFormat = 0; - return result; -} - -static void deleteRecursive(const char* path) { - char pathbuf[PATH_MAX]; - size_t pathLength = strlen(path); - if (pathLength >= sizeof(pathbuf) - 1) { - MTPE("path too long: %s\n", path); - } - strcpy(pathbuf, path); - if (pathbuf[pathLength - 1] != '/') { - pathbuf[pathLength++] = '/'; - } - char* fileSpot = pathbuf + pathLength; - int pathRemaining = sizeof(pathbuf) - pathLength - 1; - - DIR* dir = opendir(path); - if (!dir) { - MTPE("opendir %s failed: %s", path, strerror(errno)); - return; - } - - struct dirent* entry; - while ((entry = readdir(dir))) { - const char* name = entry->d_name; - - // ignore "." and ".." - if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { - continue; - } - - int nameLength = strlen(name); - if (nameLength > pathRemaining) { - MTPE("path %s/%s too long\n", path, name); - continue; - } - strcpy(fileSpot, name); - - int type = entry->d_type; - struct stat st; - if (lstat(pathbuf, &st)) { - MTPE("Failed to lstat '%s'\n", pathbuf); - continue; - } - if (st.st_mode & S_IFDIR) { - deleteRecursive(pathbuf); - rmdir(pathbuf); - } else { - unlink(pathbuf); - } - } - closedir(dir); -} - -static void deletePath(const char* path) { - struct stat statbuf; - if (stat(path, &statbuf) == 0) { - if (S_ISDIR(statbuf.st_mode)) { - deleteRecursive(path); - rmdir(path); - } else { - unlink(path); - } - } else { - MTPE("deletePath stat failed for %s: %s", path, strerror(errno)); - } -} - -MtpResponseCode MtpServer::doDeleteObject() { - if (!hasStorage()) - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - MtpObjectHandle handle = mRequest.getParameter(1); - MtpObjectFormat format = mRequest.getParameter(2); - // FIXME - support deleting all objects if handle is 0xFFFFFFFF - // FIXME - implement deleting objects by format - - MtpString filePath; - int64_t fileLength; - MTPD("MtpServer::doDeleteObject calling getObjectFilePath\n"); - mDatabase->lockMutex(); - int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format); - if (result == MTP_RESPONSE_OK) { - MTPD("deleting %s", (const char *)filePath); - result = mDatabase->deleteFile(handle); - // Don't delete the actual files unless the database deletion is allowed - if (result == MTP_RESPONSE_OK) { - deletePath((const char *)filePath); - } - } - mDatabase->unlockMutex(); - return result; -} - -MtpResponseCode MtpServer::doGetObjectPropDesc() { - MtpObjectProperty propCode = mRequest.getParameter(1); - MtpObjectFormat format = mRequest.getParameter(2); - MTPD("MtpServer::doGetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode), - MtpDebug::getFormatCodeName(format)); - mDatabase->lockMutex(); - MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format); - mDatabase->unlockMutex(); - if (!property) { - MTPE("MtpServer::doGetObjectPropDesc propery not supported\n"); - return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED; - } - property->write(mData); - delete property; - return MTP_RESPONSE_OK; -} - -MtpResponseCode MtpServer::doGetDevicePropDesc() { - MtpDeviceProperty propCode = mRequest.getParameter(1); - MTPD("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode)); - mDatabase->lockMutex(); - MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode); - mDatabase->unlockMutex(); - if (!property) { - MTPE("MtpServer::doGetDevicePropDesc property not supported\n"); - 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; - 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) { - MTPE("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) { - MTPE("writing past end of object, offset: %lld, edit->mSize: %lld", offset, edit->mSize); - return MTP_RESPONSE_GENERAL_ERROR; - } - - const char* filePath = (const char *)edit->mPath; - MTPD("receiving partial %s %lld %lld\n", filePath, offset, length); - - // read the header, and possibly some data - int ret = mData.read(mFD); - if (ret < MTP_CONTAINER_HEADER_SIZE) - return MTP_RESPONSE_GENERAL_ERROR; - int initialData = ret - MTP_CONTAINER_HEADER_SIZE; - - if (initialData > 0) { - ret = write(edit->mFD, mData.getData(), initialData); - offset += initialData; - length -= initialData; - } - - if (length > 0) { - mtp_file_range mfr; - mfr.fd = edit->mFD; - mfr.offset = offset; - mfr.length = length; - - // transfer the file - ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); - MTPD("MTP_RECEIVE_FILE returned %d", ret); - } - if (ret < 0) { - mResponse.setParameter(1, 0); - if (errno == ECANCELED) - 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() { - MtpObjectHandle handle = mRequest.getParameter(1); - ObjectEdit* edit = getEditObject(handle); - if (!edit) { - MTPE("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() { - MtpObjectHandle handle = mRequest.getParameter(1); - if (getEditObject(handle)) { - MTPE("object already open for edit in doBeginEditObject"); - return MTP_RESPONSE_GENERAL_ERROR; - } - - MtpString path; - int64_t fileLength; - MtpObjectFormat format; - MTPD("MtpServer::doBeginEditObject calling getObjectFilePath\n"); - mDatabase->lockMutex(); - int result = mDatabase->getObjectFilePath(handle, path, fileLength, format); - mDatabase->unlockMutex(); - if (result != MTP_RESPONSE_OK) - return result; - - int fd = open((const char *)path, O_RDWR | O_EXCL); - if (fd < 0) { - MTPE("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() { - MtpObjectHandle handle = mRequest.getParameter(1); - ObjectEdit* edit = getEditObject(handle); - if (!edit) { - MTPE("object not open for edit in doEndEditObject"); - return MTP_RESPONSE_GENERAL_ERROR; - } - - commitEdit(edit); - removeEditObject(handle); - return MTP_RESPONSE_OK; -} |