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/message_loop/message_loop_proxy.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::ReadDirectory(
113 const base::FilePath
& directory_path
,
114 const storage::AsyncFileUtil::ReadDirectoryCallback
& callback
) {
115 storage::AsyncFileUtil::EntryList entry_list
;
117 for (Entries::const_iterator it
= entries_
.begin(); it
!= entries_
.end();
119 const base::FilePath file_path
= it
->first
;
120 if (file_path
== directory_path
|| directory_path
.IsParent(file_path
)) {
121 const EntryMetadata
* const metadata
= it
->second
->metadata
.get();
122 entry_list
.push_back(storage::DirectoryEntry(
124 metadata
->is_directory
? storage::DirectoryEntry::DIRECTORY
125 : storage::DirectoryEntry::FILE,
127 metadata
->modification_time
));
131 return PostAbortableTask(base::Bind(
132 callback
, base::File::FILE_OK
, entry_list
, false /* has_more */));
135 AbortCallback
FakeProvidedFileSystem::OpenFile(
136 const base::FilePath
& entry_path
,
138 const OpenFileCallback
& callback
) {
139 const Entries::const_iterator entry_it
= entries_
.find(entry_path
);
141 if (entry_it
== entries_
.end()) {
142 return PostAbortableTask(base::Bind(
143 callback
, 0 /* file_handle */, base::File::FILE_ERROR_NOT_FOUND
));
146 const int file_handle
= ++last_file_handle_
;
147 opened_files_
[file_handle
] = OpenedFile(entry_path
, mode
);
148 return PostAbortableTask(
149 base::Bind(callback
, file_handle
, base::File::FILE_OK
));
152 AbortCallback
FakeProvidedFileSystem::CloseFile(
154 const storage::AsyncFileUtil::StatusCallback
& callback
) {
155 const auto opened_file_it
= opened_files_
.find(file_handle
);
157 if (opened_file_it
== opened_files_
.end()) {
158 return PostAbortableTask(
159 base::Bind(callback
, base::File::FILE_ERROR_NOT_FOUND
));
162 opened_files_
.erase(opened_file_it
);
163 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
166 AbortCallback
FakeProvidedFileSystem::ReadFile(
168 net::IOBuffer
* buffer
,
171 const ProvidedFileSystemInterface::ReadChunkReceivedCallback
& callback
) {
172 const auto opened_file_it
= opened_files_
.find(file_handle
);
174 if (opened_file_it
== opened_files_
.end() ||
175 opened_file_it
->second
.file_path
.AsUTF8Unsafe() != kFakeFilePath
) {
176 return PostAbortableTask(
178 0 /* chunk_length */,
179 false /* has_more */,
180 base::File::FILE_ERROR_INVALID_OPERATION
));
183 const Entries::const_iterator entry_it
=
184 entries_
.find(opened_file_it
->second
.file_path
);
185 if (entry_it
== entries_
.end()) {
186 return PostAbortableTask(
188 0 /* chunk_length */,
189 false /* has_more */,
190 base::File::FILE_ERROR_INVALID_OPERATION
));
193 // Send the response byte by byte.
194 int64 current_offset
= offset
;
195 int current_length
= length
;
197 // Reading behind EOF is fine, it will just return 0 bytes.
198 if (current_offset
>= entry_it
->second
->metadata
->size
|| !current_length
) {
199 return PostAbortableTask(base::Bind(callback
,
200 0 /* chunk_length */,
201 false /* has_more */,
202 base::File::FILE_OK
));
205 const FakeEntry
* const entry
= entry_it
->second
.get();
206 std::vector
<int> task_ids
;
207 while (current_offset
< entry
->metadata
->size
&& current_length
) {
208 buffer
->data()[current_offset
- offset
] = entry
->contents
[current_offset
];
209 const bool has_more
=
210 (current_offset
+ 1 < entry
->metadata
->size
) && (current_length
- 1);
211 const int task_id
= tracker_
.PostTask(
212 base::MessageLoopProxy::current().get(),
215 callback
, 1 /* chunk_length */, has_more
, base::File::FILE_OK
));
216 task_ids
.push_back(task_id
);
221 return base::Bind(&FakeProvidedFileSystem::AbortMany
,
222 weak_ptr_factory_
.GetWeakPtr(),
226 AbortCallback
FakeProvidedFileSystem::CreateDirectory(
227 const base::FilePath
& directory_path
,
229 const storage::AsyncFileUtil::StatusCallback
& callback
) {
230 // TODO(mtomasz): Implement it once needed.
231 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
234 AbortCallback
FakeProvidedFileSystem::DeleteEntry(
235 const base::FilePath
& entry_path
,
237 const storage::AsyncFileUtil::StatusCallback
& callback
) {
238 // TODO(mtomasz): Implement it once needed.
239 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
242 AbortCallback
FakeProvidedFileSystem::CreateFile(
243 const base::FilePath
& file_path
,
244 const storage::AsyncFileUtil::StatusCallback
& callback
) {
245 const base::File::Error result
= file_path
.AsUTF8Unsafe() != kFakeFilePath
246 ? base::File::FILE_ERROR_EXISTS
247 : base::File::FILE_OK
;
249 return PostAbortableTask(base::Bind(callback
, result
));
252 AbortCallback
FakeProvidedFileSystem::CopyEntry(
253 const base::FilePath
& source_path
,
254 const base::FilePath
& target_path
,
255 const storage::AsyncFileUtil::StatusCallback
& callback
) {
256 // TODO(mtomasz): Implement it once needed.
257 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
260 AbortCallback
FakeProvidedFileSystem::MoveEntry(
261 const base::FilePath
& source_path
,
262 const base::FilePath
& target_path
,
263 const storage::AsyncFileUtil::StatusCallback
& callback
) {
264 // TODO(mtomasz): Implement it once needed.
265 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
268 AbortCallback
FakeProvidedFileSystem::Truncate(
269 const base::FilePath
& file_path
,
271 const storage::AsyncFileUtil::StatusCallback
& callback
) {
272 // TODO(mtomasz): Implement it once needed.
273 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
276 AbortCallback
FakeProvidedFileSystem::WriteFile(
278 net::IOBuffer
* buffer
,
281 const storage::AsyncFileUtil::StatusCallback
& callback
) {
282 const auto opened_file_it
= opened_files_
.find(file_handle
);
284 if (opened_file_it
== opened_files_
.end() ||
285 opened_file_it
->second
.file_path
.AsUTF8Unsafe() != kFakeFilePath
) {
286 return PostAbortableTask(
287 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
290 const Entries::iterator entry_it
=
291 entries_
.find(opened_file_it
->second
.file_path
);
292 if (entry_it
== entries_
.end()) {
293 return PostAbortableTask(
294 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
297 FakeEntry
* const entry
= entry_it
->second
.get();
298 if (offset
> entry
->metadata
->size
) {
299 return PostAbortableTask(
300 base::Bind(callback
, base::File::FILE_ERROR_INVALID_OPERATION
));
303 // Allocate the string size in advance.
304 if (offset
+ length
> entry
->metadata
->size
) {
305 entry
->metadata
->size
= offset
+ length
;
306 entry
->contents
.resize(entry
->metadata
->size
);
309 entry
->contents
.replace(offset
, length
, buffer
->data(), length
);
311 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
314 AbortCallback
FakeProvidedFileSystem::AddWatcher(
316 const base::FilePath
& entry_watcher
,
319 const storage::AsyncFileUtil::StatusCallback
& callback
,
320 const storage::WatcherManager::NotificationCallback
&
321 notification_callback
) {
322 // TODO(mtomasz): Implement it once needed.
323 return PostAbortableTask(base::Bind(callback
, base::File::FILE_OK
));
326 void FakeProvidedFileSystem::RemoveWatcher(
328 const base::FilePath
& entry_path
,
330 const storage::AsyncFileUtil::StatusCallback
& callback
) {
331 // TODO(mtomasz): Implement it once needed.
332 callback
.Run(base::File::FILE_OK
);
335 const ProvidedFileSystemInfo
& FakeProvidedFileSystem::GetFileSystemInfo()
337 return file_system_info_
;
340 RequestManager
* FakeProvidedFileSystem::GetRequestManager() {
345 Watchers
* FakeProvidedFileSystem::GetWatchers() {
349 const OpenedFiles
& FakeProvidedFileSystem::GetOpenedFiles() const {
350 return opened_files_
;
353 void FakeProvidedFileSystem::AddObserver(ProvidedFileSystemObserver
* observer
) {
355 observers_
.AddObserver(observer
);
358 void FakeProvidedFileSystem::RemoveObserver(
359 ProvidedFileSystemObserver
* observer
) {
361 observers_
.RemoveObserver(observer
);
364 void FakeProvidedFileSystem::Notify(
365 const base::FilePath
& entry_path
,
367 storage::WatcherManager::ChangeType change_type
,
368 scoped_ptr
<ProvidedFileSystemObserver::Changes
> changes
,
369 const std::string
& tag
,
370 const storage::AsyncFileUtil::StatusCallback
& callback
) {
372 callback
.Run(base::File::FILE_ERROR_SECURITY
);
375 ProvidedFileSystemInterface
* FakeProvidedFileSystem::Create(
377 const ProvidedFileSystemInfo
& file_system_info
) {
378 return new FakeProvidedFileSystem(file_system_info
);
381 base::WeakPtr
<ProvidedFileSystemInterface
>
382 FakeProvidedFileSystem::GetWeakPtr() {
383 return weak_ptr_factory_
.GetWeakPtr();
386 AbortCallback
FakeProvidedFileSystem::PostAbortableTask(
387 const base::Closure
& callback
) {
388 const int task_id
= tracker_
.PostTask(
389 base::MessageLoopProxy::current().get(), FROM_HERE
, callback
);
391 &FakeProvidedFileSystem::Abort
, weak_ptr_factory_
.GetWeakPtr(), task_id
);
394 void FakeProvidedFileSystem::Abort(int task_id
) {
395 tracker_
.TryCancel(task_id
);
398 void FakeProvidedFileSystem::AbortMany(const std::vector
<int>& task_ids
) {
399 for (size_t i
= 0; i
< task_ids
.size(); ++i
) {
400 tracker_
.TryCancel(task_ids
[i
]);
404 } // namespace file_system_provider
405 } // namespace chromeos