// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "mtpd_server_impl.h" #include #include #include #include "build_config.h" #include "service_constants.h" // TODO(thestig) Merge these once libchrome catches up to Chromium's base, // or when mtpd moves into its own repo. http://crbug.com/221123 #if defined(CROS_BUILD) #include #else #include #endif namespace mtpd { namespace { // Maximum number of bytes to read from the device at one time. This is set low // enough such that a reasonable device can read this much data before D-Bus // times out. const uint32_t kMaxReadCount = 1024 * 1024; const char kInvalidHandleErrorMessage[] = "Invalid handle "; void SetInvalidHandleError(const std::string& handle, DBus::Error* error) { std::string error_msg = kInvalidHandleErrorMessage + handle; error->set(kMtpdServiceError, error_msg.c_str()); } template ReturnType InvalidHandle(const std::string& handle, DBus::Error* error) { SetInvalidHandleError(handle, error); return ReturnType(); } } // namespace MtpdServer::MtpdServer(DBus::Connection& connection) : DBus::ObjectAdaptor(connection, kMtpdServicePath), device_manager_(this) { } MtpdServer::~MtpdServer() { } std::vector MtpdServer::EnumerateStorages(DBus::Error& error) { return device_manager_.EnumerateStorages(); } std::vector MtpdServer::GetStorageInfo(const std::string& storageName, DBus::Error& error) { const StorageInfo* info = device_manager_.GetStorageInfo(storageName); return info ? info->ToDBusFormat() : StorageInfo().ToDBusFormat(); } std::string MtpdServer::OpenStorage(const std::string& storageName, const std::string& mode, DBus::Error& error) { // TODO(thestig) Handle read-write and possibly append-only modes. if (mode != kReadOnlyMode) { std::string error_msg = "Cannot open " + storageName + " in mode: " + mode; error.set(kMtpdServiceError, error_msg.c_str()); return std::string(); } if (!device_manager_.HasStorage(storageName)) { std::string error_msg = "Cannot open unknown storage " + storageName; error.set(kMtpdServiceError, error_msg.c_str()); return std::string(); } std::string id; uint32_t random_data[4]; do { base::RandBytes(random_data, sizeof(random_data)); id = base::HexEncode(random_data, sizeof(random_data)); } while (ContainsKey(handle_map_, id)); handle_map_.insert(std::make_pair(id, storageName)); return id; } void MtpdServer::CloseStorage(const std::string& handle, DBus::Error& error) { if (handle_map_.erase(handle) == 0) SetInvalidHandleError(handle, &error); } std::vector MtpdServer::ReadDirectoryByPath( const std::string& handle, const std::string& filePath, DBus::Error& error) { std::string storage_name = LookupHandle(handle); if (storage_name.empty()) { SetInvalidHandleError(handle, &error); return FileEntry::EmptyFileEntriesToDBusFormat(); } std::vector directory_listing; if (!device_manager_.ReadDirectoryByPath(storage_name, filePath, &directory_listing)) { error.set(kMtpdServiceError, "ReadDirectoryByPath failed"); return FileEntry::EmptyFileEntriesToDBusFormat(); } return FileEntry::FileEntriesToDBusFormat(directory_listing); } std::vector MtpdServer::ReadDirectoryById(const std::string& handle, const uint32_t& fileId, DBus::Error& error) { std::string storage_name = LookupHandle(handle); if (storage_name.empty()) { SetInvalidHandleError(handle, &error); return FileEntry::EmptyFileEntriesToDBusFormat(); } std::vector directory_listing; if (!device_manager_.ReadDirectoryById(storage_name, fileId, &directory_listing)) { error.set(kMtpdServiceError, "ReadDirectoryById failed"); return FileEntry::EmptyFileEntriesToDBusFormat(); } return FileEntry::FileEntriesToDBusFormat(directory_listing); } std::vector MtpdServer::ReadFileChunkByPath( const std::string& handle, const std::string& filePath, const uint32_t& offset, const uint32_t& count, DBus::Error& error) { if (count > kMaxReadCount || count == 0) { error.set(kMtpdServiceError, "Invalid count for ReadFileChunkByPath"); return std::vector(); } std::string storage_name = LookupHandle(handle); if (storage_name.empty()) return InvalidHandle >(handle, &error); std::vector file_contents; if (!device_manager_.ReadFileChunkByPath(storage_name, filePath, offset, count, &file_contents)) { error.set(kMtpdServiceError, "ReadFileChunkByPath failed"); return std::vector(); } return file_contents; } std::vector MtpdServer::ReadFileChunkById(const std::string& handle, const uint32_t& fileId, const uint32_t& offset, const uint32_t& count, DBus::Error& error) { if (count > kMaxReadCount || count == 0) { error.set(kMtpdServiceError, "Invalid count for ReadFileChunkById"); return std::vector(); } std::string storage_name = LookupHandle(handle); if (storage_name.empty()) return InvalidHandle >(handle, &error); std::vector file_contents; if (!device_manager_.ReadFileChunkById(storage_name, fileId, offset, count, &file_contents)) { error.set(kMtpdServiceError, "ReadFileChunkById failed"); return std::vector(); } return file_contents; } std::vector MtpdServer::GetFileInfoByPath(const std::string& handle, const std::string& filePath, DBus::Error& error) { std::string storage_name = LookupHandle(handle); if (storage_name.empty()) { SetInvalidHandleError(handle, &error); return FileEntry().ToDBusFormat(); } FileEntry entry; if (!device_manager_.GetFileInfoByPath(storage_name, filePath, &entry)) { error.set(kMtpdServiceError, "GetFileInfoByPath failed"); return FileEntry().ToDBusFormat(); } return entry.ToDBusFormat(); } std::vector MtpdServer::GetFileInfoById(const std::string& handle, const uint32_t& fileId, DBus::Error& error) { std::string storage_name = LookupHandle(handle); if (storage_name.empty()) { SetInvalidHandleError(handle, &error); return FileEntry().ToDBusFormat(); } FileEntry entry; if (!device_manager_.GetFileInfoById(storage_name, fileId, &entry)) { error.set(kMtpdServiceError, "GetFileInfoById failed"); return FileEntry().ToDBusFormat(); } return entry.ToDBusFormat(); } bool MtpdServer::IsAlive(DBus::Error& error) { return true; } void MtpdServer::StorageAttached(const std::string& storage_name) { // Fire DBus signal. MTPStorageAttached(storage_name); } void MtpdServer::StorageDetached(const std::string& storage_name) { // Fire DBus signal. MTPStorageDetached(storage_name); } int MtpdServer::GetDeviceEventDescriptor() const { return device_manager_.GetDeviceEventDescriptor(); } void MtpdServer::ProcessDeviceEvents() { device_manager_.ProcessDeviceEvents(); } std::string MtpdServer::LookupHandle(const std::string& handle) { HandleMap::const_iterator it = handle_map_.find(handle); return (it == handle_map_.end()) ? std::string() : it->second; } } // namespace mtpd