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"
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"
16 #include "webkit/common/database/database_identifier.h"
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
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);
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
;
92 if (path
.value().empty())
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
);
106 void VirtualPath::GetComponentsUTF8Unsafe(
107 const base::FilePath
& path
,
108 std::vector
<std::string
>* components
) {
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();
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();
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.
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
) {
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
;
215 return quota::kStorageTypeUnknown
;
219 std::string
GetFileSystemTypeString(FileSystemType type
) {
221 case kFileSystemTypeTemporary
:
223 case kFileSystemTypePersistent
:
225 case kFileSystemTypeIsolated
:
227 case kFileSystemTypeExternal
:
229 case kFileSystemTypeTest
:
231 case kFileSystemTypeNativeLocal
:
232 return "NativeLocal";
233 case kFileSystemTypeRestrictedNativeLocal
:
234 return "RestrictedNativeLocal";
235 case kFileSystemTypeDragged
:
237 case kFileSystemTypeNativeMedia
:
238 return "NativeMedia";
239 case kFileSystemTypeDeviceMedia
:
240 return "DeviceMedia";
241 case kFileSystemTypePicasa
:
243 case kFileSystemTypeItunes
:
245 case kFileSystemTypeIphoto
:
247 case kFileSystemTypeDrive
:
249 case kFileSystemTypeSyncable
:
250 case kFileSystemTypeSyncableForInternalSync
:
252 case kFileSystemTypeNativeForPlatformApp
:
253 return "NativeForPlatformApp";
254 case kFileSystemTypeForTransientFile
:
255 return "TransientFile";
256 case kFileSystemTypePluginPrivate
:
257 return "PluginPrivate";
258 case kFileSystemInternalTypeEnumStart
:
259 case kFileSystemInternalTypeEnumEnd
:
262 case kFileSystemTypeUnknown
:
266 return std::string();
269 std::string
FilePathToString(const base::FilePath
& file_path
) {
271 return UTF16ToUTF8(file_path
.value());
272 #elif defined(OS_POSIX)
273 return file_path
.value();
277 base::FilePath
StringToFilePath(const std::string
& file_path_string
) {
279 return base::FilePath(UTF8ToUTF16(file_path_string
));
280 #elif defined(OS_POSIX)
281 return base::FilePath(file_path_string
);
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
;
310 return blink::WebFileErrorInvalidModification
;
314 bool GetFileSystemPublicType(
315 const std::string type_string
,
316 blink::WebFileSystemType
* type
) {
318 if (type_string
== "Temporary") {
319 *type
= blink::WebFileSystemTypeTemporary
;
322 if (type_string
== "Persistent") {
323 *type
= blink::WebFileSystemTypePersistent
;
326 if (type_string
== "Isolated") {
327 *type
= blink::WebFileSystemTypeIsolated
;
330 if (type_string
== "External") {
331 *type
= blink::WebFileSystemTypeExternal
;
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
));
343 name
.append(filesystem_id
);
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
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
)
367 *filesystem_id
= filesystem_name
.substr(pos
+ start_token
.length(),
369 if (filesystem_id
->empty())
375 bool ValidateIsolatedFileSystemId(const std::string
& filesystem_id
) {
376 const size_t kExpectedFileSystemIdSize
= 32;
377 if (filesystem_id
.size() != kExpectedFileSystemIdSize
)
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
);
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
);
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
);
414 base::PlatformFileError
NetErrorToPlatformFileError(int error
) {
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
;
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
),
455 } // namespace fileapi