blob: 37e02a3f65297332160a40bedf5a8f438c3b0686 [file] [log] [blame]
Mike Lockwood56118b52010-05-11 17:16:59 -04001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/types.h>
20#include <sys/ioctl.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <errno.h>
Mike Lockwoodccb6e962010-09-13 17:15:58 -040024#include <sys/stat.h>
25#include <dirent.h>
Mike Lockwood56118b52010-05-11 17:16:59 -040026
Mike Lockwood622ccdc2010-06-14 17:58:08 -070027#include <cutils/properties.h>
28
Mike Lockwood9f679242010-09-23 22:32:05 -040029#define LOG_TAG "MtpServer"
30
Mike Lockwood56118b52010-05-11 17:16:59 -040031#include "MtpDebug.h"
Mike Lockwoodc5c78532010-07-09 10:45:22 -040032#include "MtpDatabase.h"
Mike Lockwood767c5e42010-06-30 17:00:35 -040033#include "MtpProperty.h"
Mike Lockwood56118b52010-05-11 17:16:59 -040034#include "MtpServer.h"
35#include "MtpStorage.h"
36#include "MtpStringBuffer.h"
Mike Lockwood56118b52010-05-11 17:16:59 -040037
Mike Lockwood9c7fdf52010-07-15 13:36:52 -040038#include <linux/usb/f_mtp.h>
Mike Lockwood56118b52010-05-11 17:16:59 -040039
Mike Lockwood8d3257a2010-05-14 10:10:36 -040040namespace android {
41
Mike Lockwood56118b52010-05-11 17:16:59 -040042static const MtpOperationCode kSupportedOperationCodes[] = {
43 MTP_OPERATION_GET_DEVICE_INFO,
44 MTP_OPERATION_OPEN_SESSION,
45 MTP_OPERATION_CLOSE_SESSION,
46 MTP_OPERATION_GET_STORAGE_IDS,
47 MTP_OPERATION_GET_STORAGE_INFO,
48 MTP_OPERATION_GET_NUM_OBJECTS,
49 MTP_OPERATION_GET_OBJECT_HANDLES,
50 MTP_OPERATION_GET_OBJECT_INFO,
51 MTP_OPERATION_GET_OBJECT,
52// MTP_OPERATION_GET_THUMB,
53 MTP_OPERATION_DELETE_OBJECT,
54 MTP_OPERATION_SEND_OBJECT_INFO,
55 MTP_OPERATION_SEND_OBJECT,
56// MTP_OPERATION_INITIATE_CAPTURE,
57// MTP_OPERATION_FORMAT_STORE,
58// MTP_OPERATION_RESET_DEVICE,
59// MTP_OPERATION_SELF_TEST,
60// MTP_OPERATION_SET_OBJECT_PROTECTION,
61// MTP_OPERATION_POWER_DOWN,
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040062 MTP_OPERATION_GET_DEVICE_PROP_DESC,
Mike Lockwood828d19d2010-08-10 15:20:35 -040063 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
64 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
65 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
Mike Lockwood56118b52010-05-11 17:16:59 -040066// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
67// MTP_OPERATION_MOVE_OBJECT,
68// MTP_OPERATION_COPY_OBJECT,
Mike Lockwood44e82dd2010-11-23 09:08:01 -050069 MTP_OPERATION_GET_PARTIAL_OBJECT,
Mike Lockwood56118b52010-05-11 17:16:59 -040070// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
71 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
Mike Lockwood828d19d2010-08-10 15:20:35 -040072 MTP_OPERATION_GET_OBJECT_PROP_DESC,
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -040073 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
74 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040075 MTP_OPERATION_GET_OBJECT_PROP_LIST,
76// MTP_OPERATION_SET_OBJECT_PROP_LIST,
77// MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
78// MTP_OPERATION_SEND_OBJECT_PROP_LIST,
Mike Lockwood9a2046f2010-08-03 15:30:09 -040079 MTP_OPERATION_GET_OBJECT_REFERENCES,
80 MTP_OPERATION_SET_OBJECT_REFERENCES,
Mike Lockwood56118b52010-05-11 17:16:59 -040081// MTP_OPERATION_SKIP,
82};
83
Mike Lockwoodbe125a52010-07-12 18:54:16 -040084static const MtpEventCode kSupportedEventCodes[] = {
85 MTP_EVENT_OBJECT_ADDED,
86 MTP_EVENT_OBJECT_REMOVED,
Mike Lockwood467ca0d2011-02-18 09:07:14 -050087 MTP_EVENT_STORE_ADDED,
88 MTP_EVENT_STORE_REMOVED,
Mike Lockwoodbe125a52010-07-12 18:54:16 -040089};
90
Mike Lockwoodd21eac92010-07-03 00:44:05 -040091MtpServer::MtpServer(int fd, MtpDatabase* database,
Mike Lockwooddad69272010-07-02 15:15:07 -040092 int fileGroup, int filePerm, int directoryPerm)
Mike Lockwood56118b52010-05-11 17:16:59 -040093 : mFD(fd),
Mike Lockwoodd21eac92010-07-03 00:44:05 -040094 mDatabase(database),
Mike Lockwooddad69272010-07-02 15:15:07 -040095 mFileGroup(fileGroup),
96 mFilePermission(filePerm),
97 mDirectoryPermission(directoryPerm),
Mike Lockwood56118b52010-05-11 17:16:59 -040098 mSessionID(0),
99 mSessionOpen(false),
100 mSendObjectHandle(kInvalidObjectHandle),
Mike Lockwoodd815f792010-07-12 08:49:01 -0400101 mSendObjectFormat(0),
Mike Lockwood56118b52010-05-11 17:16:59 -0400102 mSendObjectFileSize(0)
103{
Mike Lockwood56118b52010-05-11 17:16:59 -0400104}
105
106MtpServer::~MtpServer() {
107}
108
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500109void MtpServer::addStorage(MtpStorage* storage) {
110 Mutex::Autolock autoLock(mMutex);
111
112 mStorages.push(storage);
113 sendStoreAdded(storage->getStorageID());
114}
115
116void MtpServer::removeStorage(MtpStorage* storage) {
117 Mutex::Autolock autoLock(mMutex);
118
119 for (int i = 0; i < mStorages.size(); i++) {
120 if (mStorages[i] == storage) {
121 mStorages.removeAt(i);
122 sendStoreRemoved(storage->getStorageID());
123 break;
124 }
125 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400126}
127
128MtpStorage* MtpServer::getStorage(MtpStorageID id) {
Mike Lockwood365e03e2010-12-08 16:08:01 -0800129 if (id == 0)
130 return mStorages[0];
Mike Lockwood56118b52010-05-11 17:16:59 -0400131 for (int i = 0; i < mStorages.size(); i++) {
Mike Lockwood365e03e2010-12-08 16:08:01 -0800132 MtpStorage* storage = mStorages[i];
Mike Lockwood56118b52010-05-11 17:16:59 -0400133 if (storage->getStorageID() == id)
134 return storage;
135 }
136 return NULL;
137}
138
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500139bool MtpServer::hasStorage(MtpStorageID id) {
140 if (id == 0 || id == 0xFFFFFFFF)
141 return mStorages.size() > 0;
142 return (getStorage(id) != NULL);
143}
144
Mike Lockwood56118b52010-05-11 17:16:59 -0400145void MtpServer::run() {
146 int fd = mFD;
147
Mike Lockwood767c5e42010-06-30 17:00:35 -0400148 LOGV("MtpServer::run fd: %d\n", fd);
Mike Lockwood56118b52010-05-11 17:16:59 -0400149
150 while (1) {
151 int ret = mRequest.read(fd);
152 if (ret < 0) {
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800153 LOGV("request read returned %d, errno: %d", ret, errno);
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400154 if (errno == ECANCELED) {
155 // return to top of loop and wait for next command
156 continue;
157 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400158 break;
159 }
160 MtpOperationCode operation = mRequest.getOperationCode();
161 MtpTransactionID transaction = mRequest.getTransactionID();
162
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400163 LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood56118b52010-05-11 17:16:59 -0400164 mRequest.dump();
165
166 // FIXME need to generalize this
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400167 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
Mike Lockwood828d19d2010-08-10 15:20:35 -0400168 || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
169 || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
170 || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
Mike Lockwood56118b52010-05-11 17:16:59 -0400171 if (dataIn) {
172 int ret = mData.read(fd);
173 if (ret < 0) {
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400174 LOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400175 if (errno == ECANCELED) {
176 // return to top of loop and wait for next command
177 continue;
178 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400179 break;
180 }
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400181 LOGV("received data:");
Mike Lockwood56118b52010-05-11 17:16:59 -0400182 mData.dump();
183 } else {
184 mData.reset();
185 }
186
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400187 if (handleRequest()) {
188 if (!dataIn && mData.hasData()) {
189 mData.setOperationCode(operation);
190 mData.setTransactionID(transaction);
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400191 LOGV("sending data:");
Mike Lockwooddb774312010-10-11 17:31:44 -0400192 mData.dump();
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400193 ret = mData.write(fd);
194 if (ret < 0) {
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400195 LOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400196 if (errno == ECANCELED) {
197 // return to top of loop and wait for next command
198 continue;
199 }
200 break;
201 }
202 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400203
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400204 mResponse.setTransactionID(transaction);
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400205 LOGV("sending response %04X", mResponse.getResponseCode());
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400206 ret = mResponse.write(fd);
Mike Lockwooddb774312010-10-11 17:31:44 -0400207 mResponse.dump();
Mike Lockwood56118b52010-05-11 17:16:59 -0400208 if (ret < 0) {
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400209 LOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400210 if (errno == ECANCELED) {
211 // return to top of loop and wait for next command
212 continue;
213 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400214 break;
215 }
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400216 } else {
Mike Lockwood767c5e42010-06-30 17:00:35 -0400217 LOGV("skipping response\n");
Mike Lockwood56118b52010-05-11 17:16:59 -0400218 }
219 }
Mike Lockwood2837eef2010-08-31 16:25:12 -0400220
221 if (mSessionOpen)
222 mDatabase->sessionEnded();
Mike Lockwood56118b52010-05-11 17:16:59 -0400223}
224
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400225void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500226 LOGV("sendObjectAdded %d\n", handle);
227 sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400228}
229
230void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500231 LOGV("sendObjectRemoved %d\n", handle);
232 sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
233}
234
235void MtpServer::sendStoreAdded(MtpStorageID id) {
236 LOGV("sendStoreAdded %08X\n", id);
237 sendEvent(MTP_EVENT_STORE_ADDED, id);
238}
239
240void MtpServer::sendStoreRemoved(MtpStorageID id) {
241 LOGV("sendStoreRemoved %08X\n", id);
242 sendEvent(MTP_EVENT_STORE_REMOVED, id);
243}
244
245void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
Mike Lockwooddc453d42010-07-19 14:29:58 -0400246 if (mSessionOpen) {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500247 mEvent.setEventCode(code);
Mike Lockwooddc453d42010-07-19 14:29:58 -0400248 mEvent.setTransactionID(mRequest.getTransactionID());
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500249 mEvent.setParameter(1, param1);
Mike Lockwooddc453d42010-07-19 14:29:58 -0400250 int ret = mEvent.write(mFD);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800251 LOGV("mEvent.write returned %d\n", ret);
Mike Lockwooddc453d42010-07-19 14:29:58 -0400252 }
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400253}
254
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400255bool MtpServer::handleRequest() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500256 Mutex::Autolock autoLock(mMutex);
257
Mike Lockwood56118b52010-05-11 17:16:59 -0400258 MtpOperationCode operation = mRequest.getOperationCode();
259 MtpResponseCode response;
260
261 mResponse.reset();
262
263 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
264 // FIXME - need to delete mSendObjectHandle from the database
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400265 LOGE("expected SendObject after SendObjectInfo");
Mike Lockwood56118b52010-05-11 17:16:59 -0400266 mSendObjectHandle = kInvalidObjectHandle;
267 }
268
269 switch (operation) {
270 case MTP_OPERATION_GET_DEVICE_INFO:
271 response = doGetDeviceInfo();
272 break;
273 case MTP_OPERATION_OPEN_SESSION:
274 response = doOpenSession();
275 break;
276 case MTP_OPERATION_CLOSE_SESSION:
277 response = doCloseSession();
278 break;
279 case MTP_OPERATION_GET_STORAGE_IDS:
280 response = doGetStorageIDs();
281 break;
282 case MTP_OPERATION_GET_STORAGE_INFO:
283 response = doGetStorageInfo();
284 break;
285 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
286 response = doGetObjectPropsSupported();
287 break;
288 case MTP_OPERATION_GET_OBJECT_HANDLES:
289 response = doGetObjectHandles();
290 break;
Mike Lockwood7a047c82010-08-02 10:52:20 -0400291 case MTP_OPERATION_GET_NUM_OBJECTS:
292 response = doGetNumObjects();
293 break;
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400294 case MTP_OPERATION_GET_OBJECT_REFERENCES:
295 response = doGetObjectReferences();
296 break;
297 case MTP_OPERATION_SET_OBJECT_REFERENCES:
298 response = doSetObjectReferences();
299 break;
Mike Lockwood56118b52010-05-11 17:16:59 -0400300 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
301 response = doGetObjectPropValue();
302 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400303 case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
304 response = doSetObjectPropValue();
305 break;
306 case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
307 response = doGetDevicePropValue();
308 break;
309 case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
310 response = doSetDevicePropValue();
311 break;
312 case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
313 response = doResetDevicePropValue();
314 break;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400315 case MTP_OPERATION_GET_OBJECT_PROP_LIST:
316 response = doGetObjectPropList();
317 break;
Mike Lockwood56118b52010-05-11 17:16:59 -0400318 case MTP_OPERATION_GET_OBJECT_INFO:
319 response = doGetObjectInfo();
320 break;
321 case MTP_OPERATION_GET_OBJECT:
322 response = doGetObject();
323 break;
Mike Lockwood44e82dd2010-11-23 09:08:01 -0500324 case MTP_OPERATION_GET_PARTIAL_OBJECT:
325 response = doGetPartialObject();
326 break;
Mike Lockwood56118b52010-05-11 17:16:59 -0400327 case MTP_OPERATION_SEND_OBJECT_INFO:
328 response = doSendObjectInfo();
329 break;
330 case MTP_OPERATION_SEND_OBJECT:
331 response = doSendObject();
332 break;
333 case MTP_OPERATION_DELETE_OBJECT:
334 response = doDeleteObject();
335 break;
336 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
Mike Lockwood767c5e42010-06-30 17:00:35 -0400337 response = doGetObjectPropDesc();
338 break;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400339 case MTP_OPERATION_GET_DEVICE_PROP_DESC:
340 response = doGetDevicePropDesc();
341 break;
Mike Lockwood56118b52010-05-11 17:16:59 -0400342 default:
Mike Lockwood9f679242010-09-23 22:32:05 -0400343 LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood56118b52010-05-11 17:16:59 -0400344 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
345 break;
346 }
347
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400348 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
349 return false;
Mike Lockwood56118b52010-05-11 17:16:59 -0400350 mResponse.setResponseCode(response);
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400351 return true;
Mike Lockwood56118b52010-05-11 17:16:59 -0400352}
353
354MtpResponseCode MtpServer::doGetDeviceInfo() {
355 MtpStringBuffer string;
Mike Lockwood622ccdc2010-06-14 17:58:08 -0700356 char prop_value[PROPERTY_VALUE_MAX];
Mike Lockwood56118b52010-05-11 17:16:59 -0400357
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400358 MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
359 MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
360 MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
361
Mike Lockwood56118b52010-05-11 17:16:59 -0400362 // fill in device info
363 mData.putUInt16(MTP_STANDARD_VERSION);
364 mData.putUInt32(6); // MTP Vendor Extension ID
365 mData.putUInt16(MTP_STANDARD_VERSION);
366 string.set("microsoft.com: 1.0;");
367 mData.putString(string); // MTP Extensions
368 mData.putUInt16(0); //Functional Mode
369 mData.putAUInt16(kSupportedOperationCodes,
370 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400371 mData.putAUInt16(kSupportedEventCodes,
372 sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400373 mData.putAUInt16(deviceProperties); // Device Properties Supported
374 mData.putAUInt16(captureFormats); // Capture Formats
375 mData.putAUInt16(playbackFormats); // Playback Formats
Mike Lockwood46395322011-01-31 16:44:44 -0500376
377 property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
378 string.set(prop_value);
Mike Lockwood56118b52010-05-11 17:16:59 -0400379 mData.putString(string); // Manufacturer
Mike Lockwood622ccdc2010-06-14 17:58:08 -0700380
381 property_get("ro.product.model", prop_value, "MTP Device");
382 string.set(prop_value);
Mike Lockwood56118b52010-05-11 17:16:59 -0400383 mData.putString(string); // Model
384 string.set("1.0");
385 mData.putString(string); // Device Version
Mike Lockwood622ccdc2010-06-14 17:58:08 -0700386
387 property_get("ro.serialno", prop_value, "????????");
388 string.set(prop_value);
Mike Lockwood56118b52010-05-11 17:16:59 -0400389 mData.putString(string); // Serial Number
390
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400391 delete playbackFormats;
392 delete captureFormats;
393 delete deviceProperties;
394
Mike Lockwood56118b52010-05-11 17:16:59 -0400395 return MTP_RESPONSE_OK;
396}
397
398MtpResponseCode MtpServer::doOpenSession() {
399 if (mSessionOpen) {
400 mResponse.setParameter(1, mSessionID);
401 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
402 }
403 mSessionID = mRequest.getParameter(1);
404 mSessionOpen = true;
Mike Lockwood2837eef2010-08-31 16:25:12 -0400405
406 mDatabase->sessionStarted();
407
Mike Lockwood56118b52010-05-11 17:16:59 -0400408 return MTP_RESPONSE_OK;
409}
410
411MtpResponseCode MtpServer::doCloseSession() {
412 if (!mSessionOpen)
413 return MTP_RESPONSE_SESSION_NOT_OPEN;
414 mSessionID = 0;
415 mSessionOpen = false;
Mike Lockwood2837eef2010-08-31 16:25:12 -0400416 mDatabase->sessionEnded();
Mike Lockwood56118b52010-05-11 17:16:59 -0400417 return MTP_RESPONSE_OK;
418}
419
420MtpResponseCode MtpServer::doGetStorageIDs() {
421 if (!mSessionOpen)
422 return MTP_RESPONSE_SESSION_NOT_OPEN;
423
424 int count = mStorages.size();
425 mData.putUInt32(count);
426 for (int i = 0; i < count; i++)
427 mData.putUInt32(mStorages[i]->getStorageID());
428
429 return MTP_RESPONSE_OK;
430}
431
432MtpResponseCode MtpServer::doGetStorageInfo() {
433 MtpStringBuffer string;
434
435 if (!mSessionOpen)
436 return MTP_RESPONSE_SESSION_NOT_OPEN;
437 MtpStorageID id = mRequest.getParameter(1);
438 MtpStorage* storage = getStorage(id);
439 if (!storage)
440 return MTP_RESPONSE_INVALID_STORAGE_ID;
441
442 mData.putUInt16(storage->getType());
443 mData.putUInt16(storage->getFileSystemType());
444 mData.putUInt16(storage->getAccessCapability());
445 mData.putUInt64(storage->getMaxCapacity());
446 mData.putUInt64(storage->getFreeSpace());
447 mData.putUInt32(1024*1024*1024); // Free Space in Objects
448 string.set(storage->getDescription());
449 mData.putString(string);
450 mData.putEmptyString(); // Volume Identifier
451
452 return MTP_RESPONSE_OK;
453}
454
455MtpResponseCode MtpServer::doGetObjectPropsSupported() {
456 if (!mSessionOpen)
457 return MTP_RESPONSE_SESSION_NOT_OPEN;
458 MtpObjectFormat format = mRequest.getParameter(1);
Mike Lockwood4cb956c2010-12-07 10:51:20 -0800459 MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400460 mData.putAUInt16(properties);
Mike Lockwood33ea5a42010-08-10 15:11:32 -0400461 delete properties;
Mike Lockwood56118b52010-05-11 17:16:59 -0400462 return MTP_RESPONSE_OK;
463}
464
465MtpResponseCode MtpServer::doGetObjectHandles() {
466 if (!mSessionOpen)
467 return MTP_RESPONSE_SESSION_NOT_OPEN;
468 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwood37433652010-05-19 15:12:14 -0400469 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood56118b52010-05-11 17:16:59 -0400470 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
471 // 0x00000000 for all objects?
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500472
473 if (!hasStorage(storageID))
474 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400475 if (parent == 0xFFFFFFFF)
476 parent = 0;
Mike Lockwood56118b52010-05-11 17:16:59 -0400477
478 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
479 mData.putAUInt32(handles);
480 delete handles;
481 return MTP_RESPONSE_OK;
482}
483
Mike Lockwood7a047c82010-08-02 10:52:20 -0400484MtpResponseCode MtpServer::doGetNumObjects() {
485 if (!mSessionOpen)
486 return MTP_RESPONSE_SESSION_NOT_OPEN;
487 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
488 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
489 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
490 // 0x00000000 for all objects?
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500491 if (!hasStorage(storageID))
492 return MTP_RESPONSE_INVALID_STORAGE_ID;
Mike Lockwood7a047c82010-08-02 10:52:20 -0400493 if (parent == 0xFFFFFFFF)
494 parent = 0;
495
496 int count = mDatabase->getNumObjects(storageID, format, parent);
497 if (count >= 0) {
498 mResponse.setParameter(1, count);
499 return MTP_RESPONSE_OK;
500 } else {
501 mResponse.setParameter(1, 0);
502 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
503 }
504}
505
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400506MtpResponseCode MtpServer::doGetObjectReferences() {
507 if (!mSessionOpen)
508 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500509 if (!hasStorage())
510 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
511 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400512
513 // FIXME - check for invalid object handle
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400514 MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400515 if (handles) {
516 mData.putAUInt32(handles);
517 delete handles;
518 } else {
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400519 mData.putEmptyArray();
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400520 }
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400521 return MTP_RESPONSE_OK;
522}
523
524MtpResponseCode MtpServer::doSetObjectReferences() {
525 if (!mSessionOpen)
526 return MTP_RESPONSE_SESSION_NOT_OPEN;
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500527 if (!hasStorage())
528 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400529 MtpStorageID handle = mRequest.getParameter(1);
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500530
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400531 MtpObjectHandleList* references = mData.getAUInt32();
532 MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
533 delete references;
534 return result;
535}
536
Mike Lockwood56118b52010-05-11 17:16:59 -0400537MtpResponseCode MtpServer::doGetObjectPropValue() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500538 if (!hasStorage())
539 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood56118b52010-05-11 17:16:59 -0400540 MtpObjectHandle handle = mRequest.getParameter(1);
541 MtpObjectProperty property = mRequest.getParameter(2);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800542 LOGV("GetObjectPropValue %d %s\n", handle,
Mike Lockwood828d19d2010-08-10 15:20:35 -0400543 MtpDebug::getObjectPropCodeName(property));
Mike Lockwood56118b52010-05-11 17:16:59 -0400544
Mike Lockwood828d19d2010-08-10 15:20:35 -0400545 return mDatabase->getObjectPropertyValue(handle, property, mData);
546}
547
548MtpResponseCode MtpServer::doSetObjectPropValue() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500549 if (!hasStorage())
550 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400551 MtpObjectHandle handle = mRequest.getParameter(1);
552 MtpObjectProperty property = mRequest.getParameter(2);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800553 LOGV("SetObjectPropValue %d %s\n", handle,
Mike Lockwood828d19d2010-08-10 15:20:35 -0400554 MtpDebug::getObjectPropCodeName(property));
555
556 return mDatabase->setObjectPropertyValue(handle, property, mData);
557}
558
559MtpResponseCode MtpServer::doGetDevicePropValue() {
560 MtpDeviceProperty property = mRequest.getParameter(1);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800561 LOGV("GetDevicePropValue %s\n",
Mike Lockwood828d19d2010-08-10 15:20:35 -0400562 MtpDebug::getDevicePropCodeName(property));
563
564 return mDatabase->getDevicePropertyValue(property, mData);
565}
566
567MtpResponseCode MtpServer::doSetDevicePropValue() {
568 MtpDeviceProperty property = mRequest.getParameter(1);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800569 LOGV("SetDevicePropValue %s\n",
Mike Lockwood828d19d2010-08-10 15:20:35 -0400570 MtpDebug::getDevicePropCodeName(property));
571
572 return mDatabase->setDevicePropertyValue(property, mData);
573}
574
575MtpResponseCode MtpServer::doResetDevicePropValue() {
576 MtpDeviceProperty property = mRequest.getParameter(1);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800577 LOGV("ResetDevicePropValue %s\n",
Mike Lockwood828d19d2010-08-10 15:20:35 -0400578 MtpDebug::getDevicePropCodeName(property));
579
580 return mDatabase->resetDeviceProperty(property);
Mike Lockwood56118b52010-05-11 17:16:59 -0400581}
582
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400583MtpResponseCode MtpServer::doGetObjectPropList() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500584 if (!hasStorage())
585 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400586
587 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500588 // use uint32_t so we can support 0xFFFFFFFF
589 uint32_t format = mRequest.getParameter(2);
590 uint32_t property = mRequest.getParameter(3);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400591 int groupCode = mRequest.getParameter(4);
Mike Lockwoode3634c32010-11-23 18:45:25 -0500592 int depth = mRequest.getParameter(5);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800593 LOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400594 handle, MtpDebug::getFormatCodeName(format),
595 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
596
597 return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
598}
599
Mike Lockwood56118b52010-05-11 17:16:59 -0400600MtpResponseCode MtpServer::doGetObjectInfo() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500601 if (!hasStorage())
602 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood56118b52010-05-11 17:16:59 -0400603 MtpObjectHandle handle = mRequest.getParameter(1);
604 return mDatabase->getObjectInfo(handle, mData);
605}
606
607MtpResponseCode MtpServer::doGetObject() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500608 if (!hasStorage())
609 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood56118b52010-05-11 17:16:59 -0400610 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwood42dbfa52010-06-22 15:03:53 -0400611 MtpString pathBuf;
Mike Lockwood56118b52010-05-11 17:16:59 -0400612 int64_t fileLength;
Mike Lockwood365e03e2010-12-08 16:08:01 -0800613 MtpObjectFormat format;
614 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400615 if (result != MTP_RESPONSE_OK)
616 return result;
Mike Lockwood56118b52010-05-11 17:16:59 -0400617
Mike Lockwood59c777a2010-08-02 10:37:41 -0400618 const char* filePath = (const char *)pathBuf;
Mike Lockwood56118b52010-05-11 17:16:59 -0400619 mtp_file_range mfr;
Mike Lockwood42dbfa52010-06-22 15:03:53 -0400620 mfr.fd = open(filePath, O_RDONLY);
621 if (mfr.fd < 0) {
622 return MTP_RESPONSE_GENERAL_ERROR;
623 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400624 mfr.offset = 0;
625 mfr.length = fileLength;
626
627 // send data header
628 mData.setOperationCode(mRequest.getOperationCode());
629 mData.setTransactionID(mRequest.getTransactionID());
Mike Lockwooddb774312010-10-11 17:31:44 -0400630 mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
Mike Lockwood56118b52010-05-11 17:16:59 -0400631
632 // then transfer the file
633 int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
Mike Lockwood42dbfa52010-06-22 15:03:53 -0400634 close(mfr.fd);
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400635 if (ret < 0) {
636 if (errno == ECANCELED)
637 return MTP_RESPONSE_TRANSACTION_CANCELLED;
638 else
639 return MTP_RESPONSE_GENERAL_ERROR;
640 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400641 return MTP_RESPONSE_OK;
642}
643
Mike Lockwood44e82dd2010-11-23 09:08:01 -0500644MtpResponseCode MtpServer::doGetPartialObject() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500645 if (!hasStorage())
646 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood44e82dd2010-11-23 09:08:01 -0500647 MtpObjectHandle handle = mRequest.getParameter(1);
648 uint32_t offset = mRequest.getParameter(2);
649 uint32_t length = mRequest.getParameter(3);
650 MtpString pathBuf;
651 int64_t fileLength;
Mike Lockwood365e03e2010-12-08 16:08:01 -0800652 MtpObjectFormat format;
653 int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
Mike Lockwood44e82dd2010-11-23 09:08:01 -0500654 if (result != MTP_RESPONSE_OK)
655 return result;
656 if (offset + length > fileLength)
657 length = fileLength - offset;
658
659 const char* filePath = (const char *)pathBuf;
660 mtp_file_range mfr;
661 mfr.fd = open(filePath, O_RDONLY);
662 if (mfr.fd < 0) {
663 return MTP_RESPONSE_GENERAL_ERROR;
664 }
665 mfr.offset = offset;
666 mfr.length = length;
667 mResponse.setParameter(1, length);
668
669 // send data header
670 mData.setOperationCode(mRequest.getOperationCode());
671 mData.setTransactionID(mRequest.getTransactionID());
672 mData.writeDataHeader(mFD, length + MTP_CONTAINER_HEADER_SIZE);
673
674 // then transfer the file
675 int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
676 close(mfr.fd);
677 if (ret < 0) {
678 if (errno == ECANCELED)
679 return MTP_RESPONSE_TRANSACTION_CANCELLED;
680 else
681 return MTP_RESPONSE_GENERAL_ERROR;
682 }
683 return MTP_RESPONSE_OK;
684}
685
Mike Lockwood56118b52010-05-11 17:16:59 -0400686MtpResponseCode MtpServer::doSendObjectInfo() {
687 MtpString path;
688 MtpStorageID storageID = mRequest.getParameter(1);
689 MtpStorage* storage = getStorage(storageID);
690 MtpObjectHandle parent = mRequest.getParameter(2);
691 if (!storage)
692 return MTP_RESPONSE_INVALID_STORAGE_ID;
693
694 // special case the root
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400695 if (parent == MTP_PARENT_ROOT) {
Mike Lockwood56118b52010-05-11 17:16:59 -0400696 path = storage->getPath();
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400697 parent = 0;
698 } else {
Mike Lockwood365e03e2010-12-08 16:08:01 -0800699 int64_t length;
700 MtpObjectFormat format;
701 int result = mDatabase->getObjectFilePath(parent, path, length, format);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400702 if (result != MTP_RESPONSE_OK)
703 return result;
Mike Lockwood365e03e2010-12-08 16:08:01 -0800704 if (format != MTP_FORMAT_ASSOCIATION)
705 return MTP_RESPONSE_INVALID_PARENT_OBJECT;
Mike Lockwood56118b52010-05-11 17:16:59 -0400706 }
707
708 // read only the fields we need
709 mData.getUInt32(); // storage ID
710 MtpObjectFormat format = mData.getUInt16();
711 mData.getUInt16(); // protection status
712 mSendObjectFileSize = mData.getUInt32();
713 mData.getUInt16(); // thumb format
714 mData.getUInt32(); // thumb compressed size
715 mData.getUInt32(); // thumb pix width
716 mData.getUInt32(); // thumb pix height
717 mData.getUInt32(); // image pix width
718 mData.getUInt32(); // image pix height
719 mData.getUInt32(); // image bit depth
720 mData.getUInt32(); // parent
721 uint16_t associationType = mData.getUInt16();
722 uint32_t associationDesc = mData.getUInt32(); // association desc
723 mData.getUInt32(); // sequence number
724 MtpStringBuffer name, created, modified;
725 mData.getString(name); // file name
726 mData.getString(created); // date created
727 mData.getString(modified); // date modified
728 // keywords follow
729
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800730 LOGV("name: %s format: %04X\n", (const char *)name, format);
Mike Lockwoodd0782672010-05-14 15:35:17 -0400731 time_t modifiedTime;
Mike Lockwood56118b52010-05-11 17:16:59 -0400732 if (!parseDateTime(modified, modifiedTime))
733 modifiedTime = 0;
Mike Lockwood56118b52010-05-11 17:16:59 -0400734
735 if (path[path.size() - 1] != '/')
736 path += "/";
737 path += (const char *)name;
738
Mike Lockwood7f36b192010-12-12 12:17:43 -0800739 // check space first
740 if (mSendObjectFileSize > storage->getFreeSpace())
741 return MTP_RESPONSE_STORAGE_FULL;
742
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500743LOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
Mike Lockwoodd815f792010-07-12 08:49:01 -0400744 MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
745 format, parent, storageID, mSendObjectFileSize, modifiedTime);
Mike Lockwoodd0782672010-05-14 15:35:17 -0400746 if (handle == kInvalidObjectHandle) {
Mike Lockwood56118b52010-05-11 17:16:59 -0400747 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd0782672010-05-14 15:35:17 -0400748 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400749
750 if (format == MTP_FORMAT_ASSOCIATION) {
751 mode_t mask = umask(0);
Mike Lockwooddad69272010-07-02 15:15:07 -0400752 int ret = mkdir((const char *)path, mDirectoryPermission);
Mike Lockwood56118b52010-05-11 17:16:59 -0400753 umask(mask);
754 if (ret && ret != -EEXIST)
755 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwooddad69272010-07-02 15:15:07 -0400756 chown((const char *)path, getuid(), mFileGroup);
Mike Lockwood7a0bd172011-01-18 11:06:19 -0800757
758 // SendObject does not get sent for directories, so call endSendObject here instead
759 mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
Mike Lockwood56118b52010-05-11 17:16:59 -0400760 } else {
761 mSendObjectFilePath = path;
762 // save the handle for the SendObject call, which should follow
763 mSendObjectHandle = handle;
Mike Lockwoodd815f792010-07-12 08:49:01 -0400764 mSendObjectFormat = format;
Mike Lockwood56118b52010-05-11 17:16:59 -0400765 }
766
767 mResponse.setParameter(1, storageID);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400768 mResponse.setParameter(2, parent);
Mike Lockwood56118b52010-05-11 17:16:59 -0400769 mResponse.setParameter(3, handle);
770
771 return MTP_RESPONSE_OK;
772}
773
774MtpResponseCode MtpServer::doSendObject() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500775 if (!hasStorage())
776 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodd815f792010-07-12 08:49:01 -0400777 MtpResponseCode result = MTP_RESPONSE_OK;
778 mode_t mask;
779 int ret;
780
Mike Lockwood56118b52010-05-11 17:16:59 -0400781 if (mSendObjectHandle == kInvalidObjectHandle) {
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400782 LOGE("Expected SendObjectInfo before SendObject");
Mike Lockwoodd815f792010-07-12 08:49:01 -0400783 result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
784 goto done;
Mike Lockwood56118b52010-05-11 17:16:59 -0400785 }
786
787 // read the header
Mike Lockwoodd815f792010-07-12 08:49:01 -0400788 ret = mData.readDataHeader(mFD);
Mike Lockwood56118b52010-05-11 17:16:59 -0400789 // FIXME - check for errors here.
790
791 // reset so we don't attempt to send this back
792 mData.reset();
793
794 mtp_file_range mfr;
Mike Lockwood42dbfa52010-06-22 15:03:53 -0400795 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
796 if (mfr.fd < 0) {
Mike Lockwoodd815f792010-07-12 08:49:01 -0400797 result = MTP_RESPONSE_GENERAL_ERROR;
798 goto done;
Mike Lockwood42dbfa52010-06-22 15:03:53 -0400799 }
Mike Lockwooddad69272010-07-02 15:15:07 -0400800 fchown(mfr.fd, getuid(), mFileGroup);
801 // set permissions
Mike Lockwoodd815f792010-07-12 08:49:01 -0400802 mask = umask(0);
Mike Lockwooddad69272010-07-02 15:15:07 -0400803 fchmod(mfr.fd, mFilePermission);
804 umask(mask);
805
Mike Lockwood56118b52010-05-11 17:16:59 -0400806 mfr.offset = 0;
807 mfr.length = mSendObjectFileSize;
808
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800809 LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
Mike Lockwood56118b52010-05-11 17:16:59 -0400810 // transfer the file
811 ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
Mike Lockwood42dbfa52010-06-22 15:03:53 -0400812 close(mfr.fd);
Mike Lockwooddad69272010-07-02 15:15:07 -0400813
Mike Lockwood3e6616d2010-06-29 18:11:52 -0400814 LOGV("MTP_RECEIVE_FILE returned %d", ret);
Mike Lockwood56118b52010-05-11 17:16:59 -0400815
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400816 if (ret < 0) {
817 unlink(mSendObjectFilePath);
818 if (errno == ECANCELED)
Mike Lockwoodd815f792010-07-12 08:49:01 -0400819 result = MTP_RESPONSE_TRANSACTION_CANCELLED;
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400820 else
Mike Lockwoodd815f792010-07-12 08:49:01 -0400821 result = MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwooda82d3c52010-06-04 09:49:21 -0400822 }
Mike Lockwoodd815f792010-07-12 08:49:01 -0400823
824done:
825 mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
Mike Lockwood7a0bd172011-01-18 11:06:19 -0800826 result == MTP_RESPONSE_OK);
Mike Lockwoodd815f792010-07-12 08:49:01 -0400827 mSendObjectHandle = kInvalidObjectHandle;
828 mSendObjectFormat = 0;
829 return result;
Mike Lockwood56118b52010-05-11 17:16:59 -0400830}
831
Mike Lockwoodccb6e962010-09-13 17:15:58 -0400832static void deleteRecursive(const char* path) {
833 char pathbuf[PATH_MAX];
834 int pathLength = strlen(path);
835 if (pathLength >= sizeof(pathbuf) - 1) {
836 LOGE("path too long: %s\n", path);
837 }
838 strcpy(pathbuf, path);
839 if (pathbuf[pathLength - 1] != '/') {
840 pathbuf[pathLength++] = '/';
841 }
842 char* fileSpot = pathbuf + pathLength;
843 int pathRemaining = sizeof(pathbuf) - pathLength - 1;
844
845 DIR* dir = opendir(path);
846 if (!dir) {
847 LOGE("opendir %s failed: %s", path, strerror(errno));
848 return;
849 }
850
851 struct dirent* entry;
852 while ((entry = readdir(dir))) {
853 const char* name = entry->d_name;
854
855 // ignore "." and ".."
856 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
857 continue;
858 }
859
860 int nameLength = strlen(name);
861 if (nameLength > pathRemaining) {
862 LOGE("path %s/%s too long\n", path, name);
863 continue;
864 }
865 strcpy(fileSpot, name);
866
867 int type = entry->d_type;
868 if (entry->d_type == DT_DIR) {
869 deleteRecursive(pathbuf);
870 rmdir(pathbuf);
871 } else {
872 unlink(pathbuf);
873 }
874 }
Mike Lockwooda108b2f2010-11-11 11:22:32 -0500875 closedir(dir);
Mike Lockwoodccb6e962010-09-13 17:15:58 -0400876}
877
878static void deletePath(const char* path) {
879 struct stat statbuf;
880 if (stat(path, &statbuf) == 0) {
881 if (S_ISDIR(statbuf.st_mode)) {
882 deleteRecursive(path);
883 rmdir(path);
884 } else {
885 unlink(path);
886 }
887 } else {
888 LOGE("deletePath stat failed for %s: %s", path, strerror(errno));
889 }
890}
891
Mike Lockwood56118b52010-05-11 17:16:59 -0400892MtpResponseCode MtpServer::doDeleteObject() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -0500893 if (!hasStorage())
894 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwood56118b52010-05-11 17:16:59 -0400895 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodccb6e962010-09-13 17:15:58 -0400896 MtpObjectFormat format = mRequest.getParameter(2);
Mike Lockwood56118b52010-05-11 17:16:59 -0400897 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
898 // FIXME - implement deleting objects by format
Mike Lockwood56118b52010-05-11 17:16:59 -0400899
900 MtpString filePath;
901 int64_t fileLength;
Mike Lockwood365e03e2010-12-08 16:08:01 -0800902 int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400903 if (result == MTP_RESPONSE_OK) {
904 LOGV("deleting %s", (const char *)filePath);
Mike Lockwoodccb6e962010-09-13 17:15:58 -0400905 deletePath((const char *)filePath);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400906 return mDatabase->deleteFile(handle);
907 } else {
908 return result;
909 }
Mike Lockwood56118b52010-05-11 17:16:59 -0400910}
911
912MtpResponseCode MtpServer::doGetObjectPropDesc() {
Mike Lockwood767c5e42010-06-30 17:00:35 -0400913 MtpObjectProperty propCode = mRequest.getParameter(1);
Mike Lockwood56118b52010-05-11 17:16:59 -0400914 MtpObjectFormat format = mRequest.getParameter(2);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800915 LOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
Mike Lockwood828d19d2010-08-10 15:20:35 -0400916 MtpDebug::getFormatCodeName(format));
917 MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
Mike Lockwood767c5e42010-06-30 17:00:35 -0400918 if (!property)
919 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwood767c5e42010-06-30 17:00:35 -0400920 property->write(mData);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400921 delete property;
922 return MTP_RESPONSE_OK;
923}
924
925MtpResponseCode MtpServer::doGetDevicePropDesc() {
926 MtpDeviceProperty propCode = mRequest.getParameter(1);
Mike Lockwoodf26a5862011-01-21 21:00:54 -0800927 LOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
Mike Lockwood828d19d2010-08-10 15:20:35 -0400928 MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
929 if (!property)
930 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
931 property->write(mData);
932 delete property;
Mike Lockwood767c5e42010-06-30 17:00:35 -0400933 return MTP_RESPONSE_OK;
Mike Lockwood56118b52010-05-11 17:16:59 -0400934}
Mike Lockwood8d3257a2010-05-14 10:10:36 -0400935
936} // namespace android