116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood/*
216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * you may not use this file except in compliance with the License.
616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * You may obtain a copy of the License at
716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
1016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Unless required by applicable law or agreed to in writing, software
1116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
1216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * See the License for the specific language governing permissions and
1416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * limitations under the License.
1516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood */
1616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <stdio.h>
1816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <stdlib.h>
1916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <sys/types.h>
2016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <sys/ioctl.h>
2116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <sys/stat.h>
2216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <fcntl.h>
2316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <errno.h>
24d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood#include <sys/stat.h>
25d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood#include <dirent.h>
2616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
27c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood#include <cutils/properties.h>
28c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
29a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood#define LOG_TAG "MtpServer"
30a881b44cc7e18bdfa03251bc65b7d0903a1b1efcMike Lockwood
3116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpDebug.h"
327f53a190463274096155704276f3002c1620a364Mike Lockwood#include "MtpDatabase.h"
337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood#include "MtpObjectInfo.h"
3421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood#include "MtpProperty.h"
3516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpServer.h"
3616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStorage.h"
3716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpStringBuffer.h"
3816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
398065e2056073808716db32136d7acfd50eeab924Mike Lockwood#include <linux/usb/f_mtp.h>
4016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
417850ef999740f214a1990a9c090d3f3865d435aaMike Lockwoodnamespace android {
427850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
4316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic const MtpOperationCode kSupportedOperationCodes[] = {
4416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_DEVICE_INFO,
4516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_OPEN_SESSION,
4616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_CLOSE_SESSION,
4716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_IDS,
4816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_STORAGE_INFO,
4916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_NUM_OBJECTS,
5016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_HANDLES,
5116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_INFO,
5216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT,
5364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    MTP_OPERATION_GET_THUMB,
5416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_DELETE_OBJECT,
5516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT_INFO,
5616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_SEND_OBJECT,
5716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_CAPTURE,
5816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_FORMAT_STORE,
5916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_RESET_DEVICE,
6016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SELF_TEST,
6116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROTECTION,
6216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_POWER_DOWN,
63e3e76c456baee122de6715ae280130abaddc906cMike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_DESC,
648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_DEVICE_PROP_VALUE,
658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_SET_DEVICE_PROP_VALUE,
668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
6716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
6816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_MOVE_OBJECT,
6916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_COPY_OBJECT,
70d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MTP_OPERATION_GET_PARTIAL_OBJECT,
7116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_INITIATE_OPEN_CAPTURE,
7216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
738277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_DESC,
74677f5700c5ea35256079ef14e06b7382e438d860Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_VALUE,
75677f5700c5ea35256079ef14e06b7382e438d860Mike Lockwood    MTP_OPERATION_SET_OBJECT_PROP_VALUE,
76b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MTP_OPERATION_GET_OBJECT_PROP_LIST,
77b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_SET_OBJECT_PROP_LIST,
78b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
79b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood//    MTP_OPERATION_SEND_OBJECT_PROP_LIST,
80438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_GET_OBJECT_REFERENCES,
81438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MTP_OPERATION_SET_OBJECT_REFERENCES,
8216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood//    MTP_OPERATION_SKIP,
837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // Android extension for direct file IO
847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_GET_PARTIAL_OBJECT_64,
857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_SEND_PARTIAL_OBJECT,
867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_TRUNCATE_OBJECT,
877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_BEGIN_EDIT_OBJECT,
887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MTP_OPERATION_END_EDIT_OBJECT,
8916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood};
9016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodstatic const MtpEventCode kSupportedEventCodes[] = {
92873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_ADDED,
93873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    MTP_EVENT_OBJECT_REMOVED,
94a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MTP_EVENT_STORE_ADDED,
95a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MTP_EVENT_STORE_REMOVED,
96873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood};
97873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
983d1d7767afc7c488197ec40a22739159c5110721Mike LockwoodMtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
998e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood                    int fileGroup, int filePerm, int directoryPerm)
10016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    :   mFD(fd),
1011865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        mDatabase(database),
1023d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mPtp(ptp),
1038e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFileGroup(fileGroup),
1048e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mFilePermission(filePerm),
1058e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        mDirectoryPermission(directoryPerm),
10616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionID(0),
10716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSessionOpen(false),
10816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle(kInvalidObjectHandle),
1094714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat(0),
11016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFileSize(0)
11116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
11216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
11416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpServer::~MtpServer() {
11516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
11616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
117a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::addStorage(MtpStorage* storage) {
118a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
119a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
120a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    mStorages.push(storage);
121a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendStoreAdded(storage->getStorageID());
122a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
123a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
124a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::removeStorage(MtpStorage* storage) {
125a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
126a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
127a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
128a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        if (mStorages[i] == storage) {
129a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            mStorages.removeAt(i);
130a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            sendStoreRemoved(storage->getStorageID());
131a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood            break;
132a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        }
133a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    }
13416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
13516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpStorage* MtpServer::getStorage(MtpStorageID id) {
137fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    if (id == 0)
138fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        return mStorages[0];
13916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < mStorages.size(); i++) {
140fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpStorage* storage = mStorages[i];
14116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (storage->getStorageID() == id)
14216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return storage;
14316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
14416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return NULL;
14516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
14616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
147a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodbool MtpServer::hasStorage(MtpStorageID id) {
148a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (id == 0 || id == 0xFFFFFFFF)
149a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return mStorages.size() > 0;
150a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    return (getStorage(id) != NULL);
151a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
152a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
15316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid MtpServer::run() {
15416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int fd = mFD;
15516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1563856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("MtpServer::run fd: %d\n", fd);
15716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
15816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    while (1) {
15916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        int ret = mRequest.read(fd);
16016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret < 0) {
1613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("request read returned %d, errno: %d", ret, errno);
162916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (errno == ECANCELED) {
163916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                // return to top of loop and wait for next command
164916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                continue;
165916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
16616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
16716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
16816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpOperationCode operation = mRequest.getOperationCode();
16916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        MtpTransactionID transaction = mRequest.getTransactionID();
17016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
1713856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
17216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mRequest.dump();
17316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
17416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME need to generalize this
175438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
1768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
1778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
1788277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                    || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
17916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (dataIn) {
18016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            int ret = mData.read(fd);
18116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
18229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("data read returned %d, errno: %d", ret, errno);
183916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
184916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
185916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
186916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
18716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
18816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
1893856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("received data:");
19016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.dump();
19116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        } else {
19216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            mData.reset();
19316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
19416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
195916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (handleRequest()) {
196916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            if (!dataIn && mData.hasData()) {
197916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setOperationCode(operation);
198916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                mData.setTransactionID(transaction);
1993856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                ALOGV("sending data:");
20023d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood                mData.dump();
201916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                ret = mData.write(fd);
202916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (ret < 0) {
20329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("request write returned %d, errno: %d", ret, errno);
204916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    if (errno == ECANCELED) {
205916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        // return to top of loop and wait for next command
206916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                        continue;
207916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    }
208916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    break;
209916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
210916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            }
21116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
212916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            mResponse.setTransactionID(transaction);
2133856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("sending response %04X", mResponse.getResponseCode());
214916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            ret = mResponse.write(fd);
21523d2071ab44d7b5e3b16e8a81e11884faf01092fMike Lockwood            mResponse.dump();
21616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            if (ret < 0) {
21729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("request write returned %d, errno: %d", ret, errno);
218916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                if (errno == ECANCELED) {
219916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    // return to top of loop and wait for next command
220916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                    continue;
221916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood                }
22216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood                break;
22316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            }
224916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        } else {
2253856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("skipping response\n");
22616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        }
22716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
2286b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
2297d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // commit any open edits
2307d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2317d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2327d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
2337d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        commitEdit(edit);
2347d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        delete edit;
2357d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.clear();
2377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2386b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    if (mSessionOpen)
2396b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood        mDatabase->sessionEnded();
240dec7388c3edf09eaaccaaf57f6301e716319a34dMike Lockwood    close(fd);
241dec7388c3edf09eaaccaaf57f6301e716319a34dMike Lockwood    mFD = -1;
24216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
24316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
244873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectAdded(MtpObjectHandle handle) {
2453856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendObjectAdded %d\n", handle);
246a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
247873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
248873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
249873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwoodvoid MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
2503856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendObjectRemoved %d\n", handle);
251a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
252a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
253a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
254a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreAdded(MtpStorageID id) {
2553856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendStoreAdded %08X\n", id);
256a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_ADDED, id);
257a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
258a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
259a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendStoreRemoved(MtpStorageID id) {
2603856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendStoreRemoved %08X\n", id);
261a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    sendEvent(MTP_EVENT_STORE_REMOVED, id);
262a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood}
263a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
264a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwoodvoid MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
26573ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    if (mSessionOpen) {
266a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setEventCode(code);
26773ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        mEvent.setTransactionID(mRequest.getTransactionID());
268a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        mEvent.setParameter(1, param1);
26973ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood        int ret = mEvent.write(mFD);
2703856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("mEvent.write returned %d\n", ret);
27173ecd23cc2ebadb8e1fae1cc21ac559524c6b2bbMike Lockwood    }
272873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood}
273873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood
2747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
2757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t size, MtpObjectFormat format, int fd) {
276c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    ObjectEdit*  edit = new ObjectEdit(handle, path, size, format, fd);
2777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mObjectEditList.add(edit);
2787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
2817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
284c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) return edit;
2857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
2867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return NULL;
2877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
2887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
2897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::removeEditObject(MtpObjectHandle handle) {
2907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int count = mObjectEditList.size();
2917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    for (int i = 0; i < count; i++) {
2927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = mObjectEditList[i];
293c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        if (edit->mHandle == handle) {
2947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            delete edit;
2957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            mObjectEditList.removeAt(i);
2967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return;
2977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        }
2987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
29929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    ALOGE("ObjectEdit not found in removeEditObject");
3007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
3017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwoodvoid MtpServer::commitEdit(ObjectEdit* edit) {
303c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
3047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
3057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
3067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
307916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwoodbool MtpServer::handleRequest() {
308a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    Mutex::Autolock autoLock(mMutex);
309a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
31016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpOperationCode operation = mRequest.getOperationCode();
31116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpResponseCode response;
31216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
31316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.reset();
31416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
31516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
31616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // FIXME - need to delete mSendObjectHandle from the database
31729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("expected SendObject after SendObjectInfo");
31816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = kInvalidObjectHandle;
31916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
32016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
32116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    switch (operation) {
32216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_DEVICE_INFO:
32316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetDeviceInfo();
32416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_OPEN_SESSION:
32616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doOpenSession();
32716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
32816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_CLOSE_SESSION:
32916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doCloseSession();
33016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_STORAGE_IDS:
33216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageIDs();
33316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood         case MTP_OPERATION_GET_STORAGE_INFO:
33516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetStorageInfo();
33616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
33716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
33816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropsSupported();
33916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
34016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_HANDLES:
34116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectHandles();
34216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
343343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        case MTP_OPERATION_GET_NUM_OBJECTS:
344343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            response = doGetNumObjects();
345343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood            break;
346438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_GET_OBJECT_REFERENCES:
347438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doGetObjectReferences();
348438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
349438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        case MTP_OPERATION_SET_OBJECT_REFERENCES:
350438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            response = doSetObjectReferences();
351438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood            break;
35216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
35316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectPropValue();
35416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
3558277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
3568277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetObjectPropValue();
3578277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3588277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
3598277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doGetDevicePropValue();
3608277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3618277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
3628277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doSetDevicePropValue();
3638277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
3648277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
3658277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            response = doResetDevicePropValue();
3668277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            break;
367b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_LIST:
368b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            response = doGetObjectPropList();
369b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            break;
37016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_INFO:
37116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObjectInfo();
37216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
37316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT:
37416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doGetObject();
37516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
37664000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        case MTP_OPERATION_GET_THUMB:
37764000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            response = doGetThumb();
37864000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood            break;
379d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT:
3807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
3817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doGetPartialObject(operation);
382d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            break;
38316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT_INFO:
38416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObjectInfo();
38516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_SEND_OBJECT:
38716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doSendObject();
38816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
38916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_DELETE_OBJECT:
39016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = doDeleteObject();
39116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
39216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        case MTP_OPERATION_GET_OBJECT_PROP_DESC:
39321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            response = doGetObjectPropDesc();
39421ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood            break;
395e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        case MTP_OPERATION_GET_DEVICE_PROP_DESC:
396e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            response = doGetDevicePropDesc();
397e3e76c456baee122de6715ae280130abaddc906cMike Lockwood            break;
3987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_SEND_PARTIAL_OBJECT:
3997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doSendPartialObject();
4007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_TRUNCATE_OBJECT:
4027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doTruncateObject();
4037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_BEGIN_EDIT_OBJECT:
4057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doBeginEditObject();
4067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
4077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        case MTP_OPERATION_END_EDIT_OBJECT:
4087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            response = doEndEditObject();
4097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            break;
41016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        default:
41129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
41216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
41316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            break;
41416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
41516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
416916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
417916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        return false;
41816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setResponseCode(response);
419916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    return true;
42016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
42116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
42216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetDeviceInfo() {
42316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
424c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    char prop_value[PROPERTY_VALUE_MAX];
42516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
426782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
427782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
428782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
429782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
43016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // fill in device info
43116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4323d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    if (mPtp) {
4333d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mData.putUInt32(0);
4343d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    } else {
4353d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // MTP Vendor Extension ID
4363d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        mData.putUInt32(6);
4373d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    }
43816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(MTP_STANDARD_VERSION);
4393d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    if (mPtp) {
4403d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // no extensions
4413d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        string.set("");
4423d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    } else {
4433d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        // MTP extensions
4443d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood        string.set("microsoft.com: 1.0; android.com: 1.0;");
4453d1d7767afc7c488197ec40a22739159c5110721Mike Lockwood    }
44616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string); // MTP Extensions
44716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(0); //Functional Mode
44816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt16(kSupportedOperationCodes,
44916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
450873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood    mData.putAUInt16(kSupportedEventCodes,
451873871f3e75831bcda6c3f75bb4d53355ca5c53aMike Lockwood            sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
452782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(deviceProperties); // Device Properties Supported
453782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(captureFormats); // Capture Formats
454782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(playbackFormats);  // Playback Formats
4558d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood
4568d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
4578d08c5aeee05425357b6603a22fa73fd6e095a47Mike Lockwood    string.set(prop_value);
45816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Manufacturer
459c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
460c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.product.model", prop_value, "MTP Device");
461c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
46216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Model
46316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set("1.0");
46416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Device Version
465c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood
466c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    property_get("ro.serialno", prop_value, "????????");
467c42aa12f73edf79bc9cb0dbf6b74a7f1af11c683Mike Lockwood    string.set(prop_value);
46816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);   // Serial Number
46916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
470782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete playbackFormats;
471782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete captureFormats;
472782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    delete deviceProperties;
473782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood
47416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
47516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
47616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
47716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doOpenSession() {
47816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSessionOpen) {
47916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mResponse.setParameter(1, mSessionID);
48016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_ALREADY_OPEN;
48116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
48216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = mRequest.getParameter(1);
48316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = true;
4846b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
4856b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionStarted();
4866b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood
48716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
48816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
48916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
49016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doCloseSession() {
49116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
49216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
49316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionID = 0;
49416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSessionOpen = false;
4956b3a9d15c8a2282c03f1df7d72a55b6800d4ececMike Lockwood    mDatabase->sessionEnded();
49616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
49716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
49816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
49916864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageIDs() {
50016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
50116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
50216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int count = mStorages.size();
50416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(count);
50516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    for (int i = 0; i < count; i++)
50616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mData.putUInt32(mStorages[i]->getStorageID());
50716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
50816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
50916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
51016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51116864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetStorageInfo() {
51216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer   string;
51316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
51416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
51516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
51616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID id = mRequest.getParameter(1);
51716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(id);
51816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
51916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
52016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
52116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getType());
52216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getFileSystemType());
52316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt16(storage->getAccessCapability());
52416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getMaxCapacity());
52516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt64(storage->getFreeSpace());
52616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putUInt32(1024*1024*1024); // Free Space in Objects
52716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    string.set(storage->getDescription());
52816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putString(string);
52916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putEmptyString();   // Volume Identifier
53016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
53216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
53316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
53416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropsSupported() {
53516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
53616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
53716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(1);
5382e09e289b7e136481e9215bb61ed47cee5d9919bMike Lockwood    MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
539782aef17c9921a3bf401a0432878df5031f2328bMike Lockwood    mData.putAUInt16(properties);
540bf9b2052d207f8f2a23470f1c4dfe464f430f387Mike Lockwood    delete properties;
54116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
54216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
54316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
54416864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectHandles() {
54516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!mSessionOpen)
54616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
54716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
548e13401bf532c7e4bf9ab82c7e9b13642838a927dMike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
54916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
550dc3185e3e27b05e18c4ac34432a25a0c279ff351Mike Lockwood                                                            // 0x00000000 for all objects
551a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
552a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
553a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
55416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
55516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
55616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.putAUInt32(handles);
55716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    delete handles;
55816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
55916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
56016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
561343af4ef512869695456a91519e73ed3c3d82101Mike LockwoodMtpResponseCode MtpServer::doGetNumObjects() {
562343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (!mSessionOpen)
563343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
564343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
565343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
566343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
567dc3185e3e27b05e18c4ac34432a25a0c279ff351Mike Lockwood                                                            // 0x00000000 for all objects
568a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage(storageID))
569a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
570343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
571343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    int count = mDatabase->getNumObjects(storageID, format, parent);
572343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    if (count >= 0) {
573343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, count);
574343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_OK;
575343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    } else {
576343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        mResponse.setParameter(1, 0);
577343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
578343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood    }
579343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood}
580343af4ef512869695456a91519e73ed3c3d82101Mike Lockwood
581438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doGetObjectReferences() {
582438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
583438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
584a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
585a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
586a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
5878277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
5888277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    // FIXME - check for invalid object handle
589438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
5908277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (handles) {
5918277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        mData.putAUInt32(handles);
5928277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        delete handles;
5938277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    } else {
594438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        mData.putEmptyArray();
595438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    }
596438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return MTP_RESPONSE_OK;
597438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
598438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
599438344fba74ddd6b931ac733fa48643f27b63de3Mike LockwoodMtpResponseCode MtpServer::doSetObjectReferences() {
600438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    if (!mSessionOpen)
601438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood        return MTP_RESPONSE_SESSION_NOT_OPEN;
602a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
603a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
604438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpStorageID handle = mRequest.getParameter(1);
605a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood
606438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpObjectHandleList* references = mData.getAUInt32();
607438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
608438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    delete references;
609438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood    return result;
610438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood}
611438344fba74ddd6b931ac733fa48643f27b63de3Mike Lockwood
61216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropValue() {
613a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
614a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
61516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
61616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
6173856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetObjectPropValue %d %s\n", handle,
6188277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
61916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6208277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getObjectPropertyValue(handle, property, mData);
6218277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6228277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6238277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetObjectPropValue() {
624a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
625a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
6268277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6278277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpObjectProperty property = mRequest.getParameter(2);
6283856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("SetObjectPropValue %d %s\n", handle,
6298277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getObjectPropCodeName(property));
6308277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6318277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setObjectPropertyValue(handle, property, mData);
6328277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6338277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6348277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropValue() {
6358277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6363856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetDevicePropValue %s\n",
6378277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6388277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6398277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->getDevicePropertyValue(property, mData);
6408277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6418277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6428277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doSetDevicePropValue() {
6438277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6443856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("SetDevicePropValue %s\n",
6458277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6468277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6478277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->setDevicePropertyValue(property, mData);
6488277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
6498277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6508277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doResetDevicePropValue() {
6518277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty property = mRequest.getParameter(1);
6523856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("ResetDevicePropValue %s\n",
6538277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood            MtpDebug::getDevicePropCodeName(property));
6548277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood
6558277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return mDatabase->resetDeviceProperty(property);
65616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
65716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
658b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropList() {
659a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
660a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
661b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
662b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
66340ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    // use uint32_t so we can support 0xFFFFFFFF
66440ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t format = mRequest.getParameter(2);
66540ce1f262cc4edbc8b7c470830325466263acaecMike Lockwood    uint32_t property = mRequest.getParameter(3);
666b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    int groupCode = mRequest.getParameter(4);
667f05ff073495b0bb3e49859aee5b54d3e25088985Mike Lockwood    int depth = mRequest.getParameter(5);
6683856b090cd04ba5dd4a59a12430ed724d5995909Steve Block   ALOGV("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
669b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            handle, MtpDebug::getFormatCodeName(format),
670b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood            MtpDebug::getObjectPropCodeName(property), groupCode, depth);
671b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
672b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood    return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
673b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood}
674b6da06e9dfb916da4b88e09e8a83e22ddae445b5Mike Lockwood
67516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectInfo() {
676a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
677a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
67816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
6797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectInfo info(handle);
6807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
6817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
6827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        char    date[20];
6837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mStorageID);
6857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mFormat);
6867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mProtectionStatus);
6877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // if object is being edited the database size may be out of date
6897d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint32_t size = info.mCompressedSize;
6907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        ObjectEdit* edit = getEditObject(handle);
6917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (edit)
692c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood            size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize);
6937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(size);
6947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
6957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mThumbFormat);
6967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbCompressedSize);
6977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixWidth);
6987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mThumbPixHeight);
6997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixWidth);
7007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixHeight);
7017d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mImagePixDepth);
7027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mParent);
7037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt16(info.mAssociationType);
7047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mAssociationDesc);
7057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putUInt32(info.mSequenceNumber);
7067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(info.mName);
7077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putEmptyString();    // date created
7087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        formatDateTime(info.mDateModified, date, sizeof(date));
7097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putString(date);   // date modified
7107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mData.putEmptyString();   // keywords
7117d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
7127d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return result;
71316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
71416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
71516864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObject() {
716a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
717a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
71816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
719c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    MtpString pathBuf;
72016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
721fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
722fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
7239c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result != MTP_RESPONSE_OK)
7249c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        return result;
72516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
7269c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    const char* filePath = (const char *)pathBuf;
72716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
728c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    mfr.fd = open(filePath, O_RDONLY);
729c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
730c6588763ddc20541688e426a24b1b070527c051fMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
731c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
73216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.offset = 0;
73316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mfr.length = fileLength;
734ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.command = mRequest.getOperationCode();
735ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.transaction_id = mRequest.getTransactionID();
73616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
73716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // then transfer the file
738ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
7393856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
740c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    close(mfr.fd);
741916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
742916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
743916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
744916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
745916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
746916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
74716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
74816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
74916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
75064000788211f4c7e78c80a4a155390d1316e1176Mike LockwoodMtpResponseCode MtpServer::doGetThumb() {
75164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
75264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    size_t thumbSize;
75364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    void* thumb = mDatabase->getThumbnail(handle, thumbSize);
75464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    if (thumb) {
75564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        // send data
75664000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setOperationCode(mRequest.getOperationCode());
75764000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.setTransactionID(mRequest.getTransactionID());
75864000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        mData.writeData(mFD, thumb, thumbSize);
75964000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        free(thumb);
76064000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_OK;
76164000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    } else {
76264000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
76364000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood    }
76464000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood}
76564000788211f4c7e78c80a4a155390d1316e1176Mike Lockwood
7667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
767a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
768a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
769d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
7707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset;
7717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length;
7727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = mRequest.getParameter(2);
7737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) {
7747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // android extension with 64 bit offset
7757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        uint64_t offset2 = mRequest.getParameter(3);
7767d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        offset = offset | (offset2 << 32);
7777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(4);
7787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
7797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        // standard GetPartialObject
7807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        length = mRequest.getParameter(3);
7817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
782d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    MtpString pathBuf;
783d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    int64_t fileLength;
784fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    MtpObjectFormat format;
785fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
786d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (result != MTP_RESPONSE_OK)
787d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return result;
788d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (offset + length > fileLength)
789d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        length = fileLength - offset;
790d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
791d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    const char* filePath = (const char *)pathBuf;
792d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mtp_file_range  mfr;
793d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.fd = open(filePath, O_RDONLY);
794d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (mfr.fd < 0) {
795d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
796d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
797d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.offset = offset;
798d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mfr.length = length;
799ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.command = mRequest.getOperationCode();
800ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mfr.transaction_id = mRequest.getTransactionID();
801d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    mResponse.setParameter(1, length);
802d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
803ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // transfer the file
804ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
8053856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
806d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    close(mfr.fd);
807d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    if (ret < 0) {
808d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        if (errno == ECANCELED)
809d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
810d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood        else
811d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
812d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    }
813d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood    return MTP_RESPONSE_OK;
814d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood}
815d81ce3cf2e6479915658a0829eced062e3655320Mike Lockwood
81616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObjectInfo() {
81716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString path;
81816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorageID storageID = mRequest.getParameter(1);
81916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStorage* storage = getStorage(storageID);
82016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle parent = mRequest.getParameter(2);
82116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!storage)
82216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_INVALID_STORAGE_ID;
82316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
82416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // special case the root
8251865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    if (parent == MTP_PARENT_ROOT) {
82616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path = storage->getPath();
8271865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood        parent = 0;
8281865a5ddcfe7b0e8dc211419aea1094b1491a5fdMike Lockwood    } else {
829fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int64_t length;
830fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        MtpObjectFormat format;
831fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        int result = mDatabase->getObjectFilePath(parent, path, length, format);
8329c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood        if (result != MTP_RESPONSE_OK)
8339c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood            return result;
834fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood        if (format != MTP_FORMAT_ASSOCIATION)
835fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
83616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
83716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
83816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // read only the fields we need
83916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // storage ID
84016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mData.getUInt16();
84116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // protection status
84216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mSendObjectFileSize = mData.getUInt32();
84316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt16();  // thumb format
84416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb compressed size
84516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix width
84616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // thumb pix height
84716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix width
84816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image pix height
84916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // image bit depth
85016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // parent
85116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint16_t associationType = mData.getUInt16();
85216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    uint32_t associationDesc = mData.getUInt32();   // association desc
85316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getUInt32();  // sequence number
85416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpStringBuffer name, created, modified;
85516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(name);    // file name
85616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(created);      // date created
85716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mData.getString(modified);     // date modified
85816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // keywords follow
85916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
8603856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("name: %s format: %04X\n", (const char *)name, format);
861fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    time_t modifiedTime;
86216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (!parseDateTime(modified, modifiedTime))
86316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        modifiedTime = 0;
86416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
86516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (path[path.size() - 1] != '/')
86616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        path += "/";
86716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    path += (const char *)name;
86816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
86920c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    // check space first
87020c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood    if (mSendObjectFileSize > storage->getFreeSpace())
87120c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood        return MTP_RESPONSE_STORAGE_FULL;
8729b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    uint64_t maxFileSize = storage->getMaxFileSize();
8739b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    // check storage max file size
8749b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    if (maxFileSize != 0) {
8759b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size
8769b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        // is >= 0xFFFFFFFF
8779b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood        if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF)
8789b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood            return MTP_RESPONSE_OBJECT_TOO_LARGE;
8799b88b72ee2c3fd01fb46e77b7e6d80f3bd52e958Mike Lockwood    }
88020c3be0e0394e1340c036685eb1edb8f6ef5a2acMike Lockwood
881b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
8824714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
8834714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            format, parent, storageID, mSendObjectFileSize, modifiedTime);
884fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    if (handle == kInvalidObjectHandle) {
88516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
886fceef46513db3507b413f604cea89e3c7f352663Mike Lockwood    }
88716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
88816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood  if (format == MTP_FORMAT_ASSOCIATION) {
88916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mode_t mask = umask(0);
8908e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        int ret = mkdir((const char *)path, mDirectoryPermission);
89116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        umask(mask);
89216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        if (ret && ret != -EEXIST)
89316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
8948e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood        chown((const char *)path, getuid(), mFileGroup);
895aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood
896aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        // SendObject does not get sent for directories, so call endSendObject here instead
897aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood        mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
89816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    } else {
89916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectFilePath = path;
90016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        // save the handle for the SendObject call, which should follow
90116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        mSendObjectHandle = handle;
9024714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        mSendObjectFormat = format;
90316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
90416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
90516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(1, storageID);
9068277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    mResponse.setParameter(2, parent);
90716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mResponse.setParameter(3, handle);
90816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
90916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return MTP_RESPONSE_OK;
91016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
91116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
91216864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doSendObject() {
913a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
914a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
9154714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    MtpResponseCode result = MTP_RESPONSE_OK;
9164714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mode_t mask;
917ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret, initialData;
9184714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
91916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (mSendObjectHandle == kInvalidObjectHandle) {
92029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Expected SendObjectInfo before SendObject");
9214714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
9224714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
92316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    }
92416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
925ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // read the header, and possibly some data
926ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    ret = mData.read(mFD);
927ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (ret < MTP_CONTAINER_HEADER_SIZE) {
928ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
929ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        goto done;
930ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
931ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    initialData = ret - MTP_CONTAINER_HEADER_SIZE;
93216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
93316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    mtp_file_range  mfr;
934af8e8aa1ada2948972555592570ec9ad90cbf372Nick Kralevich    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
935c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    if (mfr.fd < 0) {
9364714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        result = MTP_RESPONSE_GENERAL_ERROR;
9374714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood        goto done;
938c6588763ddc20541688e426a24b1b070527c051fMike Lockwood    }
9398e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchown(mfr.fd, getuid(), mFileGroup);
9408e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    // set permissions
9414714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mask = umask(0);
9428e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    fchmod(mfr.fd, mFilePermission);
9438e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood    umask(mask);
9448e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
945ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (initialData > 0)
946ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        ret = write(mfr.fd, mData.getData(), initialData);
94716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
948ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (mSendObjectFileSize - initialData > 0) {
949ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        mfr.offset = initialData;
9500cc79c66329b9ffa7d7bdfafa5d245a11fd3660dMike Lockwood        if (mSendObjectFileSize == 0xFFFFFFFF) {
9510cc79c66329b9ffa7d7bdfafa5d245a11fd3660dMike Lockwood            // tell driver to read until it receives a short packet
9520cc79c66329b9ffa7d7bdfafa5d245a11fd3660dMike Lockwood            mfr.length = 0xFFFFFFFF;
9530cc79c66329b9ffa7d7bdfafa5d245a11fd3660dMike Lockwood        } else {
9540cc79c66329b9ffa7d7bdfafa5d245a11fd3660dMike Lockwood            mfr.length = mSendObjectFileSize - initialData;
9550cc79c66329b9ffa7d7bdfafa5d245a11fd3660dMike Lockwood        }
9568e2a280ab7f98bf00ff2651f1f93c8f8bd46c08dMike Lockwood
9573856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("receiving %s\n", (const char *)mSendObjectFilePath);
958ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        // transfer the file
959ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
9603856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("MTP_RECEIVE_FILE returned %d\n", ret);
961ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
962ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    close(mfr.fd);
96316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
964916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    if (ret < 0) {
965916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        unlink(mSendObjectFilePath);
966916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        if (errno == ECANCELED)
9674714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_TRANSACTION_CANCELLED;
968916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood        else
9694714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood            result = MTP_RESPONSE_GENERAL_ERROR;
970916076c6d84dac9b104fbdf94af5dcd7bce669fdMike Lockwood    }
9714714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood
9724714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwooddone:
973ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // reset so we don't attempt to send the data back
974ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mData.reset();
975ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood
9764714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
977aa95240d9096f97aa2e2022fae8764a4386c8951Mike Lockwood            result == MTP_RESPONSE_OK);
9784714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectHandle = kInvalidObjectHandle;
9794714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    mSendObjectFormat = 0;
9804714b0766ecf48f09f39b4781a5c4deafc092d49Mike Lockwood    return result;
98116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
98216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
983d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deleteRecursive(const char* path) {
984d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char pathbuf[PATH_MAX];
985d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathLength = strlen(path);
986d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathLength >= sizeof(pathbuf) - 1) {
98729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("path too long: %s\n", path);
988d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
989d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    strcpy(pathbuf, path);
990d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (pathbuf[pathLength - 1] != '/') {
991d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        pathbuf[pathLength++] = '/';
992d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
993d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    char* fileSpot = pathbuf + pathLength;
994d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
995d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
996d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    DIR* dir = opendir(path);
997d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (!dir) {
99829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("opendir %s failed: %s", path, strerror(errno));
999d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        return;
1000d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1001d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1002d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct dirent* entry;
1003d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    while ((entry = readdir(dir))) {
1004d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        const char* name = entry->d_name;
1005d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1006d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        // ignore "." and ".."
1007d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1008d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
1009d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1010d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1011d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int nameLength = strlen(name);
1012d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (nameLength > pathRemaining) {
101329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("path %s/%s too long\n", path, name);
1014d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            continue;
1015d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1016d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        strcpy(fileSpot, name);
1017d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1018d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        int type = entry->d_type;
1019d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (entry->d_type == DT_DIR) {
1020d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(pathbuf);
1021d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(pathbuf);
1022d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1023d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(pathbuf);
1024d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1025d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
10267ce05cf6009a2fbbceb3d2c0ff639473d0b7d6a9Mike Lockwood    closedir(dir);
1027d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1028d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
1029d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwoodstatic void deletePath(const char* path) {
1030d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    struct stat statbuf;
1031d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    if (stat(path, &statbuf) == 0) {
1032d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        if (S_ISDIR(statbuf.st_mode)) {
1033d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            deleteRecursive(path);
1034d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            rmdir(path);
1035d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        } else {
1036d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood            unlink(path);
1037d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood        }
1038d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    } else {
103929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
1040d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    }
1041d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood}
1042d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood
104316864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doDeleteObject() {
1044a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood    if (!hasStorage())
1045a849440ca96e93f700d62c6e41d48905b4d405b6Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
104616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
1047d32114950770a6e9361e0869a41e5a03a7acab42Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
104816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - support deleting all objects if handle is 0xFFFFFFFF
104916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // FIXME - implement deleting objects by format
105016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
105116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpString filePath;
105216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int64_t fileLength;
1053fd34626771a63d3a835863e1b4bf71dcb26e28d8Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
10549c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    if (result == MTP_RESPONSE_OK) {
10553856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("deleting %s", (const char *)filePath);
1056a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        result = mDatabase->deleteFile(handle);
1057a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        // Don't delete the actual files unless the database deletion is allowed
1058a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        if (result == MTP_RESPONSE_OK) {
1059a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood            deletePath((const char *)filePath);
1060a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood        }
10619c04c4cc038f924d9cb98798e1c07fe6017e85d0Mike Lockwood    }
1062a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood
1063a9a46c1f53129be8fe1f3f0a6ea868d7b4c8f8f7Mike Lockwood    return result;
106416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
106516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
106616864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodMtpResponseCode MtpServer::doGetObjectPropDesc() {
106721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    MtpObjectProperty propCode = mRequest.getParameter(1);
106816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    MtpObjectFormat format = mRequest.getParameter(2);
10693856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
10708277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood                                        MtpDebug::getFormatCodeName(format));
10718277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
107221ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    if (!property)
107321ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
10748277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    property->write(mData);
10758277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
10768277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    return MTP_RESPONSE_OK;
10778277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood}
107816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
10798277cec96ffa55082962591bca1c55abbeec8c26Mike LockwoodMtpResponseCode MtpServer::doGetDevicePropDesc() {
10808277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpDeviceProperty propCode = mRequest.getParameter(1);
10813856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
10828277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
10838277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    if (!property)
10848277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
108521ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    property->write(mData);
10868277cec96ffa55082962591bca1c55abbeec8c26Mike Lockwood    delete property;
108721ef7d0e70c5ad599bc2602cb484f8cd647055caMike Lockwood    return MTP_RESPONSE_OK;
108816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10897850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
10907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doSendPartialObject() {
10917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!hasStorage())
10927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
10937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
10947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
10957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
10967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset = offset | (offset2 << 32);
10977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint32_t length = mRequest.getParameter(4);
10987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
10997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
110129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doSendPartialObject");
11027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    // can't start writing past the end of the file
1106c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (offset > edit->mSize) {
1107b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("writing past end of object, offset: %lld, edit->mSize: %lld", offset, edit->mSize);
11087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11107d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1111ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    const char* filePath = (const char *)edit->mPath;
11123856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("receiving partial %s %lld %lld\n", filePath, offset, length);
11137d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1114ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // read the header, and possibly some data
1115ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int ret = mData.read(mFD);
1116ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (ret < MTP_CONTAINER_HEADER_SIZE)
1117ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
1118ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
11197d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1120ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (initialData > 0) {
1121ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        ret = write(edit->mFD, mData.getData(), initialData);
1122ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        offset += initialData;
1123ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        length -= initialData;
1124ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
11257d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
1126ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    if (length > 0) {
1127ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        mtp_file_range  mfr;
1128ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        mfr.fd = edit->mFD;
1129ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        mfr.offset = offset;
1130ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        mfr.length = length;
1131ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood
1132ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        // transfer the file
1133ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood        ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
11343856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("MTP_RECEIVE_FILE returned %d", ret);
1135ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    }
11367d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (ret < 0) {
11377d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        mResponse.setParameter(1, 0);
11387d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        if (errno == ECANCELED)
11397d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_TRANSACTION_CANCELLED;
11407d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        else
11417d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
11427d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
1143ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood
1144ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    // reset so we don't attempt to send this back
1145ef441d965504dbf31c5db690e5b34fcdcecd92ffMike Lockwood    mData.reset();
11467d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    mResponse.setParameter(1, length);
11477d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t end = offset + length;
1148c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (end > edit->mSize) {
1149c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = end;
11507d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11517d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11527d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11537d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11547d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doTruncateObject() {
11557d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11567d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
11577d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
115829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doTruncateObject");
11597d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11607d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11617d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11627d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset = mRequest.getParameter(2);
11637d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    uint64_t offset2 = mRequest.getParameter(3);
11647d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    offset |= (offset2 << 32);
1165c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood    if (ftruncate(edit->mFD, offset) != 0) {
11667d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11677d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    } else {
1168c3f16e5620c090aeb75c0836572a8b913a4ef864Mike Lockwood        edit->mSize = offset;
11697d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_OK;
11707d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11717d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11727d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11737d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doBeginEditObject() {
11747d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11757d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (getEditObject(handle)) {
117629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object already open for edit in doBeginEditObject");
11777d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11787d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11797d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11807d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpString path;
11817d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int64_t fileLength;
11827d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectFormat format;
11837d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
11847d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (result != MTP_RESPONSE_OK)
11857d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return result;
11867d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11877d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    int fd = open((const char *)path, O_RDWR | O_EXCL);
11887d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (fd < 0) {
118929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
11907d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
11917d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
11927d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11937d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    addEditObject(handle, path, fileLength, format, fd);
11947d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
11957d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
11967d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
11977d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike LockwoodMtpResponseCode MtpServer::doEndEditObject() {
11987d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    MtpObjectHandle handle = mRequest.getParameter(1);
11997d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    ObjectEdit* edit = getEditObject(handle);
12007d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    if (!edit) {
120129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("object not open for edit in doEndEditObject");
12027d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood        return MTP_RESPONSE_GENERAL_ERROR;
12037d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    }
12047d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12057d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    commitEdit(edit);
12067d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    removeEditObject(handle);
12077d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood    return MTP_RESPONSE_OK;
12087d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood}
12097d77dcfadd7fb637ed2c3aef5bb3990dd0a67dc0Mike Lockwood
12107850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
1211