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