MtpServer.cpp revision dcd89ecad321e2e052322fe2b1907d50d762b311
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>
23db43b34c3428e480f8c4c66e7e88f4001f37f91eMark Salyzyn#include <inttypes.h>
2416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <errno.h>
25d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood#include <sys/stat.h>
26d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood#include <dirent.h>
2716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
28c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood#include <cutils/properties.h>
29c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
30a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood#define LOG_TAG "MtpServer"
31a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood
3216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpDebug.h"
337f53a190463274096155704276f3002c1620a364Mike Lockwood#include "MtpDatabase.h"
347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood#include "MtpObjectInfo.h"
3521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood#include "MtpProperty.h"
3616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpServer.h"
3716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStorage.h"
3816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStringBuffer.h"
3916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
408065e2056073808716db32136d7acfd50eeab924Mike Lockwood#include <linux/usb/f_mtp.h>
4116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
427850ef999740f214a1990a9c090d3f3865d435aaMike Lockwoodnamespace android {
437850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
4416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic const MtpOperationCode kSupportedOperationCodes[] = {
4516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_DEVICE_INFO,
4616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_OPEN_SESSION,
4716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_CLOSE_SESSION,
4816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_IDS,
4916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_INFO,
5016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_NUM_OBJECTS,
5116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_HANDLES,
5216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_INFO,
5316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT,
5464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    MTP_OPERATION_GET_THUMB,
5516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_DELETE_OBJECT,
5616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT_INFO,
5716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT,
5816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_CAPTURE,
5916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_FORMAT_STORE,
6016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_RESET_DEVICE,
6116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SELF_TEST,
6216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROTECTION,
6316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_POWER_DOWN,
64e3e76c456baee122de6715ae280130abaddc906cMike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_DESC,
658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_VALUE,
668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_SET_DEVICE_PROP_VALUE,
678277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
6816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
6916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_MOVE_OBJECT,
7016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_COPY_OBJECT,
71d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MTP_OPERATION_GET_PARTIAL_OBJECT,
7216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_OPEN_CAPTURE,
7316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_DESC,
75677f5700c5ea35256079ef14e06b7382e438d860Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_VALUE,
76677f5700c5ea35256079ef14e06b7382e438d860Mike Lockwood    MTP_OPERATION_SET_OBJECT_PROP_VALUE,
77b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_LIST,
78b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROP_LIST,
79b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
80b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_SEND_OBJECT_PROP_LIST,
81438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_GET_OBJECT_REFERENCES,
82438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_SET_OBJECT_REFERENCES,
8316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SKIP,
847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // Android extension for direct file IO
857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_GET_PARTIAL_OBJECT_64,
867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_SEND_PARTIAL_OBJECT,
877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_TRUNCATE_OBJECT,
887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_BEGIN_EDIT_OBJECT,
897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_END_EDIT_OBJECT,
9016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood};
9116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
92873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodstatic const MtpEventCode kSupportedEventCodes[] = {
93873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_ADDED,
94873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_REMOVED,
95a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MTP_EVENT_STORE_ADDED,
96a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MTP_EVENT_STORE_REMOVED,
970fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood    MTP_EVENT_DEVICE_PROP_CHANGED,
98873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood};
99873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
1003d1d7767afc7c488197ec40a22739159c5110721Mike LockwoodMtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
1018e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood                    int fileGroup, int filePerm, int directoryPerm)
10216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    :   mFD(fd),
1031865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        mDatabase(database),
1043d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mPtp(ptp),
1058e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFileGroup(fileGroup),
1068e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFilePermission(filePerm),
1078e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mDirectoryPermission(directoryPerm),
10816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionID(0),
10916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionOpen(false),
11016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle(kInvalidObjectHandle),
1114714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat(0),
11216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFileSize(0)
11316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
11416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpServer::~MtpServer() {
11716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
119a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::addStorage(MtpStorage* storage) {
120a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
121a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
122a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    mStorages.push(storage);
123a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendStoreAdded(storage->getStorageID());
124a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
125a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
126a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::removeStorage(MtpStorage* storage) {
127a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
128a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
1293ab368e0810d894dcbc0971350c095049478a055Mark Salyzyn    for (size_t i = 0; i < mStorages.size(); i++) {
130a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        if (mStorages[i] == storage) {
131a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            mStorages.removeAt(i);
132a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            sendStoreRemoved(storage->getStorageID());
133a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            break;
134a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        }
135a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    }
13616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
13716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpStorage* MtpServer::getStorage(MtpStorageID id) {
139fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    if (id == 0)
140fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        return mStorages[0];
1413ab368e0810d894dcbc0971350c095049478a055Mark Salyzyn    for (size_t i = 0; i < mStorages.size(); i++) {
142fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpStorage* storage = mStorages[i];
14316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (storage->getStorageID() == id)
14416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return storage;
14516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
14616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return NULL;
14716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
14816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
149a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodbool MtpServer::hasStorage(MtpStorageID id) {
150a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (id == 0 || id == 0xFFFFFFFF)
151a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return mStorages.size() > 0;
152a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    return (getStorage(id) != NULL);
153a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
154a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
15516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::run() {
15616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int fd = mFD;
15716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1583856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("MtpServer::run fd: %d\n", fd);
15916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
16016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    while (1) {
16116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int ret = mRequest.read(fd);
16216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret < 0) {
1633856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("request read returned %d, errno: %d", ret, errno);
164916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (errno == ECANCELED) {
165916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                // return to top of loop and wait for next command
166916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                continue;
167916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
16816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
16916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
17016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpOperationCode operation = mRequest.getOperationCode();
17116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpTransactionID transaction = mRequest.getTransactionID();
17216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1733856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
17416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mRequest.dump();
17516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
17616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME need to generalize this
177438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
1788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
1798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
1808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
18116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (dataIn) {
18216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            int ret = mData.read(fd);
18316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
18429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("data read returned %d, errno: %d", ret, errno);
185916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
186916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
187916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
188916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
18916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
19016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
1913856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("received data:");
19216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.dump();
19316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        } else {
19416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.reset();
19516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
19616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
197916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (handleRequest()) {
198916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (!dataIn && mData.hasData()) {
199916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setOperationCode(operation);
200916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setTransactionID(transaction);
2013856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                ALOGV("sending data:");
20223d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood                mData.dump();
203916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                ret = mData.write(fd);
204916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (ret < 0) {
20529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("request write returned %d, errno: %d", ret, errno);
206916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    if (errno == ECANCELED) {
207916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        // return to top of loop and wait for next command
208916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        continue;
209916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    }
210916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    break;
211916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
212916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
21316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
214916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            mResponse.setTransactionID(transaction);
2153856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("sending response %04X", mResponse.getResponseCode());
216916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            ret = mResponse.write(fd);
21723d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood            mResponse.dump();
21816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
21929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("request write returned %d, errno: %d", ret, errno);
220916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
221916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
222916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
223916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
22416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
22516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
226916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        } else {
2273856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("skipping response\n");
22816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
22916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
2306b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
2317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // commit any open edits
2327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
2357d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        commitEdit(edit);
2367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        delete edit;
2377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2387d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.clear();
2397d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2406b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    if (mSessionOpen)
2416b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood        mDatabase->sessionEnded();
242dec7388c3edf09eaaccaaf57f6301e716319a34dMike Lockwood    close(fd);
243dec7388c3edf09eaaccaaf57f6301e716319a34dMike Lockwood    mFD = -1;
24416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
24516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
246873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
2473856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendObjectAdded %d\n", handle);
248a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
249873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
250873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
251873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
2523856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendObjectRemoved %d\n", handle);
253a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
254a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
255a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
256a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreAdded(MtpStorageID id) {
2573856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendStoreAdded %08X\n", id);
258a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_ADDED, id);
259a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
260a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
261a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreRemoved(MtpStorageID id) {
2623856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendStoreRemoved %08X\n", id);
263a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_REMOVED, id);
264a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
265a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
2660fa848d780cf990a2860637f40432d28594c85a3Mike Lockwoodvoid MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
2670fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood    ALOGV("sendDevicePropertyChanged %d\n", property);
2680fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood    sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
2690fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood}
2700fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood
271a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
27273ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
273a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setEventCode(code);
27473ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
275a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setParameter(1, param1);
27673ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
2773856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("mEvent.write returned %d\n", ret);
27873ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
279873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
280873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
2817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
2827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t size, MtpObjectFormat format, int fd) {
283c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    ObjectEdit*  edit = new ObjectEdit(handle, path, size, format, fd);
2847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.add(edit);
2857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
2887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
291c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) return edit;
2927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return NULL;
2947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::removeEditObject(MtpObjectHandle handle) {
2977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
300c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) {
3017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            delete edit;
3027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            mObjectEditList.removeAt(i);
3037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return;
3047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        }
3057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
30629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    ALOGE("ObjectEdit not found in removeEditObject");
3077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
3087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::commitEdit(ObjectEdit* edit) {
310c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
3117d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
3127d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
314916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
315a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
316a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
31716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
31816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
31916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
32016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
32116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
32429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("expected SendObject after SendObjectInfo");
32516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
32616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
328dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    int containertype = mRequest.getContainerType();
329dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
330dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        ALOGE("wrong container type %d", containertype);
331dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        return false;
332dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    }
333dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen
334dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
335dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen
33616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
33716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
33816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
33916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
34116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
34216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
34416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
34516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
34716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
34816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
35016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
35116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
35216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
35316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
35416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
35516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
35616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
35716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
358343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
359343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
360343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
361438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
362438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
363438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
364438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
365438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
366438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
36716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
36816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
36916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
3708277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
3718277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetObjectPropValue();
3728277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3738277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
3748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doGetDevicePropValue();
3758277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
3778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetDevicePropValue();
3788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
3808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doResetDevicePropValue();
3818277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
382b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_LIST:
383b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            response = doGetObjectPropList();
384b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            break;
38516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
38616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
38716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
39016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
39164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        case MTP_OPERATION_GET_THUMB:
39264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            response = doGetThumb();
39364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            break;
394d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT:
3957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
3967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doGetPartialObject(operation);
397d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            break;
39816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
39916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
40016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
40116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
40216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
40316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
40416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
40516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
40616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
40716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
40821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
40921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
410e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_DESC:
411e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            response = doGetDevicePropDesc();
412e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            break;
4137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_SEND_PARTIAL_OBJECT:
4147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doSendPartialObject();
4157d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4167d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_TRUNCATE_OBJECT:
4177d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doTruncateObject();
4187d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_BEGIN_EDIT_OBJECT:
4207d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doBeginEditObject();
4217d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4227d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_END_EDIT_OBJECT:
4237d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doEndEditObject();
4247d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
42516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
426dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ALOGE("got unsupported command %s (%x)",
427dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen                    MtpDebug::getOperationCodeName(operation), operation);
42816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
42916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
43016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
43116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
432916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
433916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
43416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
435916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
43616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
43716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
43816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
43916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
440c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
44116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
442782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
443782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
444782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
445782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
44616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
44716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4483d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    if (mPtp) {
4493d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mData.putUInt32(0);
4503d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    } else {
4513d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // MTP Vendor Extension ID
4523d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mData.putUInt32(6);
4533d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    }
45416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4553d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    if (mPtp) {
4563d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // no extensions
4573d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        string.set("");
4583d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    } else {
4593d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // MTP extensions
4603d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        string.set("microsoft.com: 1.0; android.com: 1.0;");
4613d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    }
46216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
46316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
46416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
46516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
466873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
467873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
468782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(deviceProperties); // Device Properties Supported
469782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(captureFormats); // Capture Formats
470782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(playbackFormats);  // Playback Formats
4718d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood
4728d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
4738d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    string.set(prop_value);
47416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
475c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
476c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
477c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
47816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
47916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
48016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
481c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
482c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
483c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
48416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
48516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
486782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete playbackFormats;
487782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete captureFormats;
488782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete deviceProperties;
489782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
49016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
49116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
49216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
49316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
49416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
49516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
49616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
49716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
49816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
49916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
5006b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
5016b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionStarted();
5026b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
50316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
50416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
50516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
50716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
50816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
50916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
51016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
5116b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionEnded();
51216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
51316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
51416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
51616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
51716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
51816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
52016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
52116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
52216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
52316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
52416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
52516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
52616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
52716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
52816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
52916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
53116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
53216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
53316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
53416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
53516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
53616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
53816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
53916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
54016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
54116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
54216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
54316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
54416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
54516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
54616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
54716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
54816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
54916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
55016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
55116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
55216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
55316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
5542e09e289b7e136481e9215bb61ed47cee5d9919bMike Lockwood    MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
555782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(properties);
556bf9b2052d207f8f2a23470f1c4dfe464f430f387Mike Lockwood    delete properties;
55716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
55816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
55916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
56016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
56116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
56216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
56316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
564e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
56516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
566dc3185e3e27b05e18c4ac34432a25a0c279ff351Mike Lockwood                                                            // 0x00000000 for all objects
567a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
568a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
569a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
57016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
57116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
57216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
57316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
57416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
57516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
57616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
577343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
578343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
579343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
580343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
581343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
582343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
583dc3185e3e27b05e18c4ac34432a25a0c279ff351Mike Lockwood                                                            // 0x00000000 for all objects
584a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
585a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
586343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
587343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
588343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
589343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
590343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
591343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
592343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
593343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
594343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
595343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
596343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
597438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
598438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
599438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
600a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
601a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
602a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6038277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6048277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    // FIXME - check for invalid object handle
605438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
6068277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (handles) {
6078277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        mData.putAUInt32(handles);
6088277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        delete handles;
6098277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    } else {
610438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
611438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
612438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
613438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
614438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
615438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
616438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
617438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
618a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
619a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
620438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
621a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
622438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
623438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
624438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
625438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
626438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
627438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
62816864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
629a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
630a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
63116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
63216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
6333856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetObjectPropValue %d %s\n", handle,
6348277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
63516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6368277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getObjectPropertyValue(handle, property, mData);
6378277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6388277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6398277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetObjectPropValue() {
640a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
641a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
6428277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6438277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
6443856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("SetObjectPropValue %d %s\n", handle,
6458277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
6468277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6478277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setObjectPropertyValue(handle, property, mData);
6488277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6498277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6508277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropValue() {
6518277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6523856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetDevicePropValue %s\n",
6538277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6548277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6558277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getDevicePropertyValue(property, mData);
6568277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6578277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6588277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetDevicePropValue() {
6598277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6603856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("SetDevicePropValue %s\n",
6618277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6628277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6638277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setDevicePropertyValue(property, mData);
6648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6668277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doResetDevicePropValue() {
6678277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6683856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("ResetDevicePropValue %s\n",
6698277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6708277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6718277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->resetDeviceProperty(property);
67216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
67316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
674b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropList() {
675a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
676a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
677b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
678b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
67940ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    // use uint32_t so we can support 0xFFFFFFFF
68040ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t format = mRequest.getParameter(2);
68140ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t property = mRequest.getParameter(3);
682b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    int groupCode = mRequest.getParameter(4);
683f05ff073495b0bb3e49859aee5b54d3e25088985Mike Lockwood    int depth = mRequest.getParameter(5);
6843856b090cd04ba5dd4a59a12430ed724d5995909Steve Block   ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
685b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            handle, MtpDebug::getFormatCodeName(format),
686b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            MtpDebug::getObjectPropCodeName(property), groupCode, depth);
687b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
688b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
689b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood}
690b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
69116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
692a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
693a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
69416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectInfo info(handle);
6967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
6977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
6987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        char    date[20];
6997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
7007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mStorageID);
7017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mFormat);
7027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mProtectionStatus);
7037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
7047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // if object is being edited the database size may be out of date
7057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint32_t size = info.mCompressedSize;
7067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = getEditObject(handle);
7077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (edit)
708c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood            size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
7097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(size);
7107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
7117d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mThumbFormat);
7127d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbCompressedSize);
7137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixWidth);
7147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixHeight);
7157d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixWidth);
7167d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixHeight);
7177d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixDepth);
7187d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mParent);
7197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mAssociationType);
7207d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mAssociationDesc);
7217d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mSequenceNumber);
7227d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(info.mName);
723ec24fa46443634cd29627182c5812ccf43682692Mike Lockwood        formatDateTime(info.mDateCreated, date, sizeof(date));
724ec24fa46443634cd29627182c5812ccf43682692Mike Lockwood        mData.putString(date);   // date created
7257d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        formatDateTime(info.mDateModified, date, sizeof(date));
7267d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(date);   // date modified
7277d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putEmptyString();   // keywords
7287d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
7297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return result;
73016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
73116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
733a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
734a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
73516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
736c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
73716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
738fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
739fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
7409c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
7419c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
74216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
7439c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
74416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
745c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
746c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
747c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
748c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
74916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
75016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
751ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.command = mRequest.getOperationCode();
752ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.transaction_id = mRequest.getTransactionID();
75316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
75416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
755ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
7563856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
757c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
758916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
759916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
760916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
761916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
762916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
763916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
76416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
76516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
76616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
76764000788211f4c7e78c80a4a155390d1316e1176Mike LockwoodMtpResponseCode MtpServer::doGetThumb() {
76864000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
76964000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    size_t thumbSize;
77064000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    void* thumb = mDatabase->getThumbnail(handle, thumbSize);
77164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    if (thumb) {
77264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        // send data
77364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setOperationCode(mRequest.getOperationCode());
77464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setTransactionID(mRequest.getTransactionID());
77564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.writeData(mFD, thumb, thumbSize);
77664000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        free(thumb);
77764000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_OK;
77864000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    } else {
77964000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
78064000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    }
78164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood}
78264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood
7837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
784a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
785a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
786d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
7877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset;
7887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length;
7897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = mRequest.getParameter(2);
7907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
7917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // android extension with 64 bit offset
7927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t offset2 = mRequest.getParameter(3);
7937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        offset = offset | (offset2 << 32);
7947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(4);
7957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
7967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // standard GetPartialObject
7977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(3);
7987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
799d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpString pathBuf;
800d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int64_t fileLength;
801fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
802fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
803d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (result != MTP_RESPONSE_OK)
804d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return result;
805d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (offset + length > fileLength)
806d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        length = fileLength - offset;
807d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
808d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    const char* filePath = (const char *)pathBuf;
809d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mtp_file_range  mfr;
810d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.fd = open(filePath, O_RDONLY);
811d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (mfr.fd < 0) {
812d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
813d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
814d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.offset = offset;
815d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.length = length;
816ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.command = mRequest.getOperationCode();
817ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.transaction_id = mRequest.getTransactionID();
818d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mResponse.setParameter(1, length);
819d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
820ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // transfer the file
821ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
8223856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
823d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    close(mfr.fd);
824d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (ret < 0) {
825d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        if (errno == ECANCELED)
826d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
827d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        else
828d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
829d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
830d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    return MTP_RESPONSE_OK;
831d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood}
832d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
83316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
83416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
83516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
83616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
83716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
83816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
83916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
84016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
84116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
8421865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
84316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
8441865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
8451865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
846fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int64_t length;
847fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpObjectFormat format;
848fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, length, format);
8499c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
8509c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
851fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        if (format != MTP_FORMAT_ASSOCIATION)
852fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
85316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
85416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
85516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
85616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // storage ID
85716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mData.getUInt16();
85816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // protection status
85916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSendObjectFileSize = mData.getUInt32();
86016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // thumb format
86116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb compressed size
86216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix width
86316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix height
86416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix width
86516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix height
86616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image bit depth
86716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // parent
86816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint16_t associationType = mData.getUInt16();
86916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint32_t associationDesc = mData.getUInt32();   // association desc
87016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // sequence number
87116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
87216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(name);    // file name
87316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(created);      // date created
87416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(modified);     // date modified
87516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
87616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
8773856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("name: %s format: %04X\n", (const char *)name, format);
878fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
87916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
88016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
88116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
88216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
88316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
88416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
88516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
88620c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    // check space first
88720c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    if (mSendObjectFileSize > storage->getFreeSpace())
88820c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood        return MTP_RESPONSE_STORAGE_FULL;
8899b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    uint64_t maxFileSize = storage->getMaxFileSize();
8909b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    // check storage max file size
8919b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    if (maxFileSize != 0) {
8929b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
8939b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        // is >= 0xFFFFFFFF
8949b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
8959b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood            return MTP_RESPONSE_OBJECT_TOO_LARGE;
8969b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    }
89720c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood
898b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
8994714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
9004714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
901fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
90216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
903fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
90416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
90516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
90616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
9078e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
90816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
90916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
91016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
9118e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
912aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood
913aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        // SendObject does not get sent for directories, so call endSendObject here instead
914aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
91516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
91616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
91716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
91816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
9194714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
92016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
92116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
92216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
9238277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    mResponse.setParameter(2, parent);
92416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
92516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
92616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
92716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
92816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
92916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
930a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
931a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
9324714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
9334714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
934ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret, initialData;
9354714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
93616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
93729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Expected SendObjectInfo before SendObject");
9384714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
9394714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
94016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
94116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
942ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // read the header, and possibly some data
943ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    ret = mData.read(mFD);
944ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (ret < MTP_CONTAINER_HEADER_SIZE) {
945ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
946ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        goto done;
947ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
948ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    initialData = ret - MTP_CONTAINER_HEADER_SIZE;
94916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
95016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
951af8e8aa1ada2948972555592570ec9ad90cbf372Nick Kralevich    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
952c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
9534714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
9544714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
955c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
9568e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
9578e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
9584714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
9598e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
9608e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
9618e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
962dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    if (initialData > 0) {
963ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        ret = write(mfr.fd, mData.getData(), initialData);
964dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    }
96516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
966dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    if (ret < 0) {
967dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        ALOGE("failed to write initial data");
968dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        result = MTP_RESPONSE_GENERAL_ERROR;
969dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    } else {
970dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        if (mSendObjectFileSize - initialData > 0) {
971dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mfr.offset = initialData;
972dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            if (mSendObjectFileSize == 0xFFFFFFFF) {
973dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen                // tell driver to read until it receives a short packet
974dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen                mfr.length = 0xFFFFFFFF;
975dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            } else {
976dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen                mfr.length = mSendObjectFileSize - initialData;
977dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            }
9788e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
979dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ALOGV("receiving %s\n", (const char *)mSendObjectFilePath);
980dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            // transfer the file
981dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
982dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ALOGV("MTP_RECEIVE_FILE returned %d\n", ret);
983dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        }
984ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
985ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    close(mfr.fd);
98616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
987916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
988916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
989916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
9904714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
991916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
9924714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
993916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
9944714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
9954714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
996ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // reset so we don't attempt to send the data back
997ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mData.reset();
998ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood
9994714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
1000aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood            result == MTP_RESPONSE_OK);
10014714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
10024714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
10034714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
100416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
100516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1006d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deleteRecursive(const char* path) {
1007d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char pathbuf[PATH_MAX];
1008d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathLength = strlen(path);
1009d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathLength >= sizeof(pathbuf) - 1) {
101029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("path too long: %s\n", path);
1011d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1012d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    strcpy(pathbuf, path);
1013d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathbuf[pathLength - 1] != '/') {
1014d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        pathbuf[pathLength++] = '/';
1015d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1016d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char* fileSpot = pathbuf + pathLength;
1017d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1018d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1019d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    DIR* dir = opendir(path);
1020d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (!dir) {
102129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("opendir %s failed: %s", path, strerror(errno));
1022d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        return;
1023d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1024d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1025d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct dirent* entry;
1026d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    while ((entry = readdir(dir))) {
1027d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        const char* name = entry->d_name;
1028d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1029d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        // ignore "." and ".."
1030d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1031d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
1032d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1033d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1034d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int nameLength = strlen(name);
1035d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (nameLength > pathRemaining) {
103629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("path %s/%s too long\n", path, name);
1037d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
1038d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1039d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        strcpy(fileSpot, name);
1040d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1041d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int type = entry->d_type;
1042d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (entry->d_type == DT_DIR) {
1043d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(pathbuf);
1044d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(pathbuf);
1045d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1046d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(pathbuf);
1047d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1048d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
10497ce05cf6009a2fbbceb3d2c0ff639473d0b7d6a9Mike Lockwood    closedir(dir);
1050d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1051d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1052d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deletePath(const char* path) {
1053d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct stat statbuf;
1054d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (stat(path, &statbuf) == 0) {
1055d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (S_ISDIR(statbuf.st_mode)) {
1056d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(path);
1057d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(path);
1058d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1059d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(path);
1060d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1061d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    } else {
106229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
1063d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1064d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1065d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
106616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
1067a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
1068a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
106916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
1070d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
107116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
107216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
107316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
107416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
107516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
1076fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
10779c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
10783856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("deleting %s", (const char *)filePath);
1079a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        result = mDatabase->deleteFile(handle);
1080a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        // Don't delete the actual files unless the database deletion is allowed
1081a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        if (result == MTP_RESPONSE_OK) {
1082a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood            deletePath((const char *)filePath);
1083a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        }
10849c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
1085a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood
1086a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood    return result;
108716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
108816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
108916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
109021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
109116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
10923856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
10938277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                                        MtpDebug::getFormatCodeName(format));
10948277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
109521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
109621ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
10978277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    property->write(mData);
10988277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
10998277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return MTP_RESPONSE_OK;
11008277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
110116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11028277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropDesc() {
11038277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty propCode = mRequest.getParameter(1);
11043856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
11058277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
11068277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (!property)
11078277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
110821ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
11098277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
111021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
111116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11127850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
11137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doSendPartialObject() {
11147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!hasStorage())
11157d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
11167d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11177d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
11187d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
11197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = offset | (offset2 << 32);
11207d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length = mRequest.getParameter(4);
11217d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11227d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11237d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
112429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doSendPartialObject");
11257d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11267d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11277d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11287d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // can't start writing past the end of the file
1129c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (offset > edit->mSize) {
1130b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("writing past end of object, offset: %lld, edit->mSize: %lld", offset, edit->mSize);
11317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1134ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    const char* filePath = (const char *)edit->mPath;
1135db43b34c3428e480f8c4c66e7e88f4001f37f91eMark Salyzyn    ALOGV("receiving partial %s %lld %" PRIu32 "\n", filePath, offset, length);
11367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1137ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // read the header, and possibly some data
1138ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = mData.read(mFD);
1139ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (ret < MTP_CONTAINER_HEADER_SIZE)
1140ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
1141ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
11427d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1143ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (initialData > 0) {
11440a694951c00f2135c8968fd2205f71899997a8adMike Lockwoood        ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
1145ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        offset += initialData;
1146ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        length -= initialData;
1147ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
11487d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1149dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    if (ret < 0) {
1150dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        ALOGE("failed to write initial data");
1151dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    } else {
1152dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        if (length > 0) {
1153dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mtp_file_range  mfr;
1154dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mfr.fd = edit->mFD;
1155dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mfr.offset = offset;
1156dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mfr.length = length;
1157dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen
1158dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            // transfer the file
1159dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
1160dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ALOGV("MTP_RECEIVE_FILE returned %d", ret);
1161dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        }
1162ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
11637d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (ret < 0) {
11647d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mResponse.setParameter(1, 0);
11657d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (errno == ECANCELED)
11667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
11677d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        else
11687d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
11697d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
1170ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood
1171ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // reset so we don't attempt to send this back
1172ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mData.reset();
11737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mResponse.setParameter(1, length);
11747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t end = offset + length;
1175c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (end > edit->mSize) {
1176c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = end;
11777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doTruncateObject() {
11827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
118529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doTruncateObject");
11867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
11907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
11917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset |= (offset2 << 32);
1192c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (ftruncate(edit->mFD, offset) != 0) {
11937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
1195c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = offset;
11967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_OK;
11977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doBeginEditObject() {
12017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
12027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (getEditObject(handle)) {
120329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object already open for edit in doBeginEditObject");
12047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
12057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpString path;
12087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int64_t fileLength;
12097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectFormat format;
12107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
12117d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result != MTP_RESPONSE_OK)
12127d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return result;
12137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int fd = open((const char *)path, O_RDWR | O_EXCL);
12157d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (fd < 0) {
121629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
12177d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
12187d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12207d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    addEditObject(handle, path, fileLength, format, fd);
12217d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
12227d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
12237d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12247d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doEndEditObject() {
12257d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
12267d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
12277d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
122829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doEndEditObject");
12297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
12307d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    commitEdit(edit);
12337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    removeEditObject(handle);
12347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
12357d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
12367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12377850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
1238