blob: 51b88061b6f571f1ed5e226817a0c19104de6bc6 [file] [log] [blame]
// 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 <base/logging.h>
#include <base/rand_util.h>
#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include "service_constants.h"
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<typename ReturnType>
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<std::string> MtpdServer::EnumerateStorages(DBus::Error& error) {
return device_manager_.EnumerateStorages();
}
std::vector<uint8_t> MtpdServer::GetStorageInfo(const std::string& storageName,
DBus::Error& error) {
const StorageInfo* info = device_manager_.GetStorageInfo(storageName);
return info ? info->ToDBusFormat() : StorageInfo().ToDBusFormat();
}
std::vector<uint8_t> MtpdServer::GetStorageInfoFromDevice(
const std::string& storageName,
DBus::Error& error) {
const StorageInfo* info =
device_manager_.GetStorageInfoFromDevice(storageName);
return info ? info->ToDBusFormat() : StorageInfo().ToDBusFormat();
}
std::string MtpdServer::OpenStorage(const std::string& storageName,
const std::string& mode,
DBus::Error& error) {
if (!(mode == kReadOnlyMode || mode == kReadWriteMode)) {
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, std::make_pair(storageName, mode)));
return id;
}
void MtpdServer::CloseStorage(const std::string& handle, DBus::Error& error) {
if (handle_map_.erase(handle) == 0)
SetInvalidHandleError(handle, &error);
}
std::vector<uint32_t> MtpdServer::ReadDirectoryEntryIds(
const std::string& handle,
const uint32_t& fileId,
DBus::Error& error) {
std::vector<uint32_t> directory_listing;
std::string storage_name = LookupHandle(handle);
if (storage_name.empty()) {
SetInvalidHandleError(handle, &error);
return directory_listing;
}
if (!device_manager_.ReadDirectoryEntryIds(storage_name,
fileId,
&directory_listing)) {
error.set(kMtpdServiceError, "ReadDirectoryEntryIds failed");
}
return directory_listing;
}
std::vector<uint8_t> MtpdServer::GetFileInfo(
const std::string& handle,
const std::vector<uint32_t>& fileIds,
DBus::Error& error) {
if (fileIds.empty()) {
error.set(kMtpdServiceError, "GetFileInfo called with no file ids");
return FileEntry::EmptyFileEntriesToDBusFormat();
}
std::string storage_name = LookupHandle(handle);
if (storage_name.empty()) {
SetInvalidHandleError(handle, &error);
return FileEntry::EmptyFileEntriesToDBusFormat();
}
std::vector<FileEntry> file_info;
if (!device_manager_.GetFileInfo(storage_name, fileIds, &file_info)) {
error.set(kMtpdServiceError, "GetFileInfo failed");
return FileEntry::EmptyFileEntriesToDBusFormat();
}
return FileEntry::FileEntriesToDBusFormat(file_info);
}
std::vector<uint8_t> MtpdServer::ReadFileChunk(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 ReadFileChunk");
return std::vector<uint8_t>();
}
std::string storage_name = LookupHandle(handle);
if (storage_name.empty())
return InvalidHandle<std::vector<uint8_t> >(handle, &error);
std::vector<uint8_t> file_contents;
if (!device_manager_.ReadFileChunk(storage_name, fileId, offset, count,
&file_contents)) {
error.set(kMtpdServiceError, "ReadFileChunk failed");
return std::vector<uint8_t>();
}
return file_contents;
}
void MtpdServer::CopyFileFromLocal(const std::string& handle,
const DBus::FileDescriptor& fileDescriptor,
const uint32_t& parentId,
const std::string& fileName,
DBus::Error& error) {
const std::string storage_name = LookupHandle(handle);
if (storage_name.empty() || !IsOpenedWithWrite(handle))
return InvalidHandle<void>(handle, &error);
if (!device_manager_.CopyFileFromLocal(storage_name,
fileDescriptor.get(),
parentId,
fileName)) {
error.set(kMtpdServiceError, "CopyFileFromLocal failed");
}
}
void MtpdServer::DeleteObject(const std::string& handle,
const uint32_t& objectId,
DBus::Error& error) {
const std::string storage_name = LookupHandle(handle);
if (storage_name.empty() || !IsOpenedWithWrite(handle))
return InvalidHandle<void>(handle, &error);
if (!device_manager_.DeleteObject(storage_name, objectId)) {
error.set(kMtpdServiceError, "DeleteObject failed");
}
}
void MtpdServer::RenameObject(const std::string& handle,
const uint32_t& objectId,
const std::string& newName,
DBus::Error& error) {
const std::string storage_name = LookupHandle(handle);
if (storage_name.empty() || !IsOpenedWithWrite(handle))
return InvalidHandle<void>(handle, &error);
if (!device_manager_.RenameObject(storage_name, objectId, newName)) {
error.set(kMtpdServiceError, "RenameObject failed");
}
}
void MtpdServer::CreateDirectory(const std::string& handle,
const uint32_t& parentId,
const std::string& directoryName,
DBus::Error& error) {
const std::string storage_name = LookupHandle(handle);
if (storage_name.empty() || !IsOpenedWithWrite(handle))
return InvalidHandle<void>(handle, &error);
if (!device_manager_.CreateDirectory(storage_name, parentId, directoryName)) {
error.set(kMtpdServiceError, "CreateDirectory failed.");
}
}
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.first;
}
bool MtpdServer::IsOpenedWithWrite(const std::string& handle) {
HandleMap::const_iterator it = handle_map_.find(handle);
return (it == handle_map_.end()) ? false
: it->second.second == kReadWriteMode;
}
} // namespace mtpd