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);
21707a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            const int savedErrno = errno;
21823d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood            mResponse.dump();
21916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
22029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("request write returned %d, errno: %d", ret, errno);
22107a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei                if (savedErrno == ECANCELED) {
222916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
223916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
224916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
22516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
22616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
227916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        } else {
2283856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("skipping response\n");
22916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
23016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
2316b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
2327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // commit any open edits
2337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2357d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
2367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        commitEdit(edit);
2377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        delete edit;
2387d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2397d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.clear();
2407d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2416b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    if (mSessionOpen)
2426b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood        mDatabase->sessionEnded();
243dec7388c3edf09eaaccaaf57f6301e716319a34dMike Lockwood    close(fd);
244dec7388c3edf09eaaccaaf57f6301e716319a34dMike Lockwood    mFD = -1;
24516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
24616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
247873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
2483856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendObjectAdded %d\n", handle);
249a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
250873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
251873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
252873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
2533856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendObjectRemoved %d\n", handle);
254a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
255a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
256a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
257a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreAdded(MtpStorageID id) {
2583856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendStoreAdded %08X\n", id);
259a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_ADDED, id);
260a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
261a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
262a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreRemoved(MtpStorageID id) {
2633856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendStoreRemoved %08X\n", id);
264a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_REMOVED, id);
265a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
266a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
2670fa848d780cf990a2860637f40432d28594c85a3Mike Lockwoodvoid MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
2680fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood    ALOGV("sendDevicePropertyChanged %d\n", property);
2690fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood    sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
2700fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood}
2710fa848d780cf990a2860637f40432d28594c85a3Mike Lockwood
272a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
27373ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
274a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setEventCode(code);
27573ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
276a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setParameter(1, param1);
27773ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
2783856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("mEvent.write returned %d\n", ret);
27973ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
280873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
281873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
2827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
2837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t size, MtpObjectFormat format, int fd) {
284c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    ObjectEdit*  edit = new ObjectEdit(handle, path, size, format, fd);
2857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.add(edit);
2867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
2897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
292c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) return edit;
2937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return NULL;
2957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::removeEditObject(MtpObjectHandle handle) {
2987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
3007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
301c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) {
3027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            delete edit;
3037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            mObjectEditList.removeAt(i);
3047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return;
3057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        }
3067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
30729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    ALOGE("ObjectEdit not found in removeEditObject");
3087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
3097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::commitEdit(ObjectEdit* edit) {
311c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
3127d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
3137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
315916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
316a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
317a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
31816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
31916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
32016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
32116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
32416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
32529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("expected SendObject after SendObjectInfo");
32616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
32816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
329dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    int containertype = mRequest.getContainerType();
330dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    if (containertype != MTP_CONTAINER_TYPE_COMMAND) {
331dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        ALOGE("wrong container type %d", containertype);
332dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        return false;
333dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    }
334dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen
335dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    ALOGV("got command %s (%x)", MtpDebug::getOperationCodeName(operation), operation);
336dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen
33716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
33816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
33916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
34016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
34216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
34316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
34516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
34616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
34816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
34916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
35016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
35116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
35216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
35316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
35416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
35516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
35616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
35716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
35816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
359343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
360343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
361343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
362438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
363438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
364438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
365438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
366438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
367438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
36816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
36916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
37016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
3718277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
3728277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetObjectPropValue();
3738277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
3758277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doGetDevicePropValue();
3768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
3788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetDevicePropValue();
3798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
3818277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doResetDevicePropValue();
3828277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
383b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_LIST:
384b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            response = doGetObjectPropList();
385b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            break;
38616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
38716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
38816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
39016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
39116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
39264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        case MTP_OPERATION_GET_THUMB:
39364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            response = doGetThumb();
39464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            break;
395d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT:
3967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
3977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doGetPartialObject(operation);
398d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            break;
39916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
40016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
40116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
40216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
40316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
40416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
40516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
40616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
40716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
40816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
40921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
41021ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
411e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_DESC:
412e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            response = doGetDevicePropDesc();
413e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            break;
4147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_SEND_PARTIAL_OBJECT:
4157d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doSendPartialObject();
4167d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4177d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_TRUNCATE_OBJECT:
4187d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doTruncateObject();
4197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4207d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_BEGIN_EDIT_OBJECT:
4217d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doBeginEditObject();
4227d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4237d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_END_EDIT_OBJECT:
4247d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doEndEditObject();
4257d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
42616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
427dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ALOGE("got unsupported command %s (%x)",
428dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen                    MtpDebug::getOperationCodeName(operation), operation);
42916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
43016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
43116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
43216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
433916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
434916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
43516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
436916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
43716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
43816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
43916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
44016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
441c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
44216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
443782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
444782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
445782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
446782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
44716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
44816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4493d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    if (mPtp) {
4503d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mData.putUInt32(0);
4513d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    } else {
4523d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // MTP Vendor Extension ID
4533d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mData.putUInt32(6);
4543d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    }
45516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4563d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    if (mPtp) {
4573d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // no extensions
4583d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        string.set("");
4593d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    } else {
4603d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // MTP extensions
4613d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        string.set("microsoft.com: 1.0; android.com: 1.0;");
4623d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    }
46316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
46416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
46516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
46616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
467873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
468873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
469782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(deviceProperties); // Device Properties Supported
470782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(captureFormats); // Capture Formats
471782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(playbackFormats);  // Playback Formats
4728d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood
4738d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
4748d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    string.set(prop_value);
47516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
476c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
477c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
478c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
47916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
48016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
48116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
482c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
483c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
484c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
48516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
48616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
487782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete playbackFormats;
488782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete captureFormats;
489782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete deviceProperties;
490782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
49116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
49216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
49316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
49416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
49516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
49616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
49716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
49816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
499ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
500ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
501ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood
50216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
50316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
5046b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
5056b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionStarted();
5066b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
50716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
50816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
50916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
51116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
51216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
51316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
51416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
5156b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionEnded();
51616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
51716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
51816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
52016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
52116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
52216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
52316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
52416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
52516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
52616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
52716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
52816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
52916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
53016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
53216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
53316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
53516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
536ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
537ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
538ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood
53916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
54016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
54116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
54216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
54316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
54416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
54516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
54616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
54716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
54816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
54916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
55016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
55116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
55216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
55316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
55416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
55516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
55616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
55716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
55816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
55916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
560ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
561ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
56216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
5632e09e289b7e136481e9215bb61ed47cee5d9919bMike Lockwood    MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
564782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(properties);
565bf9b2052d207f8f2a23470f1c4dfe464f430f387Mike Lockwood    delete properties;
56616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
56716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
56816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
56916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
57016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
57116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
572ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 3)
573ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
57416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
575e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
57616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
577dc3185e3e27b05e18c4ac34432a25a0c279ff351Mike Lockwood                                                            // 0x00000000 for all objects
578a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
579a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
580a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
58116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
58216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
58316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
58416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
58516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
58616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
58716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
588343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
589343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
590343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
591ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 3)
592ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
593343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
594343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
595343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
596dc3185e3e27b05e18c4ac34432a25a0c279ff351Mike Lockwood                                                            // 0x00000000 for all objects
597a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
598a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
599343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
600343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
601343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
602343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
603343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
604343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
605343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
606343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
607343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
608343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
609343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
610438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
611438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
612438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
613a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
614a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
615ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
616ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
617a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6188277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6198277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    // FIXME - check for invalid object handle
620438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
6218277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (handles) {
6228277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        mData.putAUInt32(handles);
6238277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        delete handles;
6248277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    } else {
625438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
626438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
627438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
628438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
629438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
630438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
631438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
632438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
633a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
634a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
635ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
636ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
637438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
638a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
639438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
640ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!references)
641ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
642438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
643438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
644438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
645438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
646438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
64716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
648a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
649a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
650ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 2)
651ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
65216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
65316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
6543856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetObjectPropValue %d %s\n", handle,
6558277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
65616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6578277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getObjectPropertyValue(handle, property, mData);
6588277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6598277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6608277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetObjectPropValue() {
661a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
662a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
663ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 2)
664ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
6658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
6673856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("SetObjectPropValue %d %s\n", handle,
6688277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
6698277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6708277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setObjectPropertyValue(handle, property, mData);
6718277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6728277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6738277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropValue() {
674ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
675ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
6768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6773856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetDevicePropValue %s\n",
6788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6798277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getDevicePropertyValue(property, mData);
6818277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6828277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6838277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetDevicePropValue() {
684ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
685ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
6868277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6873856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("SetDevicePropValue %s\n",
6888277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6898277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6908277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setDevicePropertyValue(property, mData);
6918277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6928277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6938277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doResetDevicePropValue() {
694ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
695ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
6968277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6973856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("ResetDevicePropValue %s\n",
6988277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6998277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
7008277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->resetDeviceProperty(property);
70116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
70216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
703b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropList() {
704a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
705a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
706ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 5)
707ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
708b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
709b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
71040ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    // use uint32_t so we can support 0xFFFFFFFF
71140ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t format = mRequest.getParameter(2);
71240ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t property = mRequest.getParameter(3);
713b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    int groupCode = mRequest.getParameter(4);
714f05ff073495b0bb3e49859aee5b54d3e25088985Mike Lockwood    int depth = mRequest.getParameter(5);
7153856b090cd04ba5dd4a59a12430ed724d5995909Steve Block   ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
716b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            handle, MtpDebug::getFormatCodeName(format),
717b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            MtpDebug::getObjectPropCodeName(property), groupCode, depth);
718b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
719b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
720b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood}
721b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
72216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
723a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
724a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
725ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
726ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
72716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
7287d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectInfo info(handle);
7297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
7307d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
7317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        char    date[20];
7327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
7337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mStorageID);
7347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mFormat);
7357d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mProtectionStatus);
7367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
7377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // if object is being edited the database size may be out of date
7387d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint32_t size = info.mCompressedSize;
7397d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = getEditObject(handle);
7407d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (edit)
741c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood            size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
7427d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(size);
7437d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
7447d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mThumbFormat);
7457d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbCompressedSize);
7467d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixWidth);
7477d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixHeight);
7487d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixWidth);
7497d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixHeight);
7507d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixDepth);
7517d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mParent);
7527d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mAssociationType);
7537d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mAssociationDesc);
7547d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mSequenceNumber);
7557d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(info.mName);
756ec24fa46443634cd29627182c5812ccf43682692Mike Lockwood        formatDateTime(info.mDateCreated, date, sizeof(date));
757ec24fa46443634cd29627182c5812ccf43682692Mike Lockwood        mData.putString(date);   // date created
7587d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        formatDateTime(info.mDateModified, date, sizeof(date));
7597d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(date);   // date modified
7607d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putEmptyString();   // keywords
7617d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
7627d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return result;
76316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
76416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
76516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
766a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
767a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
768ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
769ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
77016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
771c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
77216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
773fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
774fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
7759c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
7769c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
77716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
7789c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
77916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
780c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
781c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
782c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
783c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
78416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
78516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
786ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.command = mRequest.getOperationCode();
787ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.transaction_id = mRequest.getTransactionID();
78816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
78916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
790ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
791916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
79207a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei        if (errno == ECANCELED) {
79307a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
79407a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei        } else {
79507a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            result = MTP_RESPONSE_GENERAL_ERROR;
79607a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei        }
79707a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    } else {
79807a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei        result = MTP_RESPONSE_OK;
799916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
80007a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei
80107a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
80207a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    close(mfr.fd);
80307a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    return result;
80416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
80516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
80664000788211f4c7e78c80a4a155390d1316e1176Mike LockwoodMtpResponseCode MtpServer::doGetThumb() {
807ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
808ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
80964000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
81064000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    size_t thumbSize;
81164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    void* thumb = mDatabase->getThumbnail(handle, thumbSize);
81264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    if (thumb) {
81364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        // send data
81464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setOperationCode(mRequest.getOperationCode());
81564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setTransactionID(mRequest.getTransactionID());
81664000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.writeData(mFD, thumb, thumbSize);
81764000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        free(thumb);
81864000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_OK;
81964000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    } else {
82064000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
82164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    }
82264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood}
82364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood
8247d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
825a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
826a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
827d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
8287d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset;
8297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length;
8307d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = mRequest.getParameter(2);
8317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
832e48cf5b8f823c30af93577c1e380d752ac69b871Mike Lockwood        // MTP_OPERATION_GET_PARTIAL_OBJECT_64 takes 4 arguments
833e48cf5b8f823c30af93577c1e380d752ac69b871Mike Lockwood        if (mRequest.getParameterCount() < 4)
834e48cf5b8f823c30af93577c1e380d752ac69b871Mike Lockwood            return MTP_RESPONSE_INVALID_PARAMETER;
835e48cf5b8f823c30af93577c1e380d752ac69b871Mike Lockwood
8367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // android extension with 64 bit offset
8377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t offset2 = mRequest.getParameter(3);
8387d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        offset = offset | (offset2 << 32);
8397d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(4);
8407d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
841e48cf5b8f823c30af93577c1e380d752ac69b871Mike Lockwood        // MTP_OPERATION_GET_PARTIAL_OBJECT takes 3 arguments
842e48cf5b8f823c30af93577c1e380d752ac69b871Mike Lockwood        if (mRequest.getParameterCount() < 3)
843e48cf5b8f823c30af93577c1e380d752ac69b871Mike Lockwood            return MTP_RESPONSE_INVALID_PARAMETER;
844e48cf5b8f823c30af93577c1e380d752ac69b871Mike Lockwood
8457d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // standard GetPartialObject
8467d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(3);
8477d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
848d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpString pathBuf;
849d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int64_t fileLength;
850fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
851fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
852d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (result != MTP_RESPONSE_OK)
853d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return result;
854d239cb6e6898bdf2300e9038111727a9056c58eeMark Salyzyn    if (offset + length > (uint64_t)fileLength)
855d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        length = fileLength - offset;
856d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
857d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    const char* filePath = (const char *)pathBuf;
858d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mtp_file_range  mfr;
859d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.fd = open(filePath, O_RDONLY);
860d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (mfr.fd < 0) {
861d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
862d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
863d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.offset = offset;
864d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.length = length;
865ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.command = mRequest.getOperationCode();
866ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.transaction_id = mRequest.getTransactionID();
867d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mResponse.setParameter(1, length);
868d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
869ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // transfer the file
870ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
8713856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
87207a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    result = MTP_RESPONSE_OK;
873d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (ret < 0) {
874d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        if (errno == ECANCELED)
87507a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
876d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        else
87707a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            result = MTP_RESPONSE_GENERAL_ERROR;
878d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
87907a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    close(mfr.fd);
88007a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    return result;
881d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood}
882d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
88316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
88416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
885ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    uint16_t temp16;
886ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    uint32_t temp32;
887ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood
888ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 2)
889ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
89016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
89116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
89216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
89316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
89416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
89516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
89616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
8971865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
89816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
8991865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
9001865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
901fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int64_t length;
902fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpObjectFormat format;
903fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, length, format);
9049c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
9059c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
906fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        if (format != MTP_FORMAT_ASSOCIATION)
907fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
90816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
90916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
911ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // storage ID
912ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
913ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    MtpObjectFormat format = temp16;
914ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;  // protection status
915ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
916ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    mSendObjectFileSize = temp32;
917ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb format
918ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb compressed size
919ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb pix width
920ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb pix height
921ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image pix width
922ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image pix height
923ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image bit depth
924ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // parent
925ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
926ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
927ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // sequence number
92816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
929ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER;    // file name
9307ea72dcdeb8efc90701bfcc1f439e591e8938d4cMarco Nelissen    if (name.getCharCount() == 0) {
9317ea72dcdeb8efc90701bfcc1f439e591e8938d4cMarco Nelissen        ALOGE("empty name");
9327ea72dcdeb8efc90701bfcc1f439e591e8938d4cMarco Nelissen        return MTP_RESPONSE_INVALID_PARAMETER;
9337ea72dcdeb8efc90701bfcc1f439e591e8938d4cMarco Nelissen    }
934ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER;      // date created
935ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER;     // date modified
93616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
93716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
9383856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("name: %s format: %04X\n", (const char *)name, format);
939fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
94016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
94116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
94216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
94316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
94416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
94516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
94616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
94720c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    // check space first
94820c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    if (mSendObjectFileSize > storage->getFreeSpace())
94920c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood        return MTP_RESPONSE_STORAGE_FULL;
9509b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    uint64_t maxFileSize = storage->getMaxFileSize();
9519b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    // check storage max file size
9529b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    if (maxFileSize != 0) {
9539b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
9549b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        // is >= 0xFFFFFFFF
9559b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
9569b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood            return MTP_RESPONSE_OBJECT_TOO_LARGE;
9579b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    }
95820c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood
959b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
9604714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
9614714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
962fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
96316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
964fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
96516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
96616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
96716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
9688e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
96916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
97016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
97116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
9728e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
973aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood
974aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        // SendObject does not get sent for directories, so call endSendObject here instead
975aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
97616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
97716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
97816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
97916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
9804714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
98116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
98216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
98316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
9848277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    mResponse.setParameter(2, parent);
98516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
98616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
98716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
98816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
98916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
99016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
991a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
992a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
9934714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
9944714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
995ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret, initialData;
99607a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    bool isCanceled = false;
9974714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
99816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
99929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Expected SendObjectInfo before SendObject");
10004714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
10014714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
100216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
100316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1004ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // read the header, and possibly some data
1005ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    ret = mData.read(mFD);
1006ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (ret < MTP_CONTAINER_HEADER_SIZE) {
1007ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
1008ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        goto done;
1009ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
1010ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    initialData = ret - MTP_CONTAINER_HEADER_SIZE;
101116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
101216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
1013af8e8aa1ada2948972555592570ec9ad90cbf372Nick Kralevich    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
1014c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
10154714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
10164714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
1017c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
10188e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
10198e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
10204714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
10218e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
10228e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
10238e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
1024dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    if (initialData > 0) {
1025ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        ret = write(mfr.fd, mData.getData(), initialData);
1026dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    }
102716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1028dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    if (ret < 0) {
1029dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        ALOGE("failed to write initial data");
1030dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        result = MTP_RESPONSE_GENERAL_ERROR;
1031dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    } else {
1032dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        if (mSendObjectFileSize - initialData > 0) {
1033dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mfr.offset = initialData;
1034dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            if (mSendObjectFileSize == 0xFFFFFFFF) {
1035dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen                // tell driver to read until it receives a short packet
1036dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen                mfr.length = 0xFFFFFFFF;
1037dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            } else {
1038dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen                mfr.length = mSendObjectFileSize - initialData;
1039dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            }
10408e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
1041dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ALOGV("receiving %s\n", (const char *)mSendObjectFilePath);
1042dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            // transfer the file
1043dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
104407a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            if ((ret < 0) && (errno == ECANCELED)) {
104507a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei                isCanceled = true;
104607a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            }
104707a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei
1048dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ALOGV("MTP_RECEIVE_FILE returned %d\n", ret);
1049dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        }
1050ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
1051ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    close(mfr.fd);
105216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1053916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
1054916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
105507a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei        if (isCanceled)
10564714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
1057916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
10584714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
1059916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
10604714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
10614714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
1062ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // reset so we don't attempt to send the data back
1063ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mData.reset();
1064ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood
10654714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
1066aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood            result == MTP_RESPONSE_OK);
10674714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
10684714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
10694714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
107016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
107116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1072d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deleteRecursive(const char* path) {
1073d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char pathbuf[PATH_MAX];
1074d239cb6e6898bdf2300e9038111727a9056c58eeMark Salyzyn    size_t pathLength = strlen(path);
1075d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathLength >= sizeof(pathbuf) - 1) {
107629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("path too long: %s\n", path);
1077d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1078d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    strcpy(pathbuf, path);
1079d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathbuf[pathLength - 1] != '/') {
1080d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        pathbuf[pathLength++] = '/';
1081d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1082d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char* fileSpot = pathbuf + pathLength;
1083d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
1084d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1085d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    DIR* dir = opendir(path);
1086d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (!dir) {
108729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("opendir %s failed: %s", path, strerror(errno));
1088d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        return;
1089d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1090d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1091d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct dirent* entry;
1092d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    while ((entry = readdir(dir))) {
1093d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        const char* name = entry->d_name;
1094d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1095d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        // ignore "." and ".."
1096d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1097d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
1098d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1099d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1100d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int nameLength = strlen(name);
1101d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (nameLength > pathRemaining) {
110229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("path %s/%s too long\n", path, name);
1103d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
1104d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1105d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        strcpy(fileSpot, name);
1106d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1107d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (entry->d_type == DT_DIR) {
1108d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(pathbuf);
1109d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(pathbuf);
1110d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1111d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(pathbuf);
1112d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1113d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
11147ce05cf6009a2fbbceb3d2c0ff639473d0b7d6a9Mike Lockwood    closedir(dir);
1115d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1116d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1117d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deletePath(const char* path) {
1118d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct stat statbuf;
1119d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (stat(path, &statbuf) == 0) {
1120d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (S_ISDIR(statbuf.st_mode)) {
1121d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(path);
1122d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(path);
1123d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1124d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(path);
1125d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1126d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    } else {
112729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
1128d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1129d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1130d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
113116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
1132a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
1133a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
1134ea9f215a13f1a5e6455be91624a81a024641a26dMarco Nelissen    if (mRequest.getParameterCount() < 1)
1135ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
113616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
1137ea9f215a13f1a5e6455be91624a81a024641a26dMarco Nelissen    MtpObjectFormat format;
113816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
113916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
114016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
114116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
114216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
1143fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
11449c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
11453856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("deleting %s", (const char *)filePath);
1146a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        result = mDatabase->deleteFile(handle);
1147a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        // Don't delete the actual files unless the database deletion is allowed
1148a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        if (result == MTP_RESPONSE_OK) {
1149a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood            deletePath((const char *)filePath);
1150a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        }
11519c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
1152a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood
1153a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood    return result;
115416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
115516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
115616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
1157ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 2)
1158ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
115921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
116016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
11613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
11628277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                                        MtpDebug::getFormatCodeName(format));
11638277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
116421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
116521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
11668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    property->write(mData);
11678277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
11688277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return MTP_RESPONSE_OK;
11698277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
117016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11718277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropDesc() {
1172ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
1173ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
11748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty propCode = mRequest.getParameter(1);
11753856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
11768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
11778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (!property)
11788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
117921ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
11808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
118121ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
118216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11837850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
11847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doSendPartialObject() {
11857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!hasStorage())
11867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
1187ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 4)
1188ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
11897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
11917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
11927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = offset | (offset2 << 32);
11937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length = mRequest.getParameter(4);
11947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
119729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doSendPartialObject");
11987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // can't start writing past the end of the file
1202c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (offset > edit->mSize) {
1203d239cb6e6898bdf2300e9038111727a9056c58eeMark Salyzyn        ALOGD("writing past end of object, offset: %" PRIu64 ", edit->mSize: %" PRIu64,
1204d239cb6e6898bdf2300e9038111727a9056c58eeMark Salyzyn            offset, edit->mSize);
12057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
12067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1208ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    const char* filePath = (const char *)edit->mPath;
1209d239cb6e6898bdf2300e9038111727a9056c58eeMark Salyzyn    ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
12107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1211ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // read the header, and possibly some data
1212ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = mData.read(mFD);
1213ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (ret < MTP_CONTAINER_HEADER_SIZE)
1214ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
1215ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
12167d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1217ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (initialData > 0) {
12180a694951c00f2135c8968fd2205f71899997a8adMike Lockwoood        ret = pwrite(edit->mFD, mData.getData(), initialData, offset);
1219ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        offset += initialData;
1220ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        length -= initialData;
1221ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
12227d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
122307a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei    bool isCanceled = false;
1224dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    if (ret < 0) {
1225dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        ALOGE("failed to write initial data");
1226dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen    } else {
1227dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        if (length > 0) {
1228dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mtp_file_range  mfr;
1229dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mfr.fd = edit->mFD;
1230dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mfr.offset = offset;
1231dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            mfr.length = length;
1232dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen
1233dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            // transfer the file
1234dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
123507a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            if ((ret < 0) && (errno == ECANCELED)) {
123607a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei                isCanceled = true;
123707a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei            }
1238dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen            ALOGV("MTP_RECEIVE_FILE returned %d", ret);
1239dcd89ecad321e2e052322fe2b1907d50d762b311Marco Nelissen        }
1240ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
12417d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (ret < 0) {
12427d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mResponse.setParameter(1, 0);
124307a9e548af0ed26d7354f3defaa8f18b2c5125f1tao.pei        if (isCanceled)
12447d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
12457d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        else
12467d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
12477d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
1248ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood
1249ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // reset so we don't attempt to send this back
1250ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mData.reset();
12517d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mResponse.setParameter(1, length);
12527d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t end = offset + length;
1253c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (end > edit->mSize) {
1254c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = end;
12557d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12567d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
12577d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
12587d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12597d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doTruncateObject() {
1260ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 3)
1261ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
12627d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
12637d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
12647d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
126529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doTruncateObject");
12667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
12677d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12687d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12697d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
12707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
12717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset |= (offset2 << 32);
1272c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (ftruncate(edit->mFD, offset) != 0) {
12737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
12747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
1275c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = offset;
12767d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_OK;
12777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
12797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doBeginEditObject() {
1281ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
1282ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
12837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
12847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (getEditObject(handle)) {
128529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object already open for edit in doBeginEditObject");
12867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
12877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpString path;
12907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int64_t fileLength;
12917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectFormat format;
12927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
12937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result != MTP_RESPONSE_OK)
12947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return result;
12957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int fd = open((const char *)path, O_RDWR | O_EXCL);
12977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (fd < 0) {
129829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
12997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
13007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
13017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
13027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    addEditObject(handle, path, fileLength, format, fd);
13037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
13047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
13057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
13067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doEndEditObject() {
1307ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood    if (mRequest.getParameterCount() < 1)
1308ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        return MTP_RESPONSE_INVALID_PARAMETER;
13097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
13107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
13117d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
131229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doEndEditObject");
13137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
13147d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
13157d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
13167d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    commitEdit(edit);
13177d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    removeEditObject(handle);
13187d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
13197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
13207d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
13217850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
1322