Update V8 to version 4.7.42.
[chromium-blink-merge.git] / storage / common / fileapi / file_system_util.cc
blob16d74e44427dc58e683ff880f37bc06cae0cd32a
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.
5 #include "storage/common/fileapi/file_system_util.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "net/base/escape.h"
14 #include "net/base/net_errors.h"
15 #include "storage/common/database/database_identifier.h"
16 #include "url/gurl.h"
18 namespace storage {
20 const char kPersistentDir[] = "/persistent";
21 const char kTemporaryDir[] = "/temporary";
22 const char kIsolatedDir[] = "/isolated";
23 const char kExternalDir[] = "/external";
24 const char kTestDir[] = "/test";
26 const base::FilePath::CharType VirtualPath::kRoot[] = FILE_PATH_LITERAL("/");
27 const base::FilePath::CharType VirtualPath::kSeparator = FILE_PATH_LITERAL('/');
29 // TODO(ericu): Consider removing support for '\', even on Windows, if possible.
30 // There's a lot of test code that will need reworking, and we may have trouble
31 // with base::FilePath elsewhere [e.g. DirName and other methods may also need
32 // replacement].
33 base::FilePath VirtualPath::BaseName(const base::FilePath& virtual_path) {
34 base::FilePath::StringType path = virtual_path.value();
36 // Keep everything after the final separator, but if the pathname is only
37 // one character and it's a separator, leave it alone.
38 while (path.size() > 1 && base::FilePath::IsSeparator(path[path.size() - 1]))
39 path.resize(path.size() - 1);
40 base::FilePath::StringType::size_type last_separator =
41 path.find_last_of(base::FilePath::kSeparators);
42 if (last_separator != base::FilePath::StringType::npos &&
43 last_separator < path.size() - 1)
44 path.erase(0, last_separator + 1);
46 return base::FilePath(path);
49 base::FilePath VirtualPath::DirName(const base::FilePath& virtual_path) {
50 typedef base::FilePath::StringType StringType;
51 StringType path = virtual_path.value();
53 // The logic below is taken from that of base::FilePath::DirName, except
54 // that this version never cares about '//' or drive-letters even on win32.
56 // Strip trailing separators.
57 while (path.size() > 1 && base::FilePath::IsSeparator(path[path.size() - 1]))
58 path.resize(path.size() - 1);
60 StringType::size_type last_separator =
61 path.find_last_of(base::FilePath::kSeparators);
62 if (last_separator == StringType::npos) {
63 // path_ is in the current directory.
64 return base::FilePath(base::FilePath::kCurrentDirectory);
66 if (last_separator == 0) {
67 // path_ is in the root directory.
68 return base::FilePath(path.substr(0, 1));
70 // path_ is somewhere else, trim the basename.
71 path.resize(last_separator);
73 // Strip trailing separators.
74 while (path.size() > 1 && base::FilePath::IsSeparator(path[path.size() - 1]))
75 path.resize(path.size() - 1);
77 if (path.empty())
78 return base::FilePath(base::FilePath::kCurrentDirectory);
80 return base::FilePath(path);
83 void VirtualPath::GetComponents(
84 const base::FilePath& path,
85 std::vector<base::FilePath::StringType>* components) {
86 typedef base::FilePath::StringType StringType;
88 DCHECK(components);
89 if (!components)
90 return;
91 components->clear();
92 if (path.value().empty())
93 return;
95 StringType::size_type begin = 0, end = 0;
96 while (begin < path.value().length() && end != StringType::npos) {
97 end = path.value().find_first_of(base::FilePath::kSeparators, begin);
98 StringType component = path.value().substr(
99 begin, end == StringType::npos ? StringType::npos : end - begin);
100 if (!component.empty() && component != base::FilePath::kCurrentDirectory)
101 components->push_back(component);
102 begin = end + 1;
106 void VirtualPath::GetComponentsUTF8Unsafe(
107 const base::FilePath& path,
108 std::vector<std::string>* components) {
109 DCHECK(components);
110 if (!components)
111 return;
112 components->clear();
114 std::vector<base::FilePath::StringType> stringtype_components;
115 VirtualPath::GetComponents(path, &stringtype_components);
116 std::vector<base::FilePath::StringType>::const_iterator it;
117 for (it = stringtype_components.begin(); it != stringtype_components.end();
118 ++it) {
119 components->push_back(base::FilePath(*it).AsUTF8Unsafe());
123 base::FilePath::StringType VirtualPath::GetNormalizedFilePath(
124 const base::FilePath& path) {
125 base::FilePath::StringType normalized_path = path.value();
126 const size_t num_separators = base::FilePath::StringType(
127 base::FilePath::kSeparators).length();
128 for (size_t i = 0; i < num_separators; ++i) {
129 std::replace(normalized_path.begin(), normalized_path.end(),
130 base::FilePath::kSeparators[i], kSeparator);
133 return (IsAbsolute(normalized_path)) ?
134 normalized_path : base::FilePath::StringType(kRoot) + normalized_path;
137 bool VirtualPath::IsAbsolute(const base::FilePath::StringType& path) {
138 return path.find(kRoot) == 0;
141 bool VirtualPath::IsRootPath(const base::FilePath& path) {
142 std::vector<base::FilePath::StringType> components;
143 VirtualPath::GetComponents(path, &components);
144 return (path.empty() || components.empty() ||
145 (components.size() == 1 &&
146 components[0] == VirtualPath::kRoot));
149 bool ParseFileSystemSchemeURL(const GURL& url,
150 GURL* origin_url,
151 FileSystemType* type,
152 base::FilePath* virtual_path) {
153 GURL origin;
154 FileSystemType file_system_type = kFileSystemTypeUnknown;
156 if (!url.is_valid() || !url.SchemeIsFileSystem())
157 return false;
159 const struct {
160 FileSystemType type;
161 const char* dir;
162 } kValidTypes[] = {
163 { kFileSystemTypePersistent, kPersistentDir },
164 { kFileSystemTypeTemporary, kTemporaryDir },
165 { kFileSystemTypeIsolated, kIsolatedDir },
166 { kFileSystemTypeExternal, kExternalDir },
167 { kFileSystemTypeTest, kTestDir },
170 // A path of the inner_url contains only mount type part (e.g. "/temporary").
171 DCHECK(url.inner_url());
172 std::string inner_path = url.inner_url()->path();
173 for (size_t i = 0; i < arraysize(kValidTypes); ++i) {
174 if (inner_path == kValidTypes[i].dir) {
175 file_system_type = kValidTypes[i].type;
176 break;
180 if (file_system_type == kFileSystemTypeUnknown)
181 return false;
183 std::string path = net::UnescapeURLComponent(url.path(),
184 net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS |
185 net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS);
187 // Ensure the path is relative.
188 while (!path.empty() && path[0] == '/')
189 path.erase(0, 1);
191 base::FilePath converted_path = base::FilePath::FromUTF8Unsafe(path);
193 // All parent references should have been resolved in the renderer.
194 if (converted_path.ReferencesParent())
195 return false;
197 if (origin_url)
198 *origin_url = url.GetOrigin();
199 if (type)
200 *type = file_system_type;
201 if (virtual_path)
202 *virtual_path = converted_path.NormalizePathSeparators().
203 StripTrailingSeparators();
205 return true;
208 GURL GetFileSystemRootURI(const GURL& origin_url, FileSystemType type) {
209 // origin_url is based on a security origin, so http://foo.com or file:///
210 // instead of the corresponding filesystem URL.
211 DCHECK(!origin_url.SchemeIsFileSystem());
213 std::string url = "filesystem:" + origin_url.GetWithEmptyPath().spec();
214 switch (type) {
215 case kFileSystemTypeTemporary:
216 url += (kTemporaryDir + 1); // We don't want the leading slash.
217 return GURL(url + "/");
218 case kFileSystemTypePersistent:
219 url += (kPersistentDir + 1); // We don't want the leading slash.
220 return GURL(url + "/");
221 case kFileSystemTypeExternal:
222 url += (kExternalDir + 1); // We don't want the leading slash.
223 return GURL(url + "/");
224 case kFileSystemTypeIsolated:
225 url += (kIsolatedDir + 1); // We don't want the leading slash.
226 return GURL(url + "/");
227 case kFileSystemTypeTest:
228 url += (kTestDir + 1); // We don't want the leading slash.
229 return GURL(url + "/");
230 // Internal types are always pointed via isolated or external URLs.
231 default:
232 NOTREACHED();
234 NOTREACHED();
235 return GURL();
238 std::string GetFileSystemName(const GURL& origin_url, FileSystemType type) {
239 std::string origin_identifier = storage::GetIdentifierFromOrigin(origin_url);
240 std::string type_string = GetFileSystemTypeString(type);
241 DCHECK(!type_string.empty());
242 return origin_identifier + ":" + type_string;
245 FileSystemType QuotaStorageTypeToFileSystemType(
246 storage::StorageType storage_type) {
247 switch (storage_type) {
248 case storage::kStorageTypeTemporary:
249 return kFileSystemTypeTemporary;
250 case storage::kStorageTypePersistent:
251 return kFileSystemTypePersistent;
252 case storage::kStorageTypeSyncable:
253 return kFileSystemTypeSyncable;
254 case storage::kStorageTypeQuotaNotManaged:
255 case storage::kStorageTypeUnknown:
256 return kFileSystemTypeUnknown;
258 return kFileSystemTypeUnknown;
261 storage::StorageType FileSystemTypeToQuotaStorageType(FileSystemType type) {
262 switch (type) {
263 case kFileSystemTypeTemporary:
264 return storage::kStorageTypeTemporary;
265 case kFileSystemTypePersistent:
266 return storage::kStorageTypePersistent;
267 case kFileSystemTypeSyncable:
268 case kFileSystemTypeSyncableForInternalSync:
269 return storage::kStorageTypeSyncable;
270 case kFileSystemTypePluginPrivate:
271 return storage::kStorageTypeQuotaNotManaged;
272 default:
273 return storage::kStorageTypeUnknown;
277 std::string GetFileSystemTypeString(FileSystemType type) {
278 switch (type) {
279 case kFileSystemTypeTemporary:
280 return "Temporary";
281 case kFileSystemTypePersistent:
282 return "Persistent";
283 case kFileSystemTypeIsolated:
284 return "Isolated";
285 case kFileSystemTypeExternal:
286 return "External";
287 case kFileSystemTypeTest:
288 return "Test";
289 case kFileSystemTypeNativeLocal:
290 return "NativeLocal";
291 case kFileSystemTypeRestrictedNativeLocal:
292 return "RestrictedNativeLocal";
293 case kFileSystemTypeDragged:
294 return "Dragged";
295 case kFileSystemTypeNativeMedia:
296 return "NativeMedia";
297 case kFileSystemTypeDeviceMedia:
298 return "DeviceMedia";
299 case kFileSystemTypePicasa:
300 return "Picasa";
301 case kFileSystemTypeItunes:
302 return "Itunes";
303 case kFileSystemTypeIphoto:
304 return "Iphoto";
305 case kFileSystemTypeDrive:
306 return "Drive";
307 case kFileSystemTypeSyncable:
308 case kFileSystemTypeSyncableForInternalSync:
309 return "Syncable";
310 case kFileSystemTypeNativeForPlatformApp:
311 return "NativeForPlatformApp";
312 case kFileSystemTypeForTransientFile:
313 return "TransientFile";
314 case kFileSystemTypePluginPrivate:
315 return "PluginPrivate";
316 case kFileSystemTypeCloudDevice:
317 return "CloudDevice";
318 case kFileSystemTypeProvided:
319 return "Provided";
320 case kFileSystemTypeDeviceMediaAsFileStorage:
321 return "DeviceMediaStorage";
322 case kFileSystemInternalTypeEnumStart:
323 case kFileSystemInternalTypeEnumEnd:
324 NOTREACHED();
325 // Fall through.
326 case kFileSystemTypeUnknown:
327 return "Unknown";
329 NOTREACHED();
330 return std::string();
333 std::string FilePathToString(const base::FilePath& file_path) {
334 #if defined(OS_WIN)
335 return base::UTF16ToUTF8(file_path.value());
336 #elif defined(OS_POSIX)
337 return file_path.value();
338 #endif
341 base::FilePath StringToFilePath(const std::string& file_path_string) {
342 #if defined(OS_WIN)
343 return base::FilePath(base::UTF8ToUTF16(file_path_string));
344 #elif defined(OS_POSIX)
345 return base::FilePath(file_path_string);
346 #endif
349 blink::WebFileError FileErrorToWebFileError(
350 base::File::Error error_code) {
351 switch (error_code) {
352 case base::File::FILE_ERROR_NOT_FOUND:
353 return blink::WebFileErrorNotFound;
354 case base::File::FILE_ERROR_INVALID_OPERATION:
355 case base::File::FILE_ERROR_EXISTS:
356 case base::File::FILE_ERROR_NOT_EMPTY:
357 return blink::WebFileErrorInvalidModification;
358 case base::File::FILE_ERROR_NOT_A_DIRECTORY:
359 case base::File::FILE_ERROR_NOT_A_FILE:
360 return blink::WebFileErrorTypeMismatch;
361 case base::File::FILE_ERROR_ACCESS_DENIED:
362 return blink::WebFileErrorNoModificationAllowed;
363 case base::File::FILE_ERROR_FAILED:
364 return blink::WebFileErrorInvalidState;
365 case base::File::FILE_ERROR_ABORT:
366 return blink::WebFileErrorAbort;
367 case base::File::FILE_ERROR_SECURITY:
368 return blink::WebFileErrorSecurity;
369 case base::File::FILE_ERROR_NO_SPACE:
370 return blink::WebFileErrorQuotaExceeded;
371 case base::File::FILE_ERROR_INVALID_URL:
372 return blink::WebFileErrorEncoding;
373 default:
374 return blink::WebFileErrorInvalidModification;
378 bool GetFileSystemPublicType(
379 const std::string type_string,
380 blink::WebFileSystemType* type) {
381 DCHECK(type);
382 if (type_string == "Temporary") {
383 *type = blink::WebFileSystemTypeTemporary;
384 return true;
386 if (type_string == "Persistent") {
387 *type = blink::WebFileSystemTypePersistent;
388 return true;
390 if (type_string == "Isolated") {
391 *type = blink::WebFileSystemTypeIsolated;
392 return true;
394 if (type_string == "External") {
395 *type = blink::WebFileSystemTypeExternal;
396 return true;
398 NOTREACHED();
399 return false;
402 std::string GetIsolatedFileSystemName(const GURL& origin_url,
403 const std::string& filesystem_id) {
404 std::string name(
405 storage::GetFileSystemName(origin_url, storage::kFileSystemTypeIsolated));
406 name.append("_");
407 name.append(filesystem_id);
408 return name;
411 bool CrackIsolatedFileSystemName(const std::string& filesystem_name,
412 std::string* filesystem_id) {
413 DCHECK(filesystem_id);
415 // |filesystem_name| is of the form {origin}:isolated_{filesystem_id}.
416 std::string start_token(":");
417 start_token = start_token.append(
418 GetFileSystemTypeString(kFileSystemTypeIsolated)).append("_");
419 // WebKit uses different case in its constant for isolated file system
420 // names, so we do a case insensitive compare by converting both strings
421 // to uppercase.
422 // TODO(benwells): Remove this when WebKit uses the same constant.
423 start_token = base::ToUpperASCII(start_token);
424 std::string filesystem_name_upper = base::ToUpperASCII(filesystem_name);
425 size_t pos = filesystem_name_upper.find(start_token);
426 if (pos == std::string::npos)
427 return false;
428 if (pos == 0)
429 return false;
431 *filesystem_id = filesystem_name.substr(pos + start_token.length(),
432 std::string::npos);
433 if (filesystem_id->empty())
434 return false;
436 return true;
439 bool ValidateIsolatedFileSystemId(const std::string& filesystem_id) {
440 const size_t kExpectedFileSystemIdSize = 32;
441 if (filesystem_id.size() != kExpectedFileSystemIdSize)
442 return false;
443 const std::string kExpectedChars("ABCDEF0123456789");
444 return base::ContainsOnlyChars(filesystem_id, kExpectedChars);
447 std::string GetIsolatedFileSystemRootURIString(
448 const GURL& origin_url,
449 const std::string& filesystem_id,
450 const std::string& optional_root_name) {
451 std::string root = GetFileSystemRootURI(origin_url,
452 kFileSystemTypeIsolated).spec();
453 if (base::FilePath::FromUTF8Unsafe(filesystem_id).ReferencesParent())
454 return std::string();
455 root.append(net::EscapePath(filesystem_id));
456 root.append("/");
457 if (!optional_root_name.empty()) {
458 if (base::FilePath::FromUTF8Unsafe(optional_root_name).ReferencesParent())
459 return std::string();
460 root.append(net::EscapePath(optional_root_name));
461 root.append("/");
463 return root;
466 std::string GetExternalFileSystemRootURIString(
467 const GURL& origin_url,
468 const std::string& mount_name) {
469 std::string root = GetFileSystemRootURI(origin_url,
470 kFileSystemTypeExternal).spec();
471 if (base::FilePath::FromUTF8Unsafe(mount_name).ReferencesParent())
472 return std::string();
473 root.append(net::EscapePath(mount_name));
474 root.append("/");
475 return root;
478 base::File::Error NetErrorToFileError(int error) {
479 switch (error) {
480 case net::OK:
481 return base::File::FILE_OK;
482 case net::ERR_ADDRESS_IN_USE:
483 return base::File::FILE_ERROR_IN_USE;
484 case net::ERR_FILE_EXISTS:
485 return base::File::FILE_ERROR_EXISTS;
486 case net::ERR_FILE_NOT_FOUND:
487 return base::File::FILE_ERROR_NOT_FOUND;
488 case net::ERR_ACCESS_DENIED:
489 return base::File::FILE_ERROR_ACCESS_DENIED;
490 case net::ERR_OUT_OF_MEMORY:
491 return base::File::FILE_ERROR_NO_MEMORY;
492 case net::ERR_FILE_NO_SPACE:
493 return base::File::FILE_ERROR_NO_SPACE;
494 case net::ERR_INVALID_ARGUMENT:
495 case net::ERR_INVALID_HANDLE:
496 return base::File::FILE_ERROR_INVALID_OPERATION;
497 case net::ERR_ABORTED:
498 case net::ERR_CONNECTION_ABORTED:
499 return base::File::FILE_ERROR_ABORT;
500 case net::ERR_ADDRESS_INVALID:
501 case net::ERR_INVALID_URL:
502 return base::File::FILE_ERROR_INVALID_URL;
503 default:
504 return base::File::FILE_ERROR_FAILED;
508 } // namespace storage