blob: 73dee0dea89b49aba2eb0f27a1577ee1c8e5949e [file] [log] [blame]
Mike Lockwood16864ba2010-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>
24
25#include "MtpDebug.h"
26#include "MtpServer.h"
27#include "MtpStorage.h"
28#include "MtpStringBuffer.h"
29#include "MtpDatabase.h"
30
31#include "f_mtp.h"
32
Mike Lockwood7850ef92010-05-14 10:10:36 -040033namespace android {
34
Mike Lockwood16864ba2010-05-11 17:16:59 -040035static const MtpOperationCode kSupportedOperationCodes[] = {
36 MTP_OPERATION_GET_DEVICE_INFO,
37 MTP_OPERATION_OPEN_SESSION,
38 MTP_OPERATION_CLOSE_SESSION,
39 MTP_OPERATION_GET_STORAGE_IDS,
40 MTP_OPERATION_GET_STORAGE_INFO,
41 MTP_OPERATION_GET_NUM_OBJECTS,
42 MTP_OPERATION_GET_OBJECT_HANDLES,
43 MTP_OPERATION_GET_OBJECT_INFO,
44 MTP_OPERATION_GET_OBJECT,
45// MTP_OPERATION_GET_THUMB,
46 MTP_OPERATION_DELETE_OBJECT,
47 MTP_OPERATION_SEND_OBJECT_INFO,
48 MTP_OPERATION_SEND_OBJECT,
49// MTP_OPERATION_INITIATE_CAPTURE,
50// MTP_OPERATION_FORMAT_STORE,
51// MTP_OPERATION_RESET_DEVICE,
52// MTP_OPERATION_SELF_TEST,
53// MTP_OPERATION_SET_OBJECT_PROTECTION,
54// MTP_OPERATION_POWER_DOWN,
55 MTP_OPERATION_GET_DEVICE_PROP_DESC,
56 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
57 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
58 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
59// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
60// MTP_OPERATION_MOVE_OBJECT,
61// MTP_OPERATION_COPY_OBJECT,
62// MTP_OPERATION_GET_PARTIAL_OBJECT,
63// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
64 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
65// MTP_OPERATION_GET_OBJECT_PROP_DESC,
66 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
67 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
68// MTP_OPERATION_GET_OBJECT_REFERENCES,
69// MTP_OPERATION_SET_OBJECT_REFERENCES,
70// MTP_OPERATION_SKIP,
71};
72
73static const MtpObjectProperty kSupportedObjectProperties[] = {
74 MTP_PROPERTY_STORAGE_ID,
75 MTP_PROPERTY_OBJECT_FORMAT,
76 MTP_PROPERTY_OBJECT_SIZE,
77 MTP_PROPERTY_OBJECT_FILE_NAME,
78 MTP_PROPERTY_PARENT_OBJECT,
79};
80
81static const MtpObjectFormat kSupportedPlaybackFormats[] = {
Mike Lockwoodfceef462010-05-14 15:35:17 -040082 // MTP_FORMAT_UNDEFINED,
Mike Lockwood16864ba2010-05-11 17:16:59 -040083 MTP_FORMAT_ASSOCIATION,
Mike Lockwoodfceef462010-05-14 15:35:17 -040084 // MTP_FORMAT_TEXT,
85 // MTP_FORMAT_HTML,
Mike Lockwood16864ba2010-05-11 17:16:59 -040086 MTP_FORMAT_MP3,
Mike Lockwoodfceef462010-05-14 15:35:17 -040087 //MTP_FORMAT_AVI,
88 MTP_FORMAT_MPEG,
89 // MTP_FORMAT_ASF,
90 MTP_FORMAT_EXIF_JPEG,
91 MTP_FORMAT_TIFF_EP,
92 // MTP_FORMAT_BMP,
93 MTP_FORMAT_GIF,
94 MTP_FORMAT_JFIF,
95 MTP_FORMAT_PNG,
96 MTP_FORMAT_TIFF,
97 MTP_FORMAT_WMA,
98 MTP_FORMAT_OGG,
99 MTP_FORMAT_AAC,
100 // MTP_FORMAT_FLAC,
101 // MTP_FORMAT_WMV,
102 MTP_FORMAT_MP4_CONTAINER,
103 MTP_FORMAT_MP2,
104 MTP_FORMAT_3GP_CONTAINER,
105 // MTP_FORMAT_ABSTRACT_AUDIO_ALBUM,
106 // MTP_FORMAT_ABSTRACT_AV_PLAYLIST,
107 // MTP_FORMAT_WPL_PLAYLIST,
108 // MTP_FORMAT_M3U_PLAYLIST,
109 // MTP_FORMAT_MPL_PLAYLIST,
110 // MTP_FORMAT_PLS_PLAYLIST,
Mike Lockwood16864ba2010-05-11 17:16:59 -0400111};
112
113MtpServer::MtpServer(int fd, const char* databasePath)
114 : mFD(fd),
115 mDatabasePath(databasePath),
116 mDatabase(NULL),
117 mSessionID(0),
118 mSessionOpen(false),
119 mSendObjectHandle(kInvalidObjectHandle),
120 mSendObjectFileSize(0)
121{
122 mDatabase = new MtpDatabase();
123 mDatabase->open(databasePath, true);
124}
125
126MtpServer::~MtpServer() {
127}
128
129void MtpServer::addStorage(const char* filePath) {
130 int index = mStorages.size() + 1;
131 index |= index << 16; // set high and low part to our index
132 MtpStorage* storage = new MtpStorage(index, filePath, mDatabase);
133 addStorage(storage);
134}
135
136MtpStorage* MtpServer::getStorage(MtpStorageID id) {
137 for (int i = 0; i < mStorages.size(); i++) {
138 MtpStorage* storage = mStorages[i];
139 if (storage->getStorageID() == id)
140 return storage;
141 }
142 return NULL;
143}
144
145void MtpServer::scanStorage() {
146 for (int i = 0; i < mStorages.size(); i++) {
147 MtpStorage* storage = mStorages[i];
148 storage->scanFiles();
149 }
150}
151
152void MtpServer::run() {
153 int fd = mFD;
154
155 printf("MtpServer::run fd: %d\n", fd);
156
157 while (1) {
158 int ret = mRequest.read(fd);
159 if (ret < 0) {
160 fprintf(stderr, "request read returned %d, errno: %d\n", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400161 if (errno == ECANCELED) {
162 // return to top of loop and wait for next command
163 continue;
164 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400165 break;
166 }
167 MtpOperationCode operation = mRequest.getOperationCode();
168 MtpTransactionID transaction = mRequest.getTransactionID();
169
170 printf("operation: %s\n", MtpDebug::getOperationCodeName(operation));
171 mRequest.dump();
172
173 // FIXME need to generalize this
174 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO);
175 if (dataIn) {
176 int ret = mData.read(fd);
177 if (ret < 0) {
178 fprintf(stderr, "data read returned %d, errno: %d\n", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400179 if (errno == ECANCELED) {
180 // return to top of loop and wait for next command
181 continue;
182 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400183 break;
184 }
185 printf("received data:\n");
186 mData.dump();
187 } else {
188 mData.reset();
189 }
190
Mike Lockwood916076c2010-06-04 09:49:21 -0400191 if (handleRequest()) {
192 if (!dataIn && mData.hasData()) {
193 mData.setOperationCode(operation);
194 mData.setTransactionID(transaction);
195 printf("sending data:\n");
196 mData.dump();
197 ret = mData.write(fd);
198 if (ret < 0) {
199 fprintf(stderr, "request write returned %d, errno: %d\n", ret, errno);
200 if (errno == ECANCELED) {
201 // return to top of loop and wait for next command
202 continue;
203 }
204 break;
205 }
206 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400207
Mike Lockwood916076c2010-06-04 09:49:21 -0400208 mResponse.setTransactionID(transaction);
209 printf("sending response %04X\n", mResponse.getResponseCode());
210 ret = mResponse.write(fd);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400211 if (ret < 0) {
212 fprintf(stderr, "request write returned %d, errno: %d\n", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400213 if (errno == ECANCELED) {
214 // return to top of loop and wait for next command
215 continue;
216 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400217 break;
218 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400219 } else {
220 printf("skipping response\n");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400221 }
222 }
223}
224
Mike Lockwood916076c2010-06-04 09:49:21 -0400225bool MtpServer::handleRequest() {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400226 MtpOperationCode operation = mRequest.getOperationCode();
227 MtpResponseCode response;
228
229 mResponse.reset();
230
231 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
232 // FIXME - need to delete mSendObjectHandle from the database
233 fprintf(stderr, "expected SendObject after SendObjectInfo\n");
234 mSendObjectHandle = kInvalidObjectHandle;
235 }
236
237 switch (operation) {
238 case MTP_OPERATION_GET_DEVICE_INFO:
239 response = doGetDeviceInfo();
240 break;
241 case MTP_OPERATION_OPEN_SESSION:
242 response = doOpenSession();
243 break;
244 case MTP_OPERATION_CLOSE_SESSION:
245 response = doCloseSession();
246 break;
247 case MTP_OPERATION_GET_STORAGE_IDS:
248 response = doGetStorageIDs();
249 break;
250 case MTP_OPERATION_GET_STORAGE_INFO:
251 response = doGetStorageInfo();
252 break;
253 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
254 response = doGetObjectPropsSupported();
255 break;
256 case MTP_OPERATION_GET_OBJECT_HANDLES:
257 response = doGetObjectHandles();
258 break;
259 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
260 response = doGetObjectPropValue();
261 break;
262 case MTP_OPERATION_GET_OBJECT_INFO:
263 response = doGetObjectInfo();
264 break;
265 case MTP_OPERATION_GET_OBJECT:
266 response = doGetObject();
267 break;
268 case MTP_OPERATION_SEND_OBJECT_INFO:
269 response = doSendObjectInfo();
270 break;
271 case MTP_OPERATION_SEND_OBJECT:
272 response = doSendObject();
273 break;
274 case MTP_OPERATION_DELETE_OBJECT:
275 response = doDeleteObject();
276 break;
277 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
278 default:
279 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
280 break;
281 }
282
Mike Lockwood916076c2010-06-04 09:49:21 -0400283 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
284 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400285 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400286 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400287}
288
289MtpResponseCode MtpServer::doGetDeviceInfo() {
290 MtpStringBuffer string;
291
292 // fill in device info
293 mData.putUInt16(MTP_STANDARD_VERSION);
294 mData.putUInt32(6); // MTP Vendor Extension ID
295 mData.putUInt16(MTP_STANDARD_VERSION);
296 string.set("microsoft.com: 1.0;");
297 mData.putString(string); // MTP Extensions
298 mData.putUInt16(0); //Functional Mode
299 mData.putAUInt16(kSupportedOperationCodes,
300 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
301 mData.putEmptyArray(); // Events Supported
302 mData.putEmptyArray(); // Device Properties Supported
303 mData.putEmptyArray(); // Capture Formats
304 mData.putAUInt16(kSupportedPlaybackFormats,
305 sizeof(kSupportedPlaybackFormats) / sizeof(uint16_t)); // Playback Formats
306 // FIXME
307 string.set("Google, Inc.");
308 mData.putString(string); // Manufacturer
309 string.set("Just an Ordinary MTP Device");
310 mData.putString(string); // Model
311 string.set("1.0");
312 mData.putString(string); // Device Version
313 string.set("123456789012345678AA");
314 mData.putString(string); // Serial Number
315
316 return MTP_RESPONSE_OK;
317}
318
319MtpResponseCode MtpServer::doOpenSession() {
320 if (mSessionOpen) {
321 mResponse.setParameter(1, mSessionID);
322 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
323 }
324 mSessionID = mRequest.getParameter(1);
325 mSessionOpen = true;
326 return MTP_RESPONSE_OK;
327}
328
329MtpResponseCode MtpServer::doCloseSession() {
330 if (!mSessionOpen)
331 return MTP_RESPONSE_SESSION_NOT_OPEN;
332 mSessionID = 0;
333 mSessionOpen = false;
334 return MTP_RESPONSE_OK;
335}
336
337MtpResponseCode MtpServer::doGetStorageIDs() {
338 if (!mSessionOpen)
339 return MTP_RESPONSE_SESSION_NOT_OPEN;
340
341 int count = mStorages.size();
342 mData.putUInt32(count);
343 for (int i = 0; i < count; i++)
344 mData.putUInt32(mStorages[i]->getStorageID());
345
346 return MTP_RESPONSE_OK;
347}
348
349MtpResponseCode MtpServer::doGetStorageInfo() {
350 MtpStringBuffer string;
351
352 if (!mSessionOpen)
353 return MTP_RESPONSE_SESSION_NOT_OPEN;
354 MtpStorageID id = mRequest.getParameter(1);
355 MtpStorage* storage = getStorage(id);
356 if (!storage)
357 return MTP_RESPONSE_INVALID_STORAGE_ID;
358
359 mData.putUInt16(storage->getType());
360 mData.putUInt16(storage->getFileSystemType());
361 mData.putUInt16(storage->getAccessCapability());
362 mData.putUInt64(storage->getMaxCapacity());
363 mData.putUInt64(storage->getFreeSpace());
364 mData.putUInt32(1024*1024*1024); // Free Space in Objects
365 string.set(storage->getDescription());
366 mData.putString(string);
367 mData.putEmptyString(); // Volume Identifier
368
369 return MTP_RESPONSE_OK;
370}
371
372MtpResponseCode MtpServer::doGetObjectPropsSupported() {
373 if (!mSessionOpen)
374 return MTP_RESPONSE_SESSION_NOT_OPEN;
375 MtpObjectFormat format = mRequest.getParameter(1);
376 mData.putAUInt16(kSupportedObjectProperties,
377 sizeof(kSupportedObjectProperties) / sizeof(uint16_t));
378 return MTP_RESPONSE_OK;
379}
380
381MtpResponseCode MtpServer::doGetObjectHandles() {
382 if (!mSessionOpen)
383 return MTP_RESPONSE_SESSION_NOT_OPEN;
384 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400385 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400386 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
387 // 0x00000000 for all objects?
388
389 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
390 mData.putAUInt32(handles);
391 delete handles;
392 return MTP_RESPONSE_OK;
393}
394
395MtpResponseCode MtpServer::doGetObjectPropValue() {
396 MtpObjectHandle handle = mRequest.getParameter(1);
397 MtpObjectProperty property = mRequest.getParameter(2);
398
399 return mDatabase->getObjectProperty(handle, property, mData);
400}
401
402MtpResponseCode MtpServer::doGetObjectInfo() {
403 MtpObjectHandle handle = mRequest.getParameter(1);
404 return mDatabase->getObjectInfo(handle, mData);
405}
406
407MtpResponseCode MtpServer::doGetObject() {
408 MtpObjectHandle handle = mRequest.getParameter(1);
409 MtpString filePath;
410 int64_t fileLength;
411 if (!mDatabase->getObjectFilePath(handle, filePath, fileLength))
412 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
413
414 mtp_file_range mfr;
415 mfr.path = filePath;
416 mfr.path_length = strlen(mfr.path);
417 mfr.offset = 0;
418 mfr.length = fileLength;
419
420 // send data header
421 mData.setOperationCode(mRequest.getOperationCode());
422 mData.setTransactionID(mRequest.getTransactionID());
423 mData.writeDataHeader(mFD, fileLength);
424
425 // then transfer the file
426 int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
Mike Lockwood916076c2010-06-04 09:49:21 -0400427 if (ret < 0) {
428 if (errno == ECANCELED)
429 return MTP_RESPONSE_TRANSACTION_CANCELLED;
430 else
431 return MTP_RESPONSE_GENERAL_ERROR;
432 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400433 return MTP_RESPONSE_OK;
434}
435
436MtpResponseCode MtpServer::doSendObjectInfo() {
437 MtpString path;
438 MtpStorageID storageID = mRequest.getParameter(1);
439 MtpStorage* storage = getStorage(storageID);
440 MtpObjectHandle parent = mRequest.getParameter(2);
441 if (!storage)
442 return MTP_RESPONSE_INVALID_STORAGE_ID;
443
444 // special case the root
445 if (parent == MTP_PARENT_ROOT)
446 path = storage->getPath();
447 else {
448 int64_t dummy;
449 if (!mDatabase->getObjectFilePath(parent, path, dummy))
450 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
451 }
452
453 // read only the fields we need
454 mData.getUInt32(); // storage ID
455 MtpObjectFormat format = mData.getUInt16();
456 mData.getUInt16(); // protection status
457 mSendObjectFileSize = mData.getUInt32();
458 mData.getUInt16(); // thumb format
459 mData.getUInt32(); // thumb compressed size
460 mData.getUInt32(); // thumb pix width
461 mData.getUInt32(); // thumb pix height
462 mData.getUInt32(); // image pix width
463 mData.getUInt32(); // image pix height
464 mData.getUInt32(); // image bit depth
465 mData.getUInt32(); // parent
466 uint16_t associationType = mData.getUInt16();
467 uint32_t associationDesc = mData.getUInt32(); // association desc
468 mData.getUInt32(); // sequence number
469 MtpStringBuffer name, created, modified;
470 mData.getString(name); // file name
471 mData.getString(created); // date created
472 mData.getString(modified); // date modified
473 // keywords follow
474
Mike Lockwoodfceef462010-05-14 15:35:17 -0400475 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400476 if (!parseDateTime(modified, modifiedTime))
477 modifiedTime = 0;
478printf("SendObjectInfo format: %04X size: %d name: %s, created: %s, modified: %s\n",
479format, mSendObjectFileSize, (const char*)name, (const char*)created, (const char*)modified);
480
481 if (path[path.size() - 1] != '/')
482 path += "/";
483 path += (const char *)name;
484
Mike Lockwoodfceef462010-05-14 15:35:17 -0400485 mDatabase->beginTransaction();
486 MtpObjectHandle handle = mDatabase->addFile((const char*)path, format, parent, storageID,
487 mSendObjectFileSize, modifiedTime);
488 if (handle == kInvalidObjectHandle) {
489 mDatabase->rollbackTransaction();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400490 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400491 }
492 uint32_t table = MtpDatabase::getTableForFile(format);
493 if (table == kObjectHandleTableAudio)
494 handle = mDatabase->addAudioFile(handle);
495 mDatabase->commitTransaction();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400496
497 if (format == MTP_FORMAT_ASSOCIATION) {
498 mode_t mask = umask(0);
499 int ret = mkdir((const char *)path, S_IRWXU | S_IRWXG | S_IRWXO);
500 umask(mask);
501 if (ret && ret != -EEXIST)
502 return MTP_RESPONSE_GENERAL_ERROR;
503 } else {
504 mSendObjectFilePath = path;
505 // save the handle for the SendObject call, which should follow
506 mSendObjectHandle = handle;
507 }
508
509 mResponse.setParameter(1, storageID);
510 mResponse.setParameter(2, parent);
511 mResponse.setParameter(3, handle);
512
513 return MTP_RESPONSE_OK;
514}
515
516MtpResponseCode MtpServer::doSendObject() {
517 if (mSendObjectHandle == kInvalidObjectHandle) {
518 fprintf(stderr, "Expected SendObjectInfo before SendObject\n");
519 return MTP_RESPONSE_NO_VALID_OBJECT_INFO;
520 }
521
522 // read the header
523 int ret = mData.readDataHeader(mFD);
524 // FIXME - check for errors here.
525
526 // reset so we don't attempt to send this back
527 mData.reset();
528
529 mtp_file_range mfr;
530 mfr.path = (const char*)mSendObjectFilePath;
531 mfr.path_length = strlen(mfr.path);
532 mfr.offset = 0;
533 mfr.length = mSendObjectFileSize;
534
535 // transfer the file
536 ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
Mike Lockwood916076c2010-06-04 09:49:21 -0400537 // FIXME - we need to delete mSendObjectHandle from the database if this fails.
Mike Lockwood16864ba2010-05-11 17:16:59 -0400538 printf("MTP_RECEIVE_FILE returned %d\n", ret);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400539 mSendObjectHandle = kInvalidObjectHandle;
540
Mike Lockwood916076c2010-06-04 09:49:21 -0400541 if (ret < 0) {
542 unlink(mSendObjectFilePath);
543 if (errno == ECANCELED)
544 return MTP_RESPONSE_TRANSACTION_CANCELLED;
545 else
546 return MTP_RESPONSE_GENERAL_ERROR;
547 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400548 return MTP_RESPONSE_OK;
549}
550
551MtpResponseCode MtpServer::doDeleteObject() {
552 MtpObjectHandle handle = mRequest.getParameter(1);
553 MtpObjectFormat format = mRequest.getParameter(1);
554 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
555 // FIXME - implement deleting objects by format
556 // FIXME - handle non-empty directories
557
558 MtpString filePath;
559 int64_t fileLength;
560 if (!mDatabase->getObjectFilePath(handle, filePath, fileLength))
561 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
562
563printf("deleting %s\n", (const char *)filePath);
564 // one of these should work
565 rmdir((const char *)filePath);
566 unlink((const char *)filePath);
567
568 mDatabase->deleteFile(handle);
569
570 return MTP_RESPONSE_OK;
571}
572
573MtpResponseCode MtpServer::doGetObjectPropDesc() {
574 MtpObjectProperty property = mRequest.getParameter(1);
575 MtpObjectFormat format = mRequest.getParameter(2);
576
577 return -1;
578}
Mike Lockwood7850ef92010-05-14 10:10:36 -0400579
580} // namespace android