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

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
kinuko 2011/12/14 03:39:22 nit: extra empty line
satorux1 2011/12/14 04:43:26 Done.
9
10 namespace {
11 const int kDefaultReadDirectoryBufferSize = 100;
12 }
13
14 namespace fileapi {
15
16 MemoryFileUtil::MemoryFileUtil(const FilePath& root_path)
17 : read_directory_buffer_size_(kDefaultReadDirectoryBufferSize) {
18 FileEntry root;
19 root.is_directory = true;
20 root.last_modified = base::Time::Now();
21
22 files_[root_path] = root;
23 }
24
25 void MemoryFileUtil::GetFileInfo(
26 const FilePath& file_path,
27 const GetFileInfoCallback& callback) {
28 MessageLoop::current()->PostTask(
29 FROM_HERE,
30 base::Bind(&MemoryFileUtil::DoGetFileInfo, base::Unretained(this),
31 file_path.StripTrailingSeparators(), callback));
32 }
33
34 void MemoryFileUtil::Create(
35 const FilePath& file_path,
36 const StatusCallback& callback) {
37 MessageLoop::current()->PostTask(
38 FROM_HERE,
39 base::Bind(&MemoryFileUtil::DoCreate, base::Unretained(this),
40 file_path.StripTrailingSeparators(), false, callback));
41 }
42
43 void MemoryFileUtil::Truncate(
44 const FilePath& file_path,
45 int64 length,
46 const StatusCallback& callback) {
47 MessageLoop::current()->PostTask(
48 FROM_HERE,
49 base::Bind(&MemoryFileUtil::DoTruncate, base::Unretained(this),
50 file_path.StripTrailingSeparators(), length, callback));
51 }
52
53 void MemoryFileUtil::Touch(
54 const FilePath& file_path,
55 const base::Time& last_access_time,
56 const base::Time& last_modified_time,
57 const StatusCallback& callback) {
58 MessageLoop::current()->PostTask(
59 FROM_HERE,
60 base::Bind(&MemoryFileUtil::DoTouch, base::Unretained(this),
61 file_path.StripTrailingSeparators(),
62 last_modified_time, callback));
63 }
64
65 void MemoryFileUtil::Remove(
66 const FilePath& file_path,
67 bool recursive,
68 const StatusCallback& callback) {
69 if (recursive) {
70 MessageLoop::current()->PostTask(
71 FROM_HERE,
72 base::Bind(&MemoryFileUtil::DoRemoveRecursive,
73 base::Unretained(this), file_path.StripTrailingSeparators(),
74 callback));
75 } else {
76 MessageLoop::current()->PostTask(
77 FROM_HERE,
78 base::Bind(&MemoryFileUtil::DoRemoveSingleFile,
79 base::Unretained(this), file_path.StripTrailingSeparators(),
80 callback));
81 }
82 }
83
84 void MemoryFileUtil::CreateDirectory(
85 const FilePath& dir_path,
86 const StatusCallback& callback) {
87 MessageLoop::current()->PostTask(
88 FROM_HERE,
89 base::Bind(&MemoryFileUtil::DoCreate,
90 base::Unretained(this), dir_path.StripTrailingSeparators(),
91 true, callback));
92 }
93
94 void MemoryFileUtil::ReadDirectory(
95 const FilePath& dir_path,
96 const ReadDirectoryCallback& callback) {
97 MessageLoop::current()->PostTask(
98 FROM_HERE,
99 base::Bind(&MemoryFileUtil::DoReadDirectory,
100 base::Unretained(this), dir_path.StripTrailingSeparators(),
101 FilePath(), callback));
102 }
103
104 void MemoryFileUtil::Write(
105 const FilePath& file_path,
106 int64 offset,
107 const char* data,
108 int64 length,
109 const ReadWriteCallback& callback) {
kinuko 2011/12/14 03:39:22 DCHECK(data) ? This code assumes the data pointer
satorux1 2011/12/14 04:43:26 Added a DCHECK. I totally agree with you that this
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) {
kinuko 2011/12/14 03:39:22 DCHECK(buffer) ?
satorux1 2011/12/14 04:43:26 Done.
123 MessageLoop::current()->PostTask(
124 FROM_HERE,
125 base::Bind(&MemoryFileUtil::DoRead, base::Unretained(this),
126 file_path.StripTrailingSeparators(),
127 offset, buffer, length, callback));
128 }
129
130 bool MemoryFileUtil::IsDirectory(const FilePath& file_path) {
131 ConstFileIterator it = GetFile(file_path);
132 return it != files_.end() && it->second.is_directory;
133 }
134
135 void MemoryFileUtil::DoGetFileInfo(const FilePath& file_path,
136 const GetFileInfoCallback& callback) {
kinuko 2011/12/14 03:39:22 weird indentation
satorux1 2011/12/14 04:43:26 Done.
137 base::PlatformFileInfo file_info;
138
139 FileIterator file_it = GetFile(file_path);
140
141 if (file_it == files_.end()) {
142 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND, file_info);
143 return;
144 }
145 FileEntry& file_entry = file_it->second;
146
147 file_info.size = file_entry.contents.size();
148 file_info.is_directory = file_entry.is_directory;
149 file_info.is_symbolic_link = false;
150
151 // In this file system implementation we store only one datetime. Many
152 // popular file systems do the same.
153 file_info.last_modified = file_entry.last_modified;
154 file_info.last_accessed = file_entry.last_modified;
155 file_info.creation_time = file_entry.last_modified;
156
157 callback.Run(base::PLATFORM_FILE_OK, file_info);
158 }
159
160 void MemoryFileUtil::DoCreate(
161 const FilePath& file_path,
162 bool is_directory,
163 const StatusCallback& callback) {
164 if (FileExists(file_path)) {
165 callback.Run(base::PLATFORM_FILE_ERROR_EXISTS);
166 return;
167 }
168
169 if (!IsDirectory(file_path.DirName())) {
170 callback.Run(base::PLATFORM_FILE_ERROR_FAILED);
171 return;
172 }
173
174 FileEntry file;
175 file.is_directory = is_directory;
176 file.last_modified = base::Time::Now();
177
178 files_[file_path] = file;
179 callback.Run(base::PLATFORM_FILE_OK);
180 }
181
182 void MemoryFileUtil::DoTruncate(
183 const FilePath& file_path,
184 int64 length,
185 const StatusCallback& callback) {
186 FileIterator file_it = GetFile(file_path);
187 if (file_it == files_.end()) {
188 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
189 return;
190 }
191
192 FileEntry& file = file_it->second;
193 if (length > static_cast<int64>(file.contents.size())) {
194 callback.Run(base::PLATFORM_FILE_ERROR_FAILED);
kinuko 2011/12/14 03:39:22 I think this should NOT result in error?
satorux1 2011/12/14 04:43:26 Good point. truncate(2) allows extending to a larg
195 }
196
197 file.contents.resize(length);
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 = FilePath(file_it->first.value() + "/");
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(FilePath::StringType());
kinuko 2011/12/14 03:39:22 This looks inconsistent with line 229-- is this to
satorux1 2011/12/14 04:43:26 Good catch. Fixed.
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 FilePath from,
280 const ReadDirectoryCallback& callback) {
281 read_directory_buffer_.clear();
282
283 if (!FileExists(dir_path)) {
284 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND,
285 read_directory_buffer_, true);
286 return;
287 }
288
289 if (!IsDirectory(dir_path)) {
290 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY,
291 read_directory_buffer_, true);
292 return;
293 }
294
295 if (from.empty())
296 from = FilePath(dir_path.value() + "/");
297
298 bool completed = true;
299
300 // Here we iterate over all paths starting with the prefix dir_path + '/'.
301 // It is not very efficient in case of a deep tree with many files in
302 // subdirectories. If ever we'll need efficiency from this implementation of
303 // FS, this should be changed. (It could be done by using lower_bound instead
304 // of ++ in case we've met a subdirectory path.)
305 for (ConstFileIterator it = files_.lower_bound(from);
306 it != files_.end() && dir_path.IsParent(it->first);
307 ++it) {
308 if (it->first.DirName() != dir_path) // a file in subdirectory
309 continue;
310
311 if (read_directory_buffer_.size() == read_directory_buffer_size_) {
312 from = it->first;
313 completed = false;
314 break;
315 }
316
317 const FileEntry& file = it->second;
318 DirectoryEntry entry;
319 entry.name = it->first.BaseName().value();
320 entry.is_directory = file.is_directory;
321 entry.size = file.contents.size();
322 entry.last_modified_time = file.last_modified;
323
324 read_directory_buffer_.push_back(entry);
325 }
326
327 callback.Run(base::PLATFORM_FILE_OK, read_directory_buffer_, completed);
328
329 if (!completed) {
330 MessageLoop::current()->PostTask(
331 FROM_HERE,
332 base::Bind(&MemoryFileUtil::DoReadDirectory,
333 base::Unretained(this), dir_path,
334 from, callback));
335 }
336 }
337
338 void MemoryFileUtil::DoRead(
339 const FilePath& file_path,
340 int64 offset,
341 char* buffer,
342 int64 length,
343 const ReadWriteCallback& callback) {
344 FileIterator file_it = GetFile(file_path);
345 if (file_it == files_.end()) {
346 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND, 0);
347 return;
348 }
349
350 FileEntry& file = file_it->second;
351 if (file.is_directory) {
352 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_FILE, 0);
353 return;
354 }
355
356 const int64 file_size = static_cast<int64>(file.contents.size());
357 if (offset >= file_size) {
358 callback.Run(base::PLATFORM_FILE_ERROR_FAILED, 0);
359 return;
360 }
361
362 if (offset + length > file_size)
363 length = file.contents.size() - offset;
364
365 copy(file.contents.begin() + offset, file.contents.begin() + offset + length,
366 buffer);
367
368 callback.Run(base::PLATFORM_FILE_OK, length);
369 }
370
371 void MemoryFileUtil::DoWrite(
372 const FilePath& file_path,
373 int64 offset,
374 const char* data,
375 int64 length,
376 const ReadWriteCallback& callback) {
377 FileIterator file_it = GetFile(file_path);
378 if (file_it == files_.end()) {
379 callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND, 0);
380 return;
381 }
382
383 FileEntry& file = file_it->second;
384 if (file.is_directory) {
385 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_FILE, 0);
386 return;
387 }
388
389 const int64 file_size = static_cast<int64>(file.contents.size());
390 if (offset > file_size) {
391 callback.Run(base::PLATFORM_FILE_ERROR_FAILED, 0);
392 return;
393 }
394
395 if (offset + length > file_size)
396 file.contents.resize(offset + length);
397
398 copy(data, data + length, file.contents.begin() + offset);
399 file.last_modified = base::Time::Now();
400
401 callback.Run(base::PLATFORM_FILE_OK, length);
402 }
403
404 } // namespace file_api
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698