OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/fileapi/sandbox_mount_point_provider.h" | 5 #include "webkit/fileapi/sandbox_mount_point_provider.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/memory/scoped_callback_factory.h" | 9 #include "base/memory/scoped_callback_factory.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "base/message_loop_proxy.h" | 12 #include "base/message_loop_proxy.h" |
13 #include "base/rand_util.h" | 13 #include "base/rand_util.h" |
14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
15 #include "base/stringprintf.h" | 15 #include "base/stringprintf.h" |
16 #include "googleurl/src/gurl.h" | 16 #include "googleurl/src/gurl.h" |
17 #include "net/base/net_util.h" | 17 #include "net/base/net_util.h" |
18 #include "webkit/fileapi/file_system_operation_context.h" | 18 #include "webkit/fileapi/file_system_operation_context.h" |
19 #include "webkit/fileapi/file_system_path_manager.h" | 19 #include "webkit/fileapi/file_system_path_manager.h" |
20 #include "webkit/fileapi/file_system_types.h" | 20 #include "webkit/fileapi/file_system_types.h" |
21 #include "webkit/fileapi/file_system_usage_cache.h" | 21 #include "webkit/fileapi/file_system_usage_cache.h" |
22 #include "webkit/fileapi/file_system_util.h" | 22 #include "webkit/fileapi/file_system_util.h" |
23 #include "webkit/fileapi/local_file_system_file_util.h" | 23 #include "webkit/fileapi/local_file_util.h" |
ericu
2011/08/22 17:59:37
Is local_file_util.h needed?
Dai Mikurube (NOT FULLTIME)
2011/08/24 11:57:30
Done.
| |
24 #include "webkit/fileapi/obfuscated_file_system_file_util.h" | 24 #include "webkit/fileapi/obfuscated_file_util.h" |
25 #include "webkit/fileapi/quota_file_util.h" | 25 #include "webkit/fileapi/quota_file_util.h" |
26 #include "webkit/fileapi/sandbox_mount_point_provider.h" | 26 #include "webkit/fileapi/sandbox_mount_point_provider.h" |
27 #include "webkit/glue/webkit_glue.h" | 27 #include "webkit/glue/webkit_glue.h" |
28 #include "webkit/quota/quota_manager.h" | 28 #include "webkit/quota/quota_manager.h" |
29 | 29 |
30 using quota::QuotaManagerProxy; | 30 using quota::QuotaManagerProxy; |
31 | 31 |
32 namespace { | 32 namespace { |
33 | 33 |
34 static const FilePath::CharType kOldFileSystemUniqueNamePrefix[] = | 34 static const FilePath::CharType kOldFileSystemUniqueNamePrefix[] = |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
90 } | 90 } |
91 if (unique->empty()) | 91 if (unique->empty()) |
92 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | 92 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
93 return base::PLATFORM_FILE_OK; | 93 return base::PLATFORM_FILE_OK; |
94 } | 94 } |
95 | 95 |
96 class ObfuscatedOriginEnumerator | 96 class ObfuscatedOriginEnumerator |
97 : public fileapi::SandboxMountPointProvider::OriginEnumerator { | 97 : public fileapi::SandboxMountPointProvider::OriginEnumerator { |
98 public: | 98 public: |
99 explicit ObfuscatedOriginEnumerator( | 99 explicit ObfuscatedOriginEnumerator( |
100 fileapi::ObfuscatedFileSystemFileUtil* file_util) { | 100 fileapi::ObfuscatedFileUtil* file_util) { |
101 enum_.reset(file_util->CreateOriginEnumerator()); | 101 enum_.reset(file_util->CreateOriginEnumerator()); |
102 } | 102 } |
103 virtual ~ObfuscatedOriginEnumerator() {} | 103 virtual ~ObfuscatedOriginEnumerator() {} |
104 | 104 |
105 virtual GURL Next() OVERRIDE { | 105 virtual GURL Next() OVERRIDE { |
106 return enum_->Next(); | 106 return enum_->Next(); |
107 } | 107 } |
108 | 108 |
109 virtual bool HasFileSystemType(fileapi::FileSystemType type) const OVERRIDE { | 109 virtual bool HasFileSystemType(fileapi::FileSystemType type) const OVERRIDE { |
110 return enum_->HasFileSystemType(type); | 110 return enum_->HasFileSystemType(type); |
111 } | 111 } |
112 | 112 |
113 private: | 113 private: |
114 scoped_ptr<fileapi::ObfuscatedFileSystemFileUtil::AbstractOriginEnumerator> | 114 scoped_ptr<fileapi::ObfuscatedFileUtil::AbstractOriginEnumerator> enum_; |
115 enum_; | |
116 }; | 115 }; |
117 | 116 |
118 class OldSandboxOriginEnumerator | 117 class OldSandboxOriginEnumerator |
119 : public fileapi::SandboxMountPointProvider::OriginEnumerator { | 118 : public fileapi::SandboxMountPointProvider::OriginEnumerator { |
120 public: | 119 public: |
121 explicit OldSandboxOriginEnumerator(const FilePath& base_path) | 120 explicit OldSandboxOriginEnumerator(const FilePath& base_path) |
122 : enumerator_(base_path, false /* recursive */, | 121 : enumerator_(base_path, false /* recursive */, |
123 file_util::FileEnumerator::DIRECTORIES) {} | 122 file_util::FileEnumerator::DIRECTORIES) {} |
124 virtual ~OldSandboxOriginEnumerator() {} | 123 virtual ~OldSandboxOriginEnumerator() {} |
125 | 124 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
166 FilePath base_path = OldGetBaseDirectoryForOrigin( | 165 FilePath base_path = OldGetBaseDirectoryForOrigin( |
167 old_base_path, origin_url); | 166 old_base_path, origin_url); |
168 if (base_path.empty()) { | 167 if (base_path.empty()) { |
169 NOTREACHED(); | 168 NOTREACHED(); |
170 return FilePath(); | 169 return FilePath(); |
171 } | 170 } |
172 return base_path.AppendASCII(type_string); | 171 return base_path.AppendASCII(type_string); |
173 } | 172 } |
174 | 173 |
175 bool MigrateOneOldFileSystem( | 174 bool MigrateOneOldFileSystem( |
176 fileapi::ObfuscatedFileSystemFileUtil* file_util, | 175 fileapi::ObfuscatedFileUtil* file_util, |
177 const FilePath& old_base_path, const GURL& origin, | 176 const FilePath& old_base_path, const GURL& origin, |
178 fileapi::FileSystemType type) { | 177 fileapi::FileSystemType type) { |
179 FilePath base_path = OldGetBaseDirectoryForOriginAndType( | 178 FilePath base_path = OldGetBaseDirectoryForOriginAndType( |
180 old_base_path, origin, type); | 179 old_base_path, origin, type); |
181 if (base_path.empty()) | 180 if (base_path.empty()) |
182 return false; | 181 return false; |
183 | 182 |
184 FilePath root; | 183 FilePath root; |
185 base::PlatformFileError result = OldReadOriginDirectory(base_path, &root); | 184 base::PlatformFileError result = OldReadOriginDirectory(base_path, &root); |
186 if (base::PLATFORM_FILE_ERROR_NOT_FOUND == result) | 185 if (base::PLATFORM_FILE_ERROR_NOT_FOUND == result) |
187 return true; // There was nothing to migrate; call that a success. | 186 return true; // There was nothing to migrate; call that a success. |
188 | 187 |
189 // If we found more than one filesystem [a problem we don't know how to | 188 // If we found more than one filesystem [a problem we don't know how to |
190 // solve], the data is already not accessible through Chrome, so it won't do | 189 // solve], the data is already not accessible through Chrome, so it won't do |
191 // any harm not to migrate it. Just flag it as an error, so that we don't | 190 // any harm not to migrate it. Just flag it as an error, so that we don't |
192 // delete it. | 191 // delete it. |
193 if (base::PLATFORM_FILE_OK != result) | 192 if (base::PLATFORM_FILE_OK != result) |
194 return false; | 193 return false; |
195 | 194 |
196 if (!file_util->MigrateFromOldSandbox(origin, type, root)) { | 195 if (!file_util->MigrateFromOldSandbox(origin, type, root)) { |
197 LOG(WARNING) << "Failed to migrate filesystem for origin " << origin << | 196 LOG(WARNING) << "Failed to migrate filesystem for origin " << origin << |
198 " and type " << type; | 197 " and type " << type; |
199 return false; | 198 return false; |
200 } | 199 } |
201 return true; | 200 return true; |
202 } | 201 } |
203 | 202 |
204 void MigrateAllOldFileSystems( | 203 void MigrateAllOldFileSystems( |
205 fileapi::ObfuscatedFileSystemFileUtil* file_util, | 204 fileapi::ObfuscatedFileUtil* file_util, |
206 const FilePath& old_base_path) { | 205 const FilePath& old_base_path) { |
207 scoped_ptr<OldSandboxOriginEnumerator> old_origins( | 206 scoped_ptr<OldSandboxOriginEnumerator> old_origins( |
208 new OldSandboxOriginEnumerator(old_base_path)); | 207 new OldSandboxOriginEnumerator(old_base_path)); |
209 GURL origin; | 208 GURL origin; |
210 int failures = 0; | 209 int failures = 0; |
211 while (!(origin = old_origins->Next()).is_empty()) { | 210 while (!(origin = old_origins->Next()).is_empty()) { |
212 int failures_this_origin = 0; | 211 int failures_this_origin = 0; |
213 if (old_origins->HasFileSystemType(fileapi::kFileSystemTypeTemporary) && | 212 if (old_origins->HasFileSystemType(fileapi::kFileSystemTypeTemporary) && |
214 !MigrateOneOldFileSystem( | 213 !MigrateOneOldFileSystem( |
215 file_util, old_base_path, origin, | 214 file_util, old_base_path, origin, |
(...skipping 28 matching lines...) Expand all Loading... | |
244 } | 243 } |
245 } | 244 } |
246 | 245 |
247 // A migration, whether successful or not, will try to move this directory out | 246 // A migration, whether successful or not, will try to move this directory out |
248 // of the way so that we never try to migrate it again. We need to do this | 247 // of the way so that we never try to migrate it again. We need to do this |
249 // check on all public entry points in this file, so that it's guaranteed to be | 248 // check on all public entry points in this file, so that it's guaranteed to be |
250 // done before anyone looks up a filesystem. Most entry points start by trying | 249 // done before anyone looks up a filesystem. Most entry points start by trying |
251 // to look up the filesystem's root, so we can take care of most of them by | 250 // to look up the filesystem's root, so we can take care of most of them by |
252 // putting a check there. | 251 // putting a check there. |
253 void MigrateIfNeeded( | 252 void MigrateIfNeeded( |
254 fileapi::ObfuscatedFileSystemFileUtil* file_util, | 253 fileapi::ObfuscatedFileUtil* file_util, |
255 const FilePath& old_base_path) { | 254 const FilePath& old_base_path) { |
256 if (file_util::DirectoryExists(old_base_path)) | 255 if (file_util::DirectoryExists(old_base_path)) |
257 MigrateAllOldFileSystems(file_util, old_base_path); | 256 MigrateAllOldFileSystems(file_util, old_base_path); |
258 } | 257 } |
259 | 258 |
260 } // anonymous namespace | 259 } // anonymous namespace |
261 | 260 |
262 namespace fileapi { | 261 namespace fileapi { |
263 | 262 |
264 const FilePath::CharType SandboxMountPointProvider::kOldFileSystemDirectory[] = | 263 const FilePath::CharType SandboxMountPointProvider::kOldFileSystemDirectory[] = |
265 FILE_PATH_LITERAL("FileSystem"); | 264 FILE_PATH_LITERAL("FileSystem"); |
266 | 265 |
267 const FilePath::CharType SandboxMountPointProvider::kNewFileSystemDirectory[] = | 266 const FilePath::CharType SandboxMountPointProvider::kNewFileSystemDirectory[] = |
268 FILE_PATH_LITERAL("File System"); | 267 FILE_PATH_LITERAL("File System"); |
269 | 268 |
270 const FilePath::CharType | 269 const FilePath::CharType |
271 SandboxMountPointProvider::kRenamedOldFileSystemDirectory[] = | 270 SandboxMountPointProvider::kRenamedOldFileSystemDirectory[] = |
272 FILE_PATH_LITERAL("FS.old"); | 271 FILE_PATH_LITERAL("FS.old"); |
273 | 272 |
274 SandboxMountPointProvider::SandboxMountPointProvider( | 273 SandboxMountPointProvider::SandboxMountPointProvider( |
275 FileSystemPathManager* path_manager, | 274 FileSystemPathManager* path_manager, |
276 scoped_refptr<base::MessageLoopProxy> file_message_loop, | 275 scoped_refptr<base::MessageLoopProxy> file_message_loop, |
277 const FilePath& profile_path) | 276 const FilePath& profile_path) |
278 : FileSystemQuotaUtil(file_message_loop), | 277 : FileSystemQuotaUtil(file_message_loop), |
279 path_manager_(path_manager), | 278 path_manager_(path_manager), |
280 file_message_loop_(file_message_loop), | 279 file_message_loop_(file_message_loop), |
281 profile_path_(profile_path), | 280 profile_path_(profile_path), |
282 quota_file_util_(QuotaFileUtil::CreateDefault()), | 281 quota_file_util_(QuotaFileUtil::CreateDefault()), |
283 sandbox_file_util_( | 282 sandbox_file_util_( |
284 new ObfuscatedFileSystemFileUtil( | 283 new ObfuscatedFileUtil( |
285 profile_path.Append(kNewFileSystemDirectory), | 284 profile_path.Append(kNewFileSystemDirectory), |
286 quota_file_util_)) { | 285 quota_file_util_)) { |
287 } | 286 } |
288 | 287 |
289 SandboxMountPointProvider::~SandboxMountPointProvider() { | 288 SandboxMountPointProvider::~SandboxMountPointProvider() { |
290 if (!file_message_loop_->BelongsToCurrentThread()) | 289 if (!file_message_loop_->BelongsToCurrentThread()) |
291 file_message_loop_->ReleaseSoon(FROM_HERE, sandbox_file_util_.release()); | 290 file_message_loop_->ReleaseSoon(FROM_HERE, sandbox_file_util_.release()); |
292 } | 291 } |
293 | 292 |
294 bool SandboxMountPointProvider::IsAccessAllowed(const GURL& origin_url, | 293 bool SandboxMountPointProvider::IsAccessAllowed(const GURL& origin_url, |
295 FileSystemType type, | 294 FileSystemType type, |
296 const FilePath& unused) { | 295 const FilePath& unused) { |
297 if (type != kFileSystemTypeTemporary && type != kFileSystemTypePersistent) | 296 if (type != kFileSystemTypeTemporary && type != kFileSystemTypePersistent) |
298 return false; | 297 return false; |
299 // We essentially depend on quota to do our access controls. | 298 // We essentially depend on quota to do our access controls. |
300 return path_manager_->IsAllowedScheme(origin_url); | 299 return path_manager_->IsAllowedScheme(origin_url); |
301 } | 300 } |
302 | 301 |
303 class SandboxMountPointProvider::GetFileSystemRootPathTask | 302 class SandboxMountPointProvider::GetFileSystemRootPathTask |
304 : public base::RefCountedThreadSafe< | 303 : public base::RefCountedThreadSafe< |
305 SandboxMountPointProvider::GetFileSystemRootPathTask> { | 304 SandboxMountPointProvider::GetFileSystemRootPathTask> { |
306 public: | 305 public: |
307 GetFileSystemRootPathTask( | 306 GetFileSystemRootPathTask( |
308 scoped_refptr<base::MessageLoopProxy> file_message_loop, | 307 scoped_refptr<base::MessageLoopProxy> file_message_loop, |
309 const GURL& origin_url, | 308 const GURL& origin_url, |
310 FileSystemType type, | 309 FileSystemType type, |
311 ObfuscatedFileSystemFileUtil* file_util, | 310 ObfuscatedFileUtil* file_util, |
312 const FilePath& old_base_path, | 311 const FilePath& old_base_path, |
313 FileSystemPathManager::GetRootPathCallback* callback) | 312 FileSystemPathManager::GetRootPathCallback* callback) |
314 : file_message_loop_(file_message_loop), | 313 : file_message_loop_(file_message_loop), |
315 origin_message_loop_proxy_( | 314 origin_message_loop_proxy_( |
316 base::MessageLoopProxy::current()), | 315 base::MessageLoopProxy::current()), |
317 origin_url_(origin_url), | 316 origin_url_(origin_url), |
318 type_(type), | 317 type_(type), |
319 file_util_(file_util), | 318 file_util_(file_util), |
320 old_base_path_(old_base_path), | 319 old_base_path_(old_base_path), |
321 callback_(callback) { | 320 callback_(callback) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
355 DCHECK(!type_string.empty()); | 354 DCHECK(!type_string.empty()); |
356 std::string name = origin_identifier + ":" + type_string; | 355 std::string name = origin_identifier + ":" + type_string; |
357 callback_->Run(!root_path.empty(), root_path, name); | 356 callback_->Run(!root_path.empty(), root_path, name); |
358 callback_.reset(); | 357 callback_.reset(); |
359 } | 358 } |
360 | 359 |
361 scoped_refptr<base::MessageLoopProxy> file_message_loop_; | 360 scoped_refptr<base::MessageLoopProxy> file_message_loop_; |
362 scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_; | 361 scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_; |
363 GURL origin_url_; | 362 GURL origin_url_; |
364 FileSystemType type_; | 363 FileSystemType type_; |
365 scoped_refptr<ObfuscatedFileSystemFileUtil> file_util_; | 364 scoped_refptr<ObfuscatedFileUtil> file_util_; |
366 FilePath old_base_path_; | 365 FilePath old_base_path_; |
367 scoped_ptr<FileSystemPathManager::GetRootPathCallback> callback_; | 366 scoped_ptr<FileSystemPathManager::GetRootPathCallback> callback_; |
368 }; | 367 }; |
369 | 368 |
370 FilePath SandboxMountPointProvider::old_base_path() const { | 369 FilePath SandboxMountPointProvider::old_base_path() const { |
371 return profile_path_.Append(kOldFileSystemDirectory); | 370 return profile_path_.Append(kOldFileSystemDirectory); |
372 } | 371 } |
373 | 372 |
374 FilePath SandboxMountPointProvider::new_base_path() const { | 373 FilePath SandboxMountPointProvider::new_base_path() const { |
375 return profile_path_.Append(kNewFileSystemDirectory); | 374 return profile_path_.Append(kNewFileSystemDirectory); |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
534 // initialized and running. Read the cache file to get the usage. | 533 // initialized and running. Read the cache file to get the usage. |
535 return FileSystemUsageCache::GetUsage(usage_file_path); | 534 return FileSystemUsageCache::GetUsage(usage_file_path); |
536 } | 535 } |
537 // The usage cache has not been initialized or the cache is dirty. | 536 // The usage cache has not been initialized or the cache is dirty. |
538 // Get the directory size now and update the cache. | 537 // Get the directory size now and update the cache. |
539 FileSystemUsageCache::Delete(usage_file_path); | 538 FileSystemUsageCache::Delete(usage_file_path); |
540 | 539 |
541 FileSystemOperationContext context(NULL, sandbox_file_util_); | 540 FileSystemOperationContext context(NULL, sandbox_file_util_); |
542 context.set_src_origin_url(origin_url); | 541 context.set_src_origin_url(origin_url); |
543 context.set_src_type(type); | 542 context.set_src_type(type); |
544 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( | 543 scoped_ptr<FileApiFileUtil::AbstractFileEnumerator> enumerator( |
545 sandbox_file_util_->CreateFileEnumerator(&context, FilePath())); | 544 sandbox_file_util_->CreateFileEnumerator(&context, FilePath())); |
546 | 545 |
547 FilePath file_path_each; | 546 FilePath file_path_each; |
548 int64 usage = 0; | 547 int64 usage = 0; |
549 | 548 |
550 // TODO(ericu): This could be made much more efficient if the | 549 // TODO(ericu): This could be made much more efficient if the |
551 // AbstractFileEnumerator also had an interface to tell you the size of the | 550 // AbstractFileEnumerator also had an interface to tell you the size of the |
552 // file. ObfuscatedFileSystemFileEnumerator has already looked up the data, | 551 // file. ObfuscatedFileSystemFileEnumerator has already looked up the data, |
553 // and it's a big waste to look it up again. The other implementers could | 552 // and it's a big waste to look it up again. The other implementers could |
554 // easily add it on-demand, so as not to waste time when it's not needed. | 553 // easily add it on-demand, so as not to waste time when it's not needed. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
613 | 612 |
614 void SandboxMountPointProvider::EndUpdateOriginOnFileThread( | 613 void SandboxMountPointProvider::EndUpdateOriginOnFileThread( |
615 const GURL& origin_url, fileapi::FileSystemType type) { | 614 const GURL& origin_url, fileapi::FileSystemType type) { |
616 DCHECK(type == fileapi::kFileSystemTypeTemporary || | 615 DCHECK(type == fileapi::kFileSystemTypeTemporary || |
617 type == fileapi::kFileSystemTypePersistent); | 616 type == fileapi::kFileSystemTypePersistent); |
618 FilePath usage_file_path = GetUsageCachePathForOriginAndType( | 617 FilePath usage_file_path = GetUsageCachePathForOriginAndType( |
619 origin_url, type); | 618 origin_url, type); |
620 FileSystemUsageCache::DecrementDirty(usage_file_path); | 619 FileSystemUsageCache::DecrementDirty(usage_file_path); |
621 } | 620 } |
622 | 621 |
623 FileSystemFileUtil* SandboxMountPointProvider::GetFileSystemFileUtil() { | 622 FileApiFileUtil* SandboxMountPointProvider::GetFileUtil() { |
624 return sandbox_file_util_.get(); | 623 return sandbox_file_util_.get(); |
625 } | 624 } |
626 | 625 |
627 FilePath SandboxMountPointProvider::GetUsageCachePathForOriginAndType( | 626 FilePath SandboxMountPointProvider::GetUsageCachePathForOriginAndType( |
628 const GURL& origin_url, fileapi::FileSystemType type) const { | 627 const GURL& origin_url, fileapi::FileSystemType type) const { |
629 FilePath base_path = | 628 FilePath base_path = |
630 GetBaseDirectoryForOriginAndType(origin_url, type, false); | 629 GetBaseDirectoryForOriginAndType(origin_url, type, false); |
631 if (base_path.empty()) | 630 if (base_path.empty()) |
632 return FilePath(); | 631 return FilePath(); |
633 return base_path.AppendASCII(FileSystemUsageCache::kUsageFileName); | 632 return base_path.AppendASCII(FileSystemUsageCache::kUsageFileName); |
(...skipping 18 matching lines...) Expand all Loading... | |
652 | 651 |
653 // Creates the root directory. | 652 // Creates the root directory. |
654 root = origin_base_path.Append(OldCreateUniqueDirectoryName(origin_url)); | 653 root = origin_base_path.Append(OldCreateUniqueDirectoryName(origin_url)); |
655 if (!file_util::CreateDirectory(root)) | 654 if (!file_util::CreateDirectory(root)) |
656 return FilePath(); | 655 return FilePath(); |
657 | 656 |
658 return root; | 657 return root; |
659 } | 658 } |
660 | 659 |
661 } // namespace fileapi | 660 } // namespace fileapi |
OLD | NEW |