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 "storage/browser/fileapi/local_file_util.h"
7 #include "base/files/file_enumerator.h"
8 #include "base/files/file_util.h"
9 #include "base/files/file_util_proxy.h"
10 #include "storage/browser/fileapi/async_file_util_adapter.h"
11 #include "storage/browser/fileapi/file_system_context.h"
12 #include "storage/browser/fileapi/file_system_operation_context.h"
13 #include "storage/browser/fileapi/file_system_url.h"
14 #include "storage/browser/fileapi/native_file_util.h"
15 #include "storage/common/fileapi/file_system_types.h"
16 #include "storage/common/fileapi/file_system_util.h"
21 AsyncFileUtil
* AsyncFileUtil::CreateForLocalFileSystem() {
22 return new AsyncFileUtilAdapter(new LocalFileUtil());
25 class LocalFileEnumerator
: public FileSystemFileUtil::AbstractFileEnumerator
{
27 LocalFileEnumerator(const base::FilePath
& platform_root_path
,
28 const base::FilePath
& virtual_root_path
,
30 : file_enum_(platform_root_path
, false /* recursive */, file_type
),
31 platform_root_path_(platform_root_path
),
32 virtual_root_path_(virtual_root_path
) {
35 virtual ~LocalFileEnumerator() {}
37 virtual base::FilePath
Next() OVERRIDE
;
38 virtual int64
Size() OVERRIDE
;
39 virtual base::Time
LastModifiedTime() OVERRIDE
;
40 virtual bool IsDirectory() OVERRIDE
;
43 base::FileEnumerator file_enum_
;
44 base::FileEnumerator::FileInfo file_util_info_
;
45 base::FilePath platform_root_path_
;
46 base::FilePath virtual_root_path_
;
49 base::FilePath
LocalFileEnumerator::Next() {
50 base::FilePath next
= file_enum_
.Next();
51 // Don't return symlinks.
52 while (!next
.empty() && base::IsLink(next
))
53 next
= file_enum_
.Next();
56 file_util_info_
= file_enum_
.GetInfo();
59 platform_root_path_
.AppendRelativePath(next
, &path
);
60 return virtual_root_path_
.Append(path
);
63 int64
LocalFileEnumerator::Size() {
64 return file_util_info_
.GetSize();
67 base::Time
LocalFileEnumerator::LastModifiedTime() {
68 return file_util_info_
.GetLastModifiedTime();
71 bool LocalFileEnumerator::IsDirectory() {
72 return file_util_info_
.IsDirectory();
75 LocalFileUtil::LocalFileUtil() {}
77 LocalFileUtil::~LocalFileUtil() {}
79 base::File
LocalFileUtil::CreateOrOpen(
80 FileSystemOperationContext
* context
,
81 const FileSystemURL
& url
, int file_flags
) {
82 base::FilePath file_path
;
83 base::File::Error error
= GetLocalFilePath(context
, url
, &file_path
);
84 if (error
!= base::File::FILE_OK
)
85 return base::File(error
);
86 // Disallow opening files in symlinked paths.
87 if (base::IsLink(file_path
))
88 return base::File(base::File::FILE_ERROR_NOT_FOUND
);
90 return NativeFileUtil::CreateOrOpen(file_path
, file_flags
);
93 base::File::Error
LocalFileUtil::EnsureFileExists(
94 FileSystemOperationContext
* context
,
95 const FileSystemURL
& url
,
97 base::FilePath file_path
;
98 base::File::Error error
= GetLocalFilePath(context
, url
, &file_path
);
99 if (error
!= base::File::FILE_OK
)
101 return NativeFileUtil::EnsureFileExists(file_path
, created
);
104 base::File::Error
LocalFileUtil::CreateDirectory(
105 FileSystemOperationContext
* context
,
106 const FileSystemURL
& url
,
109 base::FilePath file_path
;
110 base::File::Error error
= GetLocalFilePath(context
, url
, &file_path
);
111 if (error
!= base::File::FILE_OK
)
113 return NativeFileUtil::CreateDirectory(file_path
, exclusive
, recursive
);
116 base::File::Error
LocalFileUtil::GetFileInfo(
117 FileSystemOperationContext
* context
,
118 const FileSystemURL
& url
,
119 base::File::Info
* file_info
,
120 base::FilePath
* platform_file_path
) {
121 base::FilePath file_path
;
122 base::File::Error error
= GetLocalFilePath(context
, url
, &file_path
);
123 if (error
!= base::File::FILE_OK
)
125 // We should not follow symbolic links in sandboxed file system.
126 if (base::IsLink(file_path
))
127 return base::File::FILE_ERROR_NOT_FOUND
;
129 error
= NativeFileUtil::GetFileInfo(file_path
, file_info
);
130 if (error
== base::File::FILE_OK
)
131 *platform_file_path
= file_path
;
135 scoped_ptr
<FileSystemFileUtil::AbstractFileEnumerator
> LocalFileUtil::
136 CreateFileEnumerator(
137 FileSystemOperationContext
* context
,
138 const FileSystemURL
& root_url
) {
139 base::FilePath file_path
;
140 if (GetLocalFilePath(context
, root_url
, &file_path
) !=
141 base::File::FILE_OK
) {
142 return make_scoped_ptr(new EmptyFileEnumerator
)
143 .PassAs
<FileSystemFileUtil::AbstractFileEnumerator
>();
145 return make_scoped_ptr(new LocalFileEnumerator(
146 file_path
, root_url
.path(),
147 base::FileEnumerator::FILES
| base::FileEnumerator::DIRECTORIES
))
148 .PassAs
<FileSystemFileUtil::AbstractFileEnumerator
>();
151 base::File::Error
LocalFileUtil::GetLocalFilePath(
152 FileSystemOperationContext
* context
,
153 const FileSystemURL
& url
,
154 base::FilePath
* local_file_path
) {
155 DCHECK(local_file_path
);
156 DCHECK(url
.is_valid());
157 if (url
.path().empty()) {
158 // Root direcory case, which should not be accessed.
159 return base::File::FILE_ERROR_ACCESS_DENIED
;
161 *local_file_path
= url
.path();
162 return base::File::FILE_OK
;
165 base::File::Error
LocalFileUtil::Touch(
166 FileSystemOperationContext
* context
,
167 const FileSystemURL
& url
,
168 const base::Time
& last_access_time
,
169 const base::Time
& last_modified_time
) {
170 base::FilePath file_path
;
171 base::File::Error error
= GetLocalFilePath(context
, url
, &file_path
);
172 if (error
!= base::File::FILE_OK
)
174 return NativeFileUtil::Touch(file_path
, last_access_time
, last_modified_time
);
177 base::File::Error
LocalFileUtil::Truncate(
178 FileSystemOperationContext
* context
,
179 const FileSystemURL
& url
,
181 base::FilePath file_path
;
182 base::File::Error error
= GetLocalFilePath(context
, url
, &file_path
);
183 if (error
!= base::File::FILE_OK
)
185 return NativeFileUtil::Truncate(file_path
, length
);
188 base::File::Error
LocalFileUtil::CopyOrMoveFile(
189 FileSystemOperationContext
* context
,
190 const FileSystemURL
& src_url
,
191 const FileSystemURL
& dest_url
,
192 CopyOrMoveOption option
,
194 base::FilePath src_file_path
;
195 base::File::Error error
= GetLocalFilePath(context
, src_url
, &src_file_path
);
196 if (error
!= base::File::FILE_OK
)
199 base::FilePath dest_file_path
;
200 error
= GetLocalFilePath(context
, dest_url
, &dest_file_path
);
201 if (error
!= base::File::FILE_OK
)
204 return NativeFileUtil::CopyOrMoveFile(
208 storage::NativeFileUtil::CopyOrMoveModeForDestination(dest_url
, copy
));
211 base::File::Error
LocalFileUtil::CopyInForeignFile(
212 FileSystemOperationContext
* context
,
213 const base::FilePath
& src_file_path
,
214 const FileSystemURL
& dest_url
) {
215 if (src_file_path
.empty())
216 return base::File::FILE_ERROR_INVALID_OPERATION
;
218 base::FilePath dest_file_path
;
219 base::File::Error error
=
220 GetLocalFilePath(context
, dest_url
, &dest_file_path
);
221 if (error
!= base::File::FILE_OK
)
223 return NativeFileUtil::CopyOrMoveFile(
226 FileSystemOperation::OPTION_NONE
,
227 storage::NativeFileUtil::CopyOrMoveModeForDestination(dest_url
,
231 base::File::Error
LocalFileUtil::DeleteFile(
232 FileSystemOperationContext
* context
,
233 const FileSystemURL
& url
) {
234 base::FilePath file_path
;
235 base::File::Error error
= GetLocalFilePath(context
, url
, &file_path
);
236 if (error
!= base::File::FILE_OK
)
238 return NativeFileUtil::DeleteFile(file_path
);
241 base::File::Error
LocalFileUtil::DeleteDirectory(
242 FileSystemOperationContext
* context
,
243 const FileSystemURL
& url
) {
244 base::FilePath file_path
;
245 base::File::Error error
= GetLocalFilePath(context
, url
, &file_path
);
246 if (error
!= base::File::FILE_OK
)
248 return NativeFileUtil::DeleteDirectory(file_path
);
251 storage::ScopedFile
LocalFileUtil::CreateSnapshotFile(
252 FileSystemOperationContext
* context
,
253 const FileSystemURL
& url
,
254 base::File::Error
* error
,
255 base::File::Info
* file_info
,
256 base::FilePath
* platform_path
) {
258 // We're just returning the local file information.
259 *error
= GetFileInfo(context
, url
, file_info
, platform_path
);
260 if (*error
== base::File::FILE_OK
&& file_info
->is_directory
)
261 *error
= base::File::FILE_ERROR_NOT_A_FILE
;
262 return storage::ScopedFile();
265 } // namespace storage