• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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/net_errors.h"
15 #include "url/gurl.h"
16 #include "webkit/common/database/database_identifier.h"
17 
18 namespace fileapi {
19 
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";
25 
26 const base::FilePath::CharType VirtualPath::kRoot[] = FILE_PATH_LITERAL("/");
27 const base::FilePath::CharType VirtualPath::kSeparator = FILE_PATH_LITERAL('/');
28 
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].
BaseName(const base::FilePath & virtual_path)33 base::FilePath VirtualPath::BaseName(const base::FilePath& virtual_path) {
34   base::FilePath::StringType path = virtual_path.value();
35 
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);
45 
46   return base::FilePath(path);
47 }
48 
DirName(const base::FilePath & virtual_path)49 base::FilePath VirtualPath::DirName(const base::FilePath& virtual_path) {
50   typedef base::FilePath::StringType StringType;
51   StringType  path = virtual_path.value();
52 
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.
55 
56   // Strip trailing separators.
57   while (path.size() > 1 && base::FilePath::IsSeparator(path[path.size() - 1]))
58     path.resize(path.size() - 1);
59 
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);
65   }
66   if (last_separator == 0) {
67     // path_ is in the root directory.
68     return base::FilePath(path.substr(0, 1));
69   }
70   // path_ is somewhere else, trim the basename.
71   path.resize(last_separator);
72 
73   // Strip trailing separators.
74   while (path.size() > 1 && base::FilePath::IsSeparator(path[path.size() - 1]))
75     path.resize(path.size() - 1);
76 
77   if (path.empty())
78     return base::FilePath(base::FilePath::kCurrentDirectory);
79 
80   return base::FilePath(path);
81 }
82 
GetComponents(const base::FilePath & path,std::vector<base::FilePath::StringType> * components)83 void VirtualPath::GetComponents(
84     const base::FilePath& path,
85     std::vector<base::FilePath::StringType>* components) {
86   typedef base::FilePath::StringType StringType;
87 
88   DCHECK(components);
89   if (!components)
90     return;
91   components->clear();
92   if (path.value().empty())
93     return;
94 
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;
103   }
104 }
105 
GetComponentsUTF8Unsafe(const base::FilePath & path,std::vector<std::string> * components)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();
113 
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());
120   }
121 }
122 
GetNormalizedFilePath(const base::FilePath & path)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);
131   }
132 
133   return (IsAbsolute(normalized_path)) ?
134       normalized_path : base::FilePath::StringType(kRoot) + normalized_path;
135 }
136 
IsAbsolute(const base::FilePath::StringType & path)137 bool VirtualPath::IsAbsolute(const base::FilePath::StringType& path) {
138   return path.find(kRoot) == 0;
139 }
140 
IsRootPath(const base::FilePath & path)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));
147 }
148 
GetFileSystemRootURI(const GURL & origin_url,FileSystemType type)149 GURL GetFileSystemRootURI(const GURL& origin_url, FileSystemType type) {
150   // origin_url is based on a security origin, so http://foo.com or file:///
151   // instead of the corresponding filesystem URL.
152   DCHECK(!origin_url.SchemeIsFileSystem());
153 
154   std::string url = "filesystem:" + origin_url.GetWithEmptyPath().spec();
155   switch (type) {
156     case kFileSystemTypeTemporary:
157       url += (kTemporaryDir + 1);  // We don't want the leading slash.
158       return GURL(url + "/");
159     case kFileSystemTypePersistent:
160       url += (kPersistentDir + 1);  // We don't want the leading slash.
161       return GURL(url + "/");
162     case kFileSystemTypeExternal:
163       url += (kExternalDir + 1);  // We don't want the leading slash.
164       return GURL(url + "/");
165     case kFileSystemTypeIsolated:
166       url += (kIsolatedDir + 1);  // We don't want the leading slash.
167       return GURL(url + "/");
168     case kFileSystemTypeTest:
169       url += (kTestDir + 1);  // We don't want the leading slash.
170       return GURL(url + "/");
171       // Internal types are always pointed via isolated or external URLs.
172     default:
173       NOTREACHED();
174   }
175   NOTREACHED();
176   return GURL();
177 }
178 
GetFileSystemName(const GURL & origin_url,FileSystemType type)179 std::string GetFileSystemName(const GURL& origin_url, FileSystemType type) {
180   std::string origin_identifier =
181       webkit_database::GetIdentifierFromOrigin(origin_url);
182   std::string type_string = GetFileSystemTypeString(type);
183   DCHECK(!type_string.empty());
184   return origin_identifier + ":" + type_string;
185 }
186 
QuotaStorageTypeToFileSystemType(quota::StorageType storage_type)187 FileSystemType QuotaStorageTypeToFileSystemType(
188     quota::StorageType storage_type) {
189   switch (storage_type) {
190     case quota::kStorageTypeTemporary:
191       return kFileSystemTypeTemporary;
192     case quota::kStorageTypePersistent:
193       return kFileSystemTypePersistent;
194     case quota::kStorageTypeSyncable:
195       return kFileSystemTypeSyncable;
196     case quota::kStorageTypeQuotaNotManaged:
197     case quota::kStorageTypeUnknown:
198       return kFileSystemTypeUnknown;
199   }
200   return kFileSystemTypeUnknown;
201 }
202 
FileSystemTypeToQuotaStorageType(FileSystemType type)203 quota::StorageType FileSystemTypeToQuotaStorageType(FileSystemType type) {
204   switch (type) {
205     case kFileSystemTypeTemporary:
206       return quota::kStorageTypeTemporary;
207     case kFileSystemTypePersistent:
208       return quota::kStorageTypePersistent;
209     case kFileSystemTypeSyncable:
210     case kFileSystemTypeSyncableForInternalSync:
211       return quota::kStorageTypeSyncable;
212     case kFileSystemTypePluginPrivate:
213       return quota::kStorageTypeQuotaNotManaged;
214     default:
215       return quota::kStorageTypeUnknown;
216   }
217 }
218 
GetFileSystemTypeString(FileSystemType type)219 std::string GetFileSystemTypeString(FileSystemType type) {
220   switch (type) {
221     case kFileSystemTypeTemporary:
222       return "Temporary";
223     case kFileSystemTypePersistent:
224       return "Persistent";
225     case kFileSystemTypeIsolated:
226       return "Isolated";
227     case kFileSystemTypeExternal:
228       return "External";
229     case kFileSystemTypeTest:
230       return "Test";
231     case kFileSystemTypeNativeLocal:
232       return "NativeLocal";
233     case kFileSystemTypeRestrictedNativeLocal:
234       return "RestrictedNativeLocal";
235     case kFileSystemTypeDragged:
236       return "Dragged";
237     case kFileSystemTypeNativeMedia:
238       return "NativeMedia";
239     case kFileSystemTypeDeviceMedia:
240       return "DeviceMedia";
241     case kFileSystemTypePicasa:
242       return "Picasa";
243     case kFileSystemTypeItunes:
244       return "Itunes";
245     case kFileSystemTypeIphoto:
246       return "Iphoto";
247     case kFileSystemTypeDrive:
248       return "Drive";
249     case kFileSystemTypeSyncable:
250     case kFileSystemTypeSyncableForInternalSync:
251       return "Syncable";
252     case kFileSystemTypeNativeForPlatformApp:
253       return "NativeForPlatformApp";
254     case kFileSystemTypeForTransientFile:
255       return "TransientFile";
256     case kFileSystemTypePluginPrivate:
257       return "PluginPrivate";
258     case kFileSystemInternalTypeEnumStart:
259     case kFileSystemInternalTypeEnumEnd:
260       NOTREACHED();
261       // Fall through.
262     case kFileSystemTypeUnknown:
263       return "Unknown";
264   }
265   NOTREACHED();
266   return std::string();
267 }
268 
FilePathToString(const base::FilePath & file_path)269 std::string FilePathToString(const base::FilePath& file_path) {
270 #if defined(OS_WIN)
271   return UTF16ToUTF8(file_path.value());
272 #elif defined(OS_POSIX)
273   return file_path.value();
274 #endif
275 }
276 
StringToFilePath(const std::string & file_path_string)277 base::FilePath StringToFilePath(const std::string& file_path_string) {
278 #if defined(OS_WIN)
279   return base::FilePath(UTF8ToUTF16(file_path_string));
280 #elif defined(OS_POSIX)
281   return base::FilePath(file_path_string);
282 #endif
283 }
284 
PlatformFileErrorToWebFileError(base::PlatformFileError error_code)285 blink::WebFileError PlatformFileErrorToWebFileError(
286     base::PlatformFileError error_code) {
287   switch (error_code) {
288     case base::PLATFORM_FILE_ERROR_NOT_FOUND:
289       return blink::WebFileErrorNotFound;
290     case base::PLATFORM_FILE_ERROR_INVALID_OPERATION:
291     case base::PLATFORM_FILE_ERROR_EXISTS:
292     case base::PLATFORM_FILE_ERROR_NOT_EMPTY:
293       return blink::WebFileErrorInvalidModification;
294     case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
295     case base::PLATFORM_FILE_ERROR_NOT_A_FILE:
296       return blink::WebFileErrorTypeMismatch;
297     case base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
298       return blink::WebFileErrorNoModificationAllowed;
299     case base::PLATFORM_FILE_ERROR_FAILED:
300       return blink::WebFileErrorInvalidState;
301     case base::PLATFORM_FILE_ERROR_ABORT:
302       return blink::WebFileErrorAbort;
303     case base::PLATFORM_FILE_ERROR_SECURITY:
304       return blink::WebFileErrorSecurity;
305     case base::PLATFORM_FILE_ERROR_NO_SPACE:
306       return blink::WebFileErrorQuotaExceeded;
307     case base::PLATFORM_FILE_ERROR_INVALID_URL:
308       return blink::WebFileErrorEncoding;
309     default:
310       return blink::WebFileErrorInvalidModification;
311   }
312 }
313 
GetFileSystemPublicType(const std::string type_string,blink::WebFileSystemType * type)314 bool GetFileSystemPublicType(
315     const std::string type_string,
316     blink::WebFileSystemType* type) {
317   DCHECK(type);
318   if (type_string == "Temporary") {
319     *type = blink::WebFileSystemTypeTemporary;
320     return true;
321   }
322   if (type_string == "Persistent") {
323     *type = blink::WebFileSystemTypePersistent;
324     return true;
325   }
326   if (type_string == "Isolated") {
327     *type = blink::WebFileSystemTypeIsolated;
328     return true;
329   }
330   if (type_string == "External") {
331     *type = blink::WebFileSystemTypeExternal;
332     return true;
333   }
334   NOTREACHED();
335   return false;
336 }
337 
GetIsolatedFileSystemName(const GURL & origin_url,const std::string & filesystem_id)338 std::string GetIsolatedFileSystemName(const GURL& origin_url,
339                                       const std::string& filesystem_id) {
340   std::string name(fileapi::GetFileSystemName(
341       origin_url, fileapi::kFileSystemTypeIsolated));
342   name.append("_");
343   name.append(filesystem_id);
344   return name;
345 }
346 
CrackIsolatedFileSystemName(const std::string & filesystem_name,std::string * filesystem_id)347 bool CrackIsolatedFileSystemName(const std::string& filesystem_name,
348                                  std::string* filesystem_id) {
349   DCHECK(filesystem_id);
350 
351   // |filesystem_name| is of the form {origin}:isolated_{filesystem_id}.
352   std::string start_token(":");
353   start_token = start_token.append(
354       GetFileSystemTypeString(kFileSystemTypeIsolated)).append("_");
355   // WebKit uses different case in its constant for isolated file system
356   // names, so we do a case insensitive compare by converting both strings
357   // to uppercase.
358   // TODO(benwells): Remove this when WebKit uses the same constant.
359   start_token = StringToUpperASCII(start_token);
360   std::string filesystem_name_upper = StringToUpperASCII(filesystem_name);
361   size_t pos = filesystem_name_upper.find(start_token);
362   if (pos == std::string::npos)
363     return false;
364   if (pos == 0)
365     return false;
366 
367   *filesystem_id = filesystem_name.substr(pos + start_token.length(),
368                                           std::string::npos);
369   if (filesystem_id->empty())
370     return false;
371 
372   return true;
373 }
374 
ValidateIsolatedFileSystemId(const std::string & filesystem_id)375 bool ValidateIsolatedFileSystemId(const std::string& filesystem_id) {
376   const size_t kExpectedFileSystemIdSize = 32;
377   if (filesystem_id.size() != kExpectedFileSystemIdSize)
378     return false;
379   const std::string kExpectedChars("ABCDEF0123456789");
380   return ContainsOnlyChars(filesystem_id, kExpectedChars);
381 }
382 
GetIsolatedFileSystemRootURIString(const GURL & origin_url,const std::string & filesystem_id,const std::string & optional_root_name)383 std::string GetIsolatedFileSystemRootURIString(
384     const GURL& origin_url,
385     const std::string& filesystem_id,
386     const std::string& optional_root_name) {
387   std::string root = GetFileSystemRootURI(origin_url,
388                                           kFileSystemTypeIsolated).spec();
389   if (base::FilePath::FromUTF8Unsafe(filesystem_id).ReferencesParent())
390     return std::string();
391   root.append(filesystem_id);
392   root.append("/");
393   if (!optional_root_name.empty()) {
394     if (base::FilePath::FromUTF8Unsafe(optional_root_name).ReferencesParent())
395       return std::string();
396     root.append(optional_root_name);
397     root.append("/");
398   }
399   return root;
400 }
401 
GetExternalFileSystemRootURIString(const GURL & origin_url,const std::string & mount_name)402 std::string GetExternalFileSystemRootURIString(
403     const GURL& origin_url,
404     const std::string& mount_name) {
405   std::string root = GetFileSystemRootURI(origin_url,
406                                           kFileSystemTypeExternal).spec();
407   if (base::FilePath::FromUTF8Unsafe(mount_name).ReferencesParent())
408     return std::string();
409   root.append(mount_name);
410   root.append("/");
411   return root;
412 }
413 
NetErrorToPlatformFileError(int error)414 base::PlatformFileError NetErrorToPlatformFileError(int error) {
415   switch (error) {
416     case net::OK:
417       return base::PLATFORM_FILE_OK;
418     case net::ERR_ADDRESS_IN_USE:
419       return base::PLATFORM_FILE_ERROR_IN_USE;
420     case net::ERR_FILE_EXISTS:
421       return base::PLATFORM_FILE_ERROR_EXISTS;
422     case net::ERR_FILE_NOT_FOUND:
423       return base::PLATFORM_FILE_ERROR_NOT_FOUND;
424     case net::ERR_ACCESS_DENIED:
425       return base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
426     case net::ERR_TOO_MANY_SOCKET_STREAMS:
427       return base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
428     case net::ERR_OUT_OF_MEMORY:
429       return base::PLATFORM_FILE_ERROR_NO_MEMORY;
430     case net::ERR_FILE_NO_SPACE:
431       return base::PLATFORM_FILE_ERROR_NO_SPACE;
432     case net::ERR_INVALID_ARGUMENT:
433     case net::ERR_INVALID_HANDLE:
434       return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
435     case net::ERR_ABORTED:
436     case net::ERR_CONNECTION_ABORTED:
437       return base::PLATFORM_FILE_ERROR_ABORT;
438     case net::ERR_ADDRESS_INVALID:
439     case net::ERR_INVALID_URL:
440       return base::PLATFORM_FILE_ERROR_INVALID_URL;
441     default:
442       return base::PLATFORM_FILE_ERROR_FAILED;
443   }
444 }
445 
446 #if defined(OS_CHROMEOS)
GetFileSystemInfoForChromeOS(const GURL & origin_url)447 FileSystemInfo GetFileSystemInfoForChromeOS(const GURL& origin_url) {
448   FileSystemType mount_type = fileapi::kFileSystemTypeExternal;
449   return FileSystemInfo(fileapi::GetFileSystemName(origin_url, mount_type),
450                         fileapi::GetFileSystemRootURI(origin_url, mount_type),
451                         mount_type);
452 }
453 #endif
454 
455 }  // namespace fileapi
456