MtpServer.cpp revision 8277cec96ffa55082962591bca1c55abbeec8c26
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,
598277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_VALUE,
608277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_SET_DEVICE_PROP_VALUE,
618277cec96ffa55082962591bca1c55abbeec8c26Mike 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,
688277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_DESC,
698277cec96ffa55082962591bca1c55abbeec8c26Mike 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
811865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike LockwoodMtpServer::MtpServer(int fd, MtpDatabase* database,
828e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood                    int fileGroup, int filePerm, int directoryPerm)
8316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    :   mFD(fd),
841865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        mDatabase(database),
858e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFileGroup(fileGroup),
868e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFilePermission(filePerm),
878e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mDirectoryPermission(directoryPerm),
8816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionID(0),
8916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionOpen(false),
9016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle(kInvalidObjectHandle),
914714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat(0),
9216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFileSize(0)
9316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
9416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
9516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
9616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpServer::~MtpServer() {
9716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
9816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
9916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::addStorage(const char* filePath) {
10016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int index = mStorages.size() + 1;
10116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    index |= index << 16;   // set high and low part to our index
10216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = new MtpStorage(index, filePath, mDatabase);
10316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    addStorage(storage);
10416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
10616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpStorage* MtpServer::getStorage(MtpStorageID id) {
10716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
10816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpStorage* storage =  mStorages[i];
10916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (storage->getStorageID() == id)
11016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return storage;
11116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
11216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return NULL;
11316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::run() {
11616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int fd = mFD;
11716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    LOGV("MtpServer::run fd: %d\n", fd);
11916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
12016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    while (1) {
12116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int ret = mRequest.read(fd);
12216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret < 0) {
123b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGE("request read returned %d, errno: %d", ret, errno);
124916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (errno == ECANCELED) {
125916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                // return to top of loop and wait for next command
126916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                continue;
127916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
12816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
12916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
13016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpOperationCode operation = mRequest.getOperationCode();
13116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpTransactionID transaction = mRequest.getTransactionID();
13216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
133b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
13416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mRequest.dump();
13516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME need to generalize this
137438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
1388277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
1398277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
1408277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
14116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (dataIn) {
14216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            int ret = mData.read(fd);
14316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
144b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("data read returned %d, errno: %d", ret, errno);
145916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
146916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
147916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
148916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
14916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
15016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
151b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("received data:");
15216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.dump();
15316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        } else {
15416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.reset();
15516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
15616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
157916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (handleRequest()) {
158916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (!dataIn && mData.hasData()) {
159916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setOperationCode(operation);
160916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setTransactionID(transaction);
161b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGV("sending data:");
162916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                ret = mData.write(fd);
163916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (ret < 0) {
164b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                    LOGE("request write 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                    }
169916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    break;
170916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
171916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
17216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
173916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            mResponse.setTransactionID(transaction);
174b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("sending response %04X", mResponse.getResponseCode());
175916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            ret = mResponse.write(fd);
17616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
177b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("request write returned %d, errno: %d", ret, errno);
178916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
179916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
180916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
181916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
18216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
18316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
184916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        } else {
18521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            LOGV("skipping response\n");
18616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
18716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
18816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
18916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
190873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
19173ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
19273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("sendObjectAdded %d\n", handle);
19373ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
19473ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
19573ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setParameter(1, handle);
19673ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
19773ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("mEvent.write returned %d\n", ret);
19873ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
199873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
200873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
201873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
20273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
20373ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("sendObjectRemoved %d\n", handle);
20473ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
20573ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
20673ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setParameter(1, handle);
20773ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
20873ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("mEvent.write returned %d\n", ret);
20973ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
210873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
211873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
212916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
21316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
21416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
21516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
21616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
21716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
21816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
21916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
220b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("expected SendObject after SendObjectInfo");
22116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
22216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
22316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
22416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
22516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
22616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
22716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
22816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
22916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
23016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
23116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
23216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
23316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
23416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
23516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
23616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
23716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
23816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
23916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
24016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
24116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
24216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
24316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
24416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
24516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
246343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
247343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
248343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
249438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
250438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
251438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
252438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
253438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
254438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
25516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
25616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
25716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
2588277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
2598277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetObjectPropValue();
2608277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
2618277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
2628277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doGetDevicePropValue();
2638277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
2648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
2658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetDevicePropValue();
2668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
2678277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
2688277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doResetDevicePropValue();
2698277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
27016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
27116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
27216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
27316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
27416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
27516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
27616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
27716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
27816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
27916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
28016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
28116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
28216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
28316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
28416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
28516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
28621ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
28721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
28816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
28916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
29016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
29116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
29216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
293916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
294916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
29516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
296916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
29716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
29816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
29916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
30016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
301c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
30216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
303782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
304782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
305782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
306782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
30716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
30816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
30916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(6); // MTP Vendor Extension ID
31016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
31116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("microsoft.com: 1.0;");
31216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
31316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
31416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
31516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
316873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
317873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
318782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(deviceProperties); // Device Properties Supported
319782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(captureFormats); // Capture Formats
320782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(playbackFormats);  // Playback Formats
32116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("Google, Inc.");
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
324c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
325c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
326c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
32816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
32916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
330c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
331c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
332c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
33316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
33416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
335782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete playbackFormats;
336782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete captureFormats;
337782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete deviceProperties;
338782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
33916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
34016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
34116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
34216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
34316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
34416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
34516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
34616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
34716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
34816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
34916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
35016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
35116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
35216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
35316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
35416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
35516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
35616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
35716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
35816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
35916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
36016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
36116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
36216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
36316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
36416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
36516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
36616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
36716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
36816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
36916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
37016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
37116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
37216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
37316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
37416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
37516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
37616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
37716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
37816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
37916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
38016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
38116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
38216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
38316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
38416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
38516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
38616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
38716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
38816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
39016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
39116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
39216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
39316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
39416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
39516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
39616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
39716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
39816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
399782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* properties = mDatabase->getSupportedObjectProperties(format);
400782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(properties);
401bf9b2052d207f8f2a23470f1c4dfe464f430f387Mike Lockwood    delete properties;
40216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
40316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
40416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
40516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
40616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
40716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
40816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
409e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
41016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
41116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                                                            // 0x00000000 for all objects?
4121865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == 0xFFFFFFFF)
4131865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
41416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
41516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
41616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
41716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
41816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
41916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
42016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
421343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
422343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
423343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
424343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
425343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
426343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
427343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood                                                            // 0x00000000 for all objects?
428343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (parent == 0xFFFFFFFF)
429343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        parent = 0;
430343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
431343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
432343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
433343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
434343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
435343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
436343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
437343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
438343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
439343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
440343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
441438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
442438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
443438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
444438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
4458277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
4468277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    // FIXME - check for invalid object handle
447438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
4488277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (handles) {
4498277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        mData.putAUInt32(handles);
4508277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        delete handles;
4518277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    } else {
452438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
453438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
454438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
455438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
456438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
457438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
458438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
459438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
460438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
461438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
462438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
463438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
464438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
465438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
466438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
46716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
46816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
46916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
4708277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("GetObjectPropValue %d %s\n", handle,
4718277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
47216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
4738277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getObjectPropertyValue(handle, property, mData);
4748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
4758277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
4768277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetObjectPropValue() {
4778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
4788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
4798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("SetObjectPropValue %d %s\n", handle,
4808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
4818277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
4828277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setObjectPropertyValue(handle, property, mData);
4838277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
4848277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
4858277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropValue() {
4868277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
4878277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("GetDevicePropValue %s\n",
4888277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
4898277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
4908277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getDevicePropertyValue(property, mData);
4918277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
4928277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
4938277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetDevicePropValue() {
4948277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
4958277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("SetDevicePropValue %s\n",
4968277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
4978277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
4988277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setDevicePropertyValue(property, mData);
4998277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5008277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5018277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doResetDevicePropValue() {
5028277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
5038277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("ResetDevicePropValue %s\n",
5048277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
5058277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5068277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->resetDeviceProperty(property);
50716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
50816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
51016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
51116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return mDatabase->getObjectInfo(handle, mData);
51216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
51316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
51516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
516c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
51716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
5189c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength);
5199c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
5209c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
52116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
5229c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
52316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
524c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
525c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
526c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
527c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
52816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
52916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
53016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // send data header
53216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
53316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
53416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.writeDataHeader(mFD, fileLength);
53516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
53716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
538c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
539916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
540916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
541916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
542916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
543916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
544916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
54516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
54616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
54716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
54816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
54916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
55016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
55116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
55216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
55316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
55416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
55516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
55616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
5571865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
55816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
5591865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
5601865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
56116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int64_t dummy;
5629c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, dummy);
5639c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
5649c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
56516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
56616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
56716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
56816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // storage ID
56916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mData.getUInt16();
57016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // protection status
57116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSendObjectFileSize = mData.getUInt32();
57216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // thumb format
57316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb compressed size
57416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix width
57516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix height
57616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix width
57716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix height
57816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image bit depth
57916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // parent
58016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint16_t associationType = mData.getUInt16();
58116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint32_t associationDesc = mData.getUInt32();   // association desc
58216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // sequence number
58316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
58416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(name);    // file name
58516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(created);      // date created
58616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(modified);     // date modified
58716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
58816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
589fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
59016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
59116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
59216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
59316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
59416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
59516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
59616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
5974714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
5984714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
599fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
60016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
601fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
60216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
60316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
60416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
6058e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
60616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
60716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
60816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
6098e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
61016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
61116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
61216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
61316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
6144714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
61516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
61616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
61716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
6188277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    mResponse.setParameter(2, parent);
61916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
62016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
62116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
62216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
62316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
62416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
6254714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
6264714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
6274714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    int ret;
6284714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
62916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
630b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("Expected SendObjectInfo before SendObject");
6314714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
6324714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
63316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
63416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
63516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read the header
6364714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    ret = mData.readDataHeader(mFD);
63716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - check for errors here.
63816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
63916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // reset so we don't attempt to send this back
64016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.reset();
64116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
64216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
643c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
644c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
6454714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
6464714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
647c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
6488e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
6498e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
6504714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
6518e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
6528e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
6538e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
65416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
65516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = mSendObjectFileSize;
65616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
65716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // transfer the file
65816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
659c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
6608e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
661b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood    LOGV("MTP_RECEIVE_FILE returned %d", ret);
66216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
663916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
664916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
665916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
6664714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
667916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
6684714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
669916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
6704714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
6714714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
6724714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
6734714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result == MTP_RESPONSE_OK);
6744714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
6754714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
6764714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
67716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
67816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
67916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
68016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
68116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
68216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
68316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
68416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - handle non-empty directories
68516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
68616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
68716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
6889c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength);
6899c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
6909c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        LOGV("deleting %s", (const char *)filePath);
6919c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        // one of these should work
6929c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        rmdir((const char *)filePath);
6939c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        unlink((const char *)filePath);
6949c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return mDatabase->deleteFile(handle);
6959c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    } else {
6969c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
6979c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
69816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
69916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
70016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
70121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
70216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
7038277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
7048277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                                        MtpDebug::getFormatCodeName(format));
7058277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
70621ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
70721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
7088277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    property->write(mData);
7098277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
7108277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return MTP_RESPONSE_OK;
7118277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
71216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
7138277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropDesc() {
7148277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty propCode = mRequest.getParameter(1);
7158277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
7168277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
7178277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (!property)
7188277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
71921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
7208277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
72121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
72216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
7237850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
7247850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
725