fake_provided_file_system.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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.
4
5#include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
6
7#include <string>
8
9#include "base/files/file.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "extensions/browser/event_router.h"
12#include "net/base/io_buffer.h"
13
14namespace chromeos {
15namespace file_system_provider {
16namespace {
17
18// Adds a fake entry to the entry list.
19void AddDirectoryEntry(fileapi::AsyncFileUtil::EntryList* entry_list,
20                       const std::string& name,
21                       fileapi::DirectoryEntry::DirectoryEntryType type,
22                       int64 size,
23                       std::string last_modified_time_string) {
24  base::Time last_modified_time;
25  const bool result = base::Time::FromString(last_modified_time_string.c_str(),
26                                             &last_modified_time);
27  DCHECK(result);
28  entry_list->push_back(
29      fileapi::DirectoryEntry(name, type, size, last_modified_time));
30}
31
32}  // namespace
33
34const char kFakeFileName[] = "hello.txt";
35const char kFakeFilePath[] = "/hello.txt";
36const char kFakeFileText[] =
37    "This is a testing file. Lorem ipsum dolor sit amet est.";
38const size_t kFakeFileSize = sizeof(kFakeFileText) - 1u;
39
40FakeProvidedFileSystem::FakeProvidedFileSystem(
41    const ProvidedFileSystemInfo& file_system_info)
42    : file_system_info_(file_system_info),
43      last_file_handle_(0),
44      weak_ptr_factory_(this) {
45}
46
47FakeProvidedFileSystem::~FakeProvidedFileSystem() {}
48
49void FakeProvidedFileSystem::RequestUnmount(
50    const fileapi::AsyncFileUtil::StatusCallback& callback) {
51  base::MessageLoopProxy::current()->PostTask(
52      FROM_HERE, base::Bind(callback, base::File::FILE_OK));
53}
54
55void FakeProvidedFileSystem::GetMetadata(
56    const base::FilePath& entry_path,
57    const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) {
58  if (entry_path.AsUTF8Unsafe() == "/") {
59    base::File::Info file_info;
60    file_info.size = 0;
61    file_info.is_directory = true;
62    file_info.is_symbolic_link = false;
63    base::Time last_modified_time;
64    const bool result = base::Time::FromString("Thu Apr 24 00:46:52 UTC 2014",
65                                               &last_modified_time);
66    DCHECK(result);
67    file_info.last_modified = last_modified_time;
68
69    base::MessageLoopProxy::current()->PostTask(
70        FROM_HERE, base::Bind(callback, base::File::FILE_OK, file_info));
71    return;
72  }
73
74  if (entry_path.AsUTF8Unsafe() == kFakeFilePath) {
75    base::File::Info file_info;
76    file_info.size = kFakeFileSize;
77    file_info.is_directory = false;
78    file_info.is_symbolic_link = false;
79    base::Time last_modified_time;
80    const bool result = base::Time::FromString("Fri Apr 25 01:47:53 UTC 2014",
81                                               &last_modified_time);
82    DCHECK(result);
83    file_info.last_modified = last_modified_time;
84
85    base::MessageLoopProxy::current()->PostTask(
86        FROM_HERE, base::Bind(callback, base::File::FILE_OK, file_info));
87    return;
88  }
89
90  base::MessageLoopProxy::current()->PostTask(
91      FROM_HERE,
92      base::Bind(
93          callback, base::File::FILE_ERROR_NOT_FOUND, base::File::Info()));
94}
95
96void FakeProvidedFileSystem::ReadDirectory(
97    const base::FilePath& directory_path,
98    const fileapi::AsyncFileUtil::ReadDirectoryCallback& callback) {
99  // Return fake contents for the root directory only.
100  if (directory_path.AsUTF8Unsafe() != "/") {
101    base::MessageLoopProxy::current()->PostTask(
102        FROM_HERE,
103        base::Bind(callback,
104                   base::File::FILE_ERROR_NOT_FOUND,
105                   fileapi::AsyncFileUtil::EntryList(),
106                   false /* has_more */));
107    return;
108  }
109
110  {
111    fileapi::AsyncFileUtil::EntryList entry_list;
112    AddDirectoryEntry(&entry_list,
113                      kFakeFileName,
114                      fileapi::DirectoryEntry::FILE,
115                      kFakeFileSize,
116                      "Thu Apr 24 00:46:52 UTC 2014");
117
118    AddDirectoryEntry(&entry_list,
119                      "world.txt",
120                      fileapi::DirectoryEntry::FILE,
121                      1024 /* size */,
122                      "Wed Apr 23 00:20:30 UTC 2014");
123
124    base::MessageLoopProxy::current()->PostTask(
125        FROM_HERE,
126        base::Bind(
127            callback, base::File::FILE_OK, entry_list, true /* has_more */));
128  }
129
130  {
131    fileapi::AsyncFileUtil::EntryList entry_list;
132    AddDirectoryEntry(&entry_list,
133                      "pictures",
134                      fileapi::DirectoryEntry::DIRECTORY,
135                      0 /* size */,
136                      "Tue May 22 00:40:50 UTC 2014");
137
138    base::MessageLoopProxy::current()->PostTask(
139        FROM_HERE,
140        base::Bind(
141            callback, base::File::FILE_OK, entry_list, false /* has_more */));
142  }
143}
144
145void FakeProvidedFileSystem::OpenFile(const base::FilePath& file_path,
146                                      OpenFileMode mode,
147                                      bool create,
148                                      const OpenFileCallback& callback) {
149  if (mode == OPEN_FILE_MODE_WRITE || create) {
150    base::MessageLoopProxy::current()->PostTask(
151        FROM_HERE,
152        base::Bind(callback,
153                   0 /* file_handle */,
154                   base::File::FILE_ERROR_ACCESS_DENIED));
155  }
156
157  if (file_path.AsUTF8Unsafe() != "/hello.txt") {
158    base::MessageLoopProxy::current()->PostTask(
159        FROM_HERE,
160        base::Bind(
161            callback, 0 /* file_handle */, base::File::FILE_ERROR_NOT_FOUND));
162    return;
163  }
164
165  const int file_handle = ++last_file_handle_;
166  opened_files_[file_handle] = file_path;
167  base::MessageLoopProxy::current()->PostTask(
168      FROM_HERE, base::Bind(callback, file_handle, base::File::FILE_OK));
169}
170
171void FakeProvidedFileSystem::CloseFile(
172    int file_handle,
173    const fileapi::AsyncFileUtil::StatusCallback& callback) {
174  const OpenedFilesMap::iterator opened_file_it =
175      opened_files_.find(file_handle);
176  if (opened_file_it == opened_files_.end()) {
177    base::MessageLoopProxy::current()->PostTask(
178        FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_NOT_FOUND));
179    return;
180  }
181
182  opened_files_.erase(opened_file_it);
183  base::MessageLoopProxy::current()->PostTask(
184      FROM_HERE, base::Bind(callback, base::File::FILE_OK));
185}
186
187void FakeProvidedFileSystem::ReadFile(
188    int file_handle,
189    net::IOBuffer* buffer,
190    int64 offset,
191    int length,
192    const ProvidedFileSystemInterface::ReadChunkReceivedCallback& callback) {
193  const OpenedFilesMap::iterator opened_file_it =
194      opened_files_.find(file_handle);
195  if (opened_file_it == opened_files_.end() ||
196      opened_file_it->second.AsUTF8Unsafe() != kFakeFilePath) {
197    base::MessageLoopProxy::current()->PostTask(
198        FROM_HERE,
199        base::Bind(callback,
200                   0 /* chunk_length */,
201                   false /* has_more */,
202                   base::File::FILE_ERROR_INVALID_OPERATION));
203    return;
204  }
205
206  // Send the response byte by byte.
207  size_t current_offset = static_cast<size_t>(offset);
208  size_t current_length = static_cast<size_t>(length);
209
210  // Reading behind EOF is fine, it will just return 0 bytes.
211  if (current_offset >= kFakeFileSize || !current_length) {
212    base::MessageLoopProxy::current()->PostTask(
213        FROM_HERE,
214        base::Bind(callback,
215                   0 /* chunk_length */,
216                   false /* has_more */,
217                   base::File::FILE_OK));
218  }
219
220  while (current_offset < kFakeFileSize && current_length) {
221    buffer->data()[current_offset - offset] = kFakeFileText[current_offset];
222    const bool has_more =
223        (current_offset + 1 < kFakeFileSize) && (current_length - 1);
224    base::MessageLoopProxy::current()->PostTask(
225        FROM_HERE,
226        base::Bind(
227            callback, 1 /* chunk_length */, has_more, base::File::FILE_OK));
228    current_offset++;
229    current_length--;
230  }
231}
232
233const ProvidedFileSystemInfo& FakeProvidedFileSystem::GetFileSystemInfo()
234    const {
235  return file_system_info_;
236}
237
238RequestManager* FakeProvidedFileSystem::GetRequestManager() {
239  NOTREACHED();
240  return NULL;
241}
242
243ProvidedFileSystemInterface* FakeProvidedFileSystem::Create(
244    extensions::EventRouter* event_router,
245    const ProvidedFileSystemInfo& file_system_info) {
246  return new FakeProvidedFileSystem(file_system_info);
247}
248
249base::WeakPtr<ProvidedFileSystemInterface>
250FakeProvidedFileSystem::GetWeakPtr() {
251  return weak_ptr_factory_.GetWeakPtr();
252}
253
254}  // namespace file_system_provider
255}  // namespace chromeos
256