MtpServer.cpp revision 438344fba74ddd6b931ac733fa48643f27b63de3
116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood/*
216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * you may not use this file except in compliance with the License.
616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * You may obtain a copy of the License at
716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
1016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Unless required by applicable law or agreed to in writing, software
1116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
1216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * See the License for the specific language governing permissions and
1416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * limitations under the License.
1516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood */
1616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <stdio.h>
1816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <stdlib.h>
1916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <sys/types.h>
2016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <sys/ioctl.h>
2116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <sys/stat.h>
2216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <fcntl.h>
2316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <errno.h>
2416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
25c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood#include <cutils/properties.h>
26c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
2716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpDebug.h"
287f53a190463274096155704276f3002c1620a364Mike Lockwood#include "MtpDatabase.h"
2921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood#include "MtpProperty.h"
3016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpServer.h"
3116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStorage.h"
3216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStringBuffer.h"
3316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
348065e2056073808716db32136d7acfd50eeab924Mike Lockwood#include <linux/usb/f_mtp.h>
3516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
367850ef999740f214a1990a9c090d3f3865d435aaMike Lockwoodnamespace android {
377850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
3816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic const MtpOperationCode kSupportedOperationCodes[] = {
3916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_DEVICE_INFO,
4016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_OPEN_SESSION,
4116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_CLOSE_SESSION,
4216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_IDS,
4316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_INFO,
4416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_NUM_OBJECTS,
4516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_HANDLES,
4616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_INFO,
4716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT,
4816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_GET_THUMB,
4916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_DELETE_OBJECT,
5016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT_INFO,
5116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT,
5216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_CAPTURE,
5316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_FORMAT_STORE,
5416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_RESET_DEVICE,
5516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SELF_TEST,
5616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROTECTION,
5716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_POWER_DOWN,
58343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood//    MTP_OPERATION_GET_DEVICE_PROP_DESC,
59343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood//    MTP_OPERATION_GET_DEVICE_PROP_VALUE,
60343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood//    MTP_OPERATION_SET_DEVICE_PROP_VALUE,
61343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood//    MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
6216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
6316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_MOVE_OBJECT,
6416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_COPY_OBJECT,
6516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_GET_PARTIAL_OBJECT,
6616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_OPEN_CAPTURE,
6716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
6816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_GET_OBJECT_PROP_DESC,
6916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_VALUE,
70343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROP_VALUE,
71438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_GET_OBJECT_REFERENCES,
72438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_SET_OBJECT_REFERENCES,
7316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SKIP,
7416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood};
7516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
76873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodstatic const MtpEventCode kSupportedEventCodes[] = {
77873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_ADDED,
78873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_REMOVED,
79873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood};
80873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
8116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic const MtpObjectProperty kSupportedObjectProperties[] = {
8216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_PROPERTY_STORAGE_ID,
8316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_PROPERTY_OBJECT_FORMAT,
8416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_PROPERTY_OBJECT_SIZE,
8516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_PROPERTY_OBJECT_FILE_NAME,
8616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_PROPERTY_PARENT_OBJECT,
8716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood};
8816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
8916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic const MtpObjectFormat kSupportedPlaybackFormats[] = {
90fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_UNDEFINED,
9116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_FORMAT_ASSOCIATION,
92fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_TEXT,
93fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_HTML,
9416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_FORMAT_MP3,
95fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    //MTP_FORMAT_AVI,
96fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_MPEG,
97fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_ASF,
98fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_EXIF_JPEG,
99fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_TIFF_EP,
100fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_BMP,
101fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_GIF,
102fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_JFIF,
103fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_PNG,
104fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_TIFF,
105fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_WMA,
106fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_OGG,
107fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_AAC,
108fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_FLAC,
109fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_WMV,
110fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_MP4_CONTAINER,
111fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_MP2,
112fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    MTP_FORMAT_3GP_CONTAINER,
113fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_ABSTRACT_AUDIO_ALBUM,
114438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_FORMAT_ABSTRACT_AV_PLAYLIST,
115438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_FORMAT_WPL_PLAYLIST,
116438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_FORMAT_M3U_PLAYLIST,
117fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    // MTP_FORMAT_MPL_PLAYLIST,
118438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_FORMAT_PLS_PLAYLIST,
11916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood};
12016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1211865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike LockwoodMtpServer::MtpServer(int fd, MtpDatabase* database,
1228e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood                    int fileGroup, int filePerm, int directoryPerm)
12316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    :   mFD(fd),
1241865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        mDatabase(database),
1258e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFileGroup(fileGroup),
1268e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFilePermission(filePerm),
1278e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mDirectoryPermission(directoryPerm),
12816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionID(0),
12916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionOpen(false),
13016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle(kInvalidObjectHandle),
1314714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat(0),
13216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFileSize(0)
13316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
13421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    initObjectProperties();
13516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
13616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpServer::~MtpServer() {
13816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
13916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
14016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::addStorage(const char* filePath) {
14116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int index = mStorages.size() + 1;
14216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    index |= index << 16;   // set high and low part to our index
14316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = new MtpStorage(index, filePath, mDatabase);
14416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    addStorage(storage);
14516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
14616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
14716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpStorage* MtpServer::getStorage(MtpStorageID id) {
14816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
14916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpStorage* storage =  mStorages[i];
15016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (storage->getStorageID() == id)
15116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return storage;
15216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
15316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return NULL;
15416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
15516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
15616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::run() {
15716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int fd = mFD;
15816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
15921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    LOGV("MtpServer::run fd: %d\n", fd);
16016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
16116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    while (1) {
16216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int ret = mRequest.read(fd);
16316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret < 0) {
164b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGE("request read returned %d, errno: %d", ret, errno);
165916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (errno == ECANCELED) {
166916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                // return to top of loop and wait for next command
167916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                continue;
168916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
16916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
17016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
17116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpOperationCode operation = mRequest.getOperationCode();
17216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpTransactionID transaction = mRequest.getTransactionID();
17316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
174b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
17516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mRequest.dump();
17616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
17716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME need to generalize this
178438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
179438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_REFERENCES);
18016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (dataIn) {
18116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            int ret = mData.read(fd);
18216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
183b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("data read returned %d, errno: %d", ret, errno);
184916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
185916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
186916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
187916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
18816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
18916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
190b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("received data:");
19116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.dump();
19216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        } else {
19316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.reset();
19416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
19516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
196916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (handleRequest()) {
197916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (!dataIn && mData.hasData()) {
198916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setOperationCode(operation);
199916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setTransactionID(transaction);
200b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGV("sending data:");
201916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.dump();
202916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                ret = mData.write(fd);
203916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (ret < 0) {
204b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                    LOGE("request write returned %d, errno: %d", ret, errno);
205916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    if (errno == ECANCELED) {
206916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        // return to top of loop and wait for next command
207916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        continue;
208916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    }
209916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    break;
210916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
211916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
21216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
213916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            mResponse.setTransactionID(transaction);
214b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("sending response %04X", mResponse.getResponseCode());
215916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            ret = mResponse.write(fd);
21616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
217b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("request write returned %d, errno: %d", ret, errno);
218916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
219916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
220916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
221916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
22216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
22316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
224916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        } else {
22521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            LOGV("skipping response\n");
22616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
22716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
22816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
22916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
23021ef7d0e70c5ad599bc2602cb484f8cd647055caMike LockwoodMtpProperty* MtpServer::getObjectProperty(MtpPropertyCode propCode) {
23121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    for (int i = 0; i < mObjectProperties.size(); i++) {
23221ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        MtpProperty* property = mObjectProperties[i];
23321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        if (property->getPropertyCode() == propCode)
23421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            return property;
23521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    }
23621ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return NULL;
23721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood}
23821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood
23921ef7d0e70c5ad599bc2602cb484f8cd647055caMike LockwoodMtpProperty* MtpServer::getDeviceProperty(MtpPropertyCode propCode) {
24021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    for (int i = 0; i < mDeviceProperties.size(); i++) {
24121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        MtpProperty* property = mDeviceProperties[i];
24221ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        if (property->getPropertyCode() == propCode)
24321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            return property;
24421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    }
24521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return NULL;
24621ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood}
24721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood
248873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
24973ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
25073ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("sendObjectAdded %d\n", handle);
25173ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
25273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
25373ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setParameter(1, handle);
25473ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
25573ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("mEvent.write returned %d\n", ret);
25673ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
257873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
258873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
259873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
26073ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
26173ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("sendObjectRemoved %d\n", handle);
26273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
26373ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
26473ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setParameter(1, handle);
26573ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
26673ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("mEvent.write returned %d\n", ret);
26773ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
268873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
269873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
27021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwoodvoid MtpServer::initObjectProperties() {
27121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT16));
27221ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16));
27321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64));
27421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR));
27521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32));
27621ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood}
27721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood
278916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
27916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
28016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
28116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
28216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
28316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
28416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
28516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
286b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("expected SendObject after SendObjectInfo");
28716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
28816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
28916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
29016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
29116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
29216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
29316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
29416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
29516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
29616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
29716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
29816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
29916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
30016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
30116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
30216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
30316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
30416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
30516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
30616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
30716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
30816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
30916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
31016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
31116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
312343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
313343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
314343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
315438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
316438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
317438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
318438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
319438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
320438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
32116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
32516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
32616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
32816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
32916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
33116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
33216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
33416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
33516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
33716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
33816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
34021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
34121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
34216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
34316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
34416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
34616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
347916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
348916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
34916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
350916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
35116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
35216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
35316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
35416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
355c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
35616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
35716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
35816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
35916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(6); // MTP Vendor Extension ID
36016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
36116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("microsoft.com: 1.0;");
36216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
36316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
36416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
36516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
366873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
367873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
36816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyArray(); // Device Properties Supported
36916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyArray(); // Capture Formats
37016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedPlaybackFormats,
37116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedPlaybackFormats) / sizeof(uint16_t)); // Playback Formats
37216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME
37316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("Google, Inc.");
37416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
375c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
376c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
377c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
37816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
37916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
38016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
381c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
382c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
383c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
38416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
38516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
38616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
38716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
38816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
39016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
39116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
39216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
39316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
39416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
39516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
39616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
39716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
39816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
39916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
40016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
40116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
40216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
40316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
40416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
40516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
40616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
40716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
40816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
40916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
41016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
41116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
41216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
41316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
41416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
41516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
41616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
41716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
41816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
41916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
42016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
42116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
42316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
42416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
42516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
42616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
42716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
42816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
43016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
43116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
43216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
43316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
43416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
43516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
43616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
43716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
43816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
43916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
44016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
44116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
44216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
44316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
44416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
44516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
44616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedObjectProperties,
44716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedObjectProperties) / sizeof(uint16_t));
44816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
44916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
45016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
45116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
45216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
45316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
45416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
455e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
45616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
45716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                                                            // 0x00000000 for all objects?
4581865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == 0xFFFFFFFF)
4591865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
46016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
46116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
46216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
46316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
46416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
46516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
46616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
467343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
468343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
469343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
470343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
471343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
472343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
473343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood                                                            // 0x00000000 for all objects?
474343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (parent == 0xFFFFFFFF)
475343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        parent = 0;
476343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
477343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
478343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
479343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
480343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
481343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
482343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
483343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
484343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
485343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
486343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
487438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
488438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
489438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
490438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
491438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
492438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!handles) {
493438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
494438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
495438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
496438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    mData.putAUInt32(handles);
497438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete handles;
498438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
499438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
500438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
501438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
502438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
503438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
504438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
505438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
506438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
507438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
508438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
509438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
510438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
51116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
51216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
51316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
51416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return mDatabase->getObjectProperty(handle, property, mData);
51616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
51716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
51916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
52016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return mDatabase->getObjectInfo(handle, mData);
52116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
52216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
52316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
52416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
525c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
52616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
5279c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength);
5289c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
5299c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
53016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
5319c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
53216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
533c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
534c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
535c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
536c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
53716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
53816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
53916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
54016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // send data header
54116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
54216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
54316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.writeDataHeader(mFD, fileLength);
54416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
54516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
54616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
547c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
548916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
549916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
550916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
551916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
552916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
553916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
55416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
55516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
55616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
55716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
55816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
55916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
56016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
56116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
56216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
56316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
56416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
56516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
5661865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
56716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
5681865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
5691865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
57016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int64_t dummy;
5719c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, dummy);
5729c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
5739c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
57416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
57516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
57616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
57716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // storage ID
57816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mData.getUInt16();
57916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // protection status
58016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSendObjectFileSize = mData.getUInt32();
58116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // thumb format
58216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb compressed size
58316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix width
58416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix height
58516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix width
58616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix height
58716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image bit depth
58816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // parent
58916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint16_t associationType = mData.getUInt16();
59016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint32_t associationDesc = mData.getUInt32();   // association desc
59116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // sequence number
59216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
59316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(name);    // file name
59416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(created);      // date created
59516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(modified);     // date modified
59616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
59716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
598fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
59916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
60016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
60116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
60216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
60316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
60416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
60516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6064714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
6074714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
608fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
60916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
610fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
61116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
61216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
61316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
6148e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
61516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
61616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
61716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
6188e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
61916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
62016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
62116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
62216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
6234714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
62416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
62516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
62616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
6271865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    mResponse.setParameter(2, (parent == 0 ? 0xFFFFFFFF: parent));
62816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
62916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
63016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
63116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
63216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
63316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
6344714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
6354714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
6364714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    int ret;
6374714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
63816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
639b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("Expected SendObjectInfo before SendObject");
6404714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
6414714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
64216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
64316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
64416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read the header
6454714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    ret = mData.readDataHeader(mFD);
64616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - check for errors here.
64716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
64816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // reset so we don't attempt to send this back
64916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.reset();
65016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
65116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
652c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
653c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
6544714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
6554714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
656c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
6578e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
6588e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
6594714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
6608e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
6618e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
6628e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
66316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
66416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = mSendObjectFileSize;
66516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
66616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // transfer the file
66716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
668c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
6698e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
670b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood    LOGV("MTP_RECEIVE_FILE returned %d", ret);
67116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
672916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
673916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
674916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
6754714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
676916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
6774714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
678916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
6794714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
6804714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
6814714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
6824714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result == MTP_RESPONSE_OK);
6834714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
6844714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
6854714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
68616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
68716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
68816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
68916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
69016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
69116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
69216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
69316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - handle non-empty directories
69416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
69516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
69616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
6979c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength);
6989c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
6999c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        LOGV("deleting %s", (const char *)filePath);
7009c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        // one of these should work
7019c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        rmdir((const char *)filePath);
7029c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        unlink((const char *)filePath);
7039c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return mDatabase->deleteFile(handle);
7049c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    } else {
7059c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
7069c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
70716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
70816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
70916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
71021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
71116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
71221ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpProperty* property = getObjectProperty(propCode);
71321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
71421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
71516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
71621ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
71721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
71816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
7197850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
7207850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
721