blob: 048d1dc48a2b2ee8b873443c639b976f878f780f [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
Mike Lockwoodb14e5882010-06-29 18:11:52 -040017#define LOG_TAG "MtpServer"
18
Mike Lockwood16864ba2010-05-11 17:16:59 -040019#include <stdio.h>
20#include <stdlib.h>
21#include <sys/types.h>
22#include <sys/ioctl.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <errno.h>
26
Mike Lockwoodc42aa122010-06-14 17:58:08 -070027#include <cutils/properties.h>
28
Mike Lockwood16864ba2010-05-11 17:16:59 -040029#include "MtpDebug.h"
30#include "MtpServer.h"
31#include "MtpStorage.h"
32#include "MtpStringBuffer.h"
33#include "MtpDatabase.h"
Mike Lockwoodb14e5882010-06-29 18:11:52 -040034#include "MtpDebug.h"
Mike Lockwood16864ba2010-05-11 17:16:59 -040035
36#include "f_mtp.h"
37
Mike Lockwood7850ef92010-05-14 10:10:36 -040038namespace android {
39
Mike Lockwood16864ba2010-05-11 17:16:59 -040040static const MtpOperationCode kSupportedOperationCodes[] = {
41 MTP_OPERATION_GET_DEVICE_INFO,
42 MTP_OPERATION_OPEN_SESSION,
43 MTP_OPERATION_CLOSE_SESSION,
44 MTP_OPERATION_GET_STORAGE_IDS,
45 MTP_OPERATION_GET_STORAGE_INFO,
46 MTP_OPERATION_GET_NUM_OBJECTS,
47 MTP_OPERATION_GET_OBJECT_HANDLES,
48 MTP_OPERATION_GET_OBJECT_INFO,
49 MTP_OPERATION_GET_OBJECT,
50// MTP_OPERATION_GET_THUMB,
51 MTP_OPERATION_DELETE_OBJECT,
52 MTP_OPERATION_SEND_OBJECT_INFO,
53 MTP_OPERATION_SEND_OBJECT,
54// MTP_OPERATION_INITIATE_CAPTURE,
55// MTP_OPERATION_FORMAT_STORE,
56// MTP_OPERATION_RESET_DEVICE,
57// MTP_OPERATION_SELF_TEST,
58// MTP_OPERATION_SET_OBJECT_PROTECTION,
59// MTP_OPERATION_POWER_DOWN,
60 MTP_OPERATION_GET_DEVICE_PROP_DESC,
61 MTP_OPERATION_GET_DEVICE_PROP_VALUE,
62 MTP_OPERATION_SET_DEVICE_PROP_VALUE,
63 MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
64// MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
65// MTP_OPERATION_MOVE_OBJECT,
66// MTP_OPERATION_COPY_OBJECT,
67// MTP_OPERATION_GET_PARTIAL_OBJECT,
68// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
69 MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
70// MTP_OPERATION_GET_OBJECT_PROP_DESC,
71 MTP_OPERATION_GET_OBJECT_PROP_VALUE,
72 MTP_OPERATION_SET_OBJECT_PROP_VALUE,
73// MTP_OPERATION_GET_OBJECT_REFERENCES,
74// MTP_OPERATION_SET_OBJECT_REFERENCES,
75// MTP_OPERATION_SKIP,
76};
77
78static const MtpObjectProperty kSupportedObjectProperties[] = {
79 MTP_PROPERTY_STORAGE_ID,
80 MTP_PROPERTY_OBJECT_FORMAT,
81 MTP_PROPERTY_OBJECT_SIZE,
82 MTP_PROPERTY_OBJECT_FILE_NAME,
83 MTP_PROPERTY_PARENT_OBJECT,
84};
85
86static const MtpObjectFormat kSupportedPlaybackFormats[] = {
Mike Lockwoodfceef462010-05-14 15:35:17 -040087 // MTP_FORMAT_UNDEFINED,
Mike Lockwood16864ba2010-05-11 17:16:59 -040088 MTP_FORMAT_ASSOCIATION,
Mike Lockwoodfceef462010-05-14 15:35:17 -040089 // MTP_FORMAT_TEXT,
90 // MTP_FORMAT_HTML,
Mike Lockwood16864ba2010-05-11 17:16:59 -040091 MTP_FORMAT_MP3,
Mike Lockwoodfceef462010-05-14 15:35:17 -040092 //MTP_FORMAT_AVI,
93 MTP_FORMAT_MPEG,
94 // MTP_FORMAT_ASF,
95 MTP_FORMAT_EXIF_JPEG,
96 MTP_FORMAT_TIFF_EP,
97 // MTP_FORMAT_BMP,
98 MTP_FORMAT_GIF,
99 MTP_FORMAT_JFIF,
100 MTP_FORMAT_PNG,
101 MTP_FORMAT_TIFF,
102 MTP_FORMAT_WMA,
103 MTP_FORMAT_OGG,
104 MTP_FORMAT_AAC,
105 // MTP_FORMAT_FLAC,
106 // MTP_FORMAT_WMV,
107 MTP_FORMAT_MP4_CONTAINER,
108 MTP_FORMAT_MP2,
109 MTP_FORMAT_3GP_CONTAINER,
110 // MTP_FORMAT_ABSTRACT_AUDIO_ALBUM,
111 // MTP_FORMAT_ABSTRACT_AV_PLAYLIST,
112 // MTP_FORMAT_WPL_PLAYLIST,
113 // MTP_FORMAT_M3U_PLAYLIST,
114 // MTP_FORMAT_MPL_PLAYLIST,
115 // MTP_FORMAT_PLS_PLAYLIST,
Mike Lockwood16864ba2010-05-11 17:16:59 -0400116};
117
118MtpServer::MtpServer(int fd, const char* databasePath)
119 : mFD(fd),
120 mDatabasePath(databasePath),
121 mDatabase(NULL),
122 mSessionID(0),
123 mSessionOpen(false),
124 mSendObjectHandle(kInvalidObjectHandle),
125 mSendObjectFileSize(0)
126{
127 mDatabase = new MtpDatabase();
128 mDatabase->open(databasePath, true);
129}
130
131MtpServer::~MtpServer() {
132}
133
134void MtpServer::addStorage(const char* filePath) {
135 int index = mStorages.size() + 1;
136 index |= index << 16; // set high and low part to our index
137 MtpStorage* storage = new MtpStorage(index, filePath, mDatabase);
138 addStorage(storage);
139}
140
141MtpStorage* MtpServer::getStorage(MtpStorageID id) {
142 for (int i = 0; i < mStorages.size(); i++) {
143 MtpStorage* storage = mStorages[i];
144 if (storage->getStorageID() == id)
145 return storage;
146 }
147 return NULL;
148}
149
150void MtpServer::scanStorage() {
151 for (int i = 0; i < mStorages.size(); i++) {
152 MtpStorage* storage = mStorages[i];
153 storage->scanFiles();
154 }
155}
156
157void MtpServer::run() {
158 int fd = mFD;
159
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400160 LOGD("MtpServer::run fd: %d", fd);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400161
162 while (1) {
163 int ret = mRequest.read(fd);
164 if (ret < 0) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400165 LOGE("request read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400166 if (errno == ECANCELED) {
167 // return to top of loop and wait for next command
168 continue;
169 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400170 break;
171 }
172 MtpOperationCode operation = mRequest.getOperationCode();
173 MtpTransactionID transaction = mRequest.getTransactionID();
174
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400175 LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
Mike Lockwood16864ba2010-05-11 17:16:59 -0400176 mRequest.dump();
177
178 // FIXME need to generalize this
179 bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO);
180 if (dataIn) {
181 int ret = mData.read(fd);
182 if (ret < 0) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400183 LOGE("data read returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400184 if (errno == ECANCELED) {
185 // return to top of loop and wait for next command
186 continue;
187 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400188 break;
189 }
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400190 LOGV("received data:");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400191 mData.dump();
192 } else {
193 mData.reset();
194 }
195
Mike Lockwood916076c2010-06-04 09:49:21 -0400196 if (handleRequest()) {
197 if (!dataIn && mData.hasData()) {
198 mData.setOperationCode(operation);
199 mData.setTransactionID(transaction);
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400200 LOGV("sending data:");
Mike Lockwood916076c2010-06-04 09:49:21 -0400201 mData.dump();
202 ret = mData.write(fd);
203 if (ret < 0) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400204 LOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400205 if (errno == ECANCELED) {
206 // return to top of loop and wait for next command
207 continue;
208 }
209 break;
210 }
211 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400212
Mike Lockwood916076c2010-06-04 09:49:21 -0400213 mResponse.setTransactionID(transaction);
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400214 LOGV("sending response %04X", mResponse.getResponseCode());
Mike Lockwood916076c2010-06-04 09:49:21 -0400215 ret = mResponse.write(fd);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400216 if (ret < 0) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400217 LOGE("request write returned %d, errno: %d", ret, errno);
Mike Lockwood916076c2010-06-04 09:49:21 -0400218 if (errno == ECANCELED) {
219 // return to top of loop and wait for next command
220 continue;
221 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400222 break;
223 }
Mike Lockwood916076c2010-06-04 09:49:21 -0400224 } else {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400225 LOGV("skipping response");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400226 }
227 }
228}
229
Mike Lockwood916076c2010-06-04 09:49:21 -0400230bool MtpServer::handleRequest() {
Mike Lockwood16864ba2010-05-11 17:16:59 -0400231 MtpOperationCode operation = mRequest.getOperationCode();
232 MtpResponseCode response;
233
234 mResponse.reset();
235
236 if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
237 // FIXME - need to delete mSendObjectHandle from the database
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400238 LOGE("expected SendObject after SendObjectInfo");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400239 mSendObjectHandle = kInvalidObjectHandle;
240 }
241
242 switch (operation) {
243 case MTP_OPERATION_GET_DEVICE_INFO:
244 response = doGetDeviceInfo();
245 break;
246 case MTP_OPERATION_OPEN_SESSION:
247 response = doOpenSession();
248 break;
249 case MTP_OPERATION_CLOSE_SESSION:
250 response = doCloseSession();
251 break;
252 case MTP_OPERATION_GET_STORAGE_IDS:
253 response = doGetStorageIDs();
254 break;
255 case MTP_OPERATION_GET_STORAGE_INFO:
256 response = doGetStorageInfo();
257 break;
258 case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
259 response = doGetObjectPropsSupported();
260 break;
261 case MTP_OPERATION_GET_OBJECT_HANDLES:
262 response = doGetObjectHandles();
263 break;
264 case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
265 response = doGetObjectPropValue();
266 break;
267 case MTP_OPERATION_GET_OBJECT_INFO:
268 response = doGetObjectInfo();
269 break;
270 case MTP_OPERATION_GET_OBJECT:
271 response = doGetObject();
272 break;
273 case MTP_OPERATION_SEND_OBJECT_INFO:
274 response = doSendObjectInfo();
275 break;
276 case MTP_OPERATION_SEND_OBJECT:
277 response = doSendObject();
278 break;
279 case MTP_OPERATION_DELETE_OBJECT:
280 response = doDeleteObject();
281 break;
282 case MTP_OPERATION_GET_OBJECT_PROP_DESC:
283 default:
284 response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
285 break;
286 }
287
Mike Lockwood916076c2010-06-04 09:49:21 -0400288 if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
289 return false;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400290 mResponse.setResponseCode(response);
Mike Lockwood916076c2010-06-04 09:49:21 -0400291 return true;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400292}
293
294MtpResponseCode MtpServer::doGetDeviceInfo() {
295 MtpStringBuffer string;
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700296 char prop_value[PROPERTY_VALUE_MAX];
Mike Lockwood16864ba2010-05-11 17:16:59 -0400297
298 // fill in device info
299 mData.putUInt16(MTP_STANDARD_VERSION);
300 mData.putUInt32(6); // MTP Vendor Extension ID
301 mData.putUInt16(MTP_STANDARD_VERSION);
302 string.set("microsoft.com: 1.0;");
303 mData.putString(string); // MTP Extensions
304 mData.putUInt16(0); //Functional Mode
305 mData.putAUInt16(kSupportedOperationCodes,
306 sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
307 mData.putEmptyArray(); // Events Supported
308 mData.putEmptyArray(); // Device Properties Supported
309 mData.putEmptyArray(); // Capture Formats
310 mData.putAUInt16(kSupportedPlaybackFormats,
311 sizeof(kSupportedPlaybackFormats) / sizeof(uint16_t)); // Playback Formats
312 // FIXME
313 string.set("Google, Inc.");
314 mData.putString(string); // Manufacturer
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700315
316 property_get("ro.product.model", prop_value, "MTP Device");
317 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400318 mData.putString(string); // Model
319 string.set("1.0");
320 mData.putString(string); // Device Version
Mike Lockwoodc42aa122010-06-14 17:58:08 -0700321
322 property_get("ro.serialno", prop_value, "????????");
323 string.set(prop_value);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400324 mData.putString(string); // Serial Number
325
326 return MTP_RESPONSE_OK;
327}
328
329MtpResponseCode MtpServer::doOpenSession() {
330 if (mSessionOpen) {
331 mResponse.setParameter(1, mSessionID);
332 return MTP_RESPONSE_SESSION_ALREADY_OPEN;
333 }
334 mSessionID = mRequest.getParameter(1);
335 mSessionOpen = true;
336 return MTP_RESPONSE_OK;
337}
338
339MtpResponseCode MtpServer::doCloseSession() {
340 if (!mSessionOpen)
341 return MTP_RESPONSE_SESSION_NOT_OPEN;
342 mSessionID = 0;
343 mSessionOpen = false;
344 return MTP_RESPONSE_OK;
345}
346
347MtpResponseCode MtpServer::doGetStorageIDs() {
348 if (!mSessionOpen)
349 return MTP_RESPONSE_SESSION_NOT_OPEN;
350
351 int count = mStorages.size();
352 mData.putUInt32(count);
353 for (int i = 0; i < count; i++)
354 mData.putUInt32(mStorages[i]->getStorageID());
355
356 return MTP_RESPONSE_OK;
357}
358
359MtpResponseCode MtpServer::doGetStorageInfo() {
360 MtpStringBuffer string;
361
362 if (!mSessionOpen)
363 return MTP_RESPONSE_SESSION_NOT_OPEN;
364 MtpStorageID id = mRequest.getParameter(1);
365 MtpStorage* storage = getStorage(id);
366 if (!storage)
367 return MTP_RESPONSE_INVALID_STORAGE_ID;
368
369 mData.putUInt16(storage->getType());
370 mData.putUInt16(storage->getFileSystemType());
371 mData.putUInt16(storage->getAccessCapability());
372 mData.putUInt64(storage->getMaxCapacity());
373 mData.putUInt64(storage->getFreeSpace());
374 mData.putUInt32(1024*1024*1024); // Free Space in Objects
375 string.set(storage->getDescription());
376 mData.putString(string);
377 mData.putEmptyString(); // Volume Identifier
378
379 return MTP_RESPONSE_OK;
380}
381
382MtpResponseCode MtpServer::doGetObjectPropsSupported() {
383 if (!mSessionOpen)
384 return MTP_RESPONSE_SESSION_NOT_OPEN;
385 MtpObjectFormat format = mRequest.getParameter(1);
386 mData.putAUInt16(kSupportedObjectProperties,
387 sizeof(kSupportedObjectProperties) / sizeof(uint16_t));
388 return MTP_RESPONSE_OK;
389}
390
391MtpResponseCode MtpServer::doGetObjectHandles() {
392 if (!mSessionOpen)
393 return MTP_RESPONSE_SESSION_NOT_OPEN;
394 MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage
Mike Lockwoode13401b2010-05-19 15:12:14 -0400395 MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
Mike Lockwood16864ba2010-05-11 17:16:59 -0400396 MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
397 // 0x00000000 for all objects?
398
399 MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
400 mData.putAUInt32(handles);
401 delete handles;
402 return MTP_RESPONSE_OK;
403}
404
405MtpResponseCode MtpServer::doGetObjectPropValue() {
406 MtpObjectHandle handle = mRequest.getParameter(1);
407 MtpObjectProperty property = mRequest.getParameter(2);
408
409 return mDatabase->getObjectProperty(handle, property, mData);
410}
411
412MtpResponseCode MtpServer::doGetObjectInfo() {
413 MtpObjectHandle handle = mRequest.getParameter(1);
414 return mDatabase->getObjectInfo(handle, mData);
415}
416
417MtpResponseCode MtpServer::doGetObject() {
418 MtpObjectHandle handle = mRequest.getParameter(1);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400419 MtpString pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400420 int64_t fileLength;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400421 if (!mDatabase->getObjectFilePath(handle, pathBuf, fileLength))
Mike Lockwood16864ba2010-05-11 17:16:59 -0400422 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400423 const char* filePath = (const char *)pathBuf;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400424
425 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400426 mfr.fd = open(filePath, O_RDONLY);
427 if (mfr.fd < 0) {
428 return MTP_RESPONSE_GENERAL_ERROR;
429 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400430 mfr.offset = 0;
431 mfr.length = fileLength;
432
433 // send data header
434 mData.setOperationCode(mRequest.getOperationCode());
435 mData.setTransactionID(mRequest.getTransactionID());
436 mData.writeDataHeader(mFD, fileLength);
437
438 // then transfer the file
439 int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400440 close(mfr.fd);
Mike Lockwood916076c2010-06-04 09:49:21 -0400441 if (ret < 0) {
442 if (errno == ECANCELED)
443 return MTP_RESPONSE_TRANSACTION_CANCELLED;
444 else
445 return MTP_RESPONSE_GENERAL_ERROR;
446 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400447 return MTP_RESPONSE_OK;
448}
449
450MtpResponseCode MtpServer::doSendObjectInfo() {
451 MtpString path;
452 MtpStorageID storageID = mRequest.getParameter(1);
453 MtpStorage* storage = getStorage(storageID);
454 MtpObjectHandle parent = mRequest.getParameter(2);
455 if (!storage)
456 return MTP_RESPONSE_INVALID_STORAGE_ID;
457
458 // special case the root
459 if (parent == MTP_PARENT_ROOT)
460 path = storage->getPath();
461 else {
462 int64_t dummy;
463 if (!mDatabase->getObjectFilePath(parent, path, dummy))
464 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
465 }
466
467 // read only the fields we need
468 mData.getUInt32(); // storage ID
469 MtpObjectFormat format = mData.getUInt16();
470 mData.getUInt16(); // protection status
471 mSendObjectFileSize = mData.getUInt32();
472 mData.getUInt16(); // thumb format
473 mData.getUInt32(); // thumb compressed size
474 mData.getUInt32(); // thumb pix width
475 mData.getUInt32(); // thumb pix height
476 mData.getUInt32(); // image pix width
477 mData.getUInt32(); // image pix height
478 mData.getUInt32(); // image bit depth
479 mData.getUInt32(); // parent
480 uint16_t associationType = mData.getUInt16();
481 uint32_t associationDesc = mData.getUInt32(); // association desc
482 mData.getUInt32(); // sequence number
483 MtpStringBuffer name, created, modified;
484 mData.getString(name); // file name
485 mData.getString(created); // date created
486 mData.getString(modified); // date modified
487 // keywords follow
488
Mike Lockwoodfceef462010-05-14 15:35:17 -0400489 time_t modifiedTime;
Mike Lockwood16864ba2010-05-11 17:16:59 -0400490 if (!parseDateTime(modified, modifiedTime))
491 modifiedTime = 0;
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400492 LOGV("SendObjectInfo format: %04X size: %d name: %s, created: %s, modified: %s",
493 format, mSendObjectFileSize, (const char*)name, (const char*)created,
494 (const char*)modified);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400495
496 if (path[path.size() - 1] != '/')
497 path += "/";
498 path += (const char *)name;
499
Mike Lockwoodfceef462010-05-14 15:35:17 -0400500 mDatabase->beginTransaction();
501 MtpObjectHandle handle = mDatabase->addFile((const char*)path, format, parent, storageID,
502 mSendObjectFileSize, modifiedTime);
503 if (handle == kInvalidObjectHandle) {
504 mDatabase->rollbackTransaction();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400505 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoodfceef462010-05-14 15:35:17 -0400506 }
507 uint32_t table = MtpDatabase::getTableForFile(format);
508 if (table == kObjectHandleTableAudio)
509 handle = mDatabase->addAudioFile(handle);
510 mDatabase->commitTransaction();
Mike Lockwood16864ba2010-05-11 17:16:59 -0400511
512 if (format == MTP_FORMAT_ASSOCIATION) {
513 mode_t mask = umask(0);
514 int ret = mkdir((const char *)path, S_IRWXU | S_IRWXG | S_IRWXO);
515 umask(mask);
516 if (ret && ret != -EEXIST)
517 return MTP_RESPONSE_GENERAL_ERROR;
518 } else {
519 mSendObjectFilePath = path;
520 // save the handle for the SendObject call, which should follow
521 mSendObjectHandle = handle;
522 }
523
524 mResponse.setParameter(1, storageID);
525 mResponse.setParameter(2, parent);
526 mResponse.setParameter(3, handle);
527
528 return MTP_RESPONSE_OK;
529}
530
531MtpResponseCode MtpServer::doSendObject() {
532 if (mSendObjectHandle == kInvalidObjectHandle) {
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400533 LOGE("Expected SendObjectInfo before SendObject");
Mike Lockwood16864ba2010-05-11 17:16:59 -0400534 return MTP_RESPONSE_NO_VALID_OBJECT_INFO;
535 }
536
537 // read the header
538 int ret = mData.readDataHeader(mFD);
539 // FIXME - check for errors here.
540
541 // reset so we don't attempt to send this back
542 mData.reset();
543
544 mtp_file_range mfr;
Mike Lockwoodc6588762010-06-22 15:03:53 -0400545 mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
546 if (mfr.fd < 0) {
547 return MTP_RESPONSE_GENERAL_ERROR;
548 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400549 mfr.offset = 0;
550 mfr.length = mSendObjectFileSize;
551
552 // transfer the file
553 ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
Mike Lockwoodc6588762010-06-22 15:03:53 -0400554 close(mfr.fd);
Mike Lockwood916076c2010-06-04 09:49:21 -0400555 // FIXME - we need to delete mSendObjectHandle from the database if this fails.
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400556 LOGV("MTP_RECEIVE_FILE returned %d", ret);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400557 mSendObjectHandle = kInvalidObjectHandle;
558
Mike Lockwood916076c2010-06-04 09:49:21 -0400559 if (ret < 0) {
560 unlink(mSendObjectFilePath);
561 if (errno == ECANCELED)
562 return MTP_RESPONSE_TRANSACTION_CANCELLED;
563 else
564 return MTP_RESPONSE_GENERAL_ERROR;
565 }
Mike Lockwood16864ba2010-05-11 17:16:59 -0400566 return MTP_RESPONSE_OK;
567}
568
569MtpResponseCode MtpServer::doDeleteObject() {
570 MtpObjectHandle handle = mRequest.getParameter(1);
571 MtpObjectFormat format = mRequest.getParameter(1);
572 // FIXME - support deleting all objects if handle is 0xFFFFFFFF
573 // FIXME - implement deleting objects by format
574 // FIXME - handle non-empty directories
575
576 MtpString filePath;
577 int64_t fileLength;
578 if (!mDatabase->getObjectFilePath(handle, filePath, fileLength))
579 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
580
Mike Lockwoodb14e5882010-06-29 18:11:52 -0400581 LOGV("deleting %s", (const char *)filePath);
Mike Lockwood16864ba2010-05-11 17:16:59 -0400582 // one of these should work
583 rmdir((const char *)filePath);
584 unlink((const char *)filePath);
585
586 mDatabase->deleteFile(handle);
587
588 return MTP_RESPONSE_OK;
589}
590
591MtpResponseCode MtpServer::doGetObjectPropDesc() {
592 MtpObjectProperty property = mRequest.getParameter(1);
593 MtpObjectFormat format = mRequest.getParameter(2);
594
595 return -1;
596}
Mike Lockwood7850ef92010-05-14 10:10:36 -0400597
598} // namespace android