MtpServer.cpp revision a849440ca96e93f700d62c6e41d48905b4d405b6
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"
3321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood#include "MtpProperty.h"
3416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpServer.h"
3516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStorage.h"
3616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStringBuffer.h"
3716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
388065e2056073808716db32136d7acfd50eeab924Mike Lockwood#include <linux/usb/f_mtp.h>
3916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
407850ef999740f214a1990a9c090d3f3865d435aaMike Lockwoodnamespace android {
417850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
4216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic const MtpOperationCode kSupportedOperationCodes[] = {
4316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_DEVICE_INFO,
4416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_OPEN_SESSION,
4516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_CLOSE_SESSION,
4616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_IDS,
4716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_INFO,
4816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_NUM_OBJECTS,
4916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_HANDLES,
5016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_INFO,
5116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT,
5216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_GET_THUMB,
5316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_DELETE_OBJECT,
5416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT_INFO,
5516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT,
5616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_CAPTURE,
5716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_FORMAT_STORE,
5816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_RESET_DEVICE,
5916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SELF_TEST,
6016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROTECTION,
6116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_POWER_DOWN,
62e3e76c456baee122de6715ae280130abaddc906cMike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_DESC,
638277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_VALUE,
648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_SET_DEVICE_PROP_VALUE,
658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
6616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
6716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_MOVE_OBJECT,
6816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_COPY_OBJECT,
69d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MTP_OPERATION_GET_PARTIAL_OBJECT,
7016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_OPEN_CAPTURE,
7116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
728277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_DESC,
73677f5700c5ea35256079ef14e06b7382e438d860Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_VALUE,
74677f5700c5ea35256079ef14e06b7382e438d860Mike Lockwood    MTP_OPERATION_SET_OBJECT_PROP_VALUE,
75b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_LIST,
76b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROP_LIST,
77b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
78b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_SEND_OBJECT_PROP_LIST,
79438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_GET_OBJECT_REFERENCES,
80438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_SET_OBJECT_REFERENCES,
8116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SKIP,
8216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood};
8316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
84873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodstatic const MtpEventCode kSupportedEventCodes[] = {
85873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_ADDED,
86873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_REMOVED,
87a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MTP_EVENT_STORE_ADDED,
88a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MTP_EVENT_STORE_REMOVED,
89873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood};
90873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
911865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike LockwoodMtpServer::MtpServer(int fd, MtpDatabase* database,
928e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood                    int fileGroup, int filePerm, int directoryPerm)
9316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    :   mFD(fd),
941865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        mDatabase(database),
958e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFileGroup(fileGroup),
968e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFilePermission(filePerm),
978e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mDirectoryPermission(directoryPerm),
9816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionID(0),
9916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionOpen(false),
10016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle(kInvalidObjectHandle),
1014714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat(0),
10216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFileSize(0)
10316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
10416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
10616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpServer::~MtpServer() {
10716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
109a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::addStorage(MtpStorage* storage) {
110a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
111a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
112a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    mStorages.push(storage);
113a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendStoreAdded(storage->getStorageID());
114a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
115a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
116a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::removeStorage(MtpStorage* storage) {
117a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
118a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
119a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
120a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        if (mStorages[i] == storage) {
121a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            mStorages.removeAt(i);
122a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            sendStoreRemoved(storage->getStorageID());
123a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            break;
124a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        }
125a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    }
12616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
12716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
12816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpStorage* MtpServer::getStorage(MtpStorageID id) {
129fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    if (id == 0)
130fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        return mStorages[0];
13116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
132fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpStorage* storage = mStorages[i];
13316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (storage->getStorageID() == id)
13416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return storage;
13516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
13616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return NULL;
13716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
13816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
139a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodbool MtpServer::hasStorage(MtpStorageID id) {
140a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (id == 0 || id == 0xFFFFFFFF)
141a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return mStorages.size() > 0;
142a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    return (getStorage(id) != NULL);
143a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
144a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
14516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::run() {
14616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int fd = mFD;
14716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
14821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    LOGV("MtpServer::run fd: %d\n", fd);
14916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
15016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    while (1) {
15116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int ret = mRequest.read(fd);
15216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret < 0) {
15359d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood            LOGV("request read returned %d, errno: %d", ret, errno);
154916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (errno == ECANCELED) {
155916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                // return to top of loop and wait for next command
156916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                continue;
157916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
15816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
15916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
16016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpOperationCode operation = mRequest.getOperationCode();
16116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpTransactionID transaction = mRequest.getTransactionID();
16216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
163b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
16416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mRequest.dump();
16516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
16616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME need to generalize this
167438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
1688277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
1698277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
1708277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
17116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (dataIn) {
17216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            int ret = mData.read(fd);
17316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
174b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("data read returned %d, errno: %d", ret, errno);
175916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
176916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
177916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
178916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
17916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
18016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
181b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("received data:");
18216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.dump();
18316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        } else {
18416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.reset();
18516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
18616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
187916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (handleRequest()) {
188916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (!dataIn && mData.hasData()) {
189916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setOperationCode(operation);
190916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setTransactionID(transaction);
191b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGV("sending data:");
19223d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood                mData.dump();
193916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                ret = mData.write(fd);
194916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (ret < 0) {
195b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                    LOGE("request write returned %d, errno: %d", ret, errno);
196916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    if (errno == ECANCELED) {
197916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        // return to top of loop and wait for next command
198916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        continue;
199916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    }
200916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    break;
201916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
202916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
20316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
204916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            mResponse.setTransactionID(transaction);
205b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("sending response %04X", mResponse.getResponseCode());
206916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            ret = mResponse.write(fd);
20723d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood            mResponse.dump();
20816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
209b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("request write returned %d, errno: %d", ret, errno);
210916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
211916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
212916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
213916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
21416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
21516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
216916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        } else {
21721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            LOGV("skipping response\n");
21816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
21916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
2206b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
2216b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    if (mSessionOpen)
2226b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood        mDatabase->sessionEnded();
22316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
22416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
225873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
226a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendObjectAdded %d\n", handle);
227a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
228873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
229873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
230873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
231a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendObjectRemoved %d\n", handle);
232a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
233a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
234a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
235a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreAdded(MtpStorageID id) {
236a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendStoreAdded %08X\n", id);
237a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_ADDED, id);
238a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
239a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
240a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreRemoved(MtpStorageID id) {
241a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    LOGV("sendStoreRemoved %08X\n", id);
242a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_REMOVED, id);
243a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
244a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
245a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
24673ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
247a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setEventCode(code);
24873ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
249a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setParameter(1, param1);
25073ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
25159d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood        LOGV("mEvent.write returned %d\n", ret);
25273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
253873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
254873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
255916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
256a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
257a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
25816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
25916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
26016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
26116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
26216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
26316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
26416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
265b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("expected SendObject after SendObjectInfo");
26616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
26716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
26816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
26916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
27016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
27116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
27216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
27316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
27416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
27516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
27616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
27716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
27816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
27916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
28016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
28116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
28216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
28316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
28416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
28516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
28616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
28716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
28816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
28916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
29016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
291343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
292343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
293343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
294438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
295438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
296438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
297438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
298438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
299438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
30016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
30116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
30216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
3038277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
3048277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetObjectPropValue();
3058277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3068277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
3078277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doGetDevicePropValue();
3088277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3098277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
3108277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetDevicePropValue();
3118277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3128277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
3138277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doResetDevicePropValue();
3148277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
315b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_LIST:
316b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            response = doGetObjectPropList();
317b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            break;
31816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
31916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
32016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
324d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT:
325d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            response = doGetPartialObject();
326d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            break;
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
32816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
32916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
33116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
33216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
33416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
33516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
33721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
33821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
339e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_DESC:
340e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            response = doGetDevicePropDesc();
341e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            break;
34216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
343a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood            LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
34416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
34516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
34716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
348916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
349916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
35016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
351916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
35216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
35316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
35416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
35516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
356c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
35716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
358782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
359782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
360782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
361782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
36216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
36316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
36416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(6); // MTP Vendor Extension ID
36516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
36616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("microsoft.com: 1.0;");
36716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
36816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
36916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
37016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
371873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
372873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
373782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(deviceProperties); // Device Properties Supported
374782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(captureFormats); // Capture Formats
375782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(playbackFormats);  // Playback Formats
3768d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood
3778d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
3788d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    string.set(prop_value);
37916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
380c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
381c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
382c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
38316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
38416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
38516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
386c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
387c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
388c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
39016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
391782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete playbackFormats;
392782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete captureFormats;
393782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete deviceProperties;
394782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
39516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
39616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
39716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
39816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
39916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
40016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
40116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
40216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
40316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
40416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
4056b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
4066b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionStarted();
4076b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
40816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
40916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
41016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
41116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
41216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
41316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
41416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
41516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
4166b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionEnded();
41716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
41816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
41916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
42116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
42216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
42316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
42516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
42616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
42716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
42816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
43016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
43116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
43216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
43316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
43416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
43516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
43616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
43716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
43816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
43916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
44016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
44116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
44216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
44316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
44416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
44516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
44616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
44716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
44816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
44916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
45016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
45116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
45216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
45316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
45416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
45516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
45616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
45716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
45816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
4592e09e289b7e136481e9215bb61ed47cee5d9919bMike Lockwood    MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
460782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(properties);
461bf9b2052d207f8f2a23470f1c4dfe464f430f387Mike Lockwood    delete properties;
46216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
46316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
46416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
46516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
46616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
46716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
46816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
469e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
47016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
47116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                                                            // 0x00000000 for all objects?
472a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
473a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
474a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
4751865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == 0xFFFFFFFF)
4761865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
47716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
47816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
47916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
48016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
48116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
48216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
48316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
484343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
485343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
486343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
487343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
488343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
489343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
490343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood                                                            // 0x00000000 for all objects?
491a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
492a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
493343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (parent == 0xFFFFFFFF)
494343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        parent = 0;
495343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
496343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
497343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
498343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
499343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
500343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
501343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
502343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
503343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
504343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
505343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
506438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
507438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
508438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
509a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
510a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
511a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
5128277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5138277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    // FIXME - check for invalid object handle
514438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
5158277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (handles) {
5168277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        mData.putAUInt32(handles);
5178277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        delete handles;
5188277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    } else {
519438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
520438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
521438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
522438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
523438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
524438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
525438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
526438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
527a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
528a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
529438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
530a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
531438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
532438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
533438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
534438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
535438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
536438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
53716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
538a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
539a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
54016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
54116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
54259d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetObjectPropValue %d %s\n", handle,
5438277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
54416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
5458277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getObjectPropertyValue(handle, property, mData);
5468277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5478277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5488277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetObjectPropValue() {
549a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
550a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
5518277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
5528277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
55359d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("SetObjectPropValue %d %s\n", handle,
5548277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
5558277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5568277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setObjectPropertyValue(handle, property, mData);
5578277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5588277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5598277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropValue() {
5608277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
56159d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetDevicePropValue %s\n",
5628277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
5638277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getDevicePropertyValue(property, mData);
5658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5678277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetDevicePropValue() {
5688277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
56959d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("SetDevicePropValue %s\n",
5708277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
5718277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5728277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setDevicePropertyValue(property, mData);
5738277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5758277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doResetDevicePropValue() {
5768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
57759d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("ResetDevicePropValue %s\n",
5788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
5798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->resetDeviceProperty(property);
58116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
58216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
583b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropList() {
584a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
585a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
586b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
587b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
58840ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    // use uint32_t so we can support 0xFFFFFFFF
58940ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t format = mRequest.getParameter(2);
59040ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t property = mRequest.getParameter(3);
591b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    int groupCode = mRequest.getParameter(4);
592f05ff073495b0bb3e49859aee5b54d3e25088985Mike Lockwood    int depth = mRequest.getParameter(5);
59359d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood   LOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
594b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            handle, MtpDebug::getFormatCodeName(format),
595b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            MtpDebug::getObjectPropCodeName(property), groupCode, depth);
596b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
597b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
598b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood}
599b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
60016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
601a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
602a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
60316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
60416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return mDatabase->getObjectInfo(handle, mData);
60516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
60616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
60716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
608a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
609a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
61016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
611c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
61216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
613fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
614fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
6159c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
6169c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
61716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6189c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
61916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
620c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
621c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
622c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
623c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
62416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
62516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
62616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
62716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // send data header
62816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
62916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
63023d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood    mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
63116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
63216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
63316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
634c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
635916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
636916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
637916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
638916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
639916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
640916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
64116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
64216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
64316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
644d81ce3cf2e6479915658a0829eced062e3655320Mike LockwoodMtpResponseCode MtpServer::doGetPartialObject() {
645a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
646a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
647d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
648d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    uint32_t offset = mRequest.getParameter(2);
649d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    uint32_t length = mRequest.getParameter(3);
650d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpString pathBuf;
651d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int64_t fileLength;
652fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
653fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
654d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (result != MTP_RESPONSE_OK)
655d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return result;
656d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (offset + length > fileLength)
657d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        length = fileLength - offset;
658d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
659d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    const char* filePath = (const char *)pathBuf;
660d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mtp_file_range  mfr;
661d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.fd = open(filePath, O_RDONLY);
662d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (mfr.fd < 0) {
663d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
664d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
665d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.offset = offset;
666d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.length = length;
667d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mResponse.setParameter(1, length);
668d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
669d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    // send data header
670d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
671d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
672d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.writeDataHeader(mFD, length + MTP_CONTAINER_HEADER_SIZE);
673d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
674d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    // then transfer the file
675d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
676d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    close(mfr.fd);
677d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (ret < 0) {
678d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        if (errno == ECANCELED)
679d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
680d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        else
681d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
682d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
683d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    return MTP_RESPONSE_OK;
684d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood}
685d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
68616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
68716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
68816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
68916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
69016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
69116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
69216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
69316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
69416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
6951865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
69616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
6971865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
6981865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
699fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int64_t length;
700fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpObjectFormat format;
701fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, length, format);
7029c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
7039c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
704fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        if (format != MTP_FORMAT_ASSOCIATION)
705fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
70616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
70716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
70816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
70916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // storage ID
71016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mData.getUInt16();
71116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // protection status
71216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSendObjectFileSize = mData.getUInt32();
71316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // thumb format
71416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb compressed size
71516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix width
71616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix height
71716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix width
71816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix height
71916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image bit depth
72016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // parent
72116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint16_t associationType = mData.getUInt16();
72216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint32_t associationDesc = mData.getUInt32();   // association desc
72316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // sequence number
72416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
72516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(name);    // file name
72616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(created);      // date created
72716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(modified);     // date modified
72816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
72916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73059d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("name: %s format: %04X\n", (const char *)name, format);
731fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
73216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
73316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
73416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
73616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
73716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
73816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73920c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    // check space first
74020c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    if (mSendObjectFileSize > storage->getFreeSpace())
74120c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood        return MTP_RESPONSE_STORAGE_FULL;
74220c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood
743a849440ca96e93f700d62c6e41d48905b4d405b6Mike LockwoodLOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
7444714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
7454714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
746fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
74716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
748fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
74916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
75016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
75116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
7528e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
75316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
75416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
75516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
7568e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
757aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood
758aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        // SendObject does not get sent for directories, so call endSendObject here instead
759aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
76016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
76116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
76216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
76316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
7644714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
76516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
76616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
76716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
7688277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    mResponse.setParameter(2, parent);
76916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
77016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
77116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
77216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
77316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
77416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
775a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
776a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
7774714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
7784714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
7794714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    int ret;
7804714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
78116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
782b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("Expected SendObjectInfo before SendObject");
7834714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
7844714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
78516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
78616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
78716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read the header
7884714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    ret = mData.readDataHeader(mFD);
78916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - check for errors here.
79016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
79116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // reset so we don't attempt to send this back
79216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.reset();
79316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
79416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
795c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
796c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
7974714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
7984714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
799c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
8008e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
8018e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
8024714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
8038e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
8048e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
8058e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
80616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
80716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = mSendObjectFileSize;
80816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
80959d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
81016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // transfer the file
81116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
812c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
8138e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
814b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood    LOGV("MTP_RECEIVE_FILE returned %d", ret);
81516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
816916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
817916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
818916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
8194714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
820916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
8214714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
822916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
8234714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
8244714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
8254714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
826aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood            result == MTP_RESPONSE_OK);
8274714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
8284714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
8294714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
83016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
83116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
832d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deleteRecursive(const char* path) {
833d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char pathbuf[PATH_MAX];
834d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathLength = strlen(path);
835d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathLength >= sizeof(pathbuf) - 1) {
836d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("path too long: %s\n", path);
837d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
838d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    strcpy(pathbuf, path);
839d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathbuf[pathLength - 1] != '/') {
840d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        pathbuf[pathLength++] = '/';
841d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
842d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char* fileSpot = pathbuf + pathLength;
843d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
844d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
845d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    DIR* dir = opendir(path);
846d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (!dir) {
847d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("opendir %s failed: %s", path, strerror(errno));
848d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        return;
849d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
850d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
851d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct dirent* entry;
852d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    while ((entry = readdir(dir))) {
853d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        const char* name = entry->d_name;
854d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
855d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        // ignore "." and ".."
856d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
857d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
858d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
859d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
860d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int nameLength = strlen(name);
861d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (nameLength > pathRemaining) {
862d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            LOGE("path %s/%s too long\n", path, name);
863d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
864d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
865d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        strcpy(fileSpot, name);
866d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
867d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int type = entry->d_type;
868d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (entry->d_type == DT_DIR) {
869d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(pathbuf);
870d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(pathbuf);
871d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
872d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(pathbuf);
873d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
874d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
8757ce05cf6009a2fbbceb3d2c0ff639473d0b7d6a9Mike Lockwood    closedir(dir);
876d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
877d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
878d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deletePath(const char* path) {
879d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct stat statbuf;
880d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (stat(path, &statbuf) == 0) {
881d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (S_ISDIR(statbuf.st_mode)) {
882d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(path);
883d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(path);
884d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
885d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(path);
886d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
887d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    } else {
888d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("deletePath stat failed for %s: %s", path, strerror(errno));
889d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
890d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
891d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
89216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
893a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
894a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
89516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
896d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
89716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
89816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
89916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
90016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
90116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
902fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
9039c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
9049c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        LOGV("deleting %s", (const char *)filePath);
905d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        deletePath((const char *)filePath);
9069c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return mDatabase->deleteFile(handle);
9079c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    } else {
9089c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
9099c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
91016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
91116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
91321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
91416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
91559d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
9168277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                                        MtpDebug::getFormatCodeName(format));
9178277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
91821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
91921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
9208277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    property->write(mData);
9218277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
9228277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return MTP_RESPONSE_OK;
9238277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
92416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
9258277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropDesc() {
9268277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty propCode = mRequest.getParameter(1);
92759d6ae5e339547fea8a350c1d855b52d5ac4f62cMike Lockwood    LOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
9288277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
9298277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (!property)
9308277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
93121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
9328277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
93321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
93416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
9357850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
9367850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
937