Revert of https://codereview.chromium.org/94133003/
[chromium-blink-merge.git] / webkit / common / fileapi / file_system_util.cc
blob4d5c352bf3722659d62e0ceac97b426078a4c7a1
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 "webkit/common/fileapi/file_system_util.h"
7 #include <algorithm>
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"
18 namespace fileapi {
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 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());
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();
175 NOTREACHED();
176 return GURL();
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;
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;
200 return kFileSystemTypeUnknown;
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;
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";
265 NOTREACHED();
266 return std::string();
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
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
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;
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;
322 if (type_string == "Persistent") {
323 *type = blink::WebFileSystemTypePersistent;
324 return true;
326 if (type_string == "Isolated") {
327 *type = blink::WebFileSystemTypeIsolated;
328 return true;
330 if (type_string == "External") {
331 *type = blink::WebFileSystemTypeExternal;
332 return true;
334 NOTREACHED();
335 return false;
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;
347 bool CrackIsolatedFileSystemName(const std::string& filesystem_name,
348 std::string* filesystem_id) {
349 DCHECK(filesystem_id);
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;
367 *filesystem_id = filesystem_name.substr(pos + start_token.length(),
368 std::string::npos);
369 if (filesystem_id->empty())
370 return false;
372 return true;
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);
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("/");
399 return root;
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;
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;
446 #if defined(OS_CHROMEOS)
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);
453 #endif
455 } // namespace fileapi