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/thread_task_runner_handle.h"
8 #include "net/base/io_buffer.h"
11 namespace file_system_provider
{
14 const char kFakeFileName
[] = "hello.txt";
15 const char kFakeFileText
[] =
16 "This is a testing file. Lorem ipsum dolor sit amet est.";
17 const size_t kFakeFileSize
= sizeof(kFakeFileText
) - 1u;
18 const char kFakeFileModificationTime
[] = "Fri Apr 25 01:47:53 UTC 2014";
19 const char kFakeFileMimeType
[] = "text/plain";
23 const base::FilePath::CharType kFakeFilePath
[] =
24 FILE_PATH_LITERAL("/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) {
42 AddEntry(base::FilePath(FILE_PATH_LITERAL("/")), true, "", 0, base::Time(),
45 base::Time modification_time
;
46 DCHECK(base::Time::FromString(kFakeFileModificationTime
, &modification_time
));
47 AddEntry(base::FilePath(kFakeFilePath
), false, kFakeFileName
, kFakeFileSize
,
48 modification_time
, kFakeFileMimeType
, kFakeFileText
);
51 FakeProvidedFileSystem::~FakeProvidedFileSystem() {}
53 void FakeProvidedFileSystem::AddEntry(const base::FilePath
& entry_path
,
55 const std::string
& name
,
57 base::Time modification_time
,
58 std::string mime_type
,
59 std::string contents
) {
60 DCHECK(entries_
.find(entry_path
) == entries_
.end());
61 scoped_ptr
<EntryMetadata
> metadata(new EntryMetadata
);
63 metadata
->is_directory
= is_directory
;
64 metadata
->name
= name
;
65 metadata
->size
= size
;
66 metadata
->modification_time
= modification_time
;
67 metadata
->mime_type
= mime_type
;
69 entries_
[entry_path
] =
70 make_linked_ptr(new FakeEntry(metadata
.Pass(), contents
));
73 const FakeEntry
* FakeProvidedFileSystem::GetEntry(
74 const base::FilePath
& entry_path
) const {
75 const Entries::const_iterator entry_it
= entries_
.find(entry_path
);
76 if (entry_it
== entries_
.end())
79 return entry_it
->second
.get();
82 AbortCallback
FakeProvidedFileSystem::RequestUnmount(
83 const storage::AsyncFileUtil::StatusCallback
& callback
) {
84 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
87 AbortCallback
FakeProvidedFileSystem::GetMetadata(
88 const base::FilePath
& entry_path
,
89 ProvidedFileSystemInterface::MetadataFieldMask fields
,
90 const ProvidedFileSystemInterface::GetMetadataCallback
& callback
) {
91 const Entries::const_iterator entry_it
= entries_
.find(entry_path
);
93 if (entry_it
== entries_
.end()) {
94 return PostAbortableTask(
96 base::Passed(make_scoped_ptr
<EntryMetadata
>(NULL
)),
97 base::File::FILE_ERROR_NOT_FOUND
));
100 scoped_ptr
<EntryMetadata
> metadata(new EntryMetadata
);
101 metadata
->is_directory
= entry_it
->second
->metadata
->is_directory
;
102 metadata
->name
= entry_it
->second
->metadata
->name
;
103 metadata
->size
= entry_it
->second
->metadata
->size
;
104 metadata
->modification_time
= entry_it
->second
->metadata
->modification_time
;
105 metadata
->mime_type
= entry_it
->second
->metadata
->mime_type
;
106 metadata
->thumbnail
= entry_it
->second
->metadata
->thumbnail
;
108 return PostAbortableTask(
109 base::Bind(callback
, base::Passed(&metadata
), base::File::FILE_OK
));
112 AbortCallback
FakeProvidedFileSystem::GetActions(
113 const base::FilePath
& entry_path
,
114 const ProvidedFileSystemInterface::GetActionsCallback
& callback
) {
115 // TODO(mtomasz): Implement it once needed.
116 const std::vector
<Action
> actions
;
117 return PostAbortableTask(base::Bind(callback
, actions
, base::File::FILE_OK
));
120 AbortCallback
FakeProvidedFileSystem::ExecuteAction(
121 const base::FilePath
& entry_path
,
122 const std::string
& action_id
,
123 const storage::AsyncFileUtil::StatusCallback
& callback
) {
124 // TODO(mtomasz): Implement it once needed.
125 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
128 AbortCallback
FakeProvidedFileSystem::ReadDirectory(
129 const base::FilePath
& directory_path
,
130 const storage::AsyncFileUtil::ReadDirectoryCallback
& callback
) {
131 storage::AsyncFileUtil::EntryList entry_list
;
133 for (Entries::const_iterator it
= entries_
.begin(); it
!= entries_
.end();
135 const base::FilePath file_path
= it
->first
;
136 if (file_path
== directory_path
|| directory_path
.IsParent(file_path
)) {
137 const EntryMetadata
* const metadata
= it
->second
->metadata
.get();
138 entry_list
.push_back(storage::DirectoryEntry(
140 metadata
->is_directory
? storage::DirectoryEntry::DIRECTORY
141 : storage::DirectoryEntry::FILE,
143 metadata
->modification_time
));
147 return PostAbortableTask(base::Bind(
148 callback
, base::File::FILE_OK
, entry_list
, false /* has_more */));
151 AbortCallback
FakeProvidedFileSystem::OpenFile(
152 const base::FilePath
& entry_path
,
154 const OpenFileCallback
& callback
) {
155 const Entries::const_iterator entry_it
= entries_
.find(entry_path
);
157 if (entry_it
== entries_
.end()) {
158 return PostAbortableTask(base::Bind(
159 callback
, 0 /* file_handle */, base::File::FILE_ERROR_NOT_FOUND
));
162 const int file_handle
= ++last_file_handle_
;
163 opened_files_
[file_handle
] = OpenedFile(entry_path
, mode
);
164 return PostAbortableTask(
165 base::Bind(callback
, file_handle
, base::File::FILE_OK
));
168 AbortCallback
FakeProvidedFileSystem::CloseFile(
170 const storage::AsyncFileUtil::StatusCallback
& callback
) {
171 const auto opened_file_it
= opened_files_
.find(file_handle
);
173 if (opened_file_it
== opened_files_
.end()) {
174 return PostAbortableTask(
175 base::Bind(callback
, base::File::FILE_ERROR_NOT_FOUND
));
178 opened_files_
.erase(opened_file_it
);
179 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
182 AbortCallback
FakeProvidedFileSystem::ReadFile(
184 net::IOBuffer
* buffer
,
187 const ProvidedFileSystemInterface::ReadChunkReceivedCallback
& callback
) {
188 const auto opened_file_it
= opened_files_
.find(file_handle
);
190 if (opened_file_it
== opened_files_
.end() ||
191 opened_file_it
->second
.file_path
.AsUTF8Unsafe() != kFakeFilePath
) {
192 return PostAbortableTask(
194 0 /* chunk_length */,
195 false /* has_more */,
196 base::File::FILE_ERROR_INVALID_OPERATION
));
199 const Entries::const_iterator entry_it
=
200 entries_
.find(opened_file_it
->second
.file_path
);
201 if (entry_it
== entries_
.end()) {
202 return PostAbortableTask(
204 0 /* chunk_length */,
205 false /* has_more */,
206 base::File::FILE_ERROR_INVALID_OPERATION
));
209 // Send the response byte by byte.
210 int64 current_offset
= offset
;
211 int current_length
= length
;
213 // Reading behind EOF is fine, it will just return 0 bytes.
214 if (current_offset
>= entry_it
->second
->metadata
->size
|| !current_length
) {
215 return PostAbortableTask(base::Bind(callback
,
216 0 /* chunk_length */,
217 false /* has_more */,
218 base::File::FILE_OK
));
221 const FakeEntry
* const entry
= entry_it
->second
.get();
222 std::vector
<int> task_ids
;
223 while (current_offset
< entry
->metadata
->size
&& current_length
) {
224 buffer
->data()[current_offset
- offset
] = entry
->contents
[current_offset
];
225 const bool has_more
=
226 (current_offset
+ 1 < entry
->metadata
->size
) && (current_length
- 1);
228 tracker_
.PostTask(base::ThreadTaskRunnerHandle::Get().get(), FROM_HERE
,
229 base::Bind(callback
, 1 /* chunk_length */, has_more
,
230 base::File::FILE_OK
));
231 task_ids
.push_back(task_id
);
236 return base::Bind(&FakeProvidedFileSystem::AbortMany
,
237 weak_ptr_factory_
.GetWeakPtr(),
241 AbortCallback
FakeProvidedFileSystem::CreateDirectory(
242 const base::FilePath
& directory_path
,
244 const storage::AsyncFileUtil::StatusCallback
& callback
) {
245 // TODO(mtomasz): Implement it once needed.
246 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
249 AbortCallback
FakeProvidedFileSystem::DeleteEntry(
250 const base::FilePath
& entry_path
,
252 const storage::AsyncFileUtil::StatusCallback
& callback
) {
253 // TODO(mtomasz): Implement it once needed.
254 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
257 AbortCallback
FakeProvidedFileSystem::CreateFile(
258 const base::FilePath
& file_path
,
259 const storage::AsyncFileUtil::StatusCallback
& callback
) {
260 const base::File::Error result
= file_path
.AsUTF8Unsafe() != kFakeFilePath
261 ? base::File::FILE_ERROR_EXISTS
262 : base::File::FILE_OK
;
264 return PostAbortableTask(base::Bind(callback
, result
));
267 AbortCallback
FakeProvidedFileSystem::CopyEntry(
268 const base::FilePath
& source_path
,
269 const base::FilePath
& target_path
,
270 const storage::AsyncFileUtil::StatusCallback
& callback
) {
271 // TODO(mtomasz): Implement it once needed.
272 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
275 AbortCallback
FakeProvidedFileSystem::MoveEntry(
276 const base::FilePath
& source_path
,
277 const base::FilePath
& target_path
,
278 const storage::AsyncFileUtil::StatusCallback
& callback
) {
279 // TODO(mtomasz): Implement it once needed.
280 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
283 AbortCallback
FakeProvidedFileSystem::Truncate(
284 const base::FilePath
& file_path
,
286 const storage::AsyncFileUtil::StatusCallback
& callback
) {
287 // TODO(mtomasz): Implement it once needed.
288 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
291 AbortCallback
FakeProvidedFileSystem::WriteFile(
293 net::IOBuffer
* buffer
,
296 const storage::AsyncFileUtil::StatusCallback
& callback
) {
297 const auto opened_file_it
= opened_files_
.find(file_handle
);
299 if (opened_file_it
== opened_files_
.end() ||
300 opened_file_it
->second
.file_path
.AsUTF8Unsafe() != kFakeFilePath
) {
301 return PostAbortableTask(
302 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
305 const Entries::iterator entry_it
=
306 entries_
.find(opened_file_it
->second
.file_path
);
307 if (entry_it
== entries_
.end()) {
308 return PostAbortableTask(
309 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
312 FakeEntry
* const entry
= entry_it
->second
.get();
313 if (offset
> entry
->metadata
->size
) {
314 return PostAbortableTask(
315 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
318 // Allocate the string size in advance.
319 if (offset
+ length
> entry
->metadata
->size
) {
320 entry
->metadata
->size
= offset
+ length
;
321 entry
->contents
.resize(entry
->metadata
->size
);
324 entry
->contents
.replace(offset
, length
, buffer
->data(), length
);
326 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
329 AbortCallback
FakeProvidedFileSystem::AddWatcher(
331 const base::FilePath
& entry_watcher
,
334 const storage::AsyncFileUtil::StatusCallback
& callback
,
335 const storage::WatcherManager::NotificationCallback
&
336 notification_callback
) {
337 // TODO(mtomasz): Implement it once needed.
338 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
341 void FakeProvidedFileSystem::RemoveWatcher(
343 const base::FilePath
& entry_path
,
345 const storage::AsyncFileUtil::StatusCallback
& callback
) {
346 // TODO(mtomasz): Implement it once needed.
347 callback
.Run(base::File::FILE_OK
);
350 const ProvidedFileSystemInfo
& FakeProvidedFileSystem::GetFileSystemInfo()
352 return file_system_info_
;
355 RequestManager
* FakeProvidedFileSystem::GetRequestManager() {
360 Watchers
* FakeProvidedFileSystem::GetWatchers() {
364 const OpenedFiles
& FakeProvidedFileSystem::GetOpenedFiles() const {
365 return opened_files_
;
368 void FakeProvidedFileSystem::AddObserver(ProvidedFileSystemObserver
* observer
) {
370 observers_
.AddObserver(observer
);
373 void FakeProvidedFileSystem::RemoveObserver(
374 ProvidedFileSystemObserver
* observer
) {
376 observers_
.RemoveObserver(observer
);
379 void FakeProvidedFileSystem::Notify(
380 const base::FilePath
& entry_path
,
382 storage::WatcherManager::ChangeType change_type
,
383 scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
,
384 const std::string
& tag
,
385 const storage::AsyncFileUtil::StatusCallback
& callback
) {
387 callback
.Run(base::File::FILE_ERROR_SECURITY
);
390 void FakeProvidedFileSystem::Configure(
391 const storage::AsyncFileUtil::StatusCallback
& callback
) {
393 callback
.Run(base::File::FILE_ERROR_SECURITY
);
396 ProvidedFileSystemInterface
* FakeProvidedFileSystem::Create(
398 const ProvidedFileSystemInfo
& file_system_info
) {
399 return new FakeProvidedFileSystem(file_system_info
);
402 base::WeakPtr
<ProvidedFileSystemInterface
>
403 FakeProvidedFileSystem::GetWeakPtr() {
404 return weak_ptr_factory_
.GetWeakPtr();
407 AbortCallback
FakeProvidedFileSystem::PostAbortableTask(
408 const base::Closure
& callback
) {
409 const int task_id
= tracker_
.PostTask(
410 base::ThreadTaskRunnerHandle::Get().get(), FROM_HERE
, callback
);
412 &FakeProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), task_id
);
415 void FakeProvidedFileSystem::Abort(int task_id
) {
416 tracker_
.TryCancel(task_id
);
419 void FakeProvidedFileSystem::AbortMany(const std::vector
<int>& task_ids
) {
420 for (size_t i
= 0; i
< task_ids
.size(); ++i
) {
421 tracker_
.TryCancel(task_ids
[i
]);
425 } // namespace file_system_provider
426 } // namespace chromeos