Loading media/mtp/MtpDatabase.h +2 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ namespace android { class MtpDataPacket; class MtpProperty; class MtpObjectInfo; class MtpDatabase { public: Loading Loading @@ -81,7 +82,7 @@ public: MtpDataPacket& packet) = 0; virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle, MtpDataPacket& packet) = 0; MtpObjectInfo& info) = 0; virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, Loading media/mtp/MtpDebug.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,12 @@ static const CodeEntry sOperationCodes[] = { { "MTP_OPERATION_GET_OBJECT_REFERENCES", 0x9810 }, { "MTP_OPERATION_SET_OBJECT_REFERENCES", 0x9811 }, { "MTP_OPERATION_SKIP", 0x9820 }, // android extensions { "MTP_OPERATION_GET_PARTIAL_OBJECT_64", 0x95C1 }, { "MTP_OPERATION_SEND_PARTIAL_OBJECT", 0x95C2 }, { "MTP_OPERATION_TRUNCATE_OBJECT", 0x95C3 }, { "MTP_OPERATION_BEGIN_EDIT_OBJECT", 0x95C4 }, { "MTP_OPERATION_END_EDIT_OBJECT", 0x95C5 }, { 0, 0 }, }; Loading media/mtp/MtpServer.cpp +225 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include "MtpDebug.h" #include "MtpDatabase.h" #include "MtpObjectInfo.h" #include "MtpProperty.h" #include "MtpServer.h" #include "MtpStorage.h" Loading Loading @@ -79,6 +80,12 @@ static const MtpOperationCode kSupportedOperationCodes[] = { 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[] = { Loading Loading @@ -218,6 +225,15 @@ void MtpServer::run() { } } // 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(); } Loading Loading @@ -252,6 +268,44 @@ void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) { } } void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path, uint64_t size, MtpObjectFormat format, int fd) { ObjectEdit* edit = new ObjectEdit; edit->handle = handle; edit->path = path; edit->size = size; edit->format = format; edit->fd = 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->handle == 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->handle == handle) { delete edit; mObjectEditList.removeAt(i); return; } } LOGE("ObjectEdit not found in removeEditObject"); } void MtpServer::commitEdit(ObjectEdit* edit) { mDatabase->endSendObject((const char *)edit->path, edit->handle, edit->format, true); } bool MtpServer::handleRequest() { Mutex::Autolock autoLock(mMutex); Loading Loading @@ -322,7 +376,8 @@ bool MtpServer::handleRequest() { response = doGetObject(); break; case MTP_OPERATION_GET_PARTIAL_OBJECT: response = doGetPartialObject(); case MTP_OPERATION_GET_PARTIAL_OBJECT_64: response = doGetPartialObject(operation); break; case MTP_OPERATION_SEND_OBJECT_INFO: response = doSendObjectInfo(); Loading @@ -339,6 +394,18 @@ bool MtpServer::handleRequest() { 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: LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation)); response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; Loading @@ -363,7 +430,7 @@ MtpResponseCode MtpServer::doGetDeviceInfo() { mData.putUInt16(MTP_STANDARD_VERSION); mData.putUInt32(6); // MTP Vendor Extension ID mData.putUInt16(MTP_STANDARD_VERSION); string.set("microsoft.com: 1.0;"); string.set("microsoft.com: 1.0; android.com: 1.0;"); mData.putString(string); // MTP Extensions mData.putUInt16(0); //Functional Mode mData.putAUInt16(kSupportedOperationCodes, Loading Loading @@ -601,7 +668,40 @@ MtpResponseCode MtpServer::doGetObjectInfo() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); return mDatabase->getObjectInfo(handle, mData); 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->size > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->size); 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); mData.putEmptyString(); // date created formatDateTime(info.mDateModified, date, sizeof(date)); mData.putString(date); // date modified mData.putEmptyString(); // keywords } return result; } MtpResponseCode MtpServer::doGetObject() { Loading Loading @@ -641,12 +741,22 @@ MtpResponseCode MtpServer::doGetObject() { return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetPartialObject() { MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); uint32_t offset = mRequest.getParameter(2); uint32_t length = mRequest.getParameter(3); 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; Loading Loading @@ -933,4 +1043,113 @@ MtpResponseCode MtpServer::doGetDevicePropDesc() { 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) { LOGE("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->size) { LOGD("writing past end of object, offset: %lld, edit->size: %lld", offset, edit->size); return MTP_RESPONSE_GENERAL_ERROR; } // read the header int ret = mData.readDataHeader(mFD); // FIXME - check for errors here. // reset so we don't attempt to send this back mData.reset(); const char* filePath = (const char *)edit->path; LOGV("receiving partial %s %lld %ld\n", filePath, offset, length); mtp_file_range mfr; mfr.fd = edit->fd; mfr.offset = offset; mfr.length = length; // transfer the file ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); LOGV("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; } mResponse.setParameter(1, length); uint64_t end = offset + length; if (end > edit->size) { edit->size = end; } return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doTruncateObject() { MtpObjectHandle handle = mRequest.getParameter(1); ObjectEdit* edit = getEditObject(handle); if (!edit) { LOGE("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->fd, offset) != 0) { return MTP_RESPONSE_GENERAL_ERROR; } else { edit->size = offset; return MTP_RESPONSE_OK; } } MtpResponseCode MtpServer::doBeginEditObject() { MtpObjectHandle handle = mRequest.getParameter(1); if (getEditObject(handle)) { LOGE("object already open for edit in doBeginEditObject"); return MTP_RESPONSE_GENERAL_ERROR; } MtpString 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) { LOGE("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) { LOGE("object not open for edit in doEndEditObject"); return MTP_RESPONSE_GENERAL_ERROR; } commitEdit(edit); removeEditObject(handle); return MTP_RESPONSE_OK; } } // namespace android media/mtp/MtpServer.h +22 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,17 @@ private: Mutex mMutex; // represents an MTP object that is being edited using the android extensions // for direct editing (BeginEditObject, SendPartialObject, TruncateObject and EndEditObject) struct ObjectEdit { MtpObjectHandle handle; MtpString path; uint64_t size; MtpObjectFormat format; int fd; }; Vector<ObjectEdit*> mObjectEditList; public: MtpServer(int fd, MtpDatabase* database, int fileGroup, int filePerm, int directoryPerm); Loading @@ -86,6 +97,12 @@ private: void sendStoreRemoved(MtpStorageID id); void sendEvent(MtpEventCode code, uint32_t param1); void addEditObject(MtpObjectHandle handle, MtpString& path, uint64_t size, MtpObjectFormat format, int fd); ObjectEdit* getEditObject(MtpObjectHandle handle); void removeEditObject(MtpObjectHandle handle); void commitEdit(ObjectEdit* edit); bool handleRequest(); MtpResponseCode doGetDeviceInfo(); Loading @@ -106,12 +123,16 @@ private: MtpResponseCode doGetObjectPropList(); MtpResponseCode doGetObjectInfo(); MtpResponseCode doGetObject(); MtpResponseCode doGetPartialObject(); MtpResponseCode doGetPartialObject(MtpOperationCode operation); MtpResponseCode doSendObjectInfo(); MtpResponseCode doSendObject(); MtpResponseCode doDeleteObject(); MtpResponseCode doGetObjectPropDesc(); MtpResponseCode doGetDevicePropDesc(); MtpResponseCode doSendPartialObject(); MtpResponseCode doTruncateObject(); MtpResponseCode doBeginEditObject(); MtpResponseCode doEndEditObject(); }; }; // namespace android Loading media/mtp/mtp.h +13 −0 Original line number Diff line number Diff line Loading @@ -391,6 +391,19 @@ #define MTP_OPERATION_SET_OBJECT_REFERENCES 0x9811 #define MTP_OPERATION_SKIP 0x9820 // Android extensions for direct file IO // Same as GetPartialObject, but with 64 bit offset #define MTP_OPERATION_GET_PARTIAL_OBJECT_64 0x95C1 // Same as GetPartialObject64, but copying host to device #define MTP_OPERATION_SEND_PARTIAL_OBJECT 0x95C2 // Truncates file to 64 bit length #define MTP_OPERATION_TRUNCATE_OBJECT 0x95C3 // Must be called before using SendPartialObject and TruncateObject #define MTP_OPERATION_BEGIN_EDIT_OBJECT 0x95C4 // Called to commit changes made by SendPartialObject and TruncateObject #define MTP_OPERATION_END_EDIT_OBJECT 0x95C5 // MTP Response Codes #define MTP_RESPONSE_UNDEFINED 0x2000 #define MTP_RESPONSE_OK 0x2001 Loading Loading
media/mtp/MtpDatabase.h +2 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ namespace android { class MtpDataPacket; class MtpProperty; class MtpObjectInfo; class MtpDatabase { public: Loading Loading @@ -81,7 +82,7 @@ public: MtpDataPacket& packet) = 0; virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle, MtpDataPacket& packet) = 0; MtpObjectInfo& info) = 0; virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, Loading
media/mtp/MtpDebug.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,12 @@ static const CodeEntry sOperationCodes[] = { { "MTP_OPERATION_GET_OBJECT_REFERENCES", 0x9810 }, { "MTP_OPERATION_SET_OBJECT_REFERENCES", 0x9811 }, { "MTP_OPERATION_SKIP", 0x9820 }, // android extensions { "MTP_OPERATION_GET_PARTIAL_OBJECT_64", 0x95C1 }, { "MTP_OPERATION_SEND_PARTIAL_OBJECT", 0x95C2 }, { "MTP_OPERATION_TRUNCATE_OBJECT", 0x95C3 }, { "MTP_OPERATION_BEGIN_EDIT_OBJECT", 0x95C4 }, { "MTP_OPERATION_END_EDIT_OBJECT", 0x95C5 }, { 0, 0 }, }; Loading
media/mtp/MtpServer.cpp +225 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include "MtpDebug.h" #include "MtpDatabase.h" #include "MtpObjectInfo.h" #include "MtpProperty.h" #include "MtpServer.h" #include "MtpStorage.h" Loading Loading @@ -79,6 +80,12 @@ static const MtpOperationCode kSupportedOperationCodes[] = { 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[] = { Loading Loading @@ -218,6 +225,15 @@ void MtpServer::run() { } } // 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(); } Loading Loading @@ -252,6 +268,44 @@ void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) { } } void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path, uint64_t size, MtpObjectFormat format, int fd) { ObjectEdit* edit = new ObjectEdit; edit->handle = handle; edit->path = path; edit->size = size; edit->format = format; edit->fd = 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->handle == 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->handle == handle) { delete edit; mObjectEditList.removeAt(i); return; } } LOGE("ObjectEdit not found in removeEditObject"); } void MtpServer::commitEdit(ObjectEdit* edit) { mDatabase->endSendObject((const char *)edit->path, edit->handle, edit->format, true); } bool MtpServer::handleRequest() { Mutex::Autolock autoLock(mMutex); Loading Loading @@ -322,7 +376,8 @@ bool MtpServer::handleRequest() { response = doGetObject(); break; case MTP_OPERATION_GET_PARTIAL_OBJECT: response = doGetPartialObject(); case MTP_OPERATION_GET_PARTIAL_OBJECT_64: response = doGetPartialObject(operation); break; case MTP_OPERATION_SEND_OBJECT_INFO: response = doSendObjectInfo(); Loading @@ -339,6 +394,18 @@ bool MtpServer::handleRequest() { 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: LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation)); response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; Loading @@ -363,7 +430,7 @@ MtpResponseCode MtpServer::doGetDeviceInfo() { mData.putUInt16(MTP_STANDARD_VERSION); mData.putUInt32(6); // MTP Vendor Extension ID mData.putUInt16(MTP_STANDARD_VERSION); string.set("microsoft.com: 1.0;"); string.set("microsoft.com: 1.0; android.com: 1.0;"); mData.putString(string); // MTP Extensions mData.putUInt16(0); //Functional Mode mData.putAUInt16(kSupportedOperationCodes, Loading Loading @@ -601,7 +668,40 @@ MtpResponseCode MtpServer::doGetObjectInfo() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); return mDatabase->getObjectInfo(handle, mData); 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->size > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->size); 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); mData.putEmptyString(); // date created formatDateTime(info.mDateModified, date, sizeof(date)); mData.putString(date); // date modified mData.putEmptyString(); // keywords } return result; } MtpResponseCode MtpServer::doGetObject() { Loading Loading @@ -641,12 +741,22 @@ MtpResponseCode MtpServer::doGetObject() { return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetPartialObject() { MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); uint32_t offset = mRequest.getParameter(2); uint32_t length = mRequest.getParameter(3); 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; Loading Loading @@ -933,4 +1043,113 @@ MtpResponseCode MtpServer::doGetDevicePropDesc() { 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) { LOGE("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->size) { LOGD("writing past end of object, offset: %lld, edit->size: %lld", offset, edit->size); return MTP_RESPONSE_GENERAL_ERROR; } // read the header int ret = mData.readDataHeader(mFD); // FIXME - check for errors here. // reset so we don't attempt to send this back mData.reset(); const char* filePath = (const char *)edit->path; LOGV("receiving partial %s %lld %ld\n", filePath, offset, length); mtp_file_range mfr; mfr.fd = edit->fd; mfr.offset = offset; mfr.length = length; // transfer the file ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); LOGV("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; } mResponse.setParameter(1, length); uint64_t end = offset + length; if (end > edit->size) { edit->size = end; } return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doTruncateObject() { MtpObjectHandle handle = mRequest.getParameter(1); ObjectEdit* edit = getEditObject(handle); if (!edit) { LOGE("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->fd, offset) != 0) { return MTP_RESPONSE_GENERAL_ERROR; } else { edit->size = offset; return MTP_RESPONSE_OK; } } MtpResponseCode MtpServer::doBeginEditObject() { MtpObjectHandle handle = mRequest.getParameter(1); if (getEditObject(handle)) { LOGE("object already open for edit in doBeginEditObject"); return MTP_RESPONSE_GENERAL_ERROR; } MtpString 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) { LOGE("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) { LOGE("object not open for edit in doEndEditObject"); return MTP_RESPONSE_GENERAL_ERROR; } commitEdit(edit); removeEditObject(handle); return MTP_RESPONSE_OK; } } // namespace android
media/mtp/MtpServer.h +22 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,17 @@ private: Mutex mMutex; // represents an MTP object that is being edited using the android extensions // for direct editing (BeginEditObject, SendPartialObject, TruncateObject and EndEditObject) struct ObjectEdit { MtpObjectHandle handle; MtpString path; uint64_t size; MtpObjectFormat format; int fd; }; Vector<ObjectEdit*> mObjectEditList; public: MtpServer(int fd, MtpDatabase* database, int fileGroup, int filePerm, int directoryPerm); Loading @@ -86,6 +97,12 @@ private: void sendStoreRemoved(MtpStorageID id); void sendEvent(MtpEventCode code, uint32_t param1); void addEditObject(MtpObjectHandle handle, MtpString& path, uint64_t size, MtpObjectFormat format, int fd); ObjectEdit* getEditObject(MtpObjectHandle handle); void removeEditObject(MtpObjectHandle handle); void commitEdit(ObjectEdit* edit); bool handleRequest(); MtpResponseCode doGetDeviceInfo(); Loading @@ -106,12 +123,16 @@ private: MtpResponseCode doGetObjectPropList(); MtpResponseCode doGetObjectInfo(); MtpResponseCode doGetObject(); MtpResponseCode doGetPartialObject(); MtpResponseCode doGetPartialObject(MtpOperationCode operation); MtpResponseCode doSendObjectInfo(); MtpResponseCode doSendObject(); MtpResponseCode doDeleteObject(); MtpResponseCode doGetObjectPropDesc(); MtpResponseCode doGetDevicePropDesc(); MtpResponseCode doSendPartialObject(); MtpResponseCode doTruncateObject(); MtpResponseCode doBeginEditObject(); MtpResponseCode doEndEditObject(); }; }; // namespace android Loading
media/mtp/mtp.h +13 −0 Original line number Diff line number Diff line Loading @@ -391,6 +391,19 @@ #define MTP_OPERATION_SET_OBJECT_REFERENCES 0x9811 #define MTP_OPERATION_SKIP 0x9820 // Android extensions for direct file IO // Same as GetPartialObject, but with 64 bit offset #define MTP_OPERATION_GET_PARTIAL_OBJECT_64 0x95C1 // Same as GetPartialObject64, but copying host to device #define MTP_OPERATION_SEND_PARTIAL_OBJECT 0x95C2 // Truncates file to 64 bit length #define MTP_OPERATION_TRUNCATE_OBJECT 0x95C3 // Must be called before using SendPartialObject and TruncateObject #define MTP_OPERATION_BEGIN_EDIT_OBJECT 0x95C4 // Called to commit changes made by SendPartialObject and TruncateObject #define MTP_OPERATION_END_EDIT_OBJECT 0x95C5 // MTP Response Codes #define MTP_RESPONSE_UNDEFINED 0x2000 #define MTP_RESPONSE_OK 0x2001 Loading