service.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/file_system_provider/service.h"
6
7#include "base/files/file_path.h"
8#include "base/strings/string_number_conversions.h"
9#include "chrome/browser/chromeos/file_system_provider/observer.h"
10#include "chrome/browser/chromeos/file_system_provider/provided_file_system.h"
11#include "chrome/browser/chromeos/file_system_provider/service_factory.h"
12#include "chrome/browser/chromeos/login/user.h"
13#include "chrome/browser/chromeos/login/user_manager.h"
14#include "content/public/browser/browser_thread.h"
15#include "webkit/browser/fileapi/external_mount_points.h"
16
17namespace chromeos {
18namespace file_system_provider {
19namespace {
20
21// Root mount path for all of the provided file systems.
22const base::FilePath::CharType kProvidedMountPointRoot[] =
23    FILE_PATH_LITERAL("/provided");
24
25// Maximum number of file systems to be mounted in the same time, per profile.
26const size_t kMaxFileSystems = 16;
27
28// Constructs a safe mount point path for the provided file system represented
29// by |file_system_handle|. The handle is a numeric part of the file system id.
30base::FilePath GetMountPointPath(Profile* profile,
31                                 std::string extension_id,
32                                 int file_system_id) {
33  chromeos::User* const user =
34      chromeos::UserManager::IsInitialized()
35          ? chromeos::UserManager::Get()->GetUserByProfile(
36                profile->GetOriginalProfile())
37          : NULL;
38  const std::string user_suffix = user ? "-" + user->username_hash() : "";
39  return base::FilePath(kProvidedMountPointRoot).AppendASCII(
40      extension_id + "-" + base::IntToString(file_system_id) + user_suffix);
41}
42
43}  // namespace
44
45Service::Service(Profile* profile) : profile_(profile), next_id_(1) {}
46
47Service::~Service() {}
48
49// static
50Service* Service::Get(content::BrowserContext* context) {
51  return ServiceFactory::Get(context);
52}
53
54void Service::AddObserver(Observer* observer) {
55  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
56  DCHECK(observer);
57  observers_.AddObserver(observer);
58}
59
60void Service::RemoveObserver(Observer* observer) {
61  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
62  DCHECK(observer);
63  observers_.RemoveObserver(observer);
64}
65
66int Service::RegisterFileSystem(const std::string& extension_id,
67                                const std::string& file_system_name) {
68  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
69
70  // Restrict number of file systems to prevent system abusing.
71  if (file_systems_.size() + 1 > kMaxFileSystems)
72    return 0;
73
74  // The file system id is unique per service, so per profile.
75  int file_system_id = next_id_;
76
77  fileapi::ExternalMountPoints* const mount_points =
78      fileapi::ExternalMountPoints::GetSystemInstance();
79  DCHECK(mount_points);
80
81  // The mount point path and name are unique per system, since they are system
82  // wide. This is necessary for copying between profiles.
83  const base::FilePath& mount_point_path =
84      GetMountPointPath(profile_, extension_id, file_system_id);
85  const std::string mount_point_name =
86      mount_point_path.BaseName().AsUTF8Unsafe();
87
88  if (!mount_points->RegisterFileSystem(mount_point_name,
89                                        fileapi::kFileSystemTypeProvided,
90                                        fileapi::FileSystemMountOption(),
91                                        mount_point_path)) {
92    return 0;
93  }
94
95  // Store the file system descriptor. Use the mount point name as the file
96  // system provider file system id.
97  // Examples:
98  //   file_system_id = 41
99  //   mount_point_name = file_system_id = b33f1337-41-5aa5
100  //   mount_point_path = /provided/b33f1337-41-5aa5
101  ProvidedFileSystem file_system(
102      extension_id, file_system_id, file_system_name, mount_point_path);
103  file_systems_[file_system_id] = file_system;
104
105  FOR_EACH_OBSERVER(
106      Observer, observers_, OnProvidedFileSystemRegistered(file_system));
107
108  next_id_++;
109  return file_system_id;
110}
111
112bool Service::UnregisterFileSystem(const std::string& extension_id,
113                                   int file_system_id) {
114  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
115
116  FileSystemMap::iterator file_system_it = file_systems_.find(file_system_id);
117  if (file_system_it == file_systems_.end() ||
118      file_system_it->second.extension_id() != extension_id) {
119    return false;
120  }
121
122  fileapi::ExternalMountPoints* const mount_points =
123      fileapi::ExternalMountPoints::GetSystemInstance();
124  DCHECK(mount_points);
125
126  const std::string mount_point_name =
127      file_system_it->second.mount_path().BaseName().value();
128  if (!mount_points->RevokeFileSystem(mount_point_name))
129    return false;
130
131  FOR_EACH_OBSERVER(Observer,
132                    observers_,
133                    OnProvidedFileSystemUnregistered(file_system_it->second));
134
135  file_systems_.erase(file_system_it);
136  return true;
137}
138
139std::vector<ProvidedFileSystem> Service::GetRegisteredFileSystems() {
140  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
141
142  std::vector<ProvidedFileSystem> result;
143  for (FileSystemMap::const_iterator it = file_systems_.begin();
144       it != file_systems_.end();
145       ++it) {
146    result.push_back(it->second);
147  }
148  return result;
149}
150
151}  // namespace file_system_provider
152}  // namespace chromeos
153