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