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/fileapi/file_system_util.h"
7 #include "build/build_config.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/string_util.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/utf_string_conversions.h"
14 #include "googleurl/src/gurl.h"
15 #include "third_party/WebKit/Source/Platform/chromium/public/WebCString.h"
16 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
18 #include "webkit/base/origin_url_conversions.h"
19 #include "webkit/fileapi/file_system_url.h"
23 const char kPersistentDir
[] = "/persistent";
24 const char kTemporaryDir
[] = "/temporary";
25 const char kIsolatedDir
[] = "/isolated";
26 const char kExternalDir
[] = "/external";
27 const char kTestDir
[] = "/test";
29 const base::FilePath::CharType
VirtualPath::kRoot
[] = FILE_PATH_LITERAL("/");
30 const base::FilePath::CharType
VirtualPath::kSeparator
= FILE_PATH_LITERAL('/');
32 // TODO(ericu): Consider removing support for '\', even on Windows, if possible.
33 // There's a lot of test code that will need reworking, and we may have trouble
34 // with base::FilePath elsewhere [e.g. DirName and other methods may also need
36 base::FilePath
VirtualPath::BaseName(const base::FilePath
& virtual_path
) {
37 base::FilePath::StringType path
= virtual_path
.value();
39 // Keep everything after the final separator, but if the pathname is only
40 // one character and it's a separator, leave it alone.
41 while (path
.size() > 1 && base::FilePath::IsSeparator(path
[path
.size() - 1]))
42 path
.resize(path
.size() - 1);
43 base::FilePath::StringType::size_type last_separator
=
44 path
.find_last_of(base::FilePath::kSeparators
);
45 if (last_separator
!= base::FilePath::StringType::npos
&&
46 last_separator
< path
.size() - 1)
47 path
.erase(0, last_separator
+ 1);
49 return base::FilePath(path
);
52 base::FilePath
VirtualPath::DirName(const base::FilePath
& virtual_path
) {
53 typedef base::FilePath::StringType StringType
;
54 StringType path
= virtual_path
.value();
56 // The logic below is taken from that of base::FilePath::DirName, except
57 // that this version never cares about '//' or drive-letters even on win32.
59 // Strip trailing separators.
60 while (path
.size() > 1 && base::FilePath::IsSeparator(path
[path
.size() - 1]))
61 path
.resize(path
.size() - 1);
63 StringType::size_type last_separator
=
64 path
.find_last_of(base::FilePath::kSeparators
);
65 if (last_separator
== StringType::npos
) {
66 // path_ is in the current directory.
67 return base::FilePath(base::FilePath::kCurrentDirectory
);
69 if (last_separator
== 0) {
70 // path_ is in the root directory.
71 return base::FilePath(path
.substr(0, 1));
73 // path_ is somewhere else, trim the basename.
74 path
.resize(last_separator
);
76 // Strip trailing separators.
77 while (path
.size() > 1 && base::FilePath::IsSeparator(path
[path
.size() - 1]))
78 path
.resize(path
.size() - 1);
81 return base::FilePath(base::FilePath::kCurrentDirectory
);
83 return base::FilePath(path
);
86 void VirtualPath::GetComponents(
87 const base::FilePath
& path
,
88 std::vector
<base::FilePath::StringType
>* components
) {
89 typedef base::FilePath::StringType StringType
;
95 if (path
.value().empty())
98 StringType::size_type begin
= 0, end
= 0;
99 while (begin
< path
.value().length() && end
!= StringType::npos
) {
100 end
= path
.value().find_first_of(base::FilePath::kSeparators
, begin
);
101 StringType component
= path
.value().substr(
102 begin
, end
== StringType::npos
? StringType::npos
: end
- begin
);
103 if (!component
.empty() && component
!= base::FilePath::kCurrentDirectory
)
104 components
->push_back(component
);
109 base::FilePath::StringType
VirtualPath::GetNormalizedFilePath(
110 const base::FilePath
& path
) {
111 base::FilePath::StringType normalized_path
= path
.value();
112 const size_t num_separators
= base::FilePath::StringType(
113 base::FilePath::kSeparators
).length();
114 for (size_t i
= 0; i
< num_separators
; ++i
) {
115 std::replace(normalized_path
.begin(), normalized_path
.end(),
116 base::FilePath::kSeparators
[i
], kSeparator
);
119 return (IsAbsolute(normalized_path
)) ?
120 normalized_path
: base::FilePath::StringType(kRoot
) + normalized_path
;
123 bool VirtualPath::IsAbsolute(const base::FilePath::StringType
& path
) {
124 return path
.find(kRoot
) == 0;
127 GURL
GetFileSystemRootURI(const GURL
& origin_url
, FileSystemType type
) {
128 // origin_url is based on a security origin, so http://foo.com or file:///
129 // instead of the corresponding filesystem URL.
130 DCHECK(!origin_url
.SchemeIsFileSystem());
132 std::string url
= "filesystem:" + origin_url
.GetWithEmptyPath().spec();
134 case kFileSystemTypeTemporary
:
135 url
+= (kTemporaryDir
+ 1); // We don't want the leading slash.
136 return GURL(url
+ "/");
137 case kFileSystemTypePersistent
:
138 url
+= (kPersistentDir
+ 1); // We don't want the leading slash.
139 return GURL(url
+ "/");
140 case kFileSystemTypeExternal
:
141 url
+= (kExternalDir
+ 1); // We don't want the leading slash.
142 return GURL(url
+ "/");
143 case kFileSystemTypeIsolated
:
144 url
+= (kIsolatedDir
+ 1); // We don't want the leading slash.
145 return GURL(url
+ "/");
146 case kFileSystemTypeTest
:
147 url
+= (kTestDir
+ 1); // We don't want the leading slash.
148 return GURL(url
+ "/");
149 // Internal types are always pointed via isolated or external URLs.
157 std::string
GetFileSystemName(const GURL
& origin_url
, FileSystemType type
) {
158 base::string16 origin_identifier
=
159 webkit_base::GetOriginIdentifierFromURL(origin_url
);
160 std::string type_string
= GetFileSystemTypeString(type
);
161 DCHECK(!type_string
.empty());
162 return UTF16ToUTF8(origin_identifier
) + ":" + type_string
;
165 FileSystemType
QuotaStorageTypeToFileSystemType(
166 quota::StorageType storage_type
) {
167 switch (storage_type
) {
168 case quota::kStorageTypeTemporary
:
169 return kFileSystemTypeTemporary
;
170 case quota::kStorageTypePersistent
:
171 return kFileSystemTypePersistent
;
172 case quota::kStorageTypeSyncable
:
173 return kFileSystemTypeSyncable
;
174 case quota::kStorageTypeUnknown
:
175 return kFileSystemTypeUnknown
;
177 return kFileSystemTypeUnknown
;
180 quota::StorageType
FileSystemTypeToQuotaStorageType(FileSystemType type
) {
182 case kFileSystemTypeTemporary
:
183 return quota::kStorageTypeTemporary
;
184 case kFileSystemTypePersistent
:
185 return quota::kStorageTypePersistent
;
186 case kFileSystemTypeSyncable
:
187 return quota::kStorageTypeSyncable
;
189 return quota::kStorageTypeUnknown
;
193 std::string
GetFileSystemTypeString(FileSystemType type
) {
195 case kFileSystemTypeTemporary
:
197 case kFileSystemTypePersistent
:
199 case kFileSystemTypeIsolated
:
201 case kFileSystemTypeExternal
:
203 case kFileSystemTypeTest
:
205 case kFileSystemTypeNativeLocal
:
206 return "NativeLocal";
207 case kFileSystemTypeRestrictedNativeLocal
:
208 return "RestrictedNativeLocal";
209 case kFileSystemTypeDragged
:
211 case kFileSystemTypeNativeMedia
:
212 return "NativeMedia";
213 case kFileSystemTypeDeviceMedia
:
214 return "DeviceMedia";
215 case kFileSystemTypePicasa
:
217 case kFileSystemTypeItunes
:
219 case kFileSystemTypeDrive
:
221 case kFileSystemTypeSyncable
:
223 case kFileSystemTypeNativeForPlatformApp
:
224 return "NativeForPlatformApp";
225 case kFileSystemTypeForTransientFile
:
226 return "TransientFile";
227 case kFileSystemInternalTypeEnumStart
:
228 case kFileSystemInternalTypeEnumEnd
:
231 case kFileSystemTypeUnknown
:
235 return std::string();
238 std::string
FilePathToString(const base::FilePath
& file_path
) {
240 return UTF16ToUTF8(file_path
.value());
241 #elif defined(OS_POSIX)
242 return file_path
.value();
246 base::FilePath
StringToFilePath(const std::string
& file_path_string
) {
248 return base::FilePath(UTF8ToUTF16(file_path_string
));
249 #elif defined(OS_POSIX)
250 return base::FilePath(file_path_string
);
254 WebKit::WebFileError
PlatformFileErrorToWebFileError(
255 base::PlatformFileError error_code
) {
256 switch (error_code
) {
257 case base::PLATFORM_FILE_ERROR_NOT_FOUND
:
258 return WebKit::WebFileErrorNotFound
;
259 case base::PLATFORM_FILE_ERROR_INVALID_OPERATION
:
260 case base::PLATFORM_FILE_ERROR_EXISTS
:
261 case base::PLATFORM_FILE_ERROR_NOT_EMPTY
:
262 return WebKit::WebFileErrorInvalidModification
;
263 case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY
:
264 case base::PLATFORM_FILE_ERROR_NOT_A_FILE
:
265 return WebKit::WebFileErrorTypeMismatch
;
266 case base::PLATFORM_FILE_ERROR_ACCESS_DENIED
:
267 return WebKit::WebFileErrorNoModificationAllowed
;
268 case base::PLATFORM_FILE_ERROR_FAILED
:
269 return WebKit::WebFileErrorInvalidState
;
270 case base::PLATFORM_FILE_ERROR_ABORT
:
271 return WebKit::WebFileErrorAbort
;
272 case base::PLATFORM_FILE_ERROR_SECURITY
:
273 return WebKit::WebFileErrorSecurity
;
274 case base::PLATFORM_FILE_ERROR_NO_SPACE
:
275 return WebKit::WebFileErrorQuotaExceeded
;
277 return WebKit::WebFileErrorInvalidModification
;
281 bool GetFileSystemPublicType(
282 const std::string type_string
,
283 WebKit::WebFileSystemType
* type
286 if (type_string
== "Temporary") {
287 *type
= WebKit::WebFileSystemTypeTemporary
;
290 if (type_string
== "Persistent") {
291 *type
= WebKit::WebFileSystemTypePersistent
;
294 if (type_string
== "Isolated") {
295 *type
= WebKit::WebFileSystemTypeIsolated
;
298 if (type_string
== "External") {
299 *type
= WebKit::WebFileSystemTypeExternal
;
306 std::string
GetIsolatedFileSystemName(const GURL
& origin_url
,
307 const std::string
& filesystem_id
) {
308 std::string
name(fileapi::GetFileSystemName(origin_url
,
309 fileapi::kFileSystemTypeIsolated
));
311 name
.append(filesystem_id
);
315 bool CrackIsolatedFileSystemName(const std::string
& filesystem_name
,
316 std::string
* filesystem_id
) {
317 DCHECK(filesystem_id
);
319 // |filesystem_name| is of the form {origin}:isolated_{filesystem_id}.
320 std::string
start_token(":");
321 start_token
= start_token
.append(
322 GetFileSystemTypeString(kFileSystemTypeIsolated
)).append("_");
323 // WebKit uses different case in its constant for isolated file system
324 // names, so we do a case insensitive compare by converting both strings
326 // TODO(benwells): Remove this when WebKit uses the same constant.
327 start_token
= StringToUpperASCII(start_token
);
328 std::string filesystem_name_upper
= StringToUpperASCII(filesystem_name
);
329 size_t pos
= filesystem_name_upper
.find(start_token
);
330 if (pos
== std::string::npos
)
335 *filesystem_id
= filesystem_name
.substr(pos
+ start_token
.length(),
337 if (filesystem_id
->empty())
343 std::string
GetIsolatedFileSystemRootURIString(
344 const GURL
& origin_url
,
345 const std::string
& filesystem_id
,
346 const std::string
& optional_root_name
) {
347 std::string root
= GetFileSystemRootURI(origin_url
,
348 kFileSystemTypeIsolated
).spec();
349 if (base::FilePath::FromUTF8Unsafe(filesystem_id
).ReferencesParent())
350 return std::string();
351 root
.append(filesystem_id
);
353 if (!optional_root_name
.empty()) {
354 if (base::FilePath::FromUTF8Unsafe(optional_root_name
).ReferencesParent())
355 return std::string();
356 root
.append(optional_root_name
);
362 bool AreSameFileSystem(const FileSystemURL
& url1
, const FileSystemURL
& url2
) {
363 return url1
.origin() == url2
.origin() && url1
.type() == url2
.type();
366 } // namespace fileapi