OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "webkit/fileapi/file_system_util.h" | |
6 | |
7 #include "build/build_config.h" | |
8 | |
9 #include "base/files/file_path.h" | |
10 #include "base/logging.h" | |
11 #include "base/string_util.h" | |
12 #include "base/strings/sys_string_conversions.h" | |
13 #include "base/utf_string_conversions.h" | |
14 #include "googleurl/src/gurl.h" | |
15 #include "third_party/WebKit/Source/Platform/chromium/public/WebCString.h" | |
16 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" | |
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" | |
18 #include "webkit/base/origin_url_conversions.h" | |
19 | |
20 namespace fileapi { | |
21 | |
22 const char kPersistentDir[] = "/persistent"; | |
23 const char kTemporaryDir[] = "/temporary"; | |
24 const char kIsolatedDir[] = "/isolated"; | |
25 const char kExternalDir[] = "/external"; | |
26 const char kTestDir[] = "/test"; | |
27 | |
28 const base::FilePath::CharType VirtualPath::kRoot[] = FILE_PATH_LITERAL("/"); | |
29 const base::FilePath::CharType VirtualPath::kSeparator = FILE_PATH_LITERAL('/'); | |
30 | |
31 // TODO(ericu): Consider removing support for '\', even on Windows, if possible. | |
32 // There's a lot of test code that will need reworking, and we may have trouble | |
33 // with base::FilePath elsewhere [e.g. DirName and other methods may also need | |
34 // replacement]. | |
35 base::FilePath VirtualPath::BaseName(const base::FilePath& virtual_path) { | |
36 base::FilePath::StringType path = virtual_path.value(); | |
37 | |
38 // Keep everything after the final separator, but if the pathname is only | |
39 // one character and it's a separator, leave it alone. | |
40 while (path.size() > 1 && base::FilePath::IsSeparator(path[path.size() - 1])) | |
41 path.resize(path.size() - 1); | |
42 base::FilePath::StringType::size_type last_separator = | |
43 path.find_last_of(base::FilePath::kSeparators); | |
44 if (last_separator != base::FilePath::StringType::npos && | |
45 last_separator < path.size() - 1) | |
46 path.erase(0, last_separator + 1); | |
47 | |
48 return base::FilePath(path); | |
49 } | |
50 | |
51 base::FilePath VirtualPath::DirName(const base::FilePath& virtual_path) { | |
52 typedef base::FilePath::StringType StringType; | |
53 StringType path = virtual_path.value(); | |
54 | |
55 // The logic below is taken from that of base::FilePath::DirName, except | |
56 // that this version never cares about '//' or drive-letters even on win32. | |
57 | |
58 // Strip trailing separators. | |
59 while (path.size() > 1 && base::FilePath::IsSeparator(path[path.size() - 1])) | |
60 path.resize(path.size() - 1); | |
61 | |
62 StringType::size_type last_separator = | |
63 path.find_last_of(base::FilePath::kSeparators); | |
64 if (last_separator == StringType::npos) { | |
65 // path_ is in the current directory. | |
66 return base::FilePath(base::FilePath::kCurrentDirectory); | |
67 } | |
68 if (last_separator == 0) { | |
69 // path_ is in the root directory. | |
70 return base::FilePath(path.substr(0, 1)); | |
71 } | |
72 // path_ is somewhere else, trim the basename. | |
73 path.resize(last_separator); | |
74 | |
75 // Strip trailing separators. | |
76 while (path.size() > 1 && base::FilePath::IsSeparator(path[path.size() - 1])) | |
77 path.resize(path.size() - 1); | |
78 | |
79 if (path.empty()) | |
80 return base::FilePath(base::FilePath::kCurrentDirectory); | |
81 | |
82 return base::FilePath(path); | |
83 } | |
84 | |
85 void VirtualPath::GetComponents( | |
86 const base::FilePath& path, | |
87 std::vector<base::FilePath::StringType>* components) { | |
88 typedef base::FilePath::StringType StringType; | |
89 | |
90 DCHECK(components); | |
91 if (!components) | |
92 return; | |
93 components->clear(); | |
94 if (path.value().empty()) | |
95 return; | |
96 | |
97 StringType::size_type begin = 0, end = 0; | |
98 while (begin < path.value().length() && end != StringType::npos) { | |
99 end = path.value().find_first_of(base::FilePath::kSeparators, begin); | |
100 StringType component = path.value().substr( | |
101 begin, end == StringType::npos ? StringType::npos : end - begin); | |
102 if (!component.empty() && component != base::FilePath::kCurrentDirectory) | |
103 components->push_back(component); | |
104 begin = end + 1; | |
105 } | |
106 } | |
107 | |
108 base::FilePath::StringType VirtualPath::GetNormalizedFilePath( | |
109 const base::FilePath& path) { | |
110 base::FilePath::StringType normalized_path = path.value(); | |
111 const size_t num_separators = base::FilePath::StringType( | |
112 base::FilePath::kSeparators).length(); | |
113 for (size_t i = 0; i < num_separators; ++i) { | |
114 std::replace(normalized_path.begin(), normalized_path.end(), | |
115 base::FilePath::kSeparators[i], kSeparator); | |
116 } | |
117 | |
118 return (IsAbsolute(normalized_path)) ? | |
119 normalized_path : base::FilePath::StringType(kRoot) + normalized_path; | |
120 } | |
121 | |
122 bool VirtualPath::IsAbsolute(const base::FilePath::StringType& path) { | |
123 return path.find(kRoot) == 0; | |
124 } | |
125 | |
126 GURL GetFileSystemRootURI(const GURL& origin_url, FileSystemType type) { | |
127 // origin_url is based on a security origin, so http://foo.com or file:/// | |
128 // instead of the corresponding filesystem URL. | |
129 DCHECK(!origin_url.SchemeIsFileSystem()); | |
130 | |
131 std::string url = "filesystem:" + origin_url.GetWithEmptyPath().spec(); | |
132 switch (type) { | |
133 case kFileSystemTypeTemporary: | |
134 url += (kTemporaryDir + 1); // We don't want the leading slash. | |
135 return GURL(url + "/"); | |
136 case kFileSystemTypePersistent: | |
137 url += (kPersistentDir + 1); // We don't want the leading slash. | |
138 return GURL(url + "/"); | |
139 case kFileSystemTypeExternal: | |
140 url += (kExternalDir + 1); // We don't want the leading slash. | |
141 return GURL(url + "/"); | |
142 case kFileSystemTypeIsolated: | |
143 url += (kIsolatedDir + 1); // We don't want the leading slash. | |
144 return GURL(url + "/"); | |
145 case kFileSystemTypeTest: | |
146 url += (kTestDir + 1); // We don't want the leading slash. | |
147 return GURL(url + "/"); | |
148 // Internal types are always pointed via isolated or external URLs. | |
149 default: | |
150 NOTREACHED(); | |
151 } | |
152 NOTREACHED(); | |
153 return GURL(); | |
154 } | |
155 | |
156 std::string GetFileSystemName(const GURL& origin_url, FileSystemType type) { | |
157 base::string16 origin_identifier = | |
158 webkit_base::GetOriginIdentifierFromURL(origin_url); | |
159 std::string type_string = GetFileSystemTypeString(type); | |
160 DCHECK(!type_string.empty()); | |
161 return UTF16ToUTF8(origin_identifier) + ":" + type_string; | |
162 } | |
163 | |
164 FileSystemType QuotaStorageTypeToFileSystemType( | |
165 quota::StorageType storage_type) { | |
166 switch (storage_type) { | |
167 case quota::kStorageTypeTemporary: | |
168 return kFileSystemTypeTemporary; | |
169 case quota::kStorageTypePersistent: | |
170 return kFileSystemTypePersistent; | |
171 case quota::kStorageTypeSyncable: | |
172 return kFileSystemTypeSyncable; | |
173 case quota::kStorageTypeUnknown: | |
174 return kFileSystemTypeUnknown; | |
175 } | |
176 return kFileSystemTypeUnknown; | |
177 } | |
178 | |
179 quota::StorageType FileSystemTypeToQuotaStorageType(FileSystemType type) { | |
180 switch (type) { | |
181 case kFileSystemTypeTemporary: | |
182 return quota::kStorageTypeTemporary; | |
183 case kFileSystemTypePersistent: | |
184 return quota::kStorageTypePersistent; | |
185 case kFileSystemTypeSyncable: | |
186 return quota::kStorageTypeSyncable; | |
187 default: | |
188 return quota::kStorageTypeUnknown; | |
189 } | |
190 } | |
191 | |
192 std::string GetFileSystemTypeString(FileSystemType type) { | |
193 switch (type) { | |
194 case kFileSystemTypeTemporary: | |
195 return "Temporary"; | |
196 case kFileSystemTypePersistent: | |
197 return "Persistent"; | |
198 case kFileSystemTypeIsolated: | |
199 return "Isolated"; | |
200 case kFileSystemTypeExternal: | |
201 return "External"; | |
202 case kFileSystemTypeTest: | |
203 return "Test"; | |
204 case kFileSystemTypeNativeLocal: | |
205 return "NativeLocal"; | |
206 case kFileSystemTypeRestrictedNativeLocal: | |
207 return "RestrictedNativeLocal"; | |
208 case kFileSystemTypeDragged: | |
209 return "Dragged"; | |
210 case kFileSystemTypeNativeMedia: | |
211 return "NativeMedia"; | |
212 case kFileSystemTypeDeviceMedia: | |
213 return "DeviceMedia"; | |
214 case kFileSystemTypePicasa: | |
215 return "Picasa"; | |
216 case kFileSystemTypeItunes: | |
217 return "Itunes"; | |
218 case kFileSystemTypeDrive: | |
219 return "Drive"; | |
220 case kFileSystemTypeSyncable: | |
221 return "Syncable"; | |
222 case kFileSystemTypeNativeForPlatformApp: | |
223 return "NativeForPlatformApp"; | |
224 case kFileSystemTypeForTransientFile: | |
225 return "TransientFile"; | |
226 case kFileSystemInternalTypeEnumStart: | |
227 case kFileSystemInternalTypeEnumEnd: | |
228 NOTREACHED(); | |
229 // Fall through. | |
230 case kFileSystemTypeUnknown: | |
231 return "Unknown"; | |
232 } | |
233 NOTREACHED(); | |
234 return std::string(); | |
235 } | |
236 | |
237 std::string FilePathToString(const base::FilePath& file_path) { | |
238 #if defined(OS_WIN) | |
239 return UTF16ToUTF8(file_path.value()); | |
240 #elif defined(OS_POSIX) | |
241 return file_path.value(); | |
242 #endif | |
243 } | |
244 | |
245 base::FilePath StringToFilePath(const std::string& file_path_string) { | |
246 #if defined(OS_WIN) | |
247 return base::FilePath(UTF8ToUTF16(file_path_string)); | |
248 #elif defined(OS_POSIX) | |
249 return base::FilePath(file_path_string); | |
250 #endif | |
251 } | |
252 | |
253 WebKit::WebFileError PlatformFileErrorToWebFileError( | |
254 base::PlatformFileError error_code) { | |
255 switch (error_code) { | |
256 case base::PLATFORM_FILE_ERROR_NOT_FOUND: | |
257 return WebKit::WebFileErrorNotFound; | |
258 case base::PLATFORM_FILE_ERROR_INVALID_OPERATION: | |
259 case base::PLATFORM_FILE_ERROR_EXISTS: | |
260 case base::PLATFORM_FILE_ERROR_NOT_EMPTY: | |
261 return WebKit::WebFileErrorInvalidModification; | |
262 case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY: | |
263 case base::PLATFORM_FILE_ERROR_NOT_A_FILE: | |
264 return WebKit::WebFileErrorTypeMismatch; | |
265 case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: | |
266 return WebKit::WebFileErrorNoModificationAllowed; | |
267 case base::PLATFORM_FILE_ERROR_FAILED: | |
268 return WebKit::WebFileErrorInvalidState; | |
269 case base::PLATFORM_FILE_ERROR_ABORT: | |
270 return WebKit::WebFileErrorAbort; | |
271 case base::PLATFORM_FILE_ERROR_SECURITY: | |
272 return WebKit::WebFileErrorSecurity; | |
273 case base::PLATFORM_FILE_ERROR_NO_SPACE: | |
274 return WebKit::WebFileErrorQuotaExceeded; | |
275 default: | |
276 return WebKit::WebFileErrorInvalidModification; | |
277 } | |
278 } | |
279 | |
280 bool GetFileSystemPublicType( | |
281 const std::string type_string, | |
282 WebKit::WebFileSystemType* type | |
283 ) { | |
284 DCHECK(type); | |
285 if (type_string == "Temporary") { | |
286 *type = WebKit::WebFileSystemTypeTemporary; | |
287 return true; | |
288 } | |
289 if (type_string == "Persistent") { | |
290 *type = WebKit::WebFileSystemTypePersistent; | |
291 return true; | |
292 } | |
293 if (type_string == "Isolated") { | |
294 *type = WebKit::WebFileSystemTypeIsolated; | |
295 return true; | |
296 } | |
297 if (type_string == "External") { | |
298 *type = WebKit::WebFileSystemTypeExternal; | |
299 return true; | |
300 } | |
301 NOTREACHED(); | |
302 return false; | |
303 } | |
304 | |
305 std::string GetIsolatedFileSystemName(const GURL& origin_url, | |
306 const std::string& filesystem_id) { | |
307 std::string name(fileapi::GetFileSystemName(origin_url, | |
308 fileapi::kFileSystemTypeIsolated)); | |
309 name.append("_"); | |
310 name.append(filesystem_id); | |
311 return name; | |
312 } | |
313 | |
314 bool CrackIsolatedFileSystemName(const std::string& filesystem_name, | |
315 std::string* filesystem_id) { | |
316 DCHECK(filesystem_id); | |
317 | |
318 // |filesystem_name| is of the form {origin}:isolated_{filesystem_id}. | |
319 std::string start_token(":"); | |
320 start_token = start_token.append( | |
321 GetFileSystemTypeString(kFileSystemTypeIsolated)).append("_"); | |
322 // WebKit uses different case in its constant for isolated file system | |
323 // names, so we do a case insensitive compare by converting both strings | |
324 // to uppercase. | |
325 // TODO(benwells): Remove this when WebKit uses the same constant. | |
326 start_token = StringToUpperASCII(start_token); | |
327 std::string filesystem_name_upper = StringToUpperASCII(filesystem_name); | |
328 size_t pos = filesystem_name_upper.find(start_token); | |
329 if (pos == std::string::npos) | |
330 return false; | |
331 if (pos == 0) | |
332 return false; | |
333 | |
334 *filesystem_id = filesystem_name.substr(pos + start_token.length(), | |
335 std::string::npos); | |
336 if (filesystem_id->empty()) | |
337 return false; | |
338 | |
339 return true; | |
340 } | |
341 | |
342 std::string GetIsolatedFileSystemRootURIString( | |
343 const GURL& origin_url, | |
344 const std::string& filesystem_id, | |
345 const std::string& optional_root_name) { | |
346 std::string root = GetFileSystemRootURI(origin_url, | |
347 kFileSystemTypeIsolated).spec(); | |
348 if (base::FilePath::FromUTF8Unsafe(filesystem_id).ReferencesParent()) | |
349 return std::string(); | |
350 root.append(filesystem_id); | |
351 root.append("/"); | |
352 if (!optional_root_name.empty()) { | |
353 if (base::FilePath::FromUTF8Unsafe(optional_root_name).ReferencesParent()) | |
354 return std::string(); | |
355 root.append(optional_root_name); | |
356 root.append("/"); | |
357 } | |
358 return root; | |
359 } | |
360 | |
361 } // namespace fileapi | |
OLD | NEW |