MtpServer.cpp revision 20c3be0e0394e1340c036685eb1edb8f6ef5a2ac
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,
87873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood};
88873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
891865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike LockwoodMtpServer::MtpServer(int fd, MtpDatabase* database,
908e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood                    int fileGroup, int filePerm, int directoryPerm)
9116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    :   mFD(fd),
921865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        mDatabase(database),
938e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFileGroup(fileGroup),
948e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFilePermission(filePerm),
958e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mDirectoryPermission(directoryPerm),
9616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionID(0),
9716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionOpen(false),
9816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle(kInvalidObjectHandle),
994714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat(0),
10016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFileSize(0)
10116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
10216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
10416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpServer::~MtpServer() {
10516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
10720c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwoodvoid MtpServer::addStorage(const char* filePath, uint64_t reserveSpace) {
10816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int index = mStorages.size() + 1;
10916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    index |= index << 16;   // set high and low part to our index
11020c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    MtpStorage* storage = new MtpStorage(index, filePath, reserveSpace);
11116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    addStorage(storage);
11216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpStorage* MtpServer::getStorage(MtpStorageID id) {
115fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    if (id == 0)
116fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        return mStorages[0];
11716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
118fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpStorage* storage = mStorages[i];
11916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (storage->getStorageID() == id)
12016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return storage;
12116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
12216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return NULL;
12316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
12416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
12516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::run() {
12616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int fd = mFD;
12716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
12821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    LOGV("MtpServer::run fd: %d\n", fd);
12916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    while (1) {
13116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int ret = mRequest.read(fd);
13216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret < 0) {
133b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGE("request read returned %d, errno: %d", ret, errno);
134916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (errno == ECANCELED) {
135916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                // return to top of loop and wait for next command
136916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                continue;
137916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
13816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
13916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
14016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpOperationCode operation = mRequest.getOperationCode();
14116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpTransactionID transaction = mRequest.getTransactionID();
14216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
143b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
14416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mRequest.dump();
14516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
14616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME need to generalize this
147438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
1488277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
1498277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
1508277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
15116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (dataIn) {
15216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            int ret = mData.read(fd);
15316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
154b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("data read returned %d, errno: %d", ret, errno);
155916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
156916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
157916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
158916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
15916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
16016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
161b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("received data:");
16216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.dump();
16316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        } else {
16416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.reset();
16516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
16616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
167916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (handleRequest()) {
168916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (!dataIn && mData.hasData()) {
169916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setOperationCode(operation);
170916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setTransactionID(transaction);
171b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGV("sending data:");
17223d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood                mData.dump();
173916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                ret = mData.write(fd);
174916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (ret < 0) {
175b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                    LOGE("request write returned %d, errno: %d", ret, errno);
176916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    if (errno == ECANCELED) {
177916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        // return to top of loop and wait for next command
178916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        continue;
179916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    }
180916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    break;
181916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
182916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
18316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
184916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            mResponse.setTransactionID(transaction);
185b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood            LOGV("sending response %04X", mResponse.getResponseCode());
186916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            ret = mResponse.write(fd);
18723d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood            mResponse.dump();
18816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
189b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood                LOGE("request write returned %d, errno: %d", ret, errno);
190916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
191916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
192916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
193916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
19416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
19516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
196916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        } else {
19721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            LOGV("skipping response\n");
19816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
19916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
2006b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
2016b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    if (mSessionOpen)
2026b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood        mDatabase->sessionEnded();
20316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
20416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
205873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
20673ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
20773ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("sendObjectAdded %d\n", handle);
20873ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
20973ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
21073ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setParameter(1, handle);
21173ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
21273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("mEvent.write returned %d\n", ret);
21373ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
214873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
215873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
216873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
21773ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
21873ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("sendObjectRemoved %d\n", handle);
21973ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
22073ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
22173ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setParameter(1, handle);
22273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
22373ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        LOGD("mEvent.write returned %d\n", ret);
22473ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
225873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
226873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
227916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
22816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
22916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
23016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
23116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
23216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
23316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
23416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
235b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("expected SendObject after SendObjectInfo");
23616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
23716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
23816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
23916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
24016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
24116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
24216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
24316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
24416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
24516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
24616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
24716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
24816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
24916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
25016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
25116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
25216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
25316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
25416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
25516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
25616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
25716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
25816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
25916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
26016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
261343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
262343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
263343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
264438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
265438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
266438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
267438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
268438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
269438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
27016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
27116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
27216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
2738277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
2748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetObjectPropValue();
2758277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
2768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
2778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doGetDevicePropValue();
2788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
2798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
2808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetDevicePropValue();
2818277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
2828277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
2838277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doResetDevicePropValue();
2848277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
285b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_LIST:
286b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            response = doGetObjectPropList();
287b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            break;
28816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
28916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
29016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
29116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
29216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
29316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
294d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT:
295d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            response = doGetPartialObject();
296d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            break;
29716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
29816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
29916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
30016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
30116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
30216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
30316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
30416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
30516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
30616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
30721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
30821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
309e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_DESC:
310e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            response = doGetDevicePropDesc();
311e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            break;
31216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
313a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood            LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
31416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
31516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
31616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
31716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
318916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
319916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
32016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
321916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
32416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
32516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
326c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
328782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
329782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
330782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
331782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
33216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
33316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
33416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(6); // MTP Vendor Extension ID
33516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
33616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("microsoft.com: 1.0;");
33716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
33816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
33916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
34016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
341873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
342873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
343782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(deviceProperties); // Device Properties Supported
344782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(captureFormats); // Capture Formats
345782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(playbackFormats);  // Playback Formats
34616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME
34716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("Google, Inc.");
34816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
349c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
350c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
351c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
35216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
35316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
35416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
355c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
356c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
357c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
35816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
35916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
360782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete playbackFormats;
361782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete captureFormats;
362782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete deviceProperties;
363782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
36416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
36516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
36616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
36716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
36816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
36916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
37016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
37116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
37216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
37316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
3746b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
3756b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionStarted();
3766b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
37716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
37816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
37916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
38016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
38116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
38216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
38316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
38416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
3856b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionEnded();
38616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
38716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
38816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
39016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
39116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
39216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
39316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
39416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
39516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
39616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
39716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
39816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
39916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
40016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
40116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
40216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
40316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
40416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
40516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
40616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
40716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
40816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
40916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
41016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
41116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
41216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
41316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
41416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
41516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
41616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
41716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
41816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
41916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
42016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
42216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
42316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
42516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
42616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
42716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
4282e09e289b7e136481e9215bb61ed47cee5d9919bMike Lockwood    MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
429782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(properties);
430bf9b2052d207f8f2a23470f1c4dfe464f430f387Mike Lockwood    delete properties;
43116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
43216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
43316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
43416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
43516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
43616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
43716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
438e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
43916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
44016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                                                            // 0x00000000 for all objects?
4411865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == 0xFFFFFFFF)
4421865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
44316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
44416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
44516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
44616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
44716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
44816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
44916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
450343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
451343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
452343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
453343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
454343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
455343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
456343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood                                                            // 0x00000000 for all objects?
457343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (parent == 0xFFFFFFFF)
458343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        parent = 0;
459343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
460343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
461343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
462343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
463343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
464343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
465343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
466343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
467343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
468343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
469343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
470438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
471438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
472438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
473438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
4748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
4758277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    // FIXME - check for invalid object handle
476438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
4778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (handles) {
4788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        mData.putAUInt32(handles);
4798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        delete handles;
4808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    } else {
481438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
482438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
483438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
484438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
485438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
486438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
487438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
488438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
489438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
490438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
491438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
492438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
493438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
494438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
495438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
49616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
49716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
49816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
4998277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("GetObjectPropValue %d %s\n", handle,
5008277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
50116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
5028277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getObjectPropertyValue(handle, property, mData);
5038277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5048277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5058277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetObjectPropValue() {
5068277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
5078277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
5088277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("SetObjectPropValue %d %s\n", handle,
5098277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
5108277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5118277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setObjectPropertyValue(handle, property, mData);
5128277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5138277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5148277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropValue() {
5158277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
5168277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("GetDevicePropValue %s\n",
5178277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
5188277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5198277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getDevicePropertyValue(property, mData);
5208277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5218277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5228277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetDevicePropValue() {
5238277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
5248277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("SetDevicePropValue %s\n",
5258277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
5268277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5278277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setDevicePropertyValue(property, mData);
5288277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
5298277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5308277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doResetDevicePropValue() {
5318277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
5328277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("ResetDevicePropValue %s\n",
5338277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
5348277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5358277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->resetDeviceProperty(property);
53616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
53716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
538b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropList() {
539b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
540b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
54140ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    // use uint32_t so we can support 0xFFFFFFFF
54240ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t format = mRequest.getParameter(2);
54340ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t property = mRequest.getParameter(3);
544b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    int groupCode = mRequest.getParameter(4);
545f05ff073495b0bb3e49859aee5b54d3e25088985Mike Lockwood    int depth = mRequest.getParameter(5);
546b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood   LOGD("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
547b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            handle, MtpDebug::getFormatCodeName(format),
548b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            MtpDebug::getObjectPropCodeName(property), groupCode, depth);
549b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
550b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
551b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood}
552b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
55316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
55416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
55516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return mDatabase->getObjectInfo(handle, mData);
55616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
55716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
55816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
55916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
560c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
56116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
562fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
563fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
5649c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
5659c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
56616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
5679c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
56816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
569c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
570c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
571c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
572c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
57316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
57416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
57516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
57616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // send data header
57716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
57816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
57923d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood    mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
58016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
58116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
58216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
583c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
584916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
585916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
586916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
587916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
588916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
589916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
59016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
59116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
59216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
593d81ce3cf2e6479915658a0829eced062e3655320Mike LockwoodMtpResponseCode MtpServer::doGetPartialObject() {
594d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
595d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    uint32_t offset = mRequest.getParameter(2);
596d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    uint32_t length = mRequest.getParameter(3);
597d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpString pathBuf;
598d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int64_t fileLength;
599fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
600fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
601d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (result != MTP_RESPONSE_OK)
602d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return result;
603d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (offset + length > fileLength)
604d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        length = fileLength - offset;
605d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
606d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    const char* filePath = (const char *)pathBuf;
607d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mtp_file_range  mfr;
608d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.fd = open(filePath, O_RDONLY);
609d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (mfr.fd < 0) {
610d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
611d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
612d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.offset = offset;
613d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.length = length;
614d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mResponse.setParameter(1, length);
615d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
616d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    // send data header
617d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
618d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
619d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mData.writeDataHeader(mFD, length + MTP_CONTAINER_HEADER_SIZE);
620d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
621d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    // then transfer the file
622d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
623d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    close(mfr.fd);
624d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (ret < 0) {
625d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        if (errno == ECANCELED)
626d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
627d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        else
628d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
629d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
630d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    return MTP_RESPONSE_OK;
631d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood}
632d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
63316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
63416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
63516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
63616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
63716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
63816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
63916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
64016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
64116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
6421865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
64316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
6441865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
6451865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
646fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int64_t length;
647fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpObjectFormat format;
648fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, length, format);
6499c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
6509c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
651fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        if (format != MTP_FORMAT_ASSOCIATION)
652fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
65316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
65416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
65516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
65616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // storage ID
65716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mData.getUInt16();
65816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // protection status
65916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSendObjectFileSize = mData.getUInt32();
66016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // thumb format
66116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb compressed size
66216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix width
66316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix height
66416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix width
66516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix height
66616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image bit depth
66716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // parent
66816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint16_t associationType = mData.getUInt16();
66916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint32_t associationDesc = mData.getUInt32();   // association desc
67016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // sequence number
67116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
67216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(name);    // file name
67316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(created);      // date created
67416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(modified);     // date modified
67516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
67616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
677f5b2ff2a636d1a98e959553376ebffa3a2749843Mike Lockwood    LOGD("name: %s format: %04X\n", (const char *)name, format);
678fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
67916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
68016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
68116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
68216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
68316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
68416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
68516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
686fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    // file should not already exist
687fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    if (access(path, R_OK) == 0)
688fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
689fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood
69020c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    // check space first
69120c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    if (mSendObjectFileSize > storage->getFreeSpace())
69220c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood        return MTP_RESPONSE_STORAGE_FULL;
69320c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood
6944714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
6954714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
696fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
69716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
698fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
69916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
70016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
70116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
7028e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
70316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
70416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
70516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
7068e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
70716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
70816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
70916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
71016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
7114714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
71216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
71316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
71416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
7158277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    mResponse.setParameter(2, parent);
71616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
71716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
71816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
71916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
72016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
72116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
7224714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
7234714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
7244714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    int ret;
725e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood    uint64_t actualSize = -1;
7264714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
72716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
728b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood        LOGE("Expected SendObjectInfo before SendObject");
7294714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
7304714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
73116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
73216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read the header
7344714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    ret = mData.readDataHeader(mFD);
73516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - check for errors here.
73616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // reset so we don't attempt to send this back
73816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.reset();
73916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
74016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
741c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
742c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
7434714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
7444714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
745c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
7468e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
7478e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
7484714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
7498e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
7508e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
7518e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
75216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
75316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = mSendObjectFileSize;
75416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
755f5b2ff2a636d1a98e959553376ebffa3a2749843Mike Lockwood    LOGD("receiving %s\n", (const char *)mSendObjectFilePath);
75616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // transfer the file
75716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
758c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
7598e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
760b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood    LOGV("MTP_RECEIVE_FILE returned %d", ret);
76116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
762916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
763916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
764916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
7654714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
766916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
7674714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
768e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood    } else if (mSendObjectFileSize == 0xFFFFFFFF) {
769e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood        // actual size is likely > 4 gig so stat the file to compute actual length
770e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood        struct stat s;
771e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood        if (lstat(mSendObjectFilePath, &s) == 0) {
772e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood            actualSize = s.st_size;
773e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood            LOGD("actualSize: %lld\n", actualSize);
774e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood        }
775916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
7764714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
7774714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
7784714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
779e1b8cf1cafb75ce1339b67eb1764e224a257c579Mike Lockwood            actualSize, result == MTP_RESPONSE_OK);
7804714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
7814714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
7824714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
78316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
78416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
785d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deleteRecursive(const char* path) {
786d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char pathbuf[PATH_MAX];
787d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathLength = strlen(path);
788d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathLength >= sizeof(pathbuf) - 1) {
789d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("path too long: %s\n", path);
790d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
791d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    strcpy(pathbuf, path);
792d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathbuf[pathLength - 1] != '/') {
793d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        pathbuf[pathLength++] = '/';
794d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
795d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char* fileSpot = pathbuf + pathLength;
796d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
797d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
798d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    DIR* dir = opendir(path);
799d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (!dir) {
800d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("opendir %s failed: %s", path, strerror(errno));
801d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        return;
802d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
803d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
804d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct dirent* entry;
805d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    while ((entry = readdir(dir))) {
806d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        const char* name = entry->d_name;
807d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
808d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        // ignore "." and ".."
809d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
810d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
811d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
812d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
813d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int nameLength = strlen(name);
814d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (nameLength > pathRemaining) {
815d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            LOGE("path %s/%s too long\n", path, name);
816d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
817d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
818d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        strcpy(fileSpot, name);
819d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
820d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int type = entry->d_type;
821d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (entry->d_type == DT_DIR) {
822d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(pathbuf);
823d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(pathbuf);
824d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
825d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(pathbuf);
826d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
827d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
8287ce05cf6009a2fbbceb3d2c0ff639473d0b7d6a9Mike Lockwood    closedir(dir);
829d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
830d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
831d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deletePath(const char* path) {
832d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct stat statbuf;
833d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (stat(path, &statbuf) == 0) {
834d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (S_ISDIR(statbuf.st_mode)) {
835d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(path);
836d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(path);
837d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
838d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(path);
839d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
840d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    } else {
841d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        LOGE("deletePath stat failed for %s: %s", path, strerror(errno));
842d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
843d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
844d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
84516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
84616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
847d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
84816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
84916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
85016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
85116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
85216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
853fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
8549c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
8559c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        LOGV("deleting %s", (const char *)filePath);
856d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        deletePath((const char *)filePath);
8579c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return mDatabase->deleteFile(handle);
8589c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    } else {
8599c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
8609c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
86116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
86216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
86316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
86421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
86516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
8668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
8678277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                                        MtpDebug::getFormatCodeName(format));
8688277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
86921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
87021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
8718277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    property->write(mData);
8728277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
8738277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return MTP_RESPONSE_OK;
8748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
87516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
8768277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropDesc() {
8778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty propCode = mRequest.getParameter(1);
8788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    LOGD("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
8798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
8808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (!property)
8818277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
88221ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
8838277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
88421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
88516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
8867850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
8877850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
888