blob: 8fa48be9df3b733fd470be15f85da15732a8201b [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/mtpd_server_impl.h"
#include <base/location.h>
#include <base/logging.h>
#include <base/rand_util.h>
#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include <chromeos/dbus/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;
void AddError(brillo::ErrorPtr* error,
const base::Location& location,
const std::string& message) {
brillo::Error::AddTo(error, location, brillo::errors::dbus::kDomain,
kMtpdServiceError, message);
}
void AddInvalidHandleError(brillo::ErrorPtr* error,
const base::Location& location,
const std::string& handle) {
brillo::Error::AddToPrintf(error, location, brillo::errors::dbus::kDomain,
kMtpdServiceError, "Invalid handle %s",
handle.c_str());
}
} // namespace
MtpdServer::MtpdServer(scoped_refptr<dbus::Bus> bus)
: org::chromium::MtpdAdaptor(this),
dbus_object_(nullptr, bus, dbus::ObjectPath(kMtpdServicePath)),
device_manager_(this) {}
MtpdServer::~MtpdServer() {}
std::vector<std::string> MtpdServer::EnumerateStorages() {
return device_manager_.EnumerateStorages();
}
std::vector<uint8_t> MtpdServer::GetStorageInfo(
const std::string& storage_name) {
const StorageInfo* info = device_manager_.GetStorageInfo(storage_name);
return info ? info->ToDBusFormat() : StorageInfo().ToDBusFormat();
}
std::vector<uint8_t> MtpdServer::GetStorageInfoFromDevice(
const std::string& storage_name) {
const StorageInfo* info =
device_manager_.GetStorageInfoFromDevice(storage_name);
return info ? info->ToDBusFormat() : StorageInfo().ToDBusFormat();
}
bool MtpdServer::OpenStorage(brillo::ErrorPtr* error,
const std::string& storage_name,
const std::string& mode,
std::string* id) {
if (!(mode == kReadOnlyMode || mode == kReadWriteMode)) {
brillo::Error::AddToPrintf(error, FROM_HERE, brillo::errors::dbus::kDomain,
kMtpdServiceError, "Cannot open %s in mode: %s",
storage_name.c_str(), mode.c_str());
return false;
}
if (!device_manager_.HasStorage(storage_name)) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kMtpdServiceError,
"Cannot open unknown storage %s", storage_name.c_str());
return false;
}
std::string new_id;
uint32_t random_data[4];
do {
base::RandBytes(random_data, sizeof(random_data));
new_id = base::HexEncode(random_data, sizeof(random_data));
} while (base::Contains(handle_map_, new_id));
handle_map_.insert(
std::make_pair(new_id, std::make_pair(storage_name, mode)));
*id = new_id;
return true;
}
bool MtpdServer::CloseStorage(brillo::ErrorPtr* error,
const std::string& handle) {
if (handle_map_.erase(handle) == 0) {
AddInvalidHandleError(error, FROM_HERE, handle);
return false;
}
return true;
}
bool MtpdServer::ReadDirectoryEntryIds(
brillo::ErrorPtr* error,
const std::string& handle,
uint32_t file_id,
std::vector<uint32_t>* directory_listing) {
std::string storage_name = LookupHandle(handle);
if (storage_name.empty()) {
AddInvalidHandleError(error, FROM_HERE, handle);
return false;
}
if (!device_manager_.ReadDirectoryEntryIds(storage_name, file_id,
directory_listing)) {
AddError(error, FROM_HERE, "ReadDirectoryEntryIds failed");
return false;
}
return true;
}
bool MtpdServer::GetFileInfo(brillo::ErrorPtr* error,
const std::string& handle,
const std::vector<uint32_t>& file_ids,
std::vector<uint8_t>* serialized_file_entries) {
if (file_ids.empty()) {
AddError(error, FROM_HERE, "GetFileInfo called with no file ids");
return false;
}
std::string storage_name = LookupHandle(handle);
if (storage_name.empty()) {
AddInvalidHandleError(error, FROM_HERE, handle);
return false;
}
std::vector<FileEntry> file_info;
if (!device_manager_.GetFileInfo(storage_name, file_ids, &file_info)) {
AddError(error, FROM_HERE, "GetFileInfo failed");
return false;
}
*serialized_file_entries = FileEntry::FileEntriesToDBusFormat(file_info);
return true;
}
bool MtpdServer::ReadFileChunk(brillo::ErrorPtr* error,
const std::string& handle,
uint32_t file_id,
uint32_t offset,
uint32_t count,
std::vector<uint8_t>* file_contents) {
if (count > kMaxReadCount || count == 0) {
AddError(error, FROM_HERE, "Invalid count for ReadFileChunk");
return false;
}
std::string storage_name = LookupHandle(handle);
if (storage_name.empty()) {
AddInvalidHandleError(error, FROM_HERE, handle);
return false;
}
if (!device_manager_.ReadFileChunk(storage_name, file_id, offset, count,
file_contents)) {
AddError(error, FROM_HERE, "ReadFileChunk failed");
return false;
}
return true;
}
bool MtpdServer::CopyFileFromLocal(brillo::ErrorPtr* error,
const std::string& handle,
const base::ScopedFD& file_descriptor,
uint32_t parent_id,
const std::string& file_name) {
const std::string storage_name = LookupHandle(handle);
if (storage_name.empty() || !IsOpenedWithWrite(handle)) {
AddInvalidHandleError(error, FROM_HERE, handle);
return false;
}
if (!device_manager_.CopyFileFromLocal(storage_name, file_descriptor.get(),
parent_id, file_name)) {
AddError(error, FROM_HERE, "CopyFileFromLocal failed");
return false;
}
return true;
}
bool MtpdServer::DeleteObject(brillo::ErrorPtr* error,
const std::string& handle,
uint32_t object_id) {
const std::string storage_name = LookupHandle(handle);
if (storage_name.empty() || !IsOpenedWithWrite(handle)) {
AddInvalidHandleError(error, FROM_HERE, handle);
return false;
}
if (!device_manager_.DeleteObject(storage_name, object_id)) {
AddError(error, FROM_HERE, "DeleteObject failed");
return false;
}
return true;
}
bool MtpdServer::RenameObject(brillo::ErrorPtr* error,
const std::string& handle,
uint32_t object_id,
const std::string& new_name) {
const std::string storage_name = LookupHandle(handle);
if (storage_name.empty() || !IsOpenedWithWrite(handle)) {
AddInvalidHandleError(error, FROM_HERE, handle);
return false;
}
if (!device_manager_.RenameObject(storage_name, object_id, new_name)) {
AddError(error, FROM_HERE, "RenameObject failed");
return false;
}
return true;
}
bool MtpdServer::CreateDirectory(brillo::ErrorPtr* error,
const std::string& handle,
uint32_t parent_id,
const std::string& directory_name) {
const std::string storage_name = LookupHandle(handle);
if (storage_name.empty() || !IsOpenedWithWrite(handle)) {
AddInvalidHandleError(error, FROM_HERE, handle);
return false;
}
if (!device_manager_.CreateDirectory(storage_name, parent_id,
directory_name)) {
AddError(error, FROM_HERE, "CreateDirectory failed.");
return false;
}
return true;
}
bool MtpdServer::IsAlive() {
return true;
}
void MtpdServer::StorageAttached(const std::string& storage_name) {
// Fire DBus signal.
SendMTPStorageAttachedSignal(storage_name);
}
void MtpdServer::StorageDetached(const std::string& storage_name) {
// Fire DBus signal.
SendMTPStorageDetachedSignal(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;
}
void MtpdServer::RegisterAsync(
const brillo::dbus_utils::AsyncEventSequencer::CompletionAction& cb) {
RegisterWithDBusObject(&dbus_object_);
dbus_object_.RegisterAsync(cb);
}
} // namespace mtpd