Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: webkit/chromeos/fileapi/memory_file_util.cc

Issue 8907014: Implement async verision of FileSystemFileUtil and in-memory file system for testing purposes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/bind.h"
6 #include "base/message_loop.h"
7 #include "webkit/chromeos/fileapi/memory_file_util.h"
8
9 namespace {
10 const int kDefaultReadDirectoryBufferSize = 100;
11 } // namespace
12
13 namespace fileapi {
14
15 MemoryFileUtil::MemoryFileUtil(const FilePath& root_path)
16 : read_directory_buffer_size_(kDefaultReadDirectoryBufferSize) {
17 FileEntry root;
18 root.is_directory = true;
19 root.last_modified = base::Time::Now();
20
21 files_[root_path] = root;
22 }
23
24 void MemoryFileUtil::GetFileInfo(
25 const FilePath& file_path,
26 const GetFileInfoCallback& callback) {
27 MessageLoop::current()->PostTask(
28 FROM_HERE,
29 base::Bind(&MemoryFileUtil::DoGetFileInfo, base::Unretained(this),
30 file_path.StripTrailingSeparators(), callback));
31 }
32
33 void MemoryFileUtil::Create(
34 const FilePath& file_path,
35 const StatusCallback& callback) {
36 MessageLoop::current()->PostTask(
37 FROM_HERE,
38 base::Bind(&MemoryFileUtil::DoCreate, base::Unretained(this),
39 file_path.StripTrailingSeparators(), false, callback));
40 }
41
42 void MemoryFileUtil::Truncate(
43 const FilePath& file_path,
44 int64 length,
45 const StatusCallback& callback) {
46 MessageLoop::current()->PostTask(
47 FROM_HERE,
48 base::Bind(&MemoryFileUtil::DoTruncate, base::Unretained(this),
49 file_path.StripTrailingSeparators(), length, callback));
50 }
51
52 void MemoryFileUtil::Touch(
53 const FilePath& file_path,
54 const base::Time& last_access_time,
55 const base::Time& last_modified_time,
56 const StatusCallback& callback) {
57 MessageLoop::current()->PostTask(
58 FROM_HERE,
59 base::Bind(&MemoryFileUtil::DoTouch, base::Unretained(this),
60 file_path.StripTrailingSeparators(),
61 last_modified_time, callback));
62 }
63
64 void MemoryFileUtil::Remove(
65 const FilePath& file_path,
66 bool recursive,
67 const StatusCallback& callback) {
68 if (recursive) {
69 MessageLoop::current()->PostTask(
70 FROM_HERE,
71 base::Bind(&MemoryFileUtil::DoRemoveRecursive,
72 base::Unretained(this), file_path.StripTrailingSeparators(),
73 callback));
74 } else {
75 MessageLoop::current()->PostTask(
76 FROM_HERE,
77 base::Bind(&MemoryFileUtil::DoRemoveSingleFile,
78 base::Unretained(this), file_path.StripTrailingSeparators(),
79 callback));
80 }
81 }
82
83 void MemoryFileUtil::CreateDirectory(
84 const FilePath& dir_path,
85 const StatusCallback& callback) {
86 MessageLoop::current()->PostTask(
87 FROM_HERE,
88 base::Bind(&MemoryFileUtil::DoCreate,
89 base::Unretained(this), dir_path.StripTrailingSeparators(),
90 true, callback));
91 }
92
93 void MemoryFileUtil::ReadDirectory(
94 const FilePath& dir_path,
95 const ReadDirectoryCallback& callback) {
96 MessageLoop::current()->PostTask(
97 FROM_HERE,
98 base::Bind(&MemoryFileUtil::DoReadDirectory,
99 base::Unretained(this), dir_path.StripTrailingSeparators(),
100 FilePath(), callback));
101 }
102
103 void MemoryFileUtil::Write(
104 const FilePath& file_path,
105 int64 offset,
106 const char* data,
107 int64 length,
108 const ReadWriteCallback& callback) {
109 DCHECK(data);
110 MessageLoop::current()->PostTask(
111 FROM_HERE,
112 base::Bind(&MemoryFileUtil::DoWrite, base::Unretained(this),
113 file_path.StripTrailingSeparators(),
114 offset, data, length, callback));
115 }
116
117 void MemoryFileUtil::Read(
118 const FilePath& file_path,
119 int64 offset,
120 char* buffer,
121 int64 length,
122 const ReadWriteCallback& callback) {
123 DCHECK(buffer);
124 MessageLoop::current()->PostTask(
125 FROM_HERE,
126 base::Bind(&MemoryFileUtil::DoRead, base::Unretained(this),
127 file_path.StripTrailingSeparators(),
128 offset, buffer, length, callback));
129 }
130
131 bool MemoryFileUtil::IsDirectory(const FilePath& file_path) {
132 ConstFileIterator it = GetFile(file_path);
133 return it != files_.end() && it->second.is_directory;
134 }
135
136 void MemoryFileUtil::DoGetFileInfo(const FilePath& file_path,
137 const GetFileInfoCallback& callback) {
138 base::PlatformFileInfo file_info;
139
140 FileIterator file_it = GetFile(file_path);
141
142 if (file_it == files_.end()) {
143 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND, file_info);
144 return;
145 }
146 FileEntry& file_entry = file_it->second;
147
148 file_info.size = file_entry.contents.size();
149 file_info.is_directory = file_entry.is_directory;
150 file_info.is_symbolic_link = false;
151
152 // In this file system implementation we store only one datetime. Many
153 // popular file systems do the same.
154 file_info.last_modified = file_entry.last_modified;
155 file_info.last_accessed = file_entry.last_modified;
156 file_info.creation_time = file_entry.last_modified;
157
158 callback.Run(base::PLATFORM_FILE_OK, file_info);
159 }
160
161 void MemoryFileUtil::DoCreate(
162 const FilePath& file_path,
163 bool is_directory,
164 const StatusCallback& callback) {
165 if (FileExists(file_path)) {
166 callback.Run(base::PLATFORM_FILE_ERROR_EXISTS);
167 return;
168 }
169
170 if (!IsDirectory(file_path.DirName())) {
171 callback.Run(base::PLATFORM_FILE_ERROR_FAILED);
172 return;
173 }
174
175 FileEntry file;
176 file.is_directory = is_directory;
177 file.last_modified = base::Time::Now();
178
179 files_[file_path] = file;
180 callback.Run(base::PLATFORM_FILE_OK);
181 }
182
183 void MemoryFileUtil::DoTruncate(
184 const FilePath& file_path,
185 int64 length,
186 const StatusCallback& callback) {
187 FileIterator file_it = GetFile(file_path);
188 if (file_it == files_.end()) {
189 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
190 return;
191 }
192
193 FileEntry& file = file_it->second;
194
195 // Fill the extended part with 0 if |length| is larger than the original
196 // contents size.
197 file.contents.resize(length, 0);
198 callback.Run(base::PLATFORM_FILE_OK);
199 }
200
201 void MemoryFileUtil::DoTouch(
202 const FilePath& file_path,
203 const base::Time& last_modified_time,
204 const StatusCallback& callback) {
205 FileIterator file_it = GetFile(file_path);
206 if (file_it == files_.end()) {
207 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
208 return;
209 }
210
211 FileEntry& file = file_it->second;
212
213 file.last_modified = last_modified_time;
214 callback.Run(base::PLATFORM_FILE_OK);
215 }
216
217 void MemoryFileUtil::DoRemoveSingleFile(
218 const FilePath& file_path,
219 const StatusCallback& callback) {
220 FileIterator file_it = GetFile(file_path);
221 if (file_it == files_.end()) {
222 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
223 return;
224 }
225
226 FileEntry& file = file_it->second;
227 if (file.is_directory) {
228 // Check that directory is empty.
229 FilePath path_with_separator = file_it->first.Append("/");
230 FileIterator file_inside_dir = files_.lower_bound(path_with_separator);
231
232 if (file_it->first.IsParent(file_inside_dir->first)) {
233 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_FILE);
234 return;
235 }
236 }
237
238 files_.erase(file_it);
239 callback.Run(base::PLATFORM_FILE_OK);
240 }
241
242 void MemoryFileUtil::DoRemoveRecursive(
243 const FilePath& file_path,
244 const StatusCallback& callback) {
245 FileIterator file_it = GetFile(file_path);
246 if (file_it == files_.end()) {
247 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
248 return;
249 }
250
251 FileEntry& file = file_it->second;
252 if (!file.is_directory) {
253 files_.erase(file_it);
254 callback.Run(base::PLATFORM_FILE_OK);
255 return;
256 }
257
258 // In the following code we rely on the fact that the paths in files_
259 // are ordered lexicographically. We iterate over files_ and delete
260 // the files from files_, then delete in one go all the files from
261 // file_by_name_.
262 FilePath file_path_with_separator = file_path.Append("/");
263 FileIterator it_first = files_.lower_bound(file_path_with_separator);
264 FileIterator it_last = it_first;
265
266 while (it_last != files_.end() && file_path.IsParent(it_last->first)) {
267 ++it_last;
268 }
269 files_.erase(it_first, it_last);
270
271 // The initial path is stored without a separator in the end, so it
272 // has not been removed in the above loop.
273 files_.erase(file_it);
274 callback.Run(base::PLATFORM_FILE_OK);
275 }
276
277 void MemoryFileUtil::DoReadDirectory(
278 const FilePath& dir_path,
279 const FilePath& in_from,
280 const ReadDirectoryCallback& callback) {
281 FilePath from = in_from;
282 read_directory_buffer_.clear();
283
284 if (!FileExists(dir_path)) {
285 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND,
286 read_directory_buffer_, true);
287 return;
288 }
289
290 if (!IsDirectory(dir_path)) {
291 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY,
292 read_directory_buffer_, true);
293 return;
294 }
295
296 if (from.empty())
297 from = dir_path.Append("/");
298
299 bool completed = true;
300
301 // Here we iterate over all paths starting with the prefix dir_path + '/'.
302 // It is not very efficient in case of a deep tree with many files in
303 // subdirectories. If ever we'll need efficiency from this implementation of
304 // FS, this should be changed. (It could be done by using lower_bound instead
305 // of ++ in case we've met a subdirectory path.)
306 for (ConstFileIterator it = files_.lower_bound(from);
307 it != files_.end() && dir_path.IsParent(it->first);
308 ++it) {
309 if (it->first.DirName() != dir_path) // a file in subdirectory
310 continue;
311
312 if (read_directory_buffer_.size() == read_directory_buffer_size_) {
313 from = it->first;
314 completed = false;
315 break;
316 }
317
318 const FileEntry& file = it->second;
319 DirectoryEntry entry;
320 entry.name = it->first.BaseName().value();
321 entry.is_directory = file.is_directory;
322 entry.size = file.contents.size();
323 entry.last_modified_time = file.last_modified;
324
325 read_directory_buffer_.push_back(entry);
326 }
327
328 callback.Run(base::PLATFORM_FILE_OK, read_directory_buffer_, completed);
329
330 if (!completed) {
331 MessageLoop::current()->PostTask(
332 FROM_HERE,
333 base::Bind(&MemoryFileUtil::DoReadDirectory,
334 base::Unretained(this), dir_path,
335 from, callback));
336 }
337 }
338
339 void MemoryFileUtil::DoRead(
340 const FilePath& file_path,
341 int64 offset,
342 char* buffer,
343 int64 length,
344 const ReadWriteCallback& callback) {
345 FileIterator file_it = GetFile(file_path);
346 if (file_it == files_.end()) {
347 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND, 0);
348 return;
349 }
350
351 FileEntry& file = file_it->second;
352 if (file.is_directory) {
353 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_FILE, 0);
354 return;
355 }
356
357 const int64 file_size = static_cast<int64>(file.contents.size());
358 if (offset >= file_size) {
359 callback.Run(base::PLATFORM_FILE_ERROR_FAILED, 0);
360 return;
361 }
362
363 if (offset + length > file_size)
364 length = file.contents.size() - offset;
365
366 copy(file.contents.begin() + offset, file.contents.begin() + offset + length,
367 buffer);
368
369 callback.Run(base::PLATFORM_FILE_OK, length);
370 }
371
372 void MemoryFileUtil::DoWrite(
373 const FilePath& file_path,
374 int64 offset,
375 const char* data,
376 int64 length,
377 const ReadWriteCallback& callback) {
378 FileIterator file_it = GetFile(file_path);
379 if (file_it == files_.end()) {
380 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND, 0);
381 return;
382 }
383
384 FileEntry& file = file_it->second;
385 if (file.is_directory) {
386 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_FILE, 0);
387 return;
388 }
389
390 const int64 file_size = static_cast<int64>(file.contents.size());
391 if (offset > file_size) {
392 callback.Run(base::PLATFORM_FILE_ERROR_FAILED, 0);
393 return;
394 }
395
396 if (offset + length > file_size)
397 file.contents.resize(offset + length);
398
399 copy(data, data + length, file.contents.begin() + offset);
400 file.last_modified = base::Time::Now();
401
402 callback.Run(base::PLATFORM_FILE_OK, length);
403 }
404
405 } // namespace file_api
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698