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) { LOGE("object not open for edit in doEndEditObject"); return MTP_RESPONSE_GENERAL_ERROR; } commitEdit(edit); removeEditObject(handle); 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->mFD, offset) != 0) { return MTP_RESPONSE_GENERAL_ERROR; } else { edit->mSize = offset; return MTP_RESPONSE_OK; } }
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::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->mSize) { LOGD("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; LOGV("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); 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; } // 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; }