1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "modules/filesystem/LocalFileSystem.h" 33 34 #include "core/dom/CrossThreadTask.h" 35 #include "core/dom/Document.h" 36 #include "core/dom/ExceptionCode.h" 37 #include "core/dom/ExecutionContext.h" 38 #include "core/fileapi/FileError.h" 39 #include "core/frame/LocalFrame.h" 40 #include "core/workers/WorkerGlobalScope.h" 41 #include "modules/filesystem/FileSystemClient.h" 42 #include "platform/AsyncFileSystemCallbacks.h" 43 #include "platform/PermissionCallbacks.h" 44 #include "public/platform/Platform.h" 45 #include "public/platform/WebFileSystem.h" 46 #include "wtf/Functional.h" 47 #include "wtf/RefCounted.h" 48 49 namespace blink { 50 51 namespace { 52 53 void reportFailure(ExecutionContext*, PassOwnPtr<AsyncFileSystemCallbacks> callbacks, FileError::ErrorCode error) 54 { 55 callbacks->didFail(error); 56 } 57 58 } // namespace 59 60 class CallbackWrapper FINAL : public GarbageCollectedFinalized<CallbackWrapper> { 61 public: 62 CallbackWrapper(PassOwnPtr<AsyncFileSystemCallbacks> c) 63 : m_callbacks(c) 64 { 65 } 66 virtual ~CallbackWrapper() { } 67 PassOwnPtr<AsyncFileSystemCallbacks> release() 68 { 69 return m_callbacks.release(); 70 } 71 72 void trace(Visitor*) { } 73 74 private: 75 OwnPtr<AsyncFileSystemCallbacks> m_callbacks; 76 }; 77 78 PassOwnPtrWillBeRawPtr<LocalFileSystem> LocalFileSystem::create(PassOwnPtr<FileSystemClient> client) 79 { 80 return adoptPtrWillBeNoop(new LocalFileSystem(client)); 81 } 82 83 LocalFileSystem::~LocalFileSystem() 84 { 85 } 86 87 void LocalFileSystem::resolveURL(ExecutionContext* context, const KURL& fileSystemURL, PassOwnPtr<AsyncFileSystemCallbacks> callbacks) 88 { 89 RefPtrWillBeRawPtr<ExecutionContext> contextPtr(context); 90 CallbackWrapper* wrapper = new CallbackWrapper(callbacks); 91 requestFileSystemAccessInternal(context, 92 bind(&LocalFileSystem::resolveURLInternal, this, contextPtr, fileSystemURL, wrapper), 93 bind(&LocalFileSystem::fileSystemNotAllowedInternal, this, contextPtr, wrapper)); 94 } 95 96 void LocalFileSystem::requestFileSystem(ExecutionContext* context, FileSystemType type, long long size, PassOwnPtr<AsyncFileSystemCallbacks> callbacks) 97 { 98 RefPtrWillBeRawPtr<ExecutionContext> contextPtr(context); 99 CallbackWrapper* wrapper = new CallbackWrapper(callbacks); 100 requestFileSystemAccessInternal(context, 101 bind(&LocalFileSystem::fileSystemAllowedInternal, this, contextPtr, type, wrapper), 102 bind(&LocalFileSystem::fileSystemNotAllowedInternal, this, contextPtr, wrapper)); 103 } 104 105 void LocalFileSystem::deleteFileSystem(ExecutionContext* context, FileSystemType type, PassOwnPtr<AsyncFileSystemCallbacks> callbacks) 106 { 107 RefPtrWillBeRawPtr<ExecutionContext> contextPtr(context); 108 ASSERT(context); 109 ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument()); 110 111 CallbackWrapper* wrapper = new CallbackWrapper(callbacks); 112 requestFileSystemAccessInternal(context, 113 bind(&LocalFileSystem::deleteFileSystemInternal, this, contextPtr, type, wrapper), 114 bind(&LocalFileSystem::fileSystemNotAllowedInternal, this, contextPtr, wrapper)); 115 } 116 117 WebFileSystem* LocalFileSystem::fileSystem() const 118 { 119 Platform* platform = Platform::current(); 120 if (!platform) 121 return nullptr; 122 return Platform::current()->fileSystem(); 123 } 124 125 void LocalFileSystem::requestFileSystemAccessInternal(ExecutionContext* context, const Closure& allowed, const Closure& denied) 126 { 127 if (!client()) { 128 denied(); 129 return; 130 } 131 if (!context->isDocument()) { 132 if (!client()->requestFileSystemAccessSync(context)) { 133 denied(); 134 return; 135 } 136 allowed(); 137 return; 138 } 139 client()->requestFileSystemAccessAsync(context, PermissionCallbacks::create(allowed, denied)); 140 } 141 142 void LocalFileSystem::fileSystemNotAvailable( 143 PassRefPtrWillBeRawPtr<ExecutionContext> context, 144 CallbackWrapper* callbacks) 145 { 146 context->postTask(createCrossThreadTask(&reportFailure, callbacks->release(), FileError::ABORT_ERR)); 147 } 148 149 void LocalFileSystem::fileSystemNotAllowedInternal( 150 PassRefPtrWillBeRawPtr<ExecutionContext> context, 151 CallbackWrapper* callbacks) 152 { 153 context->postTask(createCrossThreadTask(&reportFailure, callbacks->release(), FileError::ABORT_ERR)); 154 } 155 156 void LocalFileSystem::fileSystemAllowedInternal( 157 PassRefPtrWillBeRawPtr<ExecutionContext> context, 158 FileSystemType type, 159 CallbackWrapper* callbacks) 160 { 161 if (!fileSystem()) { 162 fileSystemNotAvailable(context, callbacks); 163 return; 164 } 165 166 KURL storagePartition = KURL(KURL(), context->securityOrigin()->toString()); 167 fileSystem()->openFileSystem(storagePartition, static_cast<WebFileSystemType>(type), callbacks->release()); 168 } 169 170 void LocalFileSystem::resolveURLInternal( 171 PassRefPtrWillBeRawPtr<ExecutionContext> context, 172 const KURL& fileSystemURL, 173 CallbackWrapper* callbacks) 174 { 175 if (!fileSystem()) { 176 fileSystemNotAvailable(context, callbacks); 177 return; 178 } 179 fileSystem()->resolveURL(fileSystemURL, callbacks->release()); 180 } 181 182 void LocalFileSystem::deleteFileSystemInternal( 183 PassRefPtrWillBeRawPtr<ExecutionContext> context, 184 FileSystemType type, 185 CallbackWrapper* callbacks) 186 { 187 if (!fileSystem()) { 188 fileSystemNotAvailable(context, callbacks); 189 return; 190 } 191 KURL storagePartition = KURL(KURL(), context->securityOrigin()->toString()); 192 fileSystem()->deleteFileSystem(storagePartition, static_cast<WebFileSystemType>(type), callbacks->release()); 193 } 194 195 LocalFileSystem::LocalFileSystem(PassOwnPtr<FileSystemClient> client) 196 : m_client(client) 197 { 198 } 199 200 const char* LocalFileSystem::supplementName() 201 { 202 return "LocalFileSystem"; 203 } 204 205 LocalFileSystem* LocalFileSystem::from(ExecutionContext& context) 206 { 207 if (context.isDocument()) { 208 return static_cast<LocalFileSystem*>(WillBeHeapSupplement<LocalFrame>::from(toDocument(context).frame(), supplementName())); 209 } 210 ASSERT(context.isWorkerGlobalScope()); 211 return static_cast<LocalFileSystem*>(WillBeHeapSupplement<WorkerClients>::from(toWorkerGlobalScope(context).clients(), supplementName())); 212 } 213 214 void provideLocalFileSystemTo(LocalFrame& frame, PassOwnPtr<FileSystemClient> client) 215 { 216 frame.provideSupplement(LocalFileSystem::supplementName(), LocalFileSystem::create(client)); 217 } 218 219 void provideLocalFileSystemToWorker(WorkerClients* clients, PassOwnPtr<FileSystemClient> client) 220 { 221 clients->provideSupplement(LocalFileSystem::supplementName(), LocalFileSystem::create(client)); 222 } 223 224 } // namespace blink 225