syncable_file_system_util.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright 2013 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/sync_file_system/syncable_file_system_util.h"
6
7#include <vector>
8
9#include "base/command_line.h"
10#include "base/location.h"
11#include "base/strings/string_util.h"
12#include "webkit/browser/fileapi/external_mount_points.h"
13#include "webkit/browser/fileapi/file_observers.h"
14#include "webkit/browser/fileapi/file_system_context.h"
15#include "webkit/common/fileapi/file_system_util.h"
16
17using fileapi::ExternalMountPoints;
18using fileapi::FileSystemContext;
19using fileapi::FileSystemURL;
20
21namespace sync_file_system {
22
23namespace {
24
25// A command switch to enable syncing directory operations in Sync FileSystem
26// API. (http://crbug.com/161442)
27// TODO(kinuko): this command-line switch should be temporary.
28const char kEnableSyncFSDirectoryOperation[] =
29    "enable-syncfs-directory-operation";
30
31// A command switch to enable V2 Sync FileSystem.
32const char kEnableSyncFileSystemV2[] = "enable-syncfs-v2";
33
34// A command switch to specify comma-separated app IDs to enable V2 Sync
35// FileSystem.
36const char kSyncFileSystemV2Whitelist[] = "syncfs-v2-whitelist";
37
38const char kSyncableMountName[] = "syncfs";
39const char kSyncableMountNameForInternalSync[] = "syncfs-internal";
40
41const base::FilePath::CharType kSyncFileSystemDir[] =
42    FILE_PATH_LITERAL("Sync FileSystem");
43const base::FilePath::CharType kSyncFileSystemDirDev[] =
44    FILE_PATH_LITERAL("Sync FileSystem Dev");
45
46// Flags to enable features for testing.
47bool g_is_directory_operation_enabled = false;
48bool g_is_syncfs_v2_enabled = false;
49
50}  // namespace
51
52void RegisterSyncableFileSystem() {
53  ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
54      kSyncableMountName,
55      fileapi::kFileSystemTypeSyncable,
56      fileapi::FileSystemMountOption(),
57      base::FilePath());
58  ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
59      kSyncableMountNameForInternalSync,
60      fileapi::kFileSystemTypeSyncableForInternalSync,
61      fileapi::FileSystemMountOption(),
62      base::FilePath());
63}
64
65void RevokeSyncableFileSystem() {
66  ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
67      kSyncableMountName);
68  ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
69      kSyncableMountNameForInternalSync);
70}
71
72GURL GetSyncableFileSystemRootURI(const GURL& origin) {
73  return GURL(fileapi::GetExternalFileSystemRootURIString(
74      origin, kSyncableMountName));
75}
76
77FileSystemURL CreateSyncableFileSystemURL(const GURL& origin,
78                                          const base::FilePath& path) {
79  base::FilePath path_for_url = path;
80  if (fileapi::VirtualPath::IsAbsolute(path.value()))
81    path_for_url = base::FilePath(path.value().substr(1));
82
83  return ExternalMountPoints::GetSystemInstance()->CreateExternalFileSystemURL(
84      origin, kSyncableMountName, path_for_url);
85}
86
87FileSystemURL CreateSyncableFileSystemURLForSync(
88    fileapi::FileSystemContext* file_system_context,
89    const FileSystemURL& syncable_url) {
90  return ExternalMountPoints::GetSystemInstance()->CreateExternalFileSystemURL(
91      syncable_url.origin(),
92      kSyncableMountNameForInternalSync,
93      syncable_url.path());
94}
95
96bool SerializeSyncableFileSystemURL(const FileSystemURL& url,
97                                    std::string* serialized_url) {
98  if (!url.is_valid() || url.type() != fileapi::kFileSystemTypeSyncable)
99    return false;
100  *serialized_url =
101      GetSyncableFileSystemRootURI(url.origin()).spec() +
102      url.path().AsUTF8Unsafe();
103  return true;
104}
105
106bool DeserializeSyncableFileSystemURL(
107    const std::string& serialized_url, FileSystemURL* url) {
108#if !defined(FILE_PATH_USES_WIN_SEPARATORS)
109  DCHECK(serialized_url.find('\\') == std::string::npos);
110#endif  // FILE_PATH_USES_WIN_SEPARATORS
111
112  FileSystemURL deserialized =
113      ExternalMountPoints::GetSystemInstance()->CrackURL(GURL(serialized_url));
114  if (!deserialized.is_valid() ||
115      deserialized.type() != fileapi::kFileSystemTypeSyncable) {
116    return false;
117  }
118
119  *url = deserialized;
120  return true;
121}
122
123void SetEnableSyncFSDirectoryOperation(bool flag) {
124  g_is_directory_operation_enabled = flag;
125}
126
127bool IsSyncFSDirectoryOperationEnabled() {
128  return IsSyncFSDirectoryOperationEnabled(GURL());
129}
130
131bool IsSyncFSDirectoryOperationEnabled(const GURL& origin) {
132  return g_is_directory_operation_enabled ||
133      CommandLine::ForCurrentProcess()->HasSwitch(
134          kEnableSyncFSDirectoryOperation) ||
135      IsV2EnabledForOrigin(origin);
136}
137
138bool IsV2Enabled() {
139  return g_is_syncfs_v2_enabled ||
140        CommandLine::ForCurrentProcess()->HasSwitch(kEnableSyncFileSystemV2);
141}
142
143bool IsV2EnabledForOrigin(const GURL& origin) {
144  if (IsV2Enabled())
145    return true;
146
147  // Spark release channel.
148  if (origin.host() == "kcjgcakhgelcejampmijgkjkadfcncjl")
149    return true;
150  // Spark dev channel.
151  if (origin.host() == "pnoffddplpippgcfjdhbmhkofpnaalpg")
152    return true;
153
154  CommandLine command_line = *CommandLine::ForCurrentProcess();
155  if (command_line.HasSwitch(kSyncFileSystemV2Whitelist)) {
156    std::string app_ids_string =
157        command_line.GetSwitchValueASCII(kSyncFileSystemV2Whitelist);
158    if (app_ids_string.find(origin.host()) == std::string::npos)
159      return false;
160    std::vector<std::string> app_ids;
161    Tokenize(app_ids_string, ",", &app_ids);
162    for (size_t i = 0; i < app_ids.size(); ++i) {
163      if (origin.host() == app_ids[i])
164        return true;
165    }
166  }
167
168  return false;
169}
170
171base::FilePath GetSyncFileSystemDir(const base::FilePath& profile_base_dir) {
172  if (IsV2Enabled())
173    return profile_base_dir.Append(kSyncFileSystemDir);
174  if (IsSyncFSDirectoryOperationEnabled())
175    return profile_base_dir.Append(kSyncFileSystemDirDev);
176  return profile_base_dir.Append(kSyncFileSystemDir);
177}
178
179ScopedEnableSyncFSDirectoryOperation::ScopedEnableSyncFSDirectoryOperation() {
180  was_enabled_ = IsSyncFSDirectoryOperationEnabled(GURL());
181  SetEnableSyncFSDirectoryOperation(true);
182}
183
184ScopedEnableSyncFSDirectoryOperation::~ScopedEnableSyncFSDirectoryOperation() {
185  DCHECK(IsSyncFSDirectoryOperationEnabled(GURL()));
186  SetEnableSyncFSDirectoryOperation(was_enabled_);
187}
188
189ScopedEnableSyncFSV2::ScopedEnableSyncFSV2() {
190  was_enabled_ = IsV2Enabled();
191  g_is_syncfs_v2_enabled = true;
192}
193
194ScopedEnableSyncFSV2::~ScopedEnableSyncFSV2() {
195  DCHECK(IsV2Enabled());
196  g_is_syncfs_v2_enabled = was_enabled_;
197}
198
199void RunSoon(const tracked_objects::Location& from_here,
200             const base::Closure& callback) {
201  base::MessageLoop::current()->PostTask(from_here, callback);
202}
203
204}  // namespace sync_file_system
205