1 // Copyright 2014 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 "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
7 #include "base/files/file.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "net/base/io_buffer.h"
12 namespace file_system_provider
{
15 const char kFakeFileName
[] = "hello.txt";
16 const char kFakeFileText
[] =
17 "This is a testing file. Lorem ipsum dolor sit amet est.";
18 const size_t kFakeFileSize
= sizeof(kFakeFileText
) - 1u;
19 const char kFakeFileModificationTime
[] = "Fri Apr 25 01:47:53 UTC 2014";
20 const char kFakeFileMimeType
[] = "text/plain";
24 const char kFakeFilePath
[] = "/hello.txt";
26 FakeEntry::FakeEntry() {
29 FakeEntry::FakeEntry(scoped_ptr
<EntryMetadata
> metadata
,
30 const std::string
& contents
)
31 : metadata(metadata
.Pass()), contents(contents
) {
34 FakeEntry::~FakeEntry() {
37 FakeProvidedFileSystem::FakeProvidedFileSystem(
38 const ProvidedFileSystemInfo
& file_system_info
)
39 : file_system_info_(file_system_info
),
41 weak_ptr_factory_(this) {
43 base::FilePath::FromUTF8Unsafe("/"), true, "", 0, base::Time(), "", "");
45 base::Time modification_time
;
46 DCHECK(base::Time::FromString(kFakeFileModificationTime
, &modification_time
));
47 AddEntry(base::FilePath::FromUTF8Unsafe(kFakeFilePath
),
56 FakeProvidedFileSystem::~FakeProvidedFileSystem() {}
58 void FakeProvidedFileSystem::AddEntry(const base::FilePath
& entry_path
,
60 const std::string
& name
,
62 base::Time modification_time
,
63 std::string mime_type
,
64 std::string contents
) {
65 DCHECK(entries_
.find(entry_path
) == entries_
.end());
66 scoped_ptr
<EntryMetadata
> metadata(new EntryMetadata
);
68 metadata
->is_directory
= is_directory
;
69 metadata
->name
= name
;
70 metadata
->size
= size
;
71 metadata
->modification_time
= modification_time
;
72 metadata
->mime_type
= mime_type
;
74 entries_
[entry_path
] =
75 make_linked_ptr(new FakeEntry(metadata
.Pass(), contents
));
78 const FakeEntry
* FakeProvidedFileSystem::GetEntry(
79 const base::FilePath
& entry_path
) const {
80 const Entries::const_iterator entry_it
= entries_
.find(entry_path
);
81 if (entry_it
== entries_
.end())
84 return entry_it
->second
.get();
87 ProvidedFileSystemInterface::AbortCallback
88 FakeProvidedFileSystem::RequestUnmount(
89 const storage::AsyncFileUtil::StatusCallback
& callback
) {
90 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
93 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::GetMetadata(
94 const base::FilePath
& entry_path
,
95 ProvidedFileSystemInterface::MetadataFieldMask fields
,
96 const ProvidedFileSystemInterface::GetMetadataCallback
& callback
) {
97 const Entries::const_iterator entry_it
= entries_
.find(entry_path
);
99 if (entry_it
== entries_
.end()) {
100 return PostAbortableTask(
102 base::Passed(make_scoped_ptr
<EntryMetadata
>(NULL
)),
103 base::File::FILE_ERROR_NOT_FOUND
));
106 scoped_ptr
<EntryMetadata
> metadata(new EntryMetadata
);
107 metadata
->is_directory
= entry_it
->second
->metadata
->is_directory
;
108 metadata
->name
= entry_it
->second
->metadata
->name
;
109 metadata
->size
= entry_it
->second
->metadata
->size
;
110 metadata
->modification_time
= entry_it
->second
->metadata
->modification_time
;
111 metadata
->mime_type
= entry_it
->second
->metadata
->mime_type
;
112 metadata
->thumbnail
= entry_it
->second
->metadata
->thumbnail
;
114 return PostAbortableTask(
115 base::Bind(callback
, base::Passed(&metadata
), base::File::FILE_OK
));
118 ProvidedFileSystemInterface::AbortCallback
119 FakeProvidedFileSystem::ReadDirectory(
120 const base::FilePath
& directory_path
,
121 const storage::AsyncFileUtil::ReadDirectoryCallback
& callback
) {
122 storage::AsyncFileUtil::EntryList entry_list
;
124 for (Entries::const_iterator it
= entries_
.begin(); it
!= entries_
.end();
126 const base::FilePath file_path
= it
->first
;
127 if (file_path
== directory_path
|| directory_path
.IsParent(file_path
)) {
128 const EntryMetadata
* const metadata
= it
->second
->metadata
.get();
129 entry_list
.push_back(storage::DirectoryEntry(
131 metadata
->is_directory
? storage::DirectoryEntry::DIRECTORY
132 : storage::DirectoryEntry::FILE,
134 metadata
->modification_time
));
138 return PostAbortableTask(base::Bind(
139 callback
, base::File::FILE_OK
, entry_list
, false /* has_more */));
142 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::OpenFile(
143 const base::FilePath
& entry_path
,
145 const OpenFileCallback
& callback
) {
146 const Entries::const_iterator entry_it
= entries_
.find(entry_path
);
148 if (entry_it
== entries_
.end()) {
149 return PostAbortableTask(base::Bind(
150 callback
, 0 /* file_handle */, base::File::FILE_ERROR_NOT_FOUND
));
153 const int file_handle
= ++last_file_handle_
;
154 opened_files_
[file_handle
] = entry_path
;
155 return PostAbortableTask(
156 base::Bind(callback
, file_handle
, base::File::FILE_OK
));
159 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::CloseFile(
161 const storage::AsyncFileUtil::StatusCallback
& callback
) {
162 const OpenedFilesMap::iterator opened_file_it
=
163 opened_files_
.find(file_handle
);
165 if (opened_file_it
== opened_files_
.end()) {
166 return PostAbortableTask(
167 base::Bind(callback
, base::File::FILE_ERROR_NOT_FOUND
));
170 opened_files_
.erase(opened_file_it
);
171 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
174 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::ReadFile(
176 net::IOBuffer
* buffer
,
179 const ProvidedFileSystemInterface::ReadChunkReceivedCallback
& callback
) {
180 const OpenedFilesMap::iterator opened_file_it
=
181 opened_files_
.find(file_handle
);
183 if (opened_file_it
== opened_files_
.end() ||
184 opened_file_it
->second
.AsUTF8Unsafe() != kFakeFilePath
) {
185 return PostAbortableTask(
187 0 /* chunk_length */,
188 false /* has_more */,
189 base::File::FILE_ERROR_INVALID_OPERATION
));
192 const Entries::const_iterator entry_it
=
193 entries_
.find(opened_file_it
->second
);
194 if (entry_it
== entries_
.end()) {
195 return PostAbortableTask(
197 0 /* chunk_length */,
198 false /* has_more */,
199 base::File::FILE_ERROR_INVALID_OPERATION
));
202 // Send the response byte by byte.
203 int64 current_offset
= offset
;
204 int current_length
= length
;
206 // Reading behind EOF is fine, it will just return 0 bytes.
207 if (current_offset
>= entry_it
->second
->metadata
->size
|| !current_length
) {
208 return PostAbortableTask(base::Bind(callback
,
209 0 /* chunk_length */,
210 false /* has_more */,
211 base::File::FILE_OK
));
214 const FakeEntry
* const entry
= entry_it
->second
.get();
215 std::vector
<int> task_ids
;
216 while (current_offset
< entry
->metadata
->size
&& current_length
) {
217 buffer
->data()[current_offset
- offset
] = entry
->contents
[current_offset
];
218 const bool has_more
=
219 (current_offset
+ 1 < entry
->metadata
->size
) && (current_length
- 1);
220 const int task_id
= tracker_
.PostTask(
221 base::MessageLoopProxy::current().get(),
224 callback
, 1 /* chunk_length */, has_more
, base::File::FILE_OK
));
225 task_ids
.push_back(task_id
);
230 return base::Bind(&FakeProvidedFileSystem::AbortMany
,
231 weak_ptr_factory_
.GetWeakPtr(),
235 ProvidedFileSystemInterface::AbortCallback
236 FakeProvidedFileSystem::CreateDirectory(
237 const base::FilePath
& directory_path
,
239 const storage::AsyncFileUtil::StatusCallback
& callback
) {
240 // TODO(mtomasz): Implement it once needed.
241 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
244 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::DeleteEntry(
245 const base::FilePath
& entry_path
,
247 const storage::AsyncFileUtil::StatusCallback
& callback
) {
248 // TODO(mtomasz): Implement it once needed.
249 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
252 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::CreateFile(
253 const base::FilePath
& file_path
,
254 const storage::AsyncFileUtil::StatusCallback
& callback
) {
255 const base::File::Error result
= file_path
.AsUTF8Unsafe() != kFakeFilePath
256 ? base::File::FILE_ERROR_EXISTS
257 : base::File::FILE_OK
;
259 return PostAbortableTask(base::Bind(callback
, result
));
262 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::CopyEntry(
263 const base::FilePath
& source_path
,
264 const base::FilePath
& target_path
,
265 const storage::AsyncFileUtil::StatusCallback
& callback
) {
266 // TODO(mtomasz): Implement it once needed.
267 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
270 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::MoveEntry(
271 const base::FilePath
& source_path
,
272 const base::FilePath
& target_path
,
273 const storage::AsyncFileUtil::StatusCallback
& callback
) {
274 // TODO(mtomasz): Implement it once needed.
275 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
278 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::Truncate(
279 const base::FilePath
& file_path
,
281 const storage::AsyncFileUtil::StatusCallback
& callback
) {
282 // TODO(mtomasz): Implement it once needed.
283 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
286 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::WriteFile(
288 net::IOBuffer
* buffer
,
291 const storage::AsyncFileUtil::StatusCallback
& callback
) {
292 const OpenedFilesMap::iterator opened_file_it
=
293 opened_files_
.find(file_handle
);
295 if (opened_file_it
== opened_files_
.end() ||
296 opened_file_it
->second
.AsUTF8Unsafe() != kFakeFilePath
) {
297 return PostAbortableTask(
298 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
301 const Entries::iterator entry_it
= entries_
.find(opened_file_it
->second
);
302 if (entry_it
== entries_
.end()) {
303 return PostAbortableTask(
304 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
307 FakeEntry
* const entry
= entry_it
->second
.get();
308 if (offset
> entry
->metadata
->size
) {
309 return PostAbortableTask(
310 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
313 // Allocate the string size in advance.
314 if (offset
+ length
> entry
->metadata
->size
) {
315 entry
->metadata
->size
= offset
+ length
;
316 entry
->contents
.resize(entry
->metadata
->size
);
319 entry
->contents
.replace(offset
, length
, buffer
->data(), length
);
321 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
324 ProvidedFileSystemInterface::AbortCallback
FakeProvidedFileSystem::AddWatcher(
326 const base::FilePath
& entry_watcher
,
329 const storage::AsyncFileUtil::StatusCallback
& callback
,
330 const storage::WatcherManager::NotificationCallback
&
331 notification_callback
) {
332 // TODO(mtomasz): Implement it once needed.
333 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
336 void FakeProvidedFileSystem::RemoveWatcher(
338 const base::FilePath
& entry_path
,
340 const storage::AsyncFileUtil::StatusCallback
& callback
) {
341 // TODO(mtomasz): Implement it once needed.
342 callback
.Run(base::File::FILE_OK
);
345 const ProvidedFileSystemInfo
& FakeProvidedFileSystem::GetFileSystemInfo()
347 return file_system_info_
;
350 RequestManager
* FakeProvidedFileSystem::GetRequestManager() {
355 Watchers
* FakeProvidedFileSystem::GetWatchers() {
359 void FakeProvidedFileSystem::AddObserver(ProvidedFileSystemObserver
* observer
) {
361 observers_
.AddObserver(observer
);
364 void FakeProvidedFileSystem::RemoveObserver(
365 ProvidedFileSystemObserver
* observer
) {
367 observers_
.RemoveObserver(observer
);
370 void FakeProvidedFileSystem::Notify(
371 const base::FilePath
& entry_path
,
373 storage::WatcherManager::ChangeType change_type
,
374 scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
,
375 const std::string
& tag
,
376 const storage::AsyncFileUtil::StatusCallback
& callback
) {
378 callback
.Run(base::File::FILE_ERROR_SECURITY
);
381 ProvidedFileSystemInterface
* FakeProvidedFileSystem::Create(
383 const ProvidedFileSystemInfo
& file_system_info
) {
384 return new FakeProvidedFileSystem(file_system_info
);
387 base::WeakPtr
<ProvidedFileSystemInterface
>
388 FakeProvidedFileSystem::GetWeakPtr() {
389 return weak_ptr_factory_
.GetWeakPtr();
392 ProvidedFileSystemInterface::AbortCallback
393 FakeProvidedFileSystem::PostAbortableTask(const base::Closure
& callback
) {
394 const int task_id
= tracker_
.PostTask(
395 base::MessageLoopProxy::current().get(), FROM_HERE
, callback
);
397 &FakeProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), task_id
);
400 void FakeProvidedFileSystem::Abort(
402 const storage::AsyncFileUtil::StatusCallback
& callback
) {
403 tracker_
.TryCancel(task_id
);
404 callback
.Run(base::File::FILE_OK
);
407 void FakeProvidedFileSystem::AbortMany(
408 const std::vector
<int>& task_ids
,
409 const storage::AsyncFileUtil::StatusCallback
& callback
) {
410 for (size_t i
= 0; i
< task_ids
.size(); ++i
) {
411 tracker_
.TryCancel(task_ids
[i
]);
413 callback
.Run(base::File::FILE_OK
);
416 } // namespace file_system_provider
417 } // namespace chromeos