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/mount_path_util.h"
6
7#include <vector>
8
9#include "base/stl_util.h"
10#include "base/strings/stringprintf.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/chromeos/file_system_provider/provided_file_system.h"
13#include "chrome/browser/chromeos/file_system_provider/service.h"
14#include "chrome/browser/chromeos/profiles/profile_helper.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/browser/profiles/profile_manager.h"
17#include "components/user_manager/user.h"
18#include "components/user_manager/user_manager.h"
19#include "content/public/browser/browser_thread.h"
20
21using content::BrowserThread;
22
23namespace chromeos {
24namespace file_system_provider {
25namespace util {
26
27namespace {
28
29// Root mount path for all of the provided file systems.
30const base::FilePath::CharType kProvidedMountPointRoot[] =
31    FILE_PATH_LITERAL("/provided");
32
33}  // namespace
34
35// Escapes the file system id so it can be used as a file/directory name.
36// This is based on net/base/escape.cc: net::(anonymous namespace)::Escape
37std::string EscapeFileSystemId(const std::string& file_system_id) {
38  std::string escaped;
39  for (size_t i = 0; i < file_system_id.size(); ++i) {
40    const char c = file_system_id[i];
41    if (c == '%' || c == '.' || c == '/') {
42      base::StringAppendF(&escaped, "%%%02X", c);
43    } else {
44      escaped.push_back(c);
45    }
46  }
47  return escaped;
48}
49
50base::FilePath GetMountPath(Profile* profile,
51                            const std::string& extension_id,
52                            const std::string& file_system_id) {
53  user_manager::User* const user =
54      user_manager::UserManager::IsInitialized()
55          ? chromeos::ProfileHelper::Get()->GetUserByProfile(
56                profile->GetOriginalProfile())
57          : NULL;
58  const std::string safe_file_system_id = EscapeFileSystemId(file_system_id);
59  const std::string username_suffix = user ? user->username_hash() : "";
60  return base::FilePath(kProvidedMountPointRoot).AppendASCII(
61      extension_id + ":" + safe_file_system_id + ":" + username_suffix);
62}
63
64bool IsFileSystemProviderLocalPath(const base::FilePath& local_path) {
65  std::vector<base::FilePath::StringType> components;
66  local_path.GetComponents(&components);
67
68  if (components.size() < 3)
69    return false;
70
71  if (components[0] != FILE_PATH_LITERAL("/"))
72    return false;
73
74  if (components[1] != kProvidedMountPointRoot + 1 /* no leading slash */)
75    return false;
76
77  return true;
78}
79
80FileSystemURLParser::FileSystemURLParser(const storage::FileSystemURL& url)
81    : url_(url), file_system_(NULL) {
82}
83
84FileSystemURLParser::~FileSystemURLParser() {
85}
86
87bool FileSystemURLParser::Parse() {
88  DCHECK_CURRENTLY_ON(BrowserThread::UI);
89
90  if (url_.type() != storage::kFileSystemTypeProvided)
91    return false;
92
93  // First, find the service handling the mount point of the URL.
94  const std::vector<Profile*>& profiles =
95      g_browser_process->profile_manager()->GetLoadedProfiles();
96
97  for (size_t i = 0; i < profiles.size(); ++i) {
98    Profile* original_profile = profiles[i]->GetOriginalProfile();
99
100    if (original_profile != profiles[i] ||
101        chromeos::ProfileHelper::IsSigninProfile(original_profile)) {
102      continue;
103    }
104
105    Service* const service = Service::Get(original_profile);
106    if (!service)
107      continue;
108
109    ProvidedFileSystemInterface* const file_system =
110        service->GetProvidedFileSystem(url_.filesystem_id());
111    if (!file_system)
112      continue;
113
114    // Strip the mount path name from the local path, to extract the file path
115    // within the provided file system.
116    file_system_ = file_system;
117    std::vector<base::FilePath::StringType> components;
118    url_.path().GetComponents(&components);
119    if (components.size() < 3)
120      return false;
121
122    file_path_ = base::FilePath::FromUTF8Unsafe("/");
123    for (size_t i = 3; i < components.size(); ++i) {
124      // TODO(mtomasz): This could be optimized, to avoid unnecessary copies.
125      file_path_ = file_path_.Append(components[i]);
126    }
127
128    return true;
129  }
130
131  // Nothing has been found.
132  return false;
133}
134
135LocalPathParser::LocalPathParser(Profile* profile,
136                                 const base::FilePath& local_path)
137    : profile_(profile), local_path_(local_path), file_system_(NULL) {
138}
139
140LocalPathParser::~LocalPathParser() {
141}
142
143bool LocalPathParser::Parse() {
144  DCHECK_CURRENTLY_ON(BrowserThread::UI);
145
146  if (!IsFileSystemProviderLocalPath(local_path_))
147    return false;
148
149  std::vector<base::FilePath::StringType> components;
150  local_path_.GetComponents(&components);
151
152  if (components.size() < 3)
153    return false;
154
155  const std::string mount_point_name = components[2];
156
157  Service* const service = Service::Get(profile_);
158  if (!service)
159    return false;
160
161  ProvidedFileSystemInterface* const file_system =
162      service->GetProvidedFileSystem(mount_point_name);
163  if (!file_system)
164    return false;
165
166  // Strip the mount point path from the virtual path, to extract the file
167  // path within the provided file system.
168  file_system_ = file_system;
169  file_path_ = base::FilePath::FromUTF8Unsafe("/");
170  for (size_t i = 3; i < components.size(); ++i) {
171    file_path_ = file_path_.Append(components[i]);
172  }
173
174  return true;
175}
176
177}  // namespace util
178}  // namespace file_system_provider
179}  // namespace chromeos
180