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