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

Side by Side Diff: content/child/fileapi/webfilesystem_impl.cc

Issue 188533002: Handle has_more correctly in WebFileSystemImpl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix race Created 6 years, 9 months 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
« no previous file with comments | « content/child/fileapi/webfilesystem_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/child/fileapi/webfilesystem_impl.h" 5 #include "content/child/fileapi/webfilesystem_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/lazy_instance.h" 8 #include "base/lazy_instance.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop/message_loop_proxy.h" 10 #include "base/message_loop/message_loop_proxy.h"
(...skipping 17 matching lines...) Expand all
28 28
29 using blink::WebFileInfo; 29 using blink::WebFileInfo;
30 using blink::WebFileSystemCallbacks; 30 using blink::WebFileSystemCallbacks;
31 using blink::WebFileSystemEntry; 31 using blink::WebFileSystemEntry;
32 using blink::WebString; 32 using blink::WebString;
33 using blink::WebURL; 33 using blink::WebURL;
34 using blink::WebVector; 34 using blink::WebVector;
35 35
36 namespace content { 36 namespace content {
37 37
38 namespace { 38 class WebFileSystemImpl::WaitableCallbackResults
39 : public base::RefCountedThreadSafe<WaitableCallbackResults> {
40 public:
41 WaitableCallbackResults()
42 : results_available_event_(true /* manual_reset */,
43 false /* initially_signaled */) {}
39 44
40 base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl> >::Leaky 45 void AddResultsAndSignal(const base::Closure& results_closure) {
41 g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER; 46 base::AutoLock lock(lock_);
42 47 results_closures_.push_back(results_closure);
43 class WaitableCallbackResults { 48 results_available_event_.Signal();
44 public:
45 static WaitableCallbackResults* MaybeCreate(
46 const WebFileSystemCallbacks& callbacks) {
47 if (callbacks.shouldBlockUntilCompletion())
48 return new WaitableCallbackResults;
49 return NULL;
50 }
51 ~WaitableCallbackResults() {}
52
53 void SetResultsAndSignal(const base::Closure& results_closure) {
54 results_closure_ = results_closure;
55 event_->Signal();
56 } 49 }
57 50
58 void WaitAndRun() { 51 void WaitAndRun() {
59 { 52 {
60 blink::WebHeap::SafePointScope safe_point; 53 blink::WebHeap::SafePointScope safe_point;
61 event_->Wait(); 54 results_available_event_.Wait();
62 } 55 }
63 DCHECK(!results_closure_.is_null()); 56 Run();
64 results_closure_.Run(); 57 }
58
59 void Run() {
60 std::vector<base::Closure> closures;
61 {
62 base::AutoLock lock(lock_);
63 results_closures_.swap(closures);
64 results_available_event_.Reset();
65 }
66 for (size_t i = 0; i < closures.size(); ++i)
67 closures[i].Run();
65 } 68 }
66 69
67 private: 70 private:
68 WaitableCallbackResults() : event_(new base::WaitableEvent(true, false)) {} 71 friend class base::RefCountedThreadSafe<WaitableCallbackResults>;
69 72
70 base::WaitableEvent* event_; 73 ~WaitableCallbackResults() {}
71 base::Closure results_closure_; 74
75 base::Lock lock_;
76 base::WaitableEvent results_available_event_;
77 std::vector<base::Closure> results_closures_;
72 DISALLOW_COPY_AND_ASSIGN(WaitableCallbackResults); 78 DISALLOW_COPY_AND_ASSIGN(WaitableCallbackResults);
73 }; 79 };
74 80
81 namespace {
82
83 typedef WebFileSystemImpl::WaitableCallbackResults WaitableCallbackResults;
84
85 base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl> >::Leaky
86 g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER;
87
75 void DidReceiveSnapshotFile(int request_id) { 88 void DidReceiveSnapshotFile(int request_id) {
76 if (ChildThread::current()) 89 if (ChildThread::current())
77 ChildThread::current()->Send( 90 ChildThread::current()->Send(
78 new FileSystemHostMsg_DidReceiveSnapshotFile(request_id)); 91 new FileSystemHostMsg_DidReceiveSnapshotFile(request_id));
79 } 92 }
80 93
81 int CurrentWorkerId() { 94 int CurrentWorkerId() {
82 return WorkerTaskRunner::Instance()->CurrentWorkerId(); 95 return WorkerTaskRunner::Instance()->CurrentWorkerId();
83 } 96 }
84 97
85 template <typename Method, typename Params> 98 template <typename Method, typename Params>
86 void CallDispatcherOnMainThread( 99 void CallDispatcherOnMainThread(
87 base::MessageLoopProxy* loop, 100 base::MessageLoopProxy* loop,
88 Method method, const Params& params, 101 Method method, const Params& params,
89 scoped_ptr<WaitableCallbackResults> waitable_results) { 102 WaitableCallbackResults* waitable_results) {
90 scoped_ptr<WaitableCallbackResults> null_waitable;
91 if (!loop->RunsTasksOnCurrentThread()) { 103 if (!loop->RunsTasksOnCurrentThread()) {
92 loop->PostTask(FROM_HERE, 104 loop->PostTask(FROM_HERE,
93 base::Bind(&CallDispatcherOnMainThread<Method, Params>, 105 base::Bind(&CallDispatcherOnMainThread<Method, Params>,
94 make_scoped_refptr(loop), method, params, 106 make_scoped_refptr(loop), method, params,
95 base::Passed(&null_waitable))); 107 scoped_refptr<WaitableCallbackResults>()));
96 if (!waitable_results) 108 if (!waitable_results)
97 return; 109 return;
98 waitable_results->WaitAndRun(); 110 waitable_results->WaitAndRun();
99 } 111 }
100 if (!ChildThread::current() || 112 if (!ChildThread::current() ||
101 !ChildThread::current()->file_system_dispatcher()) 113 !ChildThread::current()->file_system_dispatcher())
102 return; 114 return;
103 115
104 DCHECK(!waitable_results); 116 DCHECK(!waitable_results);
105 DispatchToMethod(ChildThread::current()->file_system_dispatcher(), 117 DispatchToMethod(ChildThread::current()->file_system_dispatcher(),
106 method, params); 118 method, params);
107 } 119 }
108 120
121 enum CallbacksUnregisterMode {
122 UNREGISTER_CALLBACKS,
123 DO_NOT_UNREGISTER_CALLBACKS,
124 };
125
109 // Run WebFileSystemCallbacks's |method| with |params|. 126 // Run WebFileSystemCallbacks's |method| with |params|.
110 template <typename Method, typename Params> 127 template <typename Method, typename Params>
111 void RunCallbacks(int callbacks_id, Method method, const Params& params) { 128 void RunCallbacks(int callbacks_id, Method method, const Params& params,
129 CallbacksUnregisterMode callbacks_unregister_mode) {
112 WebFileSystemImpl* filesystem = 130 WebFileSystemImpl* filesystem =
113 WebFileSystemImpl::ThreadSpecificInstance(NULL); 131 WebFileSystemImpl::ThreadSpecificInstance(NULL);
114 if (!filesystem) 132 if (!filesystem)
115 return; 133 return;
116 WebFileSystemCallbacks callbacks = 134 WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
117 filesystem->GetAndUnregisterCallbacks(callbacks_id); 135 if (callbacks_unregister_mode == UNREGISTER_CALLBACKS)
136 filesystem->UnregisterCallbacks(callbacks_id);
118 DispatchToMethod(&callbacks, method, params); 137 DispatchToMethod(&callbacks, method, params);
119 } 138 }
120 139
121 void DispatchResultsClosure(int thread_id, int callbacks_id, 140 void DispatchResultsClosure(int thread_id, int callbacks_id,
122 WaitableCallbackResults* waitable_results, 141 WaitableCallbackResults* waitable_results,
123 const base::Closure& results_closure) { 142 const base::Closure& results_closure) {
124 if (thread_id != CurrentWorkerId()) { 143 if (thread_id != CurrentWorkerId()) {
125 if (waitable_results) { 144 if (waitable_results) {
126 waitable_results->SetResultsAndSignal(results_closure); 145 // If someone is waiting, this should result in running the closure.
146 waitable_results->AddResultsAndSignal(results_closure);
147 // In case no one is waiting, post a task to run the closure.
148 WorkerTaskRunner::Instance()->PostTask(
149 thread_id,
150 base::Bind(&WaitableCallbackResults::Run,
151 make_scoped_refptr(waitable_results)));
127 return; 152 return;
128 } 153 }
129 WorkerTaskRunner::Instance()->PostTask(thread_id, results_closure); 154 WorkerTaskRunner::Instance()->PostTask(thread_id, results_closure);
130 return; 155 return;
131 } 156 }
132 results_closure.Run(); 157 results_closure.Run();
133 } 158 }
134 159
135 template <typename Method, typename Params> 160 template <typename Method, typename Params>
136 void CallbackFileSystemCallbacks( 161 void CallbackFileSystemCallbacks(
137 int thread_id, int callbacks_id, 162 int thread_id, int callbacks_id,
138 WaitableCallbackResults* waitable_results, 163 WaitableCallbackResults* waitable_results,
139 Method method, const Params& params) { 164 Method method, const Params& params,
165 CallbacksUnregisterMode callbacks_unregister_mode) {
140 DispatchResultsClosure( 166 DispatchResultsClosure(
141 thread_id, callbacks_id, waitable_results, 167 thread_id, callbacks_id, waitable_results,
142 base::Bind(&RunCallbacks<Method, Params>, callbacks_id, method, params)); 168 base::Bind(&RunCallbacks<Method, Params>, callbacks_id, method, params,
169 callbacks_unregister_mode));
143 } 170 }
144 171
145 //----------------------------------------------------------------------------- 172 //-----------------------------------------------------------------------------
146 // Callback adapters. Callbacks must be called on the original calling thread, 173 // Callback adapters. Callbacks must be called on the original calling thread,
147 // so these callback adapters relay back the results to the calling thread 174 // so these callback adapters relay back the results to the calling thread
148 // if necessary. 175 // if necessary.
149 176
150 void OpenFileSystemCallbackAdapter( 177 void OpenFileSystemCallbackAdapter(
151 int thread_id, int callbacks_id, 178 int thread_id, int callbacks_id,
152 WaitableCallbackResults* waitable_results, 179 WaitableCallbackResults* waitable_results,
153 const std::string& name, const GURL& root) { 180 const std::string& name, const GURL& root) {
154 CallbackFileSystemCallbacks( 181 CallbackFileSystemCallbacks(
155 thread_id, callbacks_id, waitable_results, 182 thread_id, callbacks_id, waitable_results,
156 &WebFileSystemCallbacks::didOpenFileSystem, 183 &WebFileSystemCallbacks::didOpenFileSystem,
157 MakeTuple(base::UTF8ToUTF16(name), root)); 184 MakeTuple(base::UTF8ToUTF16(name), root),
185 UNREGISTER_CALLBACKS);
158 } 186 }
159 187
160 void ResolveURLCallbackAdapter( 188 void ResolveURLCallbackAdapter(
161 int thread_id, int callbacks_id, 189 int thread_id, int callbacks_id,
162 WaitableCallbackResults* waitable_results, 190 WaitableCallbackResults* waitable_results,
163 const fileapi::FileSystemInfo& info, 191 const fileapi::FileSystemInfo& info,
164 const base::FilePath& file_path, bool is_directory) { 192 const base::FilePath& file_path, bool is_directory) {
165 base::FilePath normalized_path( 193 base::FilePath normalized_path(
166 fileapi::VirtualPath::GetNormalizedFilePath(file_path)); 194 fileapi::VirtualPath::GetNormalizedFilePath(file_path));
167 CallbackFileSystemCallbacks( 195 CallbackFileSystemCallbacks(
168 thread_id, callbacks_id, waitable_results, 196 thread_id, callbacks_id, waitable_results,
169 &WebFileSystemCallbacks::didResolveURL, 197 &WebFileSystemCallbacks::didResolveURL,
170 MakeTuple(base::UTF8ToUTF16(info.name), info.root_url, 198 MakeTuple(base::UTF8ToUTF16(info.name), info.root_url,
171 static_cast<blink::WebFileSystemType>(info.mount_type), 199 static_cast<blink::WebFileSystemType>(info.mount_type),
172 normalized_path.AsUTF16Unsafe(), is_directory)); 200 normalized_path.AsUTF16Unsafe(), is_directory),
201 UNREGISTER_CALLBACKS);
173 } 202 }
174 203
175 void StatusCallbackAdapter(int thread_id, int callbacks_id, 204 void StatusCallbackAdapter(int thread_id, int callbacks_id,
176 WaitableCallbackResults* waitable_results, 205 WaitableCallbackResults* waitable_results,
177 base::File::Error error) { 206 base::File::Error error) {
178 if (error == base::File::FILE_OK) { 207 if (error == base::File::FILE_OK) {
179 CallbackFileSystemCallbacks( 208 CallbackFileSystemCallbacks(
180 thread_id, callbacks_id, waitable_results, 209 thread_id, callbacks_id, waitable_results,
181 &WebFileSystemCallbacks::didSucceed, MakeTuple()); 210 &WebFileSystemCallbacks::didSucceed, MakeTuple(),
211 UNREGISTER_CALLBACKS);
182 } else { 212 } else {
183 CallbackFileSystemCallbacks( 213 CallbackFileSystemCallbacks(
184 thread_id, callbacks_id, waitable_results, 214 thread_id, callbacks_id, waitable_results,
185 &WebFileSystemCallbacks::didFail, 215 &WebFileSystemCallbacks::didFail,
186 MakeTuple(fileapi::FileErrorToWebFileError(error))); 216 MakeTuple(fileapi::FileErrorToWebFileError(error)),
217 UNREGISTER_CALLBACKS);
187 } 218 }
188 } 219 }
189 220
190 void ReadMetadataCallbackAdapter(int thread_id, int callbacks_id, 221 void ReadMetadataCallbackAdapter(int thread_id, int callbacks_id,
191 WaitableCallbackResults* waitable_results, 222 WaitableCallbackResults* waitable_results,
192 const base::File::Info& file_info) { 223 const base::File::Info& file_info) {
193 WebFileInfo web_file_info; 224 WebFileInfo web_file_info;
194 FileInfoToWebFileInfo(file_info, &web_file_info); 225 FileInfoToWebFileInfo(file_info, &web_file_info);
195 CallbackFileSystemCallbacks( 226 CallbackFileSystemCallbacks(
196 thread_id, callbacks_id, waitable_results, 227 thread_id, callbacks_id, waitable_results,
197 &WebFileSystemCallbacks::didReadMetadata, 228 &WebFileSystemCallbacks::didReadMetadata,
198 MakeTuple(web_file_info)); 229 MakeTuple(web_file_info),
230 UNREGISTER_CALLBACKS);
199 } 231 }
200 232
201 void ReadDirectoryCallbackAdapater( 233 void ReadDirectoryCallbackAdapter(
202 int thread_id, int callbacks_id, WaitableCallbackResults* waitable_results, 234 int thread_id, int callbacks_id, WaitableCallbackResults* waitable_results,
203 const std::vector<fileapi::DirectoryEntry>& entries, 235 const std::vector<fileapi::DirectoryEntry>& entries,
204 bool has_more) { 236 bool has_more) {
205 WebVector<WebFileSystemEntry> file_system_entries(entries.size()); 237 WebVector<WebFileSystemEntry> file_system_entries(entries.size());
206 for (size_t i = 0; i < entries.size(); i++) { 238 for (size_t i = 0; i < entries.size(); i++) {
207 file_system_entries[i].name = 239 file_system_entries[i].name =
208 base::FilePath(entries[i].name).AsUTF16Unsafe(); 240 base::FilePath(entries[i].name).AsUTF16Unsafe();
209 file_system_entries[i].isDirectory = entries[i].is_directory; 241 file_system_entries[i].isDirectory = entries[i].is_directory;
210 } 242 }
211 CallbackFileSystemCallbacks( 243 CallbackFileSystemCallbacks(
212 thread_id, callbacks_id, waitable_results, 244 thread_id, callbacks_id, waitable_results,
213 &WebFileSystemCallbacks::didReadDirectory, 245 &WebFileSystemCallbacks::didReadDirectory,
214 MakeTuple(file_system_entries, has_more)); 246 MakeTuple(file_system_entries, has_more),
247 has_more ? DO_NOT_UNREGISTER_CALLBACKS : UNREGISTER_CALLBACKS);
215 } 248 }
216 249
217 void DidCreateFileWriter( 250 void DidCreateFileWriter(
218 int callbacks_id, 251 int callbacks_id,
219 const GURL& path, 252 const GURL& path,
220 blink::WebFileWriterClient* client, 253 blink::WebFileWriterClient* client,
221 base::MessageLoopProxy* main_thread_loop, 254 base::MessageLoopProxy* main_thread_loop,
222 const base::File::Info& file_info) { 255 const base::File::Info& file_info) {
223 WebFileSystemImpl* filesystem = 256 WebFileSystemImpl* filesystem =
224 WebFileSystemImpl::ThreadSpecificInstance(NULL); 257 WebFileSystemImpl::ThreadSpecificInstance(NULL);
225 if (!filesystem) 258 if (!filesystem)
226 return; 259 return;
227 260
228 WebFileSystemCallbacks callbacks = 261 WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
229 filesystem->GetAndUnregisterCallbacks(callbacks_id); 262 filesystem->UnregisterCallbacks(callbacks_id);
230 263
231 if (file_info.is_directory || file_info.size < 0) { 264 if (file_info.is_directory || file_info.size < 0) {
232 callbacks.didFail(blink::WebFileErrorInvalidState); 265 callbacks.didFail(blink::WebFileErrorInvalidState);
233 return; 266 return;
234 } 267 }
235 WebFileWriterImpl::Type type = 268 WebFileWriterImpl::Type type =
236 callbacks.shouldBlockUntilCompletion() ? 269 callbacks.shouldBlockUntilCompletion() ?
237 WebFileWriterImpl::TYPE_SYNC : WebFileWriterImpl::TYPE_ASYNC; 270 WebFileWriterImpl::TYPE_SYNC : WebFileWriterImpl::TYPE_ASYNC;
238 callbacks.didCreateFileWriter( 271 callbacks.didCreateFileWriter(
239 new WebFileWriterImpl(path, client, type, main_thread_loop), 272 new WebFileWriterImpl(path, client, type, main_thread_loop),
(...skipping 17 matching lines...) Expand all
257 int callbacks_id, 290 int callbacks_id,
258 base::MessageLoopProxy* main_thread_loop, 291 base::MessageLoopProxy* main_thread_loop,
259 const base::File::Info& file_info, 292 const base::File::Info& file_info,
260 const base::FilePath& platform_path, 293 const base::FilePath& platform_path,
261 int request_id) { 294 int request_id) {
262 WebFileSystemImpl* filesystem = 295 WebFileSystemImpl* filesystem =
263 WebFileSystemImpl::ThreadSpecificInstance(NULL); 296 WebFileSystemImpl::ThreadSpecificInstance(NULL);
264 if (!filesystem) 297 if (!filesystem)
265 return; 298 return;
266 299
267 WebFileSystemCallbacks callbacks = 300 WebFileSystemCallbacks callbacks = filesystem->GetCallbacks(callbacks_id);
268 filesystem->GetAndUnregisterCallbacks(callbacks_id); 301 filesystem->UnregisterCallbacks(callbacks_id);
269 302
270 WebFileInfo web_file_info; 303 WebFileInfo web_file_info;
271 FileInfoToWebFileInfo(file_info, &web_file_info); 304 FileInfoToWebFileInfo(file_info, &web_file_info);
272 web_file_info.platformPath = platform_path.AsUTF16Unsafe(); 305 web_file_info.platformPath = platform_path.AsUTF16Unsafe();
273 callbacks.didCreateSnapshotFile(web_file_info); 306 callbacks.didCreateSnapshotFile(web_file_info);
274 307
275 // TODO(michaeln,kinuko): Use ThreadSafeSender when Blob becomes 308 // TODO(michaeln,kinuko): Use ThreadSafeSender when Blob becomes
276 // non-bridge model. 309 // non-bridge model.
277 main_thread_loop->PostTask( 310 main_thread_loop->PostTask(
278 FROM_HERE, base::Bind(&DidReceiveSnapshotFile, request_id)); 311 FROM_HERE, base::Bind(&DidReceiveSnapshotFile, request_id));
(...skipping 29 matching lines...) Expand all
308 } 341 }
309 342
310 void WebFileSystemImpl::DeleteThreadSpecificInstance() { 343 void WebFileSystemImpl::DeleteThreadSpecificInstance() {
311 DCHECK(!WorkerTaskRunner::Instance()->CurrentWorkerId()); 344 DCHECK(!WorkerTaskRunner::Instance()->CurrentWorkerId());
312 if (g_webfilesystem_tls.Pointer()->Get()) 345 if (g_webfilesystem_tls.Pointer()->Get())
313 delete g_webfilesystem_tls.Pointer()->Get(); 346 delete g_webfilesystem_tls.Pointer()->Get();
314 } 347 }
315 348
316 WebFileSystemImpl::WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop) 349 WebFileSystemImpl::WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop)
317 : main_thread_loop_(main_thread_loop), 350 : main_thread_loop_(main_thread_loop),
318 next_callbacks_id_(0) { 351 next_callbacks_id_(1) {
319 g_webfilesystem_tls.Pointer()->Set(this); 352 g_webfilesystem_tls.Pointer()->Set(this);
320 } 353 }
321 354
322 WebFileSystemImpl::~WebFileSystemImpl() { 355 WebFileSystemImpl::~WebFileSystemImpl() {
323 g_webfilesystem_tls.Pointer()->Set(NULL); 356 g_webfilesystem_tls.Pointer()->Set(NULL);
324 } 357 }
325 358
326 void WebFileSystemImpl::OnWorkerRunLoopStopped() { 359 void WebFileSystemImpl::OnWorkerRunLoopStopped() {
327 delete this; 360 delete this;
328 } 361 }
329 362
330 void WebFileSystemImpl::openFileSystem( 363 void WebFileSystemImpl::openFileSystem(
331 const blink::WebURL& storage_partition, 364 const blink::WebURL& storage_partition,
332 blink::WebFileSystemType type, 365 blink::WebFileSystemType type,
333 WebFileSystemCallbacks callbacks) { 366 WebFileSystemCallbacks callbacks) {
334 int callbacks_id = RegisterCallbacks(callbacks); 367 int callbacks_id = RegisterCallbacks(callbacks);
335 WaitableCallbackResults* waitable_results = 368 scoped_refptr<WaitableCallbackResults> waitable_results =
336 WaitableCallbackResults::MaybeCreate(callbacks); 369 MaybeCreateWaitableResults(callbacks, callbacks_id);
337 CallDispatcherOnMainThread( 370 CallDispatcherOnMainThread(
338 main_thread_loop_.get(), 371 main_thread_loop_.get(),
339 &FileSystemDispatcher::OpenFileSystem, 372 &FileSystemDispatcher::OpenFileSystem,
340 MakeTuple(GURL(storage_partition), 373 MakeTuple(GURL(storage_partition),
341 static_cast<fileapi::FileSystemType>(type), 374 static_cast<fileapi::FileSystemType>(type),
342 base::Bind(&OpenFileSystemCallbackAdapter, 375 base::Bind(&OpenFileSystemCallbackAdapter,
343 CurrentWorkerId(), callbacks_id, 376 CurrentWorkerId(), callbacks_id, waitable_results),
344 base::Unretained(waitable_results)),
345 base::Bind(&StatusCallbackAdapter, 377 base::Bind(&StatusCallbackAdapter,
346 CurrentWorkerId(), callbacks_id, 378 CurrentWorkerId(), callbacks_id, waitable_results)),
347 base::Unretained(waitable_results))), 379 waitable_results.get());
348 make_scoped_ptr(waitable_results));
349 } 380 }
350 381
351 void WebFileSystemImpl::resolveURL( 382 void WebFileSystemImpl::resolveURL(
352 const blink::WebURL& filesystem_url, 383 const blink::WebURL& filesystem_url,
353 WebFileSystemCallbacks callbacks) { 384 WebFileSystemCallbacks callbacks) {
354 int callbacks_id = RegisterCallbacks(callbacks); 385 int callbacks_id = RegisterCallbacks(callbacks);
355 WaitableCallbackResults* waitable_results = 386 scoped_refptr<WaitableCallbackResults> waitable_results =
356 WaitableCallbackResults::MaybeCreate(callbacks); 387 MaybeCreateWaitableResults(callbacks, callbacks_id);
357 CallDispatcherOnMainThread( 388 CallDispatcherOnMainThread(
358 main_thread_loop_.get(), 389 main_thread_loop_.get(),
359 &FileSystemDispatcher::ResolveURL, 390 &FileSystemDispatcher::ResolveURL,
360 MakeTuple(GURL(filesystem_url), 391 MakeTuple(GURL(filesystem_url),
361 base::Bind(&ResolveURLCallbackAdapter, 392 base::Bind(&ResolveURLCallbackAdapter,
362 CurrentWorkerId(), callbacks_id, 393 CurrentWorkerId(), callbacks_id, waitable_results),
363 base::Unretained(waitable_results)),
364 base::Bind(&StatusCallbackAdapter, 394 base::Bind(&StatusCallbackAdapter,
365 CurrentWorkerId(), callbacks_id, 395 CurrentWorkerId(), callbacks_id, waitable_results)),
366 base::Unretained(waitable_results))), 396 waitable_results.get());
367 make_scoped_ptr(waitable_results));
368 } 397 }
369 398
370 void WebFileSystemImpl::deleteFileSystem( 399 void WebFileSystemImpl::deleteFileSystem(
371 const blink::WebURL& storage_partition, 400 const blink::WebURL& storage_partition,
372 blink::WebFileSystemType type, 401 blink::WebFileSystemType type,
373 WebFileSystemCallbacks callbacks) { 402 WebFileSystemCallbacks callbacks) {
374 int callbacks_id = RegisterCallbacks(callbacks); 403 int callbacks_id = RegisterCallbacks(callbacks);
375 WaitableCallbackResults* waitable_results = 404 scoped_refptr<WaitableCallbackResults> waitable_results =
376 WaitableCallbackResults::MaybeCreate(callbacks); 405 MaybeCreateWaitableResults(callbacks, callbacks_id);
377 CallDispatcherOnMainThread( 406 CallDispatcherOnMainThread(
378 main_thread_loop_.get(), 407 main_thread_loop_.get(),
379 &FileSystemDispatcher::DeleteFileSystem, 408 &FileSystemDispatcher::DeleteFileSystem,
380 MakeTuple(GURL(storage_partition), 409 MakeTuple(GURL(storage_partition),
381 static_cast<fileapi::FileSystemType>(type), 410 static_cast<fileapi::FileSystemType>(type),
382 base::Bind(&StatusCallbackAdapter, 411 base::Bind(&StatusCallbackAdapter,
383 CurrentWorkerId(), callbacks_id, 412 CurrentWorkerId(), callbacks_id, waitable_results)),
384 base::Unretained(waitable_results))), 413 waitable_results.get());
385 make_scoped_ptr(waitable_results));
386 } 414 }
387 415
388 void WebFileSystemImpl::move( 416 void WebFileSystemImpl::move(
389 const blink::WebURL& src_path, 417 const blink::WebURL& src_path,
390 const blink::WebURL& dest_path, 418 const blink::WebURL& dest_path,
391 WebFileSystemCallbacks callbacks) { 419 WebFileSystemCallbacks callbacks) {
392 int callbacks_id = RegisterCallbacks(callbacks); 420 int callbacks_id = RegisterCallbacks(callbacks);
393 WaitableCallbackResults* waitable_results = 421 scoped_refptr<WaitableCallbackResults> waitable_results =
394 WaitableCallbackResults::MaybeCreate(callbacks); 422 MaybeCreateWaitableResults(callbacks, callbacks_id);
395 CallDispatcherOnMainThread( 423 CallDispatcherOnMainThread(
396 main_thread_loop_.get(), 424 main_thread_loop_.get(),
397 &FileSystemDispatcher::Move, 425 &FileSystemDispatcher::Move,
398 MakeTuple(GURL(src_path), GURL(dest_path), 426 MakeTuple(GURL(src_path), GURL(dest_path),
399 base::Bind(&StatusCallbackAdapter, 427 base::Bind(&StatusCallbackAdapter,
400 CurrentWorkerId(), callbacks_id, 428 CurrentWorkerId(), callbacks_id, waitable_results)),
401 base::Unretained(waitable_results))), 429 waitable_results.get());
402 make_scoped_ptr(waitable_results));
403 } 430 }
404 431
405 void WebFileSystemImpl::copy( 432 void WebFileSystemImpl::copy(
406 const blink::WebURL& src_path, 433 const blink::WebURL& src_path,
407 const blink::WebURL& dest_path, 434 const blink::WebURL& dest_path,
408 WebFileSystemCallbacks callbacks) { 435 WebFileSystemCallbacks callbacks) {
409 int callbacks_id = RegisterCallbacks(callbacks); 436 int callbacks_id = RegisterCallbacks(callbacks);
410 WaitableCallbackResults* waitable_results = 437 scoped_refptr<WaitableCallbackResults> waitable_results =
411 WaitableCallbackResults::MaybeCreate(callbacks); 438 MaybeCreateWaitableResults(callbacks, callbacks_id);
412 CallDispatcherOnMainThread( 439 CallDispatcherOnMainThread(
413 main_thread_loop_.get(), 440 main_thread_loop_.get(),
414 &FileSystemDispatcher::Copy, 441 &FileSystemDispatcher::Copy,
415 MakeTuple(GURL(src_path), GURL(dest_path), 442 MakeTuple(GURL(src_path), GURL(dest_path),
416 base::Bind(&StatusCallbackAdapter, 443 base::Bind(&StatusCallbackAdapter,
417 CurrentWorkerId(), callbacks_id, 444 CurrentWorkerId(), callbacks_id, waitable_results)),
418 base::Unretained(waitable_results))), 445 waitable_results.get());
419 make_scoped_ptr(waitable_results));
420 } 446 }
421 447
422 void WebFileSystemImpl::remove( 448 void WebFileSystemImpl::remove(
423 const blink::WebURL& path, 449 const blink::WebURL& path,
424 WebFileSystemCallbacks callbacks) { 450 WebFileSystemCallbacks callbacks) {
425 int callbacks_id = RegisterCallbacks(callbacks); 451 int callbacks_id = RegisterCallbacks(callbacks);
426 WaitableCallbackResults* waitable_results = 452 scoped_refptr<WaitableCallbackResults> waitable_results =
427 WaitableCallbackResults::MaybeCreate(callbacks); 453 MaybeCreateWaitableResults(callbacks, callbacks_id);
428 CallDispatcherOnMainThread( 454 CallDispatcherOnMainThread(
429 main_thread_loop_.get(), 455 main_thread_loop_.get(),
430 &FileSystemDispatcher::Remove, 456 &FileSystemDispatcher::Remove,
431 MakeTuple(GURL(path), false /* recursive */, 457 MakeTuple(GURL(path), false /* recursive */,
432 base::Bind(&StatusCallbackAdapter, 458 base::Bind(&StatusCallbackAdapter,
433 CurrentWorkerId(), callbacks_id, 459 CurrentWorkerId(), callbacks_id, waitable_results)),
434 base::Unretained(waitable_results))), 460 waitable_results.get());
435 make_scoped_ptr(waitable_results));
436 } 461 }
437 462
438 void WebFileSystemImpl::removeRecursively( 463 void WebFileSystemImpl::removeRecursively(
439 const blink::WebURL& path, 464 const blink::WebURL& path,
440 WebFileSystemCallbacks callbacks) { 465 WebFileSystemCallbacks callbacks) {
441 int callbacks_id = RegisterCallbacks(callbacks); 466 int callbacks_id = RegisterCallbacks(callbacks);
442 WaitableCallbackResults* waitable_results = 467 scoped_refptr<WaitableCallbackResults> waitable_results =
443 WaitableCallbackResults::MaybeCreate(callbacks); 468 MaybeCreateWaitableResults(callbacks, callbacks_id);
444 CallDispatcherOnMainThread( 469 CallDispatcherOnMainThread(
445 main_thread_loop_.get(), 470 main_thread_loop_.get(),
446 &FileSystemDispatcher::Remove, 471 &FileSystemDispatcher::Remove,
447 MakeTuple(GURL(path), true /* recursive */, 472 MakeTuple(GURL(path), true /* recursive */,
448 base::Bind(&StatusCallbackAdapter, 473 base::Bind(&StatusCallbackAdapter,
449 CurrentWorkerId(), callbacks_id, 474 CurrentWorkerId(), callbacks_id, waitable_results)),
450 base::Unretained(waitable_results))), 475 waitable_results.get());
451 make_scoped_ptr(waitable_results));
452 } 476 }
453 477
454 void WebFileSystemImpl::readMetadata( 478 void WebFileSystemImpl::readMetadata(
455 const blink::WebURL& path, 479 const blink::WebURL& path,
456 WebFileSystemCallbacks callbacks) { 480 WebFileSystemCallbacks callbacks) {
457 int callbacks_id = RegisterCallbacks(callbacks); 481 int callbacks_id = RegisterCallbacks(callbacks);
458 WaitableCallbackResults* waitable_results = 482 scoped_refptr<WaitableCallbackResults> waitable_results =
459 WaitableCallbackResults::MaybeCreate(callbacks); 483 MaybeCreateWaitableResults(callbacks, callbacks_id);
460 CallDispatcherOnMainThread( 484 CallDispatcherOnMainThread(
461 main_thread_loop_.get(), 485 main_thread_loop_.get(),
462 &FileSystemDispatcher::ReadMetadata, 486 &FileSystemDispatcher::ReadMetadata,
463 MakeTuple(GURL(path), 487 MakeTuple(GURL(path),
464 base::Bind(&ReadMetadataCallbackAdapter, 488 base::Bind(&ReadMetadataCallbackAdapter,
465 CurrentWorkerId(), callbacks_id, 489 CurrentWorkerId(), callbacks_id, waitable_results),
466 base::Unretained(waitable_results)),
467 base::Bind(&StatusCallbackAdapter, 490 base::Bind(&StatusCallbackAdapter,
468 CurrentWorkerId(), callbacks_id, 491 CurrentWorkerId(), callbacks_id, waitable_results)),
469 base::Unretained(waitable_results))), 492 waitable_results.get());
470 make_scoped_ptr(waitable_results));
471 } 493 }
472 494
473 void WebFileSystemImpl::createFile( 495 void WebFileSystemImpl::createFile(
474 const blink::WebURL& path, 496 const blink::WebURL& path,
475 bool exclusive, 497 bool exclusive,
476 WebFileSystemCallbacks callbacks) { 498 WebFileSystemCallbacks callbacks) {
477 int callbacks_id = RegisterCallbacks(callbacks); 499 int callbacks_id = RegisterCallbacks(callbacks);
478 WaitableCallbackResults* waitable_results = 500 scoped_refptr<WaitableCallbackResults> waitable_results =
479 WaitableCallbackResults::MaybeCreate(callbacks); 501 MaybeCreateWaitableResults(callbacks, callbacks_id);
480 CallDispatcherOnMainThread( 502 CallDispatcherOnMainThread(
481 main_thread_loop_.get(), 503 main_thread_loop_.get(),
482 &FileSystemDispatcher::CreateFile, 504 &FileSystemDispatcher::CreateFile,
483 MakeTuple(GURL(path), exclusive, 505 MakeTuple(GURL(path), exclusive,
484 base::Bind(&StatusCallbackAdapter, 506 base::Bind(&StatusCallbackAdapter,
485 CurrentWorkerId(), callbacks_id, 507 CurrentWorkerId(), callbacks_id, waitable_results)),
486 base::Unretained(waitable_results))), 508 waitable_results.get());
487 make_scoped_ptr(waitable_results));
488 } 509 }
489 510
490 void WebFileSystemImpl::createDirectory( 511 void WebFileSystemImpl::createDirectory(
491 const blink::WebURL& path, 512 const blink::WebURL& path,
492 bool exclusive, 513 bool exclusive,
493 WebFileSystemCallbacks callbacks) { 514 WebFileSystemCallbacks callbacks) {
494 int callbacks_id = RegisterCallbacks(callbacks); 515 int callbacks_id = RegisterCallbacks(callbacks);
495 WaitableCallbackResults* waitable_results = 516 scoped_refptr<WaitableCallbackResults> waitable_results =
496 WaitableCallbackResults::MaybeCreate(callbacks); 517 MaybeCreateWaitableResults(callbacks, callbacks_id);
497 CallDispatcherOnMainThread( 518 CallDispatcherOnMainThread(
498 main_thread_loop_.get(), 519 main_thread_loop_.get(),
499 &FileSystemDispatcher::CreateDirectory, 520 &FileSystemDispatcher::CreateDirectory,
500 MakeTuple(GURL(path), exclusive, false /* recursive */, 521 MakeTuple(GURL(path), exclusive, false /* recursive */,
501 base::Bind(&StatusCallbackAdapter, 522 base::Bind(&StatusCallbackAdapter,
502 CurrentWorkerId(), callbacks_id, 523 CurrentWorkerId(), callbacks_id, waitable_results)),
503 base::Unretained(waitable_results))), 524 waitable_results.get());
504 make_scoped_ptr(waitable_results));
505 } 525 }
506 526
507 void WebFileSystemImpl::fileExists( 527 void WebFileSystemImpl::fileExists(
508 const blink::WebURL& path, 528 const blink::WebURL& path,
509 WebFileSystemCallbacks callbacks) { 529 WebFileSystemCallbacks callbacks) {
510 int callbacks_id = RegisterCallbacks(callbacks); 530 int callbacks_id = RegisterCallbacks(callbacks);
511 WaitableCallbackResults* waitable_results = 531 scoped_refptr<WaitableCallbackResults> waitable_results =
512 WaitableCallbackResults::MaybeCreate(callbacks); 532 MaybeCreateWaitableResults(callbacks, callbacks_id);
513 CallDispatcherOnMainThread( 533 CallDispatcherOnMainThread(
514 main_thread_loop_.get(), 534 main_thread_loop_.get(),
515 &FileSystemDispatcher::Exists, 535 &FileSystemDispatcher::Exists,
516 MakeTuple(GURL(path), false /* directory */, 536 MakeTuple(GURL(path), false /* directory */,
517 base::Bind(&StatusCallbackAdapter, 537 base::Bind(&StatusCallbackAdapter,
518 CurrentWorkerId(), callbacks_id, 538 CurrentWorkerId(), callbacks_id, waitable_results)),
519 base::Unretained(waitable_results))), 539 waitable_results.get());
520 make_scoped_ptr(waitable_results));
521 } 540 }
522 541
523 void WebFileSystemImpl::directoryExists( 542 void WebFileSystemImpl::directoryExists(
524 const blink::WebURL& path, 543 const blink::WebURL& path,
525 WebFileSystemCallbacks callbacks) { 544 WebFileSystemCallbacks callbacks) {
526 int callbacks_id = RegisterCallbacks(callbacks); 545 int callbacks_id = RegisterCallbacks(callbacks);
527 WaitableCallbackResults* waitable_results = 546 scoped_refptr<WaitableCallbackResults> waitable_results =
528 WaitableCallbackResults::MaybeCreate(callbacks); 547 MaybeCreateWaitableResults(callbacks, callbacks_id);
529 CallDispatcherOnMainThread( 548 CallDispatcherOnMainThread(
530 main_thread_loop_.get(), 549 main_thread_loop_.get(),
531 &FileSystemDispatcher::Exists, 550 &FileSystemDispatcher::Exists,
532 MakeTuple(GURL(path), true /* directory */, 551 MakeTuple(GURL(path), true /* directory */,
533 base::Bind(&StatusCallbackAdapter, 552 base::Bind(&StatusCallbackAdapter,
534 CurrentWorkerId(), callbacks_id, 553 CurrentWorkerId(), callbacks_id, waitable_results)),
535 base::Unretained(waitable_results))), 554 waitable_results.get());
536 make_scoped_ptr(waitable_results));
537 } 555 }
538 556
539 void WebFileSystemImpl::readDirectory( 557 READ_DIRECTORY_RETURN_TYPE WebFileSystemImpl::readDirectory(
540 const blink::WebURL& path, 558 const blink::WebURL& path,
541 WebFileSystemCallbacks callbacks) { 559 WebFileSystemCallbacks callbacks) {
542 int callbacks_id = RegisterCallbacks(callbacks); 560 int callbacks_id = RegisterCallbacks(callbacks);
543 WaitableCallbackResults* waitable_results = 561 scoped_refptr<WaitableCallbackResults> waitable_results =
544 WaitableCallbackResults::MaybeCreate(callbacks); 562 MaybeCreateWaitableResults(callbacks, callbacks_id);
545 CallDispatcherOnMainThread( 563 CallDispatcherOnMainThread(
546 main_thread_loop_.get(), 564 main_thread_loop_.get(),
547 &FileSystemDispatcher::ReadDirectory, 565 &FileSystemDispatcher::ReadDirectory,
548 MakeTuple(GURL(path), 566 MakeTuple(GURL(path),
549 base::Bind(&ReadDirectoryCallbackAdapater, 567 base::Bind(&ReadDirectoryCallbackAdapter,
550 CurrentWorkerId(), callbacks_id, 568 CurrentWorkerId(), callbacks_id, waitable_results),
551 base::Unretained(waitable_results)),
552 base::Bind(&StatusCallbackAdapter, 569 base::Bind(&StatusCallbackAdapter,
553 CurrentWorkerId(), callbacks_id, 570 CurrentWorkerId(), callbacks_id, waitable_results)),
554 base::Unretained(waitable_results))), 571 waitable_results.get());
555 make_scoped_ptr(waitable_results)); 572 #if defined(READ_DIRECTORY_RETURNS_INT)
573 return callbacks_id;
574 #endif
556 } 575 }
557 576
558 void WebFileSystemImpl::createFileWriter( 577 void WebFileSystemImpl::createFileWriter(
559 const WebURL& path, 578 const WebURL& path,
560 blink::WebFileWriterClient* client, 579 blink::WebFileWriterClient* client,
561 WebFileSystemCallbacks callbacks) { 580 WebFileSystemCallbacks callbacks) {
562 int callbacks_id = RegisterCallbacks(callbacks); 581 int callbacks_id = RegisterCallbacks(callbacks);
563 WaitableCallbackResults* waitable_results = 582 scoped_refptr<WaitableCallbackResults> waitable_results =
564 WaitableCallbackResults::MaybeCreate(callbacks); 583 MaybeCreateWaitableResults(callbacks, callbacks_id);
565 CallDispatcherOnMainThread( 584 CallDispatcherOnMainThread(
566 main_thread_loop_.get(), 585 main_thread_loop_.get(),
567 &FileSystemDispatcher::ReadMetadata, 586 &FileSystemDispatcher::ReadMetadata,
568 MakeTuple(GURL(path), 587 MakeTuple(GURL(path),
569 base::Bind(&CreateFileWriterCallbackAdapter, 588 base::Bind(&CreateFileWriterCallbackAdapter,
570 CurrentWorkerId(), callbacks_id, 589 CurrentWorkerId(), callbacks_id, waitable_results,
571 base::Unretained(waitable_results),
572 main_thread_loop_, GURL(path), client), 590 main_thread_loop_, GURL(path), client),
573 base::Bind(&StatusCallbackAdapter, 591 base::Bind(&StatusCallbackAdapter,
574 CurrentWorkerId(), callbacks_id, 592 CurrentWorkerId(), callbacks_id, waitable_results)),
575 base::Unretained(waitable_results))), 593 waitable_results.get());
576 make_scoped_ptr(waitable_results));
577 } 594 }
578 595
579 void WebFileSystemImpl::createSnapshotFileAndReadMetadata( 596 void WebFileSystemImpl::createSnapshotFileAndReadMetadata(
580 const blink::WebURL& path, 597 const blink::WebURL& path,
581 WebFileSystemCallbacks callbacks) { 598 WebFileSystemCallbacks callbacks) {
582 int callbacks_id = RegisterCallbacks(callbacks); 599 int callbacks_id = RegisterCallbacks(callbacks);
583 WaitableCallbackResults* waitable_results = 600 scoped_refptr<WaitableCallbackResults> waitable_results =
584 WaitableCallbackResults::MaybeCreate(callbacks); 601 MaybeCreateWaitableResults(callbacks, callbacks_id);
585 CallDispatcherOnMainThread( 602 CallDispatcherOnMainThread(
586 main_thread_loop_.get(), 603 main_thread_loop_.get(),
587 &FileSystemDispatcher::CreateSnapshotFile, 604 &FileSystemDispatcher::CreateSnapshotFile,
588 MakeTuple(GURL(path), 605 MakeTuple(GURL(path),
589 base::Bind(&CreateSnapshotFileCallbackAdapter, 606 base::Bind(&CreateSnapshotFileCallbackAdapter,
590 CurrentWorkerId(), callbacks_id, 607 CurrentWorkerId(), callbacks_id, waitable_results,
591 base::Unretained(waitable_results),
592 main_thread_loop_), 608 main_thread_loop_),
593 base::Bind(&StatusCallbackAdapter, 609 base::Bind(&StatusCallbackAdapter,
594 CurrentWorkerId(), callbacks_id, 610 CurrentWorkerId(), callbacks_id, waitable_results)),
595 base::Unretained(waitable_results))), 611 waitable_results.get());
596 make_scoped_ptr(waitable_results)); 612 }
613
614 bool WebFileSystemImpl::waitForAdditionalResult(int callbacksId) {
615 WaitableCallbackResultsMap::iterator found =
616 waitable_results_.find(callbacksId);
617 if (found == waitable_results_.end())
618 return false;
619
620 found->second->WaitAndRun();
621 return true;
597 } 622 }
598 623
599 int WebFileSystemImpl::RegisterCallbacks( 624 int WebFileSystemImpl::RegisterCallbacks(
600 const WebFileSystemCallbacks& callbacks) { 625 const WebFileSystemCallbacks& callbacks) {
601 DCHECK(CalledOnValidThread()); 626 DCHECK(CalledOnValidThread());
602 int id = next_callbacks_id_++; 627 int id = next_callbacks_id_++;
603 callbacks_[id] = callbacks; 628 callbacks_[id] = callbacks;
604 return id; 629 return id;
605 } 630 }
606 631
607 WebFileSystemCallbacks WebFileSystemImpl::GetAndUnregisterCallbacks( 632 WebFileSystemCallbacks WebFileSystemImpl::GetCallbacks(int callbacks_id) {
608 int callbacks_id) {
609 DCHECK(CalledOnValidThread()); 633 DCHECK(CalledOnValidThread());
610 CallbacksMap::iterator found = callbacks_.find(callbacks_id); 634 CallbacksMap::iterator found = callbacks_.find(callbacks_id);
611 DCHECK(found != callbacks_.end()); 635 DCHECK(found != callbacks_.end());
612 WebFileSystemCallbacks callbacks = found->second; 636 return found->second;
637 }
638
639 void WebFileSystemImpl::UnregisterCallbacks(int callbacks_id) {
640 DCHECK(CalledOnValidThread());
641 CallbacksMap::iterator found = callbacks_.find(callbacks_id);
642 DCHECK(found != callbacks_.end());
613 callbacks_.erase(found); 643 callbacks_.erase(found);
614 return callbacks; 644
645 waitable_results_.erase(callbacks_id);
646 }
647
648 WaitableCallbackResults* WebFileSystemImpl::MaybeCreateWaitableResults(
649 const WebFileSystemCallbacks& callbacks, int callbacks_id) {
650 if (!callbacks.shouldBlockUntilCompletion())
651 return NULL;
652 WaitableCallbackResults* results = new WaitableCallbackResults();
653 waitable_results_[callbacks_id] = results;
654 return results;
615 } 655 }
616 656
617 } // namespace content 657 } // namespace content
OLDNEW
« no previous file with comments | « content/child/fileapi/webfilesystem_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698