MtpServer.cpp revision 3d1d7767afc7c488197ec40a22739159c5110721
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>
24d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood#include <sys/stat.h>
25d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood#include <dirent.h>
2616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
27c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood#include <cutils/properties.h>
28c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
29a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood#define LOG_TAG "MtpServer"
30a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood
3116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpDebug.h"
327f53a190463274096155704276f3002c1620a364Mike Lockwood#include "MtpDatabase.h"
337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood#include "MtpObjectInfo.h"
3421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood#include "MtpProperty.h"
3516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpServer.h"
3616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStorage.h"
3716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStringBuffer.h"
3816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
398065e2056073808716db32136d7acfd50eeab924Mike Lockwood#include <linux/usb/f_mtp.h>
4016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
417850ef999740f214a1990a9c090d3f3865d435aaMike Lockwoodnamespace android {
427850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
4316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic const MtpOperationCode kSupportedOperationCodes[] = {
4416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_DEVICE_INFO,
4516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_OPEN_SESSION,
4616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_CLOSE_SESSION,
4716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_IDS,
4816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_INFO,
4916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_NUM_OBJECTS,
5016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_HANDLES,
5116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_INFO,
5216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT,
5364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    MTP_OPERATION_GET_THUMB,
5416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_DELETE_OBJECT,
5516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT_INFO,
5616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT,
5716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_CAPTURE,
5816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_FORMAT_STORE,
5916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_RESET_DEVICE,
6016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SELF_TEST,
6116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROTECTION,
6216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_POWER_DOWN,
63e3e76c456baee122de6715ae280130abaddc906cMike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_DESC,
648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_VALUE,
658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_SET_DEVICE_PROP_VALUE,
668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
6716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
6816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_MOVE_OBJECT,
6916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_COPY_OBJECT,
70d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MTP_OPERATION_GET_PARTIAL_OBJECT,
7116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_OPEN_CAPTURE,
7216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
738277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_DESC,
74677f5700c5ea35256079ef14e06b7382e438d860Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_VALUE,
75677f5700c5ea35256079ef14e06b7382e438d860Mike Lockwood    MTP_OPERATION_SET_OBJECT_PROP_VALUE,
76b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_LIST,
77b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROP_LIST,
78b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
79b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_SEND_OBJECT_PROP_LIST,
80438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_GET_OBJECT_REFERENCES,
81438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_SET_OBJECT_REFERENCES,
8216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SKIP,
837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // Android extension for direct file IO
847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_GET_PARTIAL_OBJECT_64,
857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_SEND_PARTIAL_OBJECT,
867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_TRUNCATE_OBJECT,
877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_BEGIN_EDIT_OBJECT,
887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_END_EDIT_OBJECT,
8916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood};
9016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodstatic const MtpEventCode kSupportedEventCodes[] = {
92873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_ADDED,
93873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_REMOVED,
94a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MTP_EVENT_STORE_ADDED,
95a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MTP_EVENT_STORE_REMOVED,
96873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood};
97873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
983d1d7767afc7c488197ec40a22739159c5110721Mike LockwoodMtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
998e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood                    int fileGroup, int filePerm, int directoryPerm)
10016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    :   mFD(fd),
1011865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        mDatabase(database),
1023d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mPtp(ptp),
1038e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFileGroup(fileGroup),
1048e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFilePermission(filePerm),
1058e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mDirectoryPermission(directoryPerm),
10616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionID(0),
10716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionOpen(false),
10816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle(kInvalidObjectHandle),
1094714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat(0),
11016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFileSize(0)
11116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
11216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpServer::~MtpServer() {
11516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
117a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::addStorage(MtpStorage* storage) {
118a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
119a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
120a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    mStorages.push(storage);
121a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendStoreAdded(storage->getStorageID());
122a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
123a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
124a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::removeStorage(MtpStorage* storage) {
125a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
126a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
127a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
128a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        if (mStorages[i] == storage) {
129a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            mStorages.removeAt(i);
130a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            sendStoreRemoved(storage->getStorageID());
131a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            break;
132a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        }
133a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    }
13416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
13516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpStorage* MtpServer::getStorage(MtpStorageID id) {
137fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    if (id == 0)
138fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        return mStorages[0];
13916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
140fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpStorage* storage = mStorages[i];
14116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (storage->getStorageID() == id)
14216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return storage;
14316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
14416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return NULL;
14516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
14616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
147a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodbool MtpServer::hasStorage(MtpStorageID id) {
148a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (id == 0 || id == 0xFFFFFFFF)
149a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return mStorages.size() > 0;
150a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    return (getStorage(id) != NULL);
151a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
152a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
15316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::run() {
15416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int fd = mFD;
15516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
15621ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    LOGV("MtpServer::run fd: %d\n", fd);
15716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
15816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    while (1) {
15916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int ret = mRequest.read(fd);
16016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret < 0) {
16159d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood            LOGV("request read returned %d, errno: %d", ret, errno);
162916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (errno == ECANCELED) {
163916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                // return to top of loop and wait for next command
164916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                continue;
165916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
16616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
16716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
16816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpOperationCode operation = mRequest.getOperationCode();
16916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpTransactionID transaction = mRequest.getTransactionID();
17016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
171b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
17216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mRequest.dump();
17316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
17416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME need to generalize this
175438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
1768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
1778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
1788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
17916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (dataIn) {
18016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            int ret = mData.read(fd);
18116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
182b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("data read returned %d, errno: %d", ret, errno);
183916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
184916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
185916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
186916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
18716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
18816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
189b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("received data:");
19016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.dump();
19116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        } else {
19216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.reset();
19316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
19416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
195916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (handleRequest()) {
196916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (!dataIn && mData.hasData()) {
197916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setOperationCode(operation);
198916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setTransactionID(transaction);
199b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGV("sending data:");
20023d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood                mData.dump();
201916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                ret = mData.write(fd);
202916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (ret < 0) {
203b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                    LOGE("request write returned %d, errno: %d", ret, errno);
204916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    if (errno == ECANCELED) {
205916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        // return to top of loop and wait for next command
206916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        continue;
207916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    }
208916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    break;
209916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
210916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
21116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
212916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            mResponse.setTransactionID(transaction);
213b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("sending response %04X", mResponse.getResponseCode());
214916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            ret = mResponse.write(fd);
21523d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood            mResponse.dump();
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    }
2286b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
2297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // commit any open edits
2307d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
2337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        commitEdit(edit);
2347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        delete edit;
2357d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.clear();
2377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2386b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    if (mSessionOpen)
2396b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood        mDatabase->sessionEnded();
24016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
24116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
242873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
243a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendObjectAdded %d\n", handle);
244a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
245873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
246873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
247873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
248a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendObjectRemoved %d\n", handle);
249a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
250a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
251a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
252a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreAdded(MtpStorageID id) {
253a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendStoreAdded %08X\n", id);
254a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_ADDED, id);
255a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
256a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
257a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreRemoved(MtpStorageID id) {
258a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendStoreRemoved %08X\n", id);
259a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_REMOVED, id);
260a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
261a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
262a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
26373ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
264a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setEventCode(code);
26573ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
266a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setParameter(1, param1);
26773ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
26859d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood        LOGV("mEvent.write returned %d\n", ret);
26973ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
270873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
271873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
2727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
2737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t size, MtpObjectFormat format, int fd) {
274c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    ObjectEdit*  edit = new ObjectEdit(handle, path, size, format, fd);
2757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.add(edit);
2767d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
2797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
282c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) return edit;
2837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return NULL;
2857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::removeEditObject(MtpObjectHandle handle) {
2887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
291c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) {
2927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            delete edit;
2937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            mObjectEditList.removeAt(i);
2947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return;
2957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        }
2967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    LOGE("ObjectEdit not found in removeEditObject");
2987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::commitEdit(ObjectEdit* edit) {
301c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
3027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
3037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
305916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
306a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
307a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
30816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
30916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
31016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
31116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
31216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
31316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
31416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
315b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("expected SendObject after SendObjectInfo");
31616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
31716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
31816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
31916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
32016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
32116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
32416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
32516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
32816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
33016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
33116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
33316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
33416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
33616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
33716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
33916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
34016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
341343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
342343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
343343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
344438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
345438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
346438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
347438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
348438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
349438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
35016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
35116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
35216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
3538277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
3548277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetObjectPropValue();
3558277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3568277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
3578277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doGetDevicePropValue();
3588277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3598277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
3608277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetDevicePropValue();
3618277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3628277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
3638277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doResetDevicePropValue();
3648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
365b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_LIST:
366b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            response = doGetObjectPropList();
367b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            break;
36816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
36916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
37016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
37116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
37216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
37316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
37464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        case MTP_OPERATION_GET_THUMB:
37564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            response = doGetThumb();
37664000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            break;
377d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT:
3787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
3797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doGetPartialObject(operation);
380d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            break;
38116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
38216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
38316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
38516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
38616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
38816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
39016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
39121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
39221ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
393e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_DESC:
394e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            response = doGetDevicePropDesc();
395e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            break;
3967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_SEND_PARTIAL_OBJECT:
3977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doSendPartialObject();
3987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
3997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_TRUNCATE_OBJECT:
4007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doTruncateObject();
4017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_BEGIN_EDIT_OBJECT:
4037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doBeginEditObject();
4047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_END_EDIT_OBJECT:
4067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doEndEditObject();
4077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
40816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
409a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood            LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
41016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
41116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
41216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
41316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
414916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
415916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
41616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
417916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
41816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
41916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
42116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
422c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
42316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
424782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
425782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
426782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
427782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
42816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
42916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4303d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    if (mPtp) {
4313d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mData.putUInt32(0);
4323d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    } else {
4333d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // MTP Vendor Extension ID
4343d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mData.putUInt32(6);
4353d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    }
43616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4373d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    if (mPtp) {
4383d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // no extensions
4393d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        string.set("");
4403d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    } else {
4413d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // MTP extensions
4423d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        string.set("microsoft.com: 1.0; android.com: 1.0;");
4433d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    }
44416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
44516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
44616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
44716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
448873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
449873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
450782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(deviceProperties); // Device Properties Supported
451782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(captureFormats); // Capture Formats
452782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(playbackFormats);  // Playback Formats
4538d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood
4548d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
4558d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    string.set(prop_value);
45616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
457c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
458c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
459c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
46016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
46116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
46216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
463c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
464c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
465c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
46616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
46716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
468782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete playbackFormats;
469782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete captureFormats;
470782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete deviceProperties;
471782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
47216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
47316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
47416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
47516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
47616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
47716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
47816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
47916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
48016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
48116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
4826b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
4836b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionStarted();
4846b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
48516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
48616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
48716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
48816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
48916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
49016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
49116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
49216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
4936b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionEnded();
49416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
49516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
49616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
49716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
49816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
49916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
50016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
50216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
50316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
50416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
50516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
50716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
50816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
51016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
51116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
51316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
51416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
51516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
51616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
51716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
51816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
52016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
52116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
52216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
52316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
52416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
52516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
52616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
52716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
52816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
52916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
53016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
53116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
53316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
53416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
53516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
5362e09e289b7e136481e9215bb61ed47cee5d9919bMike Lockwood    MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
537782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(properties);
538bf9b2052d207f8f2a23470f1c4dfe464f430f387Mike Lockwood    delete properties;
53916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
54016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
54116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
54216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
54316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
54416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
54516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
546e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
54716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
548dc3185e3e27b05e18c4ac34432a25a0c279ff351Mike Lockwood                                                            // 0x00000000 for all objects
549a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
550a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
551a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
55216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
55316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
55416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
55516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
55616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
55716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
55816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
559343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
560343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
561343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
562343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
563343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
564343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
565dc3185e3e27b05e18c4ac34432a25a0c279ff351Mike Lockwood                                                            // 0x00000000 for all objects
566a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
567a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
568343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
569343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
570343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
571343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
572343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
573343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
574343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
575343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
576343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
577343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
578343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
579438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
580438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
581438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
582a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
583a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
584a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
5858277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5868277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    // FIXME - check for invalid object handle
587438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
5888277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (handles) {
5898277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        mData.putAUInt32(handles);
5908277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        delete handles;
5918277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    } else {
592438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
593438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
594438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
595438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
596438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
597438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
598438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
599438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
600a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
601a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
602438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
603a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
604438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
605438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
606438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
607438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
608438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
609438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
61016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
611a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
612a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
61316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
61416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
61559d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetObjectPropValue %d %s\n", handle,
6168277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
61716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6188277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getObjectPropertyValue(handle, property, mData);
6198277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6208277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6218277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetObjectPropValue() {
622a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
623a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
6248277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6258277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
62659d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("SetObjectPropValue %d %s\n", handle,
6278277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
6288277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6298277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setObjectPropertyValue(handle, property, mData);
6308277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6318277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6328277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropValue() {
6338277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
63459d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetDevicePropValue %s\n",
6358277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6368277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6378277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getDevicePropertyValue(property, mData);
6388277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6398277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6408277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetDevicePropValue() {
6418277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
64259d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("SetDevicePropValue %s\n",
6438277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6448277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6458277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setDevicePropertyValue(property, mData);
6468277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6478277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6488277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doResetDevicePropValue() {
6498277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
65059d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("ResetDevicePropValue %s\n",
6518277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6528277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6538277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->resetDeviceProperty(property);
65416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
65516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
656b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropList() {
657a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
658a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
659b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
660b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
66140ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    // use uint32_t so we can support 0xFFFFFFFF
66240ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t format = mRequest.getParameter(2);
66340ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t property = mRequest.getParameter(3);
664b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    int groupCode = mRequest.getParameter(4);
665f05ff073495b0bb3e49859aee5b54d3e25088985Mike Lockwood    int depth = mRequest.getParameter(5);
66659d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood   LOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
667b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            handle, MtpDebug::getFormatCodeName(format),
668b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            MtpDebug::getObjectPropCodeName(property), groupCode, depth);
669b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
670b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
671b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood}
672b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
67316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
674a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
675a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
67616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectInfo info(handle);
6787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
6797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
6807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        char    date[20];
6817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mStorageID);
6837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mFormat);
6847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mProtectionStatus);
6857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // if object is being edited the database size may be out of date
6877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint32_t size = info.mCompressedSize;
6887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = getEditObject(handle);
6897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (edit)
690c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood            size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
6917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(size);
6927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mThumbFormat);
6947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbCompressedSize);
6957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixWidth);
6967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixHeight);
6977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixWidth);
6987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixHeight);
6997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixDepth);
7007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mParent);
7017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mAssociationType);
7027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mAssociationDesc);
7037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mSequenceNumber);
7047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(info.mName);
7057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putEmptyString();    // date created
7067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        formatDateTime(info.mDateModified, date, sizeof(date));
7077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(date);   // date modified
7087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putEmptyString();   // keywords
7097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
7107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return result;
71116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
71216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
71316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
714a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
715a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
71616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
717c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
71816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
719fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
720fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
7219c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
7229c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
72316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
7249c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
72516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
726c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
727c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
728c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
729c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
73016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
73116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
73216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // send data header
73416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
73516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
73623d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood    mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
73716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
73916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
740c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
741916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
742916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
743916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
744916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
745916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
746916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
74716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
74816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
74916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
75064000788211f4c7e78c80a4a155390d1316e1176Mike LockwoodMtpResponseCode MtpServer::doGetThumb() {
75164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
75264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    size_t thumbSize;
75364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    void* thumb = mDatabase->getThumbnail(handle, thumbSize);
75464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    if (thumb) {
75564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        // send data
75664000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setOperationCode(mRequest.getOperationCode());
75764000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setTransactionID(mRequest.getTransactionID());
75864000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.writeData(mFD, thumb, thumbSize);
75964000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        free(thumb);
76064000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_OK;
76164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    } else {
76264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
76364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    }
76464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood}
76564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood
7667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
767a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
768a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
769d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
7707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset;
7717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length;
7727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = mRequest.getParameter(2);
7737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
7747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // android extension with 64 bit offset
7757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t offset2 = mRequest.getParameter(3);
7767d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        offset = offset | (offset2 << 32);
7777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(4);
7787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
7797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // standard GetPartialObject
7807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(3);
7817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
782d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpString pathBuf;
783d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int64_t fileLength;
784fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
785fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
786d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (result != MTP_RESPONSE_OK)
787d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return result;
788d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (offset + length > fileLength)
789d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        length = fileLength - offset;
790d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
791d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    const char* filePath = (const char *)pathBuf;
792d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mtp_file_range  mfr;
793d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.fd = open(filePath, O_RDONLY);
794d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (mfr.fd < 0) {
795d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
796d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
797d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.offset = offset;
798d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.length = length;
799d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mResponse.setParameter(1, length);
800d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
801d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    // send data header
802d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
803d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
804d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.writeDataHeader(mFD, length + MTP_CONTAINER_HEADER_SIZE);
805d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
806d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    // then transfer the file
807d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
808d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    close(mfr.fd);
809d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (ret < 0) {
810d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        if (errno == ECANCELED)
811d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
812d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        else
813d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
814d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
815d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    return MTP_RESPONSE_OK;
816d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood}
817d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
81816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
81916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
82016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
82116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
82216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
82316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
82416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
82516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
82616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
8271865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
82816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
8291865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
8301865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
831fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int64_t length;
832fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpObjectFormat format;
833fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, length, format);
8349c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
8359c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
836fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        if (format != MTP_FORMAT_ASSOCIATION)
837fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
83816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
83916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
84016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
84116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // storage ID
84216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mData.getUInt16();
84316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // protection status
84416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSendObjectFileSize = mData.getUInt32();
84516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // thumb format
84616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb compressed size
84716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix width
84816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix height
84916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix width
85016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix height
85116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image bit depth
85216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // parent
85316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint16_t associationType = mData.getUInt16();
85416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint32_t associationDesc = mData.getUInt32();   // association desc
85516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // sequence number
85616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
85716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(name);    // file name
85816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(created);      // date created
85916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(modified);     // date modified
86016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
86116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
86259d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("name: %s format: %04X\n", (const char *)name, format);
863fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
86416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
86516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
86616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
86716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
86816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
86916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
87016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
87120c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    // check space first
87220c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    if (mSendObjectFileSize > storage->getFreeSpace())
87320c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood        return MTP_RESPONSE_STORAGE_FULL;
87420c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood
875a849440ca96e93f700d62c6e41d48905b4d405b6Mike LockwoodLOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
8764714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
8774714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
878fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
87916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
880fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
88116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
88216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
88316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
8848e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
88516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
88616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
88716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
8888e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
889aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood
890aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        // SendObject does not get sent for directories, so call endSendObject here instead
891aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
89216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
89316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
89416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
89516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
8964714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
89716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
89816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
89916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
9008277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    mResponse.setParameter(2, parent);
90116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
90216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
90316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
90416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
90516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
90616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
907a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
908a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
9094714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
9104714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
9114714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    int ret;
9124714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
91316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
914b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("Expected SendObjectInfo before SendObject");
9154714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
9164714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
91716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
91816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read the header
9204714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    ret = mData.readDataHeader(mFD);
92116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - check for errors here.
92216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
92316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // reset so we don't attempt to send this back
92416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.reset();
92516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
92616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
927c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
928c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
9294714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
9304714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
931c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
9328e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
9338e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
9344714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
9358e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
9368e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
9378e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
93816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
93916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = mSendObjectFileSize;
94016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
94159d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
94216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // transfer the file
94316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
944c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
9458e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
946b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood    LOGV("MTP_RECEIVE_FILE returned %d", ret);
94716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
948916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
949916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
950916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
9514714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
952916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
9534714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
954916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
9554714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
9564714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
9574714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
958aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood            result == MTP_RESPONSE_OK);
9594714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
9604714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
9614714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
96216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
96316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
964d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deleteRecursive(const char* path) {
965d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char pathbuf[PATH_MAX];
966d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathLength = strlen(path);
967d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathLength >= sizeof(pathbuf) - 1) {
968d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("path too long: %s\n", path);
969d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
970d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    strcpy(pathbuf, path);
971d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathbuf[pathLength - 1] != '/') {
972d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        pathbuf[pathLength++] = '/';
973d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
974d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char* fileSpot = pathbuf + pathLength;
975d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
976d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
977d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    DIR* dir = opendir(path);
978d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (!dir) {
979d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("opendir %s failed: %s", path, strerror(errno));
980d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        return;
981d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
982d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
983d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct dirent* entry;
984d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    while ((entry = readdir(dir))) {
985d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        const char* name = entry->d_name;
986d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
987d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        // ignore "." and ".."
988d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
989d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
990d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
991d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
992d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int nameLength = strlen(name);
993d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (nameLength > pathRemaining) {
994d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            LOGE("path %s/%s too long\n", path, name);
995d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
996d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
997d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        strcpy(fileSpot, name);
998d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
999d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int type = entry->d_type;
1000d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (entry->d_type == DT_DIR) {
1001d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(pathbuf);
1002d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(pathbuf);
1003d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1004d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(pathbuf);
1005d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1006d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
10077ce05cf6009a2fbbceb3d2c0ff639473d0b7d6a9Mike Lockwood    closedir(dir);
1008d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1009d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1010d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deletePath(const char* path) {
1011d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct stat statbuf;
1012d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (stat(path, &statbuf) == 0) {
1013d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (S_ISDIR(statbuf.st_mode)) {
1014d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(path);
1015d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(path);
1016d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1017d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(path);
1018d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1019d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    } else {
1020d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("deletePath stat failed for %s: %s", path, strerror(errno));
1021d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1022d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1023d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
102416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
1025a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
1026a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
102716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
1028d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
102916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
103016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
103116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
103216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
103316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
1034fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
10359c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
10369c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        LOGV("deleting %s", (const char *)filePath);
1037d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        deletePath((const char *)filePath);
10389c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return mDatabase->deleteFile(handle);
10399c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    } else {
10409c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
10419c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
104216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
104316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
104416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
104521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
104616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
104759d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
10488277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                                        MtpDebug::getFormatCodeName(format));
10498277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
105021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
105121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
10528277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    property->write(mData);
10538277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
10548277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return MTP_RESPONSE_OK;
10558277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
105616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
10578277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropDesc() {
10588277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty propCode = mRequest.getParameter(1);
105959d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
10608277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
10618277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (!property)
10628277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
106321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
10648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
106521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
106616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10677850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
10687d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doSendPartialObject() {
10697d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!hasStorage())
10707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
10717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
10727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
10737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
10747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = offset | (offset2 << 32);
10757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length = mRequest.getParameter(4);
10767d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
10787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
10797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("object not open for edit in doSendPartialObject");
10807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
10817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
10827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // can't start writing past the end of the file
1084c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (offset > edit->mSize) {
1085c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        LOGD("writing past end of object, offset: %lld, edit->mSize: %lld", offset, edit->mSize);
10867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
10877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
10887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // read the header
10907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int ret = mData.readDataHeader(mFD);
10917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // FIXME - check for errors here.
10927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // reset so we don't attempt to send this back
10947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mData.reset();
10957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1096c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    const char* filePath = (const char *)edit->mPath;
10977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    LOGV("receiving partial %s %lld %ld\n", filePath, offset, length);
10987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mtp_file_range  mfr;
1099c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    mfr.fd = edit->mFD;
11007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mfr.offset = offset;
11017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mfr.length = length;
11027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // transfer the file
11047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
11057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    LOGV("MTP_RECEIVE_FILE returned %d", ret);
11067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (ret < 0) {
11077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mResponse.setParameter(1, 0);
11087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (errno == ECANCELED)
11097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
11107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        else
11117d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
11127d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mResponse.setParameter(1, length);
11147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t end = offset + length;
1115c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (end > edit->mSize) {
1116c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = end;
11177d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11187d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11207d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11217d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doTruncateObject() {
11227d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11237d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11247d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
11257d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("object not open for edit in doTruncateObject");
11267d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11277d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11287d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
11307d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
11317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset |= (offset2 << 32);
1132c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (ftruncate(edit->mFD, offset) != 0) {
11337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
1135c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = offset;
11367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_OK;
11377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11387d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11397d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11407d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doBeginEditObject() {
11417d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11427d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (getEditObject(handle)) {
11437d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("object already open for edit in doBeginEditObject");
11447d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11457d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11467d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11477d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpString path;
11487d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int64_t fileLength;
11497d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectFormat format;
11507d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
11517d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result != MTP_RESPONSE_OK)
11527d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return result;
11537d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11547d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int fd = open((const char *)path, O_RDWR | O_EXCL);
11557d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (fd < 0) {
11567d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
11577d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11587d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11597d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11607d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    addEditObject(handle, path, fileLength, format, fd);
11617d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11627d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11637d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11647d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doEndEditObject() {
11657d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11677d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
11687d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("object not open for edit in doEndEditObject");
11697d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    commitEdit(edit);
11737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    removeEditObject(handle);
11747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11767d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11777850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
1178