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/local_file_system_file_util.h" | 5 #include "webkit/fileapi/local_file_util.h" |
6 | 6 |
7 #include "base/file_util_proxy.h" | 7 #include "base/file_util_proxy.h" |
8 #include "googleurl/src/gurl.h" | 8 #include "googleurl/src/gurl.h" |
9 #include "webkit/fileapi/file_system_context.h" | 9 #include "webkit/fileapi/file_system_context.h" |
10 #include "webkit/fileapi/file_system_operation_context.h" | 10 #include "webkit/fileapi/file_system_operation_context.h" |
11 #include "webkit/fileapi/file_system_path_manager.h" | 11 #include "webkit/fileapi/file_system_path_manager.h" |
12 #include "webkit/fileapi/file_system_types.h" | 12 #include "webkit/fileapi/file_system_types.h" |
13 #include "webkit/fileapi/file_system_util.h" | 13 #include "webkit/fileapi/file_system_util.h" |
14 | 14 |
15 namespace fileapi { | 15 namespace fileapi { |
16 | 16 |
17 LocalFileSystemFileUtil::LocalFileSystemFileUtil( | 17 class LocalFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { |
18 FileSystemFileUtil* underlying_file_util) | 18 public: |
19 : underlying_file_util_(underlying_file_util) { | 19 LocalFileEnumerator(const FilePath& platform_root_path, |
| 20 const FilePath& virtual_root_path, |
| 21 bool recursive, |
| 22 file_util::FileEnumerator::FileType file_type) |
| 23 : file_enum_(platform_root_path, recursive, file_type), |
| 24 platform_root_path_(platform_root_path), |
| 25 virtual_root_path_(virtual_root_path) { |
| 26 } |
| 27 |
| 28 ~LocalFileEnumerator() {} |
| 29 |
| 30 virtual FilePath Next(); |
| 31 virtual bool IsDirectory(); |
| 32 |
| 33 private: |
| 34 file_util::FileEnumerator file_enum_; |
| 35 FilePath platform_root_path_; |
| 36 FilePath virtual_root_path_; |
| 37 }; |
| 38 |
| 39 FilePath LocalFileEnumerator::Next() { |
| 40 FilePath next = file_enum_.Next(); |
| 41 if (next.empty()) |
| 42 return next; |
| 43 |
| 44 FilePath path; |
| 45 platform_root_path_.AppendRelativePath(next, &path); |
| 46 return virtual_root_path_.Append(path); |
20 } | 47 } |
21 | 48 |
22 LocalFileSystemFileUtil::~LocalFileSystemFileUtil() { | 49 bool LocalFileEnumerator::IsDirectory() { |
| 50 file_util::FileEnumerator::FindInfo file_util_info; |
| 51 file_enum_.GetFindInfo(&file_util_info); |
| 52 return file_util::FileEnumerator::IsDirectory(file_util_info); |
23 } | 53 } |
24 | 54 |
25 PlatformFileError LocalFileSystemFileUtil::CreateOrOpen( | 55 LocalFileUtil::LocalFileUtil(FileSystemFileUtil* underlying_file_util) |
| 56 : FileSystemFileUtil(underlying_file_util) { |
| 57 } |
| 58 |
| 59 LocalFileUtil::~LocalFileUtil() { |
| 60 } |
| 61 |
| 62 PlatformFileError LocalFileUtil::CreateOrOpen( |
26 FileSystemOperationContext* context, | 63 FileSystemOperationContext* context, |
27 const FilePath& file_path, int file_flags, | 64 const FilePath& file_path, int file_flags, |
28 PlatformFile* file_handle, bool* created) { | 65 PlatformFile* file_handle, bool* created) { |
29 FilePath local_path = | 66 FilePath local_path = |
30 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 67 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
31 file_path); | 68 file_path); |
32 if (local_path.empty()) | 69 if (local_path.empty()) |
33 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 70 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
34 return underlying_file_util_->CreateOrOpen( | 71 return underlying_file_util()->CreateOrOpen( |
35 context, local_path, file_flags, file_handle, created); | 72 context, local_path, file_flags, file_handle, created); |
36 } | 73 } |
37 | 74 |
38 PlatformFileError LocalFileSystemFileUtil::EnsureFileExists( | 75 PlatformFileError LocalFileUtil::EnsureFileExists( |
39 FileSystemOperationContext* context, | 76 FileSystemOperationContext* context, |
40 const FilePath& file_path, | 77 const FilePath& file_path, |
41 bool* created) { | 78 bool* created) { |
42 FilePath local_path = | 79 FilePath local_path = |
43 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 80 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
44 file_path); | 81 file_path); |
45 if (local_path.empty()) | 82 if (local_path.empty()) |
46 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 83 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
47 return underlying_file_util_->EnsureFileExists( | 84 return underlying_file_util()->EnsureFileExists( |
48 context, local_path, created); | 85 context, local_path, created); |
49 } | 86 } |
50 | 87 |
51 PlatformFileError LocalFileSystemFileUtil::GetLocalFilePath( | 88 PlatformFileError LocalFileUtil::CreateDirectory( |
52 FileSystemOperationContext* context, | 89 FileSystemOperationContext* context, |
53 const FilePath& virtual_path, | 90 const FilePath& file_path, |
54 FilePath* local_path) { | 91 bool exclusive, |
55 FilePath path = | 92 bool recursive) { |
| 93 FilePath local_path = |
56 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 94 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
57 virtual_path); | 95 file_path); |
58 if (path.empty()) | 96 if (local_path.empty()) |
59 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | 97 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
60 | 98 return underlying_file_util()->CreateDirectory( |
61 *local_path = path; | 99 context, local_path, exclusive, recursive); |
62 return base::PLATFORM_FILE_OK; | |
63 } | 100 } |
64 | 101 |
65 PlatformFileError LocalFileSystemFileUtil::GetFileInfo( | 102 PlatformFileError LocalFileUtil::GetFileInfo( |
66 FileSystemOperationContext* context, | 103 FileSystemOperationContext* context, |
67 const FilePath& file_path, | 104 const FilePath& file_path, |
68 base::PlatformFileInfo* file_info, | 105 base::PlatformFileInfo* file_info, |
69 FilePath* platform_file_path) { | 106 FilePath* platform_file_path) { |
70 FilePath local_path = | 107 FilePath local_path = |
71 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 108 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
72 file_path); | 109 file_path); |
73 if (local_path.empty()) | 110 if (local_path.empty()) |
74 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 111 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
75 return underlying_file_util_->GetFileInfo( | 112 return underlying_file_util()->GetFileInfo( |
76 context, local_path, file_info, platform_file_path); | 113 context, local_path, file_info, platform_file_path); |
77 } | 114 } |
78 | 115 |
79 PlatformFileError LocalFileSystemFileUtil::ReadDirectory( | 116 PlatformFileError LocalFileUtil::ReadDirectory( |
80 FileSystemOperationContext* context, | 117 FileSystemOperationContext* context, |
81 const FilePath& file_path, | 118 const FilePath& file_path, |
82 std::vector<base::FileUtilProxy::Entry>* entries) { | 119 std::vector<base::FileUtilProxy::Entry>* entries) { |
83 // TODO(kkanetkar): Implement directory read in multiple chunks. | 120 // TODO(kkanetkar): Implement directory read in multiple chunks. |
84 FilePath local_path = | 121 FilePath local_path = |
85 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 122 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
86 file_path); | 123 file_path); |
87 if (local_path.empty()) | 124 if (local_path.empty()) |
88 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 125 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
89 return underlying_file_util_->ReadDirectory( | 126 return underlying_file_util()->ReadDirectory( |
90 context, local_path, entries); | 127 context, local_path, entries); |
91 } | 128 } |
92 | 129 |
93 PlatformFileError LocalFileSystemFileUtil::CreateDirectory( | 130 FileSystemFileUtil::AbstractFileEnumerator* LocalFileUtil::CreateFileEnumerator( |
94 FileSystemOperationContext* context, | 131 FileSystemOperationContext* context, |
95 const FilePath& file_path, | 132 const FilePath& root_path) { |
96 bool exclusive, | |
97 bool recursive) { | |
98 FilePath local_path = | 133 FilePath local_path = |
99 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 134 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
100 file_path); | 135 root_path); |
101 if (local_path.empty()) | 136 if (local_path.empty()) |
102 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 137 return new EmptyFileEnumerator(); |
103 return underlying_file_util_->CreateDirectory( | 138 return new LocalFileEnumerator( |
104 context, local_path, exclusive, recursive); | 139 local_path, root_path, true, |
| 140 static_cast<file_util::FileEnumerator::FileType>( |
| 141 file_util::FileEnumerator::FILES | |
| 142 file_util::FileEnumerator::DIRECTORIES)); |
105 } | 143 } |
106 | 144 |
107 PlatformFileError LocalFileSystemFileUtil::CopyOrMoveFile( | 145 PlatformFileError LocalFileUtil::GetLocalFilePath( |
108 FileSystemOperationContext* context, | 146 FileSystemOperationContext* context, |
109 const FilePath& src_file_path, | 147 const FilePath& virtual_path, |
110 const FilePath& dest_file_path, | 148 FilePath* local_path) { |
111 bool copy) { | 149 FilePath path = |
112 // TODO(ericu): If they share a root URL, this could be optimized. | |
113 FilePath local_src_path = | |
114 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 150 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
115 src_file_path); | 151 virtual_path); |
116 if (local_src_path.empty()) | 152 if (path.empty()) |
117 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 153 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
118 FilePath local_dest_path = | 154 |
119 GetLocalPath(context, context->dest_origin_url(), context->dest_type(), | 155 *local_path = path; |
120 dest_file_path); | 156 return base::PLATFORM_FILE_OK; |
121 if (local_dest_path.empty()) | |
122 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
123 return underlying_file_util_->CopyOrMoveFile( | |
124 context, local_src_path, local_dest_path, copy); | |
125 } | 157 } |
126 | 158 |
127 // TODO(dmikurube): Make it independent from CopyOrMoveFile. | 159 PlatformFileError LocalFileUtil::Touch( |
128 PlatformFileError LocalFileSystemFileUtil::CopyInForeignFile( | |
129 FileSystemOperationContext* context, | |
130 const FilePath& src_file_path, | |
131 const FilePath& dest_file_path) { | |
132 if (src_file_path.empty()) | |
133 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
134 FilePath local_dest_path = | |
135 GetLocalPath(context, context->dest_origin_url(), context->dest_type(), | |
136 dest_file_path); | |
137 if (local_dest_path.empty()) | |
138 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
139 return underlying_file_util_->CopyOrMoveFile( | |
140 context, src_file_path, local_dest_path, true); | |
141 } | |
142 | |
143 PlatformFileError LocalFileSystemFileUtil::DeleteFile( | |
144 FileSystemOperationContext* context, | |
145 const FilePath& file_path) { | |
146 FilePath local_path = | |
147 GetLocalPath(context, context->src_origin_url(), context->src_type(), | |
148 file_path); | |
149 if (local_path.empty()) | |
150 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
151 return underlying_file_util_->DeleteFile( | |
152 context, local_path); | |
153 } | |
154 | |
155 PlatformFileError LocalFileSystemFileUtil::DeleteSingleDirectory( | |
156 FileSystemOperationContext* context, | |
157 const FilePath& file_path) { | |
158 FilePath local_path = | |
159 GetLocalPath(context, context->src_origin_url(), context->src_type(), | |
160 file_path); | |
161 if (local_path.empty()) | |
162 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
163 return underlying_file_util_->DeleteSingleDirectory( | |
164 context, local_path); | |
165 } | |
166 | |
167 PlatformFileError LocalFileSystemFileUtil::Touch( | |
168 FileSystemOperationContext* context, | 160 FileSystemOperationContext* context, |
169 const FilePath& file_path, | 161 const FilePath& file_path, |
170 const base::Time& last_access_time, | 162 const base::Time& last_access_time, |
171 const base::Time& last_modified_time) { | 163 const base::Time& last_modified_time) { |
172 FilePath local_path = | 164 FilePath local_path = |
173 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 165 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
174 file_path); | 166 file_path); |
175 if (local_path.empty()) | 167 if (local_path.empty()) |
176 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 168 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
177 return underlying_file_util_->Touch( | 169 return underlying_file_util()->Touch( |
178 context, local_path, last_access_time, last_modified_time); | 170 context, local_path, last_access_time, last_modified_time); |
179 } | 171 } |
180 | 172 |
181 PlatformFileError LocalFileSystemFileUtil::Truncate( | 173 PlatformFileError LocalFileUtil::Truncate( |
182 FileSystemOperationContext* context, | 174 FileSystemOperationContext* context, |
183 const FilePath& file_path, | 175 const FilePath& file_path, |
184 int64 length) { | 176 int64 length) { |
185 FilePath local_path = | 177 FilePath local_path = |
186 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 178 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
187 file_path); | 179 file_path); |
188 if (local_path.empty()) | 180 if (local_path.empty()) |
189 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 181 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
190 return underlying_file_util_->Truncate( | 182 return underlying_file_util()->Truncate( |
191 context, local_path, length); | 183 context, local_path, length); |
192 } | 184 } |
193 | 185 |
194 bool LocalFileSystemFileUtil::PathExists( | 186 bool LocalFileUtil::PathExists( |
195 FileSystemOperationContext* context, | 187 FileSystemOperationContext* context, |
196 const FilePath& file_path) { | 188 const FilePath& file_path) { |
197 FilePath local_path = | 189 FilePath local_path = |
198 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 190 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
199 file_path); | 191 file_path); |
200 if (local_path.empty()) | 192 if (local_path.empty()) |
201 return false; | 193 return false; |
202 return underlying_file_util_->PathExists( | 194 return underlying_file_util()->PathExists( |
203 context, local_path); | 195 context, local_path); |
204 } | 196 } |
205 | 197 |
206 bool LocalFileSystemFileUtil::DirectoryExists( | 198 bool LocalFileUtil::DirectoryExists( |
207 FileSystemOperationContext* context, | 199 FileSystemOperationContext* context, |
208 const FilePath& file_path) { | 200 const FilePath& file_path) { |
209 FilePath local_path = | 201 FilePath local_path = |
210 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 202 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
211 file_path); | 203 file_path); |
212 if (local_path.empty()) | 204 if (local_path.empty()) |
213 return false; | 205 return false; |
214 return underlying_file_util_->DirectoryExists( | 206 return underlying_file_util()->DirectoryExists( |
215 context, local_path); | 207 context, local_path); |
216 } | 208 } |
217 | 209 |
218 bool LocalFileSystemFileUtil::IsDirectoryEmpty( | 210 bool LocalFileUtil::IsDirectoryEmpty( |
219 FileSystemOperationContext* context, | 211 FileSystemOperationContext* context, |
220 const FilePath& file_path) { | 212 const FilePath& file_path) { |
221 FilePath local_path = | 213 FilePath local_path = |
222 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 214 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
223 file_path); | 215 file_path); |
224 if (local_path.empty()) | 216 if (local_path.empty()) |
225 return true; | 217 return true; |
226 return underlying_file_util_->IsDirectoryEmpty( | 218 return underlying_file_util()->IsDirectoryEmpty( |
227 context, local_path); | 219 context, local_path); |
228 } | 220 } |
229 | 221 |
230 class LocalFileSystemFileEnumerator | 222 PlatformFileError LocalFileUtil::CopyOrMoveFile( |
231 : public FileSystemFileUtil::AbstractFileEnumerator { | 223 FileSystemOperationContext* context, |
232 public: | 224 const FilePath& src_file_path, |
233 LocalFileSystemFileEnumerator(const FilePath& platform_root_path, | 225 const FilePath& dest_file_path, |
234 const FilePath& virtual_root_path, | 226 bool copy) { |
235 bool recursive, | 227 // TODO(ericu): If they share a root URL, this could be optimized. |
236 file_util::FileEnumerator::FileType file_type) | 228 FilePath local_src_path = |
237 : file_enum_(platform_root_path, recursive, file_type), | 229 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
238 platform_root_path_(platform_root_path), | 230 src_file_path); |
239 virtual_root_path_(virtual_root_path) { | 231 if (local_src_path.empty()) |
240 } | 232 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
241 | 233 FilePath local_dest_path = |
242 ~LocalFileSystemFileEnumerator() {} | 234 GetLocalPath(context, context->dest_origin_url(), context->dest_type(), |
243 | 235 dest_file_path); |
244 virtual FilePath Next(); | 236 if (local_dest_path.empty()) |
245 virtual bool IsDirectory(); | 237 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
246 | 238 return underlying_file_util()->CopyOrMoveFile( |
247 private: | 239 context, local_src_path, local_dest_path, copy); |
248 file_util::FileEnumerator file_enum_; | |
249 FilePath platform_root_path_; | |
250 FilePath virtual_root_path_; | |
251 }; | |
252 | |
253 FilePath LocalFileSystemFileEnumerator::Next() { | |
254 FilePath next = file_enum_.Next(); | |
255 if (next.empty()) | |
256 return next; | |
257 | |
258 FilePath path; | |
259 platform_root_path_.AppendRelativePath(next, &path); | |
260 return virtual_root_path_.Append(path); | |
261 } | 240 } |
262 | 241 |
263 bool LocalFileSystemFileEnumerator::IsDirectory() { | 242 // TODO(dmikurube): Make it independent from CopyOrMoveFile. |
264 file_util::FileEnumerator::FindInfo file_util_info; | 243 PlatformFileError LocalFileUtil::CopyInForeignFile( |
265 file_enum_.GetFindInfo(&file_util_info); | 244 FileSystemOperationContext* context, |
266 return file_util::FileEnumerator::IsDirectory(file_util_info); | 245 const FilePath& src_file_path, |
| 246 const FilePath& dest_file_path) { |
| 247 if (src_file_path.empty()) |
| 248 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
| 249 FilePath local_dest_path = |
| 250 GetLocalPath(context, context->dest_origin_url(), context->dest_type(), |
| 251 dest_file_path); |
| 252 if (local_dest_path.empty()) |
| 253 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
| 254 return underlying_file_util()->CopyOrMoveFile( |
| 255 context, src_file_path, local_dest_path, true); |
267 } | 256 } |
268 | 257 |
269 FileSystemFileUtil::AbstractFileEnumerator* | 258 PlatformFileError LocalFileUtil::DeleteFile( |
270 LocalFileSystemFileUtil::CreateFileEnumerator( | |
271 FileSystemOperationContext* context, | 259 FileSystemOperationContext* context, |
272 const FilePath& root_path) { | 260 const FilePath& file_path) { |
273 FilePath local_path = | 261 FilePath local_path = |
274 GetLocalPath(context, context->src_origin_url(), context->src_type(), | 262 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
275 root_path); | 263 file_path); |
276 if (local_path.empty()) | 264 if (local_path.empty()) |
277 return new EmptyFileEnumerator(); | 265 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
278 return new LocalFileSystemFileEnumerator( | 266 return underlying_file_util()->DeleteFile( |
279 local_path, root_path, true, | 267 context, local_path); |
280 static_cast<file_util::FileEnumerator::FileType>( | |
281 file_util::FileEnumerator::FILES | | |
282 file_util::FileEnumerator::DIRECTORIES)); | |
283 } | 268 } |
284 | 269 |
285 FilePath LocalFileSystemFileUtil::GetLocalPath( | 270 PlatformFileError LocalFileUtil::DeleteSingleDirectory( |
| 271 FileSystemOperationContext* context, |
| 272 const FilePath& file_path) { |
| 273 FilePath local_path = |
| 274 GetLocalPath(context, context->src_origin_url(), context->src_type(), |
| 275 file_path); |
| 276 if (local_path.empty()) |
| 277 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
| 278 return underlying_file_util()->DeleteSingleDirectory( |
| 279 context, local_path); |
| 280 } |
| 281 |
| 282 FilePath LocalFileUtil::GetLocalPath( |
286 FileSystemOperationContext* context, | 283 FileSystemOperationContext* context, |
287 const GURL& origin_url, | 284 const GURL& origin_url, |
288 FileSystemType type, | 285 FileSystemType type, |
289 const FilePath& virtual_path) { | 286 const FilePath& virtual_path) { |
290 FilePath root = context->file_system_context()->path_manager()-> | 287 FilePath root = context->file_system_context()->path_manager()-> |
291 ValidateFileSystemRootAndGetPathOnFileThread(origin_url, type, | 288 ValidateFileSystemRootAndGetPathOnFileThread(origin_url, type, |
292 virtual_path, false); | 289 virtual_path, false); |
293 if (root.empty()) | 290 if (root.empty()) |
294 return FilePath(); | 291 return FilePath(); |
295 return root.Append(virtual_path); | 292 return root.Append(virtual_path); |
296 } | 293 } |
297 | 294 |
298 } // namespace fileapi | 295 } // namespace fileapi |
OLD | NEW |