| // Copyright 2017 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 "virtual_file_provider/service.h" |
| |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <base/guid.h> |
| #include <base/logging.h> |
| #include <base/posix/eintr_wrapper.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <dbus/bus.h> |
| #include <dbus/message.h> |
| #include <dbus/object_proxy.h> |
| |
| namespace virtual_file_provider { |
| |
| Service::Service(const base::FilePath& fuse_mount_path, SizeMap* size_map) |
| : fuse_mount_path_(fuse_mount_path), |
| size_map_(size_map), |
| weak_ptr_factory_(this) { |
| thread_checker_.DetachFromThread(); |
| } |
| |
| Service::~Service() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| if (bus_) |
| bus_->ShutdownAndBlock(); |
| } |
| |
| bool Service::Initialize() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| // Connect the bus. |
| dbus::Bus::Options options; |
| options.bus_type = dbus::Bus::SYSTEM; |
| bus_ = new dbus::Bus(options); |
| if (!bus_->Connect()) { |
| LOG(ERROR) << "Failed to initialize D-Bus connection."; |
| return false; |
| } |
| request_handler_proxy_ = bus_->GetObjectProxy( |
| chromeos::kVirtualFileRequestServiceName, |
| dbus::ObjectPath(chromeos::kVirtualFileRequestServicePath)); |
| // Export methods. |
| exported_object_ = bus_->GetExportedObject( |
| dbus::ObjectPath(kVirtualFileProviderServicePath)); |
| if (!exported_object_->ExportMethodAndBlock( |
| kVirtualFileProviderInterface, |
| kOpenFileMethod, |
| base::Bind(&Service::OpenFile, weak_ptr_factory_.GetWeakPtr()))) { |
| LOG(ERROR) << "Failed to export OpenFile method."; |
| return false; |
| } |
| // Request the ownership of the service name. |
| if (!bus_->RequestOwnershipAndBlock(kVirtualFileProviderServiceName, |
| dbus::Bus::REQUIRE_PRIMARY)) { |
| LOG(ERROR) << "Failed to own the service name"; |
| return false; |
| } |
| return true; |
| } |
| |
| void Service::SendReadRequest(const std::string& id, |
| int64_t offset, |
| int64_t size, |
| base::ScopedFD fd) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| dbus::MethodCall method_call( |
| chromeos::kVirtualFileRequestServiceInterface, |
| chromeos::kVirtualFileRequestServiceHandleReadRequestMethod); |
| |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(id); |
| writer.AppendInt64(offset); |
| writer.AppendInt64(size); |
| writer.AppendFileDescriptor(fd.get()); |
| request_handler_proxy_->CallMethod( |
| &method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| dbus::ObjectProxy::EmptyResponseCallback()); |
| } |
| |
| void Service::SendIdReleased(const std::string& id) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| dbus::MethodCall method_call( |
| chromeos::kVirtualFileRequestServiceInterface, |
| chromeos::kVirtualFileRequestServiceHandleIdReleasedMethod); |
| |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(id); |
| request_handler_proxy_->CallMethod( |
| &method_call, |
| dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| dbus::ObjectProxy::EmptyResponseCallback()); |
| } |
| |
| void Service::OpenFile(dbus::MethodCall* method_call, |
| dbus::ExportedObject::ResponseSender response_sender) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| dbus::MessageReader reader(method_call); |
| int64_t size = 0; |
| if (!reader.PopInt64(&size)) { |
| response_sender.Run(dbus::ErrorResponse::FromMethodCall( |
| method_call, DBUS_ERROR_INVALID_ARGS, "Size must be provided.")); |
| return; |
| } |
| // Generate a new ID. |
| std::string id = base::GenerateGUID(); |
| |
| // Set the size of the ID. |
| // NOTE: Currently, updating the size value is not supported. If the virtual |
| // file gets modified later, the size map's value can contradict with the real |
| // value and it can result in read errors. |
| CHECK_EQ(-1, size_map_->GetSize(id)); |
| size_map_->SetSize(id, size); |
| |
| // An ID corresponds to a file name in the FUSE file system. |
| base::FilePath path = fuse_mount_path_.AppendASCII(id); |
| // Create a new FD associated with the ID. |
| base::ScopedFD fd(HANDLE_EINTR(open(path.value().c_str(), |
| O_RDONLY | O_CLOEXEC))); |
| |
| // Send response. |
| std::unique_ptr<dbus::Response> response = |
| dbus::Response::FromMethodCall(method_call); |
| dbus::MessageWriter writer(response.get()); |
| writer.AppendString(id); |
| writer.AppendFileDescriptor(fd.get()); |
| response_sender.Run(std::move(response)); |
| } |
| |
| } // namespace virtual_file_provider |