Directory.cpp (5547B)
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 "mozilla/dom/Directory.h" 8 9 #include "GetDirectoryListingTask.h" 10 #include "GetFilesTask.h" 11 #include "mozilla/dom/BlobImpl.h" 12 #include "mozilla/dom/DirectoryBinding.h" 13 #include "mozilla/dom/FileSystemBase.h" 14 #include "mozilla/dom/FileSystemUtils.h" 15 #include "mozilla/dom/OSFileSystem.h" 16 #include "mozilla/dom/WorkerPrivate.h" 17 #include "nsIFile.h" 18 #include "nsString.h" 19 20 namespace mozilla::dom { 21 22 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Directory) 23 24 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Directory) 25 if (tmp->mFileSystem) { 26 tmp->mFileSystem->Unlink(); 27 tmp->mFileSystem = nullptr; 28 } 29 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal) 30 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 31 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 32 33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory) 34 if (tmp->mFileSystem) { 35 tmp->mFileSystem->Traverse(cb); 36 } 37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) 38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 39 40 NS_IMPL_CYCLE_COLLECTING_ADDREF(Directory) 41 NS_IMPL_CYCLE_COLLECTING_RELEASE(Directory) 42 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Directory) 43 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 44 NS_INTERFACE_MAP_ENTRY(nsISupports) 45 NS_INTERFACE_MAP_END 46 47 /* static */ 48 already_AddRefed<Directory> Directory::Constructor(const GlobalObject& aGlobal, 49 const nsAString& aRealPath, 50 ErrorResult& aRv) { 51 nsCOMPtr<nsIFile> path; 52 aRv = NS_NewLocalFile(aRealPath, getter_AddRefs(path)); 53 if (NS_WARN_IF(aRv.Failed())) { 54 return nullptr; 55 } 56 57 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); 58 if (NS_WARN_IF(!global)) { 59 aRv.Throw(NS_ERROR_FAILURE); 60 return nullptr; 61 } 62 63 return Create(global, path); 64 } 65 66 /* static */ 67 already_AddRefed<Directory> Directory::Create(nsIGlobalObject* aGlobal, 68 nsIFile* aFile, 69 FileSystemBase* aFileSystem) { 70 MOZ_ASSERT(aGlobal); 71 MOZ_ASSERT(aFile); 72 73 RefPtr<Directory> directory = new Directory(aGlobal, aFile, aFileSystem); 74 return directory.forget(); 75 } 76 77 Directory::Directory(nsIGlobalObject* aGlobal, nsIFile* aFile, 78 FileSystemBase* aFileSystem) 79 : mGlobal(aGlobal), mFile(aFile) { 80 MOZ_ASSERT(aFile); 81 82 // aFileSystem can be null. In this case we create a OSFileSystem when needed. 83 if (aFileSystem) { 84 // More likely, this is a OSFileSystem. This object keeps a reference of 85 // mGlobal but it's not cycle collectable and to avoid manual 86 // addref/release, it's better to have 1 object per directory. For this 87 // reason we clone it here. 88 mFileSystem = aFileSystem->Clone(); 89 } 90 } 91 92 Directory::~Directory() = default; 93 94 nsIGlobalObject* Directory::GetParentObject() const { return mGlobal; } 95 96 JSObject* Directory::WrapObject(JSContext* aCx, 97 JS::Handle<JSObject*> aGivenProto) { 98 return Directory_Binding::Wrap(aCx, this, aGivenProto); 99 } 100 101 void Directory::GetName(nsAString& aRetval, ErrorResult& aRv) { 102 aRetval.Truncate(); 103 104 RefPtr<FileSystemBase> fs = GetFileSystem(aRv); 105 if (NS_WARN_IF(aRv.Failed())) { 106 return; 107 } 108 109 fs->GetDirectoryName(mFile, aRetval, aRv); 110 } 111 112 void Directory::GetPath(nsAString& aRetval, ErrorResult& aRv) { 113 // This operation is expensive. Better to cache the result. 114 if (mPath.IsEmpty()) { 115 RefPtr<FileSystemBase> fs = GetFileSystem(aRv); 116 if (NS_WARN_IF(aRv.Failed())) { 117 return; 118 } 119 120 fs->GetDOMPath(mFile, mPath, aRv); 121 if (NS_WARN_IF(aRv.Failed())) { 122 return; 123 } 124 } 125 126 aRetval = mPath; 127 } 128 129 nsresult Directory::GetFullRealPath(nsAString& aPath) { 130 nsresult rv = mFile->GetPath(aPath); 131 if (NS_WARN_IF(NS_FAILED(rv))) { 132 return rv; 133 } 134 135 return NS_OK; 136 } 137 138 already_AddRefed<Promise> Directory::GetFilesAndDirectories(ErrorResult& aRv) { 139 RefPtr<FileSystemBase> fs = GetFileSystem(aRv); 140 if (NS_WARN_IF(aRv.Failed())) { 141 return nullptr; 142 } 143 144 RefPtr<GetDirectoryListingTaskChild> task = 145 GetDirectoryListingTaskChild::Create(fs, this, mFile, mFilters, aRv); 146 if (NS_WARN_IF(aRv.Failed())) { 147 return nullptr; 148 } 149 150 task->Start(); 151 152 return task->GetPromise(); 153 } 154 155 already_AddRefed<Promise> Directory::GetFiles(bool aRecursiveFlag, 156 ErrorResult& aRv) { 157 ErrorResult rv; 158 RefPtr<FileSystemBase> fs = GetFileSystem(rv); 159 if (NS_WARN_IF(rv.Failed())) { 160 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 161 return nullptr; 162 } 163 164 RefPtr<GetFilesTaskChild> task = 165 GetFilesTaskChild::Create(fs, this, mFile, aRecursiveFlag, rv); 166 if (NS_WARN_IF(rv.Failed())) { 167 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 168 return nullptr; 169 } 170 171 task->Start(); 172 173 return task->GetPromise(); 174 } 175 176 void Directory::SetContentFilters(const nsAString& aFilters) { 177 mFilters = aFilters; 178 } 179 180 FileSystemBase* Directory::GetFileSystem(ErrorResult& aRv) { 181 if (!mFileSystem) { 182 nsAutoString path; 183 aRv = mFile->GetPath(path); 184 if (NS_WARN_IF(aRv.Failed())) { 185 return nullptr; 186 } 187 188 RefPtr<OSFileSystem> fs = new OSFileSystem(path); 189 fs->Init(mGlobal); 190 191 mFileSystem = fs; 192 } 193 194 return mFileSystem; 195 } 196 197 } // namespace mozilla::dom