file_system_util.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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 "googleurl/src/gurl.h" 15#include "webkit/common/database/database_identifier.h" 16 17namespace fileapi { 18 19const char kPersistentDir[] = "/persistent"; 20const char kTemporaryDir[] = "/temporary"; 21const char kIsolatedDir[] = "/isolated"; 22const char kExternalDir[] = "/external"; 23const char kTestDir[] = "/test"; 24 25const base::FilePath::CharType VirtualPath::kRoot[] = FILE_PATH_LITERAL("/"); 26const 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]. 32base::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 48base::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 82void 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 105void 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 122base::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 136bool VirtualPath::IsAbsolute(const base::FilePath::StringType& path) { 137 return path.find(kRoot) == 0; 138} 139 140GURL GetFileSystemRootURI(const GURL& origin_url, FileSystemType type) { 141 // origin_url is based on a security origin, so http://foo.com or file:/// 142 // instead of the corresponding filesystem URL. 143 DCHECK(!origin_url.SchemeIsFileSystem()); 144 145 std::string url = "filesystem:" + origin_url.GetWithEmptyPath().spec(); 146 switch (type) { 147 case kFileSystemTypeTemporary: 148 url += (kTemporaryDir + 1); // We don't want the leading slash. 149 return GURL(url + "/"); 150 case kFileSystemTypePersistent: 151 url += (kPersistentDir + 1); // We don't want the leading slash. 152 return GURL(url + "/"); 153 case kFileSystemTypeExternal: 154 url += (kExternalDir + 1); // We don't want the leading slash. 155 return GURL(url + "/"); 156 case kFileSystemTypeIsolated: 157 url += (kIsolatedDir + 1); // We don't want the leading slash. 158 return GURL(url + "/"); 159 case kFileSystemTypeTest: 160 url += (kTestDir + 1); // We don't want the leading slash. 161 return GURL(url + "/"); 162 // Internal types are always pointed via isolated or external URLs. 163 default: 164 NOTREACHED(); 165 } 166 NOTREACHED(); 167 return GURL(); 168} 169 170std::string GetFileSystemName(const GURL& origin_url, FileSystemType type) { 171 std::string origin_identifier = 172 webkit_database::GetIdentifierFromOrigin(origin_url); 173 std::string type_string = GetFileSystemTypeString(type); 174 DCHECK(!type_string.empty()); 175 return origin_identifier + ":" + type_string; 176} 177 178FileSystemType QuotaStorageTypeToFileSystemType( 179 quota::StorageType storage_type) { 180 switch (storage_type) { 181 case quota::kStorageTypeTemporary: 182 return kFileSystemTypeTemporary; 183 case quota::kStorageTypePersistent: 184 return kFileSystemTypePersistent; 185 case quota::kStorageTypeSyncable: 186 return kFileSystemTypeSyncable; 187 case quota::kStorageTypeUnknown: 188 return kFileSystemTypeUnknown; 189 } 190 return kFileSystemTypeUnknown; 191} 192 193quota::StorageType FileSystemTypeToQuotaStorageType(FileSystemType type) { 194 switch (type) { 195 case kFileSystemTypeTemporary: 196 return quota::kStorageTypeTemporary; 197 case kFileSystemTypePersistent: 198 return quota::kStorageTypePersistent; 199 case kFileSystemTypeSyncable: 200 case kFileSystemTypeSyncableForInternalSync: 201 return quota::kStorageTypeSyncable; 202 default: 203 return quota::kStorageTypeUnknown; 204 } 205} 206 207std::string GetFileSystemTypeString(FileSystemType type) { 208 switch (type) { 209 case kFileSystemTypeTemporary: 210 return "Temporary"; 211 case kFileSystemTypePersistent: 212 return "Persistent"; 213 case kFileSystemTypeIsolated: 214 return "Isolated"; 215 case kFileSystemTypeExternal: 216 return "External"; 217 case kFileSystemTypeTest: 218 return "Test"; 219 case kFileSystemTypeNativeLocal: 220 return "NativeLocal"; 221 case kFileSystemTypeRestrictedNativeLocal: 222 return "RestrictedNativeLocal"; 223 case kFileSystemTypeDragged: 224 return "Dragged"; 225 case kFileSystemTypeNativeMedia: 226 return "NativeMedia"; 227 case kFileSystemTypeDeviceMedia: 228 return "DeviceMedia"; 229 case kFileSystemTypePicasa: 230 return "Picasa"; 231 case kFileSystemTypeItunes: 232 return "Itunes"; 233 case kFileSystemTypeDrive: 234 return "Drive"; 235 case kFileSystemTypeSyncable: 236 case kFileSystemTypeSyncableForInternalSync: 237 return "Syncable"; 238 case kFileSystemTypeNativeForPlatformApp: 239 return "NativeForPlatformApp"; 240 case kFileSystemTypeForTransientFile: 241 return "TransientFile"; 242 case kFileSystemInternalTypeEnumStart: 243 case kFileSystemInternalTypeEnumEnd: 244 NOTREACHED(); 245 // Fall through. 246 case kFileSystemTypeUnknown: 247 return "Unknown"; 248 } 249 NOTREACHED(); 250 return std::string(); 251} 252 253std::string FilePathToString(const base::FilePath& file_path) { 254#if defined(OS_WIN) 255 return UTF16ToUTF8(file_path.value()); 256#elif defined(OS_POSIX) 257 return file_path.value(); 258#endif 259} 260 261base::FilePath StringToFilePath(const std::string& file_path_string) { 262#if defined(OS_WIN) 263 return base::FilePath(UTF8ToUTF16(file_path_string)); 264#elif defined(OS_POSIX) 265 return base::FilePath(file_path_string); 266#endif 267} 268 269WebKit::WebFileError PlatformFileErrorToWebFileError( 270 base::PlatformFileError error_code) { 271 switch (error_code) { 272 case base::PLATFORM_FILE_ERROR_NOT_FOUND: 273 return WebKit::WebFileErrorNotFound; 274 case base::PLATFORM_FILE_ERROR_INVALID_OPERATION: 275 case base::PLATFORM_FILE_ERROR_EXISTS: 276 case base::PLATFORM_FILE_ERROR_NOT_EMPTY: 277 return WebKit::WebFileErrorInvalidModification; 278 case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY: 279 case base::PLATFORM_FILE_ERROR_NOT_A_FILE: 280 return WebKit::WebFileErrorTypeMismatch; 281 case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: 282 return WebKit::WebFileErrorNoModificationAllowed; 283 case base::PLATFORM_FILE_ERROR_FAILED: 284 return WebKit::WebFileErrorInvalidState; 285 case base::PLATFORM_FILE_ERROR_ABORT: 286 return WebKit::WebFileErrorAbort; 287 case base::PLATFORM_FILE_ERROR_SECURITY: 288 return WebKit::WebFileErrorSecurity; 289 case base::PLATFORM_FILE_ERROR_NO_SPACE: 290 return WebKit::WebFileErrorQuotaExceeded; 291 default: 292 return WebKit::WebFileErrorInvalidModification; 293 } 294} 295 296bool GetFileSystemPublicType( 297 const std::string type_string, 298 WebKit::WebFileSystemType* type 299) { 300 DCHECK(type); 301 if (type_string == "Temporary") { 302 *type = WebKit::WebFileSystemTypeTemporary; 303 return true; 304 } 305 if (type_string == "Persistent") { 306 *type = WebKit::WebFileSystemTypePersistent; 307 return true; 308 } 309 if (type_string == "Isolated") { 310 *type = WebKit::WebFileSystemTypeIsolated; 311 return true; 312 } 313 if (type_string == "External") { 314 *type = WebKit::WebFileSystemTypeExternal; 315 return true; 316 } 317 NOTREACHED(); 318 return false; 319} 320 321std::string GetIsolatedFileSystemName(const GURL& origin_url, 322 const std::string& filesystem_id) { 323 std::string name(fileapi::GetFileSystemName(origin_url, 324 fileapi::kFileSystemTypeIsolated)); 325 name.append("_"); 326 name.append(filesystem_id); 327 return name; 328} 329 330bool CrackIsolatedFileSystemName(const std::string& filesystem_name, 331 std::string* filesystem_id) { 332 DCHECK(filesystem_id); 333 334 // |filesystem_name| is of the form {origin}:isolated_{filesystem_id}. 335 std::string start_token(":"); 336 start_token = start_token.append( 337 GetFileSystemTypeString(kFileSystemTypeIsolated)).append("_"); 338 // WebKit uses different case in its constant for isolated file system 339 // names, so we do a case insensitive compare by converting both strings 340 // to uppercase. 341 // TODO(benwells): Remove this when WebKit uses the same constant. 342 start_token = StringToUpperASCII(start_token); 343 std::string filesystem_name_upper = StringToUpperASCII(filesystem_name); 344 size_t pos = filesystem_name_upper.find(start_token); 345 if (pos == std::string::npos) 346 return false; 347 if (pos == 0) 348 return false; 349 350 *filesystem_id = filesystem_name.substr(pos + start_token.length(), 351 std::string::npos); 352 if (filesystem_id->empty()) 353 return false; 354 355 return true; 356} 357 358std::string GetIsolatedFileSystemRootURIString( 359 const GURL& origin_url, 360 const std::string& filesystem_id, 361 const std::string& optional_root_name) { 362 std::string root = GetFileSystemRootURI(origin_url, 363 kFileSystemTypeIsolated).spec(); 364 if (base::FilePath::FromUTF8Unsafe(filesystem_id).ReferencesParent()) 365 return std::string(); 366 root.append(filesystem_id); 367 root.append("/"); 368 if (!optional_root_name.empty()) { 369 if (base::FilePath::FromUTF8Unsafe(optional_root_name).ReferencesParent()) 370 return std::string(); 371 root.append(optional_root_name); 372 root.append("/"); 373 } 374 return root; 375} 376 377std::string GetExternalFileSystemRootURIString( 378 const GURL& origin_url, 379 const std::string& mount_name) { 380 std::string root = GetFileSystemRootURI(origin_url, 381 kFileSystemTypeExternal).spec(); 382 if (base::FilePath::FromUTF8Unsafe(mount_name).ReferencesParent()) 383 return std::string(); 384 root.append(mount_name); 385 root.append("/"); 386 return root; 387} 388 389} // namespace fileapi 390