GetFileOrDirectoryTask.cpp (7418B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "GetFileOrDirectoryTask.h" 8 9 #include "js/Value.h" 10 #include "mozilla/dom/FileBlobImpl.h" 11 #include "mozilla/dom/FileSystemBase.h" 12 #include "mozilla/dom/FileSystemUtils.h" 13 #include "mozilla/dom/IPCBlobUtils.h" 14 #include "mozilla/dom/PFileSystemParams.h" 15 #include "mozilla/dom/Promise.h" 16 #include "mozilla/ipc/BackgroundParent.h" 17 #include "nsIFile.h" 18 #include "nsString.h" 19 20 namespace mozilla::dom { 21 22 /** 23 * GetFileOrDirectoryTaskChild 24 */ 25 26 /* static */ 27 already_AddRefed<GetFileOrDirectoryTaskChild> 28 GetFileOrDirectoryTaskChild::Create(FileSystemBase* aFileSystem, 29 nsIFile* aTargetPath, ErrorResult& aRv) { 30 MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); 31 MOZ_ASSERT(aFileSystem); 32 33 nsCOMPtr<nsIGlobalObject> globalObject = aFileSystem->GetParentObject(); 34 if (NS_WARN_IF(!globalObject)) { 35 aRv.Throw(NS_ERROR_FAILURE); 36 return nullptr; 37 } 38 39 RefPtr<GetFileOrDirectoryTaskChild> task = 40 new GetFileOrDirectoryTaskChild(globalObject, aFileSystem, aTargetPath); 41 42 // aTargetPath can be null. In this case SetError will be called. 43 44 task->mPromise = Promise::Create(globalObject, aRv); 45 if (NS_WARN_IF(aRv.Failed())) { 46 return nullptr; 47 } 48 49 return task.forget(); 50 } 51 52 GetFileOrDirectoryTaskChild::GetFileOrDirectoryTaskChild( 53 nsIGlobalObject* aGlobalObject, FileSystemBase* aFileSystem, 54 nsIFile* aTargetPath) 55 : FileSystemTaskChildBase(aGlobalObject, aFileSystem), 56 mTargetPath(aTargetPath) { 57 MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); 58 MOZ_ASSERT(aFileSystem); 59 } 60 61 GetFileOrDirectoryTaskChild::~GetFileOrDirectoryTaskChild() { 62 MOZ_ASSERT(NS_IsMainThread()); 63 } 64 65 already_AddRefed<Promise> GetFileOrDirectoryTaskChild::GetPromise() { 66 MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); 67 return RefPtr<Promise>(mPromise).forget(); 68 } 69 70 FileSystemParams GetFileOrDirectoryTaskChild::GetRequestParams( 71 const nsString& aSerializedDOMPath, ErrorResult& aRv) const { 72 MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); 73 74 nsAutoString path; 75 aRv = mTargetPath->GetPath(path); 76 if (NS_WARN_IF(aRv.Failed())) { 77 return FileSystemGetFileOrDirectoryParams(); 78 } 79 80 return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path); 81 } 82 83 void GetFileOrDirectoryTaskChild::SetSuccessRequestResult( 84 const FileSystemResponseValue& aValue, ErrorResult& aRv) { 85 MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); 86 switch (aValue.type()) { 87 case FileSystemResponseValue::TFileSystemFileResponse: { 88 FileSystemFileResponse r = aValue; 89 90 RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(r.blob()); 91 MOZ_ASSERT(blobImpl); 92 93 nsCOMPtr<nsIGlobalObject> globalObject = mFileSystem->GetParentObject(); 94 MOZ_ASSERT(globalObject); 95 96 mResultFile = File::Create(globalObject, blobImpl); 97 if (NS_WARN_IF(!mResultFile)) { 98 aRv.Throw(NS_ERROR_FAILURE); 99 } 100 break; 101 } 102 case FileSystemResponseValue::TFileSystemDirectoryResponse: { 103 FileSystemDirectoryResponse r = aValue; 104 105 nsCOMPtr<nsIFile> file; 106 aRv = NS_NewLocalFile(r.realPath(), getter_AddRefs(file)); 107 if (NS_WARN_IF(aRv.Failed())) { 108 return; 109 } 110 111 mResultDirectory = 112 Directory::Create(mFileSystem->GetParentObject(), file, mFileSystem); 113 MOZ_ASSERT(mResultDirectory); 114 break; 115 } 116 default: { 117 MOZ_CRASH("not reached"); 118 break; 119 } 120 } 121 } 122 123 void GetFileOrDirectoryTaskChild::HandlerCallback() { 124 MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); 125 if (mFileSystem->IsShutdown()) { 126 mPromise = nullptr; 127 return; 128 } 129 130 if (HasError()) { 131 mPromise->MaybeReject(mErrorValue); 132 mPromise = nullptr; 133 return; 134 } 135 136 if (mResultDirectory) { 137 mPromise->MaybeResolve(mResultDirectory); 138 mResultDirectory = nullptr; 139 mPromise = nullptr; 140 return; 141 } 142 143 MOZ_ASSERT(mResultFile); 144 mPromise->MaybeResolve(mResultFile); 145 mResultFile = nullptr; 146 mPromise = nullptr; 147 } 148 149 /** 150 * GetFileOrDirectoryTaskParent 151 */ 152 153 /* static */ 154 already_AddRefed<GetFileOrDirectoryTaskParent> 155 GetFileOrDirectoryTaskParent::Create( 156 FileSystemBase* aFileSystem, 157 const FileSystemGetFileOrDirectoryParams& aParam, 158 FileSystemRequestParent* aParent, ErrorResult& aRv) { 159 MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); 160 mozilla::ipc::AssertIsOnBackgroundThread(); 161 MOZ_ASSERT(aFileSystem); 162 163 RefPtr<GetFileOrDirectoryTaskParent> task = 164 new GetFileOrDirectoryTaskParent(aFileSystem, aParam, aParent); 165 166 aRv = NS_NewLocalFile(aParam.realPath(), getter_AddRefs(task->mTargetPath)); 167 if (NS_WARN_IF(aRv.Failed())) { 168 return nullptr; 169 } 170 171 return task.forget(); 172 } 173 174 GetFileOrDirectoryTaskParent::GetFileOrDirectoryTaskParent( 175 FileSystemBase* aFileSystem, 176 const FileSystemGetFileOrDirectoryParams& aParam, 177 FileSystemRequestParent* aParent) 178 : FileSystemTaskParentBase(aFileSystem, aParam, aParent), 179 mIsDirectory(false) { 180 MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); 181 mozilla::ipc::AssertIsOnBackgroundThread(); 182 MOZ_ASSERT(aFileSystem); 183 } 184 185 FileSystemResponseValue GetFileOrDirectoryTaskParent::GetSuccessRequestResult( 186 ErrorResult& aRv) const { 187 mozilla::ipc::AssertIsOnBackgroundThread(); 188 189 nsAutoString path; 190 aRv = mTargetPath->GetPath(path); 191 if (NS_WARN_IF(aRv.Failed())) { 192 return FileSystemDirectoryResponse(); 193 } 194 195 if (mIsDirectory) { 196 return FileSystemDirectoryResponse(path); 197 } 198 199 RefPtr<BlobImpl> blobImpl = new FileBlobImpl(mTargetPath); 200 201 IPCBlob ipcBlob; 202 aRv = IPCBlobUtils::Serialize(blobImpl, ipcBlob); 203 if (NS_WARN_IF(aRv.Failed())) { 204 return FileSystemDirectoryResponse(); 205 } 206 207 return FileSystemFileResponse(ipcBlob); 208 } 209 210 nsresult GetFileOrDirectoryTaskParent::IOWork() { 211 MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); 212 MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!"); 213 214 if (mFileSystem->IsShutdown()) { 215 return NS_ERROR_FAILURE; 216 } 217 218 // Whether we want to get the root directory. 219 bool exists; 220 nsresult rv = mTargetPath->Exists(&exists); 221 if (NS_WARN_IF(NS_FAILED(rv))) { 222 return rv; 223 } 224 225 if (!exists) { 226 if (!mFileSystem->ShouldCreateDirectory()) { 227 return NS_ERROR_DOM_FILE_NOT_FOUND_ERR; 228 } 229 230 rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777); 231 if (NS_WARN_IF(NS_FAILED(rv))) { 232 return rv; 233 } 234 } 235 236 // Get isDirectory. 237 rv = mTargetPath->IsDirectory(&mIsDirectory); 238 if (NS_WARN_IF(NS_FAILED(rv))) { 239 return rv; 240 } 241 242 if (mIsDirectory) { 243 return NS_OK; 244 } 245 246 bool isFile; 247 // Get isFile 248 rv = mTargetPath->IsFile(&isFile); 249 if (NS_WARN_IF(NS_FAILED(rv))) { 250 return rv; 251 } 252 253 if (!isFile) { 254 // Neither directory or file. 255 return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR; 256 } 257 258 if (!mFileSystem->IsSafeFile(mTargetPath)) { 259 return NS_ERROR_DOM_SECURITY_ERR; 260 } 261 262 return NS_OK; 263 } 264 265 nsresult GetFileOrDirectoryTaskParent::GetTargetPath(nsAString& aPath) const { 266 return mTargetPath->GetPath(aPath); 267 } 268 269 } // namespace mozilla::dom