MtpServer.cpp revision 64000788211f4c7e78c80a4a155390d1316e1176
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
981865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike LockwoodMtpServer::MtpServer(int fd, MtpDatabase* database,
998e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood                    int fileGroup, int filePerm, int directoryPerm)
10016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    :   mFD(fd),
1011865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        mDatabase(database),
1028e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFileGroup(fileGroup),
1038e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFilePermission(filePerm),
1048e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mDirectoryPermission(directoryPerm),
10516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionID(0),
10616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionOpen(false),
10716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle(kInvalidObjectHandle),
1084714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat(0),
10916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFileSize(0)
11016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
11116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpServer::~MtpServer() {
11416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
116a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::addStorage(MtpStorage* storage) {
117a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
118a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
119a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    mStorages.push(storage);
120a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendStoreAdded(storage->getStorageID());
121a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
122a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
123a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::removeStorage(MtpStorage* storage) {
124a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
125a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
126a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
127a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        if (mStorages[i] == storage) {
128a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            mStorages.removeAt(i);
129a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            sendStoreRemoved(storage->getStorageID());
130a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            break;
131a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        }
132a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    }
13316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
13416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpStorage* MtpServer::getStorage(MtpStorageID id) {
136fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    if (id == 0)
137fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        return mStorages[0];
13816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
139fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpStorage* storage = mStorages[i];
14016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (storage->getStorageID() == id)
14116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return storage;
14216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
14316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return NULL;
14416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
14516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
146a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodbool MtpServer::hasStorage(MtpStorageID id) {
147a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (id == 0 || id == 0xFFFFFFFF)
148a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return mStorages.size() > 0;
149a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    return (getStorage(id) != NULL);
150a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
151a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
15216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::run() {
15316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int fd = mFD;
15416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
15521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    LOGV("MtpServer::run fd: %d\n", fd);
15616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
15716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    while (1) {
15816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int ret = mRequest.read(fd);
15916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret < 0) {
16059d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood            LOGV("request read returned %d, errno: %d", ret, errno);
161916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (errno == ECANCELED) {
162916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                // return to top of loop and wait for next command
163916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                continue;
164916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
16516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
16616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
16716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpOperationCode operation = mRequest.getOperationCode();
16816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpTransactionID transaction = mRequest.getTransactionID();
16916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
170b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
17116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mRequest.dump();
17216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
17316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME need to generalize this
174438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
1758277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
1768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
1778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
17816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (dataIn) {
17916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            int ret = mData.read(fd);
18016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
181b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("data read returned %d, errno: %d", ret, errno);
182916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
183916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
184916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
185916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
18616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
18716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
188b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("received data:");
18916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.dump();
19016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        } else {
19116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.reset();
19216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
19316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
194916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (handleRequest()) {
195916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (!dataIn && mData.hasData()) {
196916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setOperationCode(operation);
197916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setTransactionID(transaction);
198b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGV("sending data:");
19923d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood                mData.dump();
200916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                ret = mData.write(fd);
201916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (ret < 0) {
202b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                    LOGE("request write returned %d, errno: %d", ret, errno);
203916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    if (errno == ECANCELED) {
204916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        // return to top of loop and wait for next command
205916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        continue;
206916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    }
207916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    break;
208916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
209916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
21016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
211916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            mResponse.setTransactionID(transaction);
212b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("sending response %04X", mResponse.getResponseCode());
213916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            ret = mResponse.write(fd);
21423d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood            mResponse.dump();
21516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
216b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("request write returned %d, errno: %d", ret, errno);
217916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
218916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
219916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
220916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
22116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
22216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
223916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        } else {
22421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            LOGV("skipping response\n");
22516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
22616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
2276b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
2287d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // commit any open edits
2297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2307d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
2327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        commitEdit(edit);
2337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        delete edit;
2347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2357d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.clear();
2367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2376b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    if (mSessionOpen)
2386b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood        mDatabase->sessionEnded();
23916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
24016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
241873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
242a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendObjectAdded %d\n", handle);
243a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
244873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
245873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
246873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
247a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendObjectRemoved %d\n", handle);
248a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
249a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
250a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
251a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreAdded(MtpStorageID id) {
252a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendStoreAdded %08X\n", id);
253a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_ADDED, id);
254a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
255a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
256a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreRemoved(MtpStorageID id) {
257a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendStoreRemoved %08X\n", id);
258a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_REMOVED, id);
259a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
260a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
261a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
26273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
263a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setEventCode(code);
26473ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
265a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setParameter(1, param1);
26673ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
26759d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood        LOGV("mEvent.write returned %d\n", ret);
26873ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
269873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
270873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
2717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
2727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t size, MtpObjectFormat format, int fd) {
273c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    ObjectEdit*  edit = new ObjectEdit(handle, path, size, format, fd);
2747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.add(edit);
2757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2767d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
2787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
281c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) return edit;
2827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return NULL;
2847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::removeEditObject(MtpObjectHandle handle) {
2877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
290c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) {
2917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            delete edit;
2927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            mObjectEditList.removeAt(i);
2937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return;
2947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        }
2957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    LOGE("ObjectEdit not found in removeEditObject");
2977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::commitEdit(ObjectEdit* edit) {
300c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
3017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
3027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
304916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
305a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
306a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
30716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
30816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
30916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
31016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
31116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
31216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
31316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
314b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("expected SendObject after SendObjectInfo");
31516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
31616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
31716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
31816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
31916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
32016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
32116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
32416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
32616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
32916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
33016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
33216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
33316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
33516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
33616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
33816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
33916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
340343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
341343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
342343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
343438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
344438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
345438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
346438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
347438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
348438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
34916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
35016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
35116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
3528277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
3538277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetObjectPropValue();
3548277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3558277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
3568277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doGetDevicePropValue();
3578277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3588277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
3598277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetDevicePropValue();
3608277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3618277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
3628277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doResetDevicePropValue();
3638277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
364b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_LIST:
365b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            response = doGetObjectPropList();
366b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            break;
36716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
36816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
36916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
37016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
37116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
37216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
37364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        case MTP_OPERATION_GET_THUMB:
37464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            response = doGetThumb();
37564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            break;
376d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT:
3777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
3787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doGetPartialObject(operation);
379d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            break;
38016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
38116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
38216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
38416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
38516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
38716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
38816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
39021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
39121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
392e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_DESC:
393e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            response = doGetDevicePropDesc();
394e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            break;
3957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_SEND_PARTIAL_OBJECT:
3967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doSendPartialObject();
3977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
3987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_TRUNCATE_OBJECT:
3997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doTruncateObject();
4007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_BEGIN_EDIT_OBJECT:
4027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doBeginEditObject();
4037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_END_EDIT_OBJECT:
4057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doEndEditObject();
4067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
40716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
408a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood            LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
40916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
41016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
41116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
41216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
413916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
414916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
41516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
416916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
41716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
41816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
41916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
42016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
421c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
42216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
423782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
424782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
425782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
426782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
42716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
42816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
42916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(6); // MTP Vendor Extension ID
43016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    string.set("microsoft.com: 1.0; android.com: 1.0;");
43216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
43316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
43416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
43516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
436873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
437873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
438782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(deviceProperties); // Device Properties Supported
439782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(captureFormats); // Capture Formats
440782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(playbackFormats);  // Playback Formats
4418d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood
4428d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
4438d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    string.set(prop_value);
44416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
445c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
446c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
447c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
44816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
44916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
45016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
451c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
452c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
453c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
45416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
45516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
456782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete playbackFormats;
457782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete captureFormats;
458782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete deviceProperties;
459782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
46016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
46116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
46216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
46316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
46416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
46516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
46616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
46716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
46816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
46916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
4706b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
4716b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionStarted();
4726b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
47316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
47416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
47516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
47616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
47716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
47816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
47916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
48016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
4816b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionEnded();
48216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
48316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
48416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
48516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
48616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
48716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
48816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
48916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
49016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
49116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
49216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
49316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
49416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
49516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
49616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
49716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
49816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
49916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
50116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
50216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
50316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
50416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
50516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
50616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
50816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
50916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
51016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
51116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
51216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
51316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
51416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
51516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
51616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
51816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
51916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
52016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
52116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
52216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
52316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
5242e09e289b7e136481e9215bb61ed47cee5d9919bMike Lockwood    MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
525782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(properties);
526bf9b2052d207f8f2a23470f1c4dfe464f430f387Mike Lockwood    delete properties;
52716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
52816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
52916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
53116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
53216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
53316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
534e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
53516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
53616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                                                            // 0x00000000 for all objects?
537a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
538a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
539a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
5401865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == 0xFFFFFFFF)
5411865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
54216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
54316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
54416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
54516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
54616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
54716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
54816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
549343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
550343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
551343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
552343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
553343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
554343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
555343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood                                                            // 0x00000000 for all objects?
556a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
557a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
558343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (parent == 0xFFFFFFFF)
559343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        parent = 0;
560343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
561343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
562343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
563343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
564343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
565343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
566343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
567343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
568343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
569343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
570343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
571438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
572438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
573438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
574a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
575a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
576a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
5778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    // FIXME - check for invalid object handle
579438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
5808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (handles) {
5818277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        mData.putAUInt32(handles);
5828277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        delete handles;
5838277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    } else {
584438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
585438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
586438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
587438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
588438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
589438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
590438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
591438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
592a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
593a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
594438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
595a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
596438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
597438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
598438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
599438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
600438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
601438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
60216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
603a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
604a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
60516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
60616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
60759d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetObjectPropValue %d %s\n", handle,
6088277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
60916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6108277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getObjectPropertyValue(handle, property, mData);
6118277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6128277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6138277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetObjectPropValue() {
614a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
615a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
6168277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6178277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
61859d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("SetObjectPropValue %d %s\n", handle,
6198277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
6208277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6218277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setObjectPropertyValue(handle, property, mData);
6228277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6238277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6248277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropValue() {
6258277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
62659d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetDevicePropValue %s\n",
6278277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6288277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6298277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getDevicePropertyValue(property, mData);
6308277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6318277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6328277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetDevicePropValue() {
6338277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
63459d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("SetDevicePropValue %s\n",
6358277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6368277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6378277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setDevicePropertyValue(property, mData);
6388277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6398277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6408277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doResetDevicePropValue() {
6418277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
64259d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("ResetDevicePropValue %s\n",
6438277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6448277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6458277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->resetDeviceProperty(property);
64616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
64716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
648b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropList() {
649a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
650a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
651b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
652b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
65340ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    // use uint32_t so we can support 0xFFFFFFFF
65440ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t format = mRequest.getParameter(2);
65540ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t property = mRequest.getParameter(3);
656b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    int groupCode = mRequest.getParameter(4);
657f05ff073495b0bb3e49859aee5b54d3e25088985Mike Lockwood    int depth = mRequest.getParameter(5);
65859d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood   LOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
659b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            handle, MtpDebug::getFormatCodeName(format),
660b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            MtpDebug::getObjectPropCodeName(property), groupCode, depth);
661b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
662b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
663b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood}
664b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
66516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
666a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
667a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
66816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6697d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectInfo info(handle);
6707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
6717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
6727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        char    date[20];
6737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mStorageID);
6757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mFormat);
6767d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mProtectionStatus);
6777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // if object is being edited the database size may be out of date
6797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint32_t size = info.mCompressedSize;
6807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = getEditObject(handle);
6817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (edit)
682c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood            size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
6837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(size);
6847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mThumbFormat);
6867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbCompressedSize);
6877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixWidth);
6887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixHeight);
6897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixWidth);
6907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixHeight);
6917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixDepth);
6927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mParent);
6937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mAssociationType);
6947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mAssociationDesc);
6957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mSequenceNumber);
6967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(info.mName);
6977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putEmptyString();    // date created
6987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        formatDateTime(info.mDateModified, date, sizeof(date));
6997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(date);   // date modified
7007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putEmptyString();   // keywords
7017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
7027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return result;
70316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
70416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
70516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
706a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
707a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
70816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
709c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
71016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
711fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
712fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
7139c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
7149c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
71516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
7169c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
71716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
718c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
719c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
720c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
721c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
72216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
72316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
72416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
72516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // send data header
72616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
72716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
72823d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood    mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
72916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
73116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
732c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
733916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
734916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
735916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
736916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
737916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
738916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
73916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
74016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
74116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
74264000788211f4c7e78c80a4a155390d1316e1176Mike LockwoodMtpResponseCode MtpServer::doGetThumb() {
74364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
74464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    size_t thumbSize;
74564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    void* thumb = mDatabase->getThumbnail(handle, thumbSize);
74664000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    if (thumb) {
74764000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        // send data
74864000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setOperationCode(mRequest.getOperationCode());
74964000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setTransactionID(mRequest.getTransactionID());
75064000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.writeData(mFD, thumb, thumbSize);
75164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        free(thumb);
75264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_OK;
75364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    } else {
75464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
75564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    }
75664000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood}
75764000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood
7587d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
759a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
760a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
761d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
7627d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset;
7637d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length;
7647d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = mRequest.getParameter(2);
7657d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
7667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // android extension with 64 bit offset
7677d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t offset2 = mRequest.getParameter(3);
7687d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        offset = offset | (offset2 << 32);
7697d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(4);
7707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
7717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // standard GetPartialObject
7727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(3);
7737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
774d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpString pathBuf;
775d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int64_t fileLength;
776fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
777fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
778d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (result != MTP_RESPONSE_OK)
779d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return result;
780d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (offset + length > fileLength)
781d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        length = fileLength - offset;
782d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
783d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    const char* filePath = (const char *)pathBuf;
784d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mtp_file_range  mfr;
785d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.fd = open(filePath, O_RDONLY);
786d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (mfr.fd < 0) {
787d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
788d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
789d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.offset = offset;
790d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.length = length;
791d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mResponse.setParameter(1, length);
792d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
793d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    // send data header
794d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
795d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
796d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.writeDataHeader(mFD, length + MTP_CONTAINER_HEADER_SIZE);
797d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
798d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    // then transfer the file
799d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
800d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    close(mfr.fd);
801d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (ret < 0) {
802d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        if (errno == ECANCELED)
803d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
804d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        else
805d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
806d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
807d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    return MTP_RESPONSE_OK;
808d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood}
809d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
81016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
81116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
81216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
81316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
81416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
81516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
81616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
81716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
81816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
8191865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
82016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
8211865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
8221865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
823fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int64_t length;
824fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpObjectFormat format;
825fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, length, format);
8269c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
8279c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
828fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        if (format != MTP_FORMAT_ASSOCIATION)
829fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
83016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
83116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
83216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
83316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // storage ID
83416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mData.getUInt16();
83516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // protection status
83616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSendObjectFileSize = mData.getUInt32();
83716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // thumb format
83816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb compressed size
83916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix width
84016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix height
84116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix width
84216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix height
84316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image bit depth
84416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // parent
84516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint16_t associationType = mData.getUInt16();
84616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint32_t associationDesc = mData.getUInt32();   // association desc
84716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // sequence number
84816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
84916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(name);    // file name
85016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(created);      // date created
85116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(modified);     // date modified
85216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
85316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
85459d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("name: %s format: %04X\n", (const char *)name, format);
855fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
85616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
85716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
85816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
85916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
86016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
86116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
86216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
86320c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    // check space first
86420c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    if (mSendObjectFileSize > storage->getFreeSpace())
86520c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood        return MTP_RESPONSE_STORAGE_FULL;
86620c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood
867a849440ca96e93f700d62c6e41d48905b4d405b6Mike LockwoodLOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
8684714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
8694714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
870fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
87116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
872fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
87316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
87416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
87516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
8768e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
87716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
87816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
87916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
8808e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
881aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood
882aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        // SendObject does not get sent for directories, so call endSendObject here instead
883aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
88416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
88516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
88616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
88716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
8884714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
88916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
89016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
89116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
8928277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    mResponse.setParameter(2, parent);
89316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
89416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
89516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
89616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
89716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
89816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
899a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
900a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
9014714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
9024714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
9034714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    int ret;
9044714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
90516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
906b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("Expected SendObjectInfo before SendObject");
9074714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
9084714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
90916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
91016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read the header
9124714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    ret = mData.readDataHeader(mFD);
91316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - check for errors here.
91416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // reset so we don't attempt to send this back
91616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.reset();
91716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
919c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
920c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
9214714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
9224714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
923c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
9248e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
9258e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
9264714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
9278e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
9288e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
9298e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
93016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
93116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = mSendObjectFileSize;
93216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
93359d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
93416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // transfer the file
93516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
936c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
9378e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
938b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood    LOGV("MTP_RECEIVE_FILE returned %d", ret);
93916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
940916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
941916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
942916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
9434714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
944916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
9454714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
946916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
9474714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
9484714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
9494714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
950aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood            result == MTP_RESPONSE_OK);
9514714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
9524714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
9534714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
95416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
95516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
956d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deleteRecursive(const char* path) {
957d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char pathbuf[PATH_MAX];
958d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathLength = strlen(path);
959d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathLength >= sizeof(pathbuf) - 1) {
960d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("path too long: %s\n", path);
961d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
962d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    strcpy(pathbuf, path);
963d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathbuf[pathLength - 1] != '/') {
964d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        pathbuf[pathLength++] = '/';
965d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
966d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char* fileSpot = pathbuf + pathLength;
967d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
968d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
969d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    DIR* dir = opendir(path);
970d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (!dir) {
971d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("opendir %s failed: %s", path, strerror(errno));
972d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        return;
973d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
974d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
975d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct dirent* entry;
976d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    while ((entry = readdir(dir))) {
977d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        const char* name = entry->d_name;
978d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
979d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        // ignore "." and ".."
980d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
981d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
982d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
983d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
984d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int nameLength = strlen(name);
985d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (nameLength > pathRemaining) {
986d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            LOGE("path %s/%s too long\n", path, name);
987d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
988d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
989d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        strcpy(fileSpot, name);
990d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
991d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int type = entry->d_type;
992d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (entry->d_type == DT_DIR) {
993d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(pathbuf);
994d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(pathbuf);
995d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
996d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(pathbuf);
997d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
998d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
9997ce05cf6009a2fbbceb3d2c0ff639473d0b7d6a9Mike Lockwood    closedir(dir);
1000d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1001d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1002d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deletePath(const char* path) {
1003d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct stat statbuf;
1004d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (stat(path, &statbuf) == 0) {
1005d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (S_ISDIR(statbuf.st_mode)) {
1006d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(path);
1007d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(path);
1008d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1009d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(path);
1010d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1011d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    } else {
1012d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("deletePath stat failed for %s: %s", path, strerror(errno));
1013d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1014d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1015d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
101616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
1017a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
1018a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
101916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
1020d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
102116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
102216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
102316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
102416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
102516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
1026fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
10279c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
10289c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        LOGV("deleting %s", (const char *)filePath);
1029d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        deletePath((const char *)filePath);
10309c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return mDatabase->deleteFile(handle);
10319c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    } else {
10329c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
10339c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
103416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
103516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
103616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
103721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
103816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
103959d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
10408277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                                        MtpDebug::getFormatCodeName(format));
10418277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
104221ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
104321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
10448277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    property->write(mData);
10458277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
10468277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return MTP_RESPONSE_OK;
10478277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
104816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
10498277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropDesc() {
10508277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty propCode = mRequest.getParameter(1);
105159d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
10528277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
10538277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (!property)
10548277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
105521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
10568277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
105721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
105816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10597850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
10607d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doSendPartialObject() {
10617d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!hasStorage())
10627d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
10637d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
10647d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
10657d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
10667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = offset | (offset2 << 32);
10677d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length = mRequest.getParameter(4);
10687d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10697d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
10707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
10717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("object not open for edit in doSendPartialObject");
10727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
10737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
10747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // can't start writing past the end of the file
1076c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (offset > edit->mSize) {
1077c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        LOGD("writing past end of object, offset: %lld, edit->mSize: %lld", offset, edit->mSize);
10787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
10797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
10807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // read the header
10827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int ret = mData.readDataHeader(mFD);
10837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // FIXME - check for errors here.
10847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // reset so we don't attempt to send this back
10867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mData.reset();
10877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1088c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    const char* filePath = (const char *)edit->mPath;
10897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    LOGV("receiving partial %s %lld %ld\n", filePath, offset, length);
10907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mtp_file_range  mfr;
1091c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    mfr.fd = edit->mFD;
10927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mfr.offset = offset;
10937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mfr.length = length;
10947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // transfer the file
10967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
10977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    LOGV("MTP_RECEIVE_FILE returned %d", ret);
10987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (ret < 0) {
10997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mResponse.setParameter(1, 0);
11007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (errno == ECANCELED)
11017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
11027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        else
11037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
11047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mResponse.setParameter(1, length);
11067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t end = offset + length;
1107c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (end > edit->mSize) {
1108c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = end;
11097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11117d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11127d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doTruncateObject() {
11147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11157d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11167d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
11177d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("object not open for edit in doTruncateObject");
11187d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11207d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11217d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
11227d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
11237d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset |= (offset2 << 32);
1124c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (ftruncate(edit->mFD, offset) != 0) {
11257d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11267d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
1127c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = offset;
11287d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_OK;
11297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11307d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doBeginEditObject() {
11337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (getEditObject(handle)) {
11357d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("object already open for edit in doBeginEditObject");
11367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11387d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11397d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpString path;
11407d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int64_t fileLength;
11417d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectFormat format;
11427d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
11437d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result != MTP_RESPONSE_OK)
11447d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return result;
11457d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11467d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int fd = open((const char *)path, O_RDWR | O_EXCL);
11477d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (fd < 0) {
11487d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
11497d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11507d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11517d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11527d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    addEditObject(handle, path, fileLength, format, fd);
11537d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11547d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11557d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11567d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doEndEditObject() {
11577d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11587d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11597d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
11607d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        LOGE("object not open for edit in doEndEditObject");
11617d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11627d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11637d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11647d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    commitEdit(edit);
11657d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    removeEditObject(handle);
11667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11677d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11687d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11697850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
1170