No Bug, mozilla-central repo-update HSTS HPKP remote-settings tld-suffixes ct-logs...
[gecko.git] / xpcom / io / nsDirectoryService.cpp
blob650eb69dd38c38f3c18cd4f1cd403434541af34f
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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ArrayUtils.h"
9 #include "nsCOMPtr.h"
10 #include "nsDirectoryService.h"
11 #include "nsLocalFile.h"
12 #include "nsDebug.h"
13 #include "nsGkAtoms.h"
14 #include "nsEnumeratorUtils.h"
15 #include "nsThreadUtils.h"
17 #include "mozilla/SimpleEnumerator.h"
18 #include "nsICategoryManager.h"
19 #include "nsISimpleEnumerator.h"
21 #if defined(XP_WIN)
22 # include <windows.h>
23 # include <shlobj.h>
24 # include <stdlib.h>
25 # include <stdio.h>
26 #elif defined(XP_UNIX)
27 # include <unistd.h>
28 # include <stdlib.h>
29 # include <sys/param.h>
30 # include "prenv.h"
31 # ifdef MOZ_WIDGET_COCOA
32 # include <CoreServices/CoreServices.h>
33 # include <Carbon/Carbon.h>
34 # endif
35 #endif
37 #include "SpecialSystemDirectory.h"
38 #include "nsAppFileLocationProvider.h"
39 #include "BinaryPath.h"
41 using namespace mozilla;
43 //----------------------------------------------------------------------------------------
44 nsresult nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile)
45 //----------------------------------------------------------------------------------------
47 if (NS_WARN_IF(!aFile)) {
48 return NS_ERROR_INVALID_ARG;
50 *aFile = nullptr;
52 // Set the component registry location:
53 if (!gService) {
54 return NS_ERROR_FAILURE;
57 if (!mXCurProcD) {
58 #if defined(ANDROID)
59 // Some callers relying on this fallback make assumptions that don't
60 // hold on Android for BinaryPath::GetFile, so use GRE_HOME instead.
61 const char* greHome = getenv("GRE_HOME");
62 if (!greHome) {
63 return NS_ERROR_FAILURE;
65 nsresult rv = NS_NewNativeLocalFile(nsDependentCString(greHome),
66 getter_AddRefs(mXCurProcD));
67 if (NS_FAILED(rv)) {
68 return rv;
70 #else
71 nsCOMPtr<nsIFile> file;
72 if (NS_SUCCEEDED(BinaryPath::GetFile(getter_AddRefs(file)))) {
73 nsresult rv = file->GetParent(getter_AddRefs(mXCurProcD));
74 if (NS_FAILED(rv)) {
75 return rv;
78 #endif
80 return mXCurProcD->Clone(aFile);
81 } // GetCurrentProcessDirectory()
83 StaticRefPtr<nsDirectoryService> nsDirectoryService::gService;
85 nsDirectoryService::nsDirectoryService() : mHashtable(128) {}
87 nsresult nsDirectoryService::Create(REFNSIID aIID, void** aResult) {
88 if (NS_WARN_IF(!aResult)) {
89 return NS_ERROR_INVALID_ARG;
92 if (!gService) {
93 return NS_ERROR_NOT_INITIALIZED;
96 return gService->QueryInterface(aIID, aResult);
99 NS_IMETHODIMP
100 nsDirectoryService::Init() {
101 MOZ_ASSERT_UNREACHABLE("nsDirectoryService::Init() for internal use only!");
102 return NS_OK;
105 void nsDirectoryService::RealInit() {
106 NS_ASSERTION(!gService,
107 "nsDirectoryService::RealInit Mustn't initialize twice!");
109 gService = new nsDirectoryService();
111 // Let the list hold the only reference to the provider.
112 nsAppFileLocationProvider* defaultProvider = new nsAppFileLocationProvider;
113 gService->mProviders.AppendElement(defaultProvider);
116 nsDirectoryService::~nsDirectoryService() = default;
118 NS_IMPL_ISUPPORTS(nsDirectoryService, nsIProperties, nsIDirectoryService,
119 nsIDirectoryServiceProvider, nsIDirectoryServiceProvider2)
121 NS_IMETHODIMP
122 nsDirectoryService::Undefine(const char* aProp) {
123 if (NS_WARN_IF(!aProp)) {
124 return NS_ERROR_INVALID_ARG;
127 nsDependentCString key(aProp);
128 return mHashtable.Remove(key) ? NS_OK : NS_ERROR_FAILURE;
131 NS_IMETHODIMP
132 nsDirectoryService::GetKeys(nsTArray<nsCString>& aKeys) {
133 return NS_ERROR_NOT_IMPLEMENTED;
136 struct MOZ_STACK_CLASS FileData {
137 FileData(const char* aProperty, const nsIID& aUUID)
138 : property(aProperty), data(nullptr), persistent(true), uuid(aUUID) {}
140 const char* property;
141 nsCOMPtr<nsISupports> data;
142 bool persistent;
143 const nsIID& uuid;
146 static bool FindProviderFile(nsIDirectoryServiceProvider* aElement,
147 FileData* aData) {
148 nsresult rv;
149 if (aData->uuid.Equals(NS_GET_IID(nsISimpleEnumerator))) {
150 // Not all providers implement this iface
151 nsCOMPtr<nsIDirectoryServiceProvider2> prov2 = do_QueryInterface(aElement);
152 if (prov2) {
153 nsCOMPtr<nsISimpleEnumerator> newFiles;
154 rv = prov2->GetFiles(aData->property, getter_AddRefs(newFiles));
155 if (NS_SUCCEEDED(rv) && newFiles) {
156 if (aData->data) {
157 nsCOMPtr<nsISimpleEnumerator> unionFiles;
159 NS_NewUnionEnumerator(getter_AddRefs(unionFiles),
160 (nsISimpleEnumerator*)aData->data.get(),
161 newFiles);
163 if (unionFiles) {
164 unionFiles.swap(*(nsISimpleEnumerator**)&aData->data);
166 } else {
167 aData->data = newFiles;
170 aData->persistent = false; // Enumerators can never be persistent
171 return rv == NS_SUCCESS_AGGREGATE_RESULT;
174 } else {
175 rv = aElement->GetFile(aData->property, &aData->persistent,
176 (nsIFile**)&aData->data);
177 if (NS_SUCCEEDED(rv) && aData->data) {
178 return false;
182 return true;
185 NS_IMETHODIMP
186 nsDirectoryService::Get(const char* aProp, const nsIID& aUuid, void** aResult) {
187 if (NS_WARN_IF(!aProp)) {
188 return NS_ERROR_INVALID_ARG;
191 MOZ_ASSERT(NS_IsMainThread(), "Do not call dirsvc::get on non-main threads!");
193 nsDependentCString key(aProp);
195 nsCOMPtr<nsIFile> cachedFile = mHashtable.Get(key);
197 if (cachedFile) {
198 nsCOMPtr<nsIFile> cloneFile;
199 cachedFile->Clone(getter_AddRefs(cloneFile));
200 return cloneFile->QueryInterface(aUuid, aResult);
203 // it is not one of our defaults, lets check any providers
204 FileData fileData(aProp, aUuid);
206 for (int32_t i = mProviders.Length() - 1; i >= 0; i--) {
207 if (!FindProviderFile(mProviders[i], &fileData)) {
208 break;
211 if (fileData.data) {
212 if (fileData.persistent) {
213 Set(aProp, static_cast<nsIFile*>(fileData.data.get()));
215 nsresult rv = (fileData.data)->QueryInterface(aUuid, aResult);
216 fileData.data = nullptr; // AddRef occurs in FindProviderFile()
217 return rv;
220 FindProviderFile(static_cast<nsIDirectoryServiceProvider*>(this), &fileData);
221 if (fileData.data) {
222 if (fileData.persistent) {
223 Set(aProp, static_cast<nsIFile*>(fileData.data.get()));
225 nsresult rv = (fileData.data)->QueryInterface(aUuid, aResult);
226 fileData.data = nullptr; // AddRef occurs in FindProviderFile()
227 return rv;
230 return NS_ERROR_FAILURE;
233 NS_IMETHODIMP
234 nsDirectoryService::Set(const char* aProp, nsISupports* aValue) {
235 if (NS_WARN_IF(!aProp)) {
236 return NS_ERROR_INVALID_ARG;
238 if (!aValue) {
239 return NS_ERROR_FAILURE;
242 const nsDependentCString key(aProp);
243 return mHashtable.WithEntryHandle(key, [&](auto&& entry) {
244 if (!entry) {
245 nsCOMPtr<nsIFile> ourFile = do_QueryInterface(aValue);
246 if (ourFile) {
247 nsCOMPtr<nsIFile> cloneFile;
248 ourFile->Clone(getter_AddRefs(cloneFile));
249 entry.Insert(std::move(cloneFile));
250 return NS_OK;
253 return NS_ERROR_FAILURE;
257 NS_IMETHODIMP
258 nsDirectoryService::Has(const char* aProp, bool* aResult) {
259 if (NS_WARN_IF(!aProp)) {
260 return NS_ERROR_INVALID_ARG;
263 *aResult = false;
264 nsCOMPtr<nsIFile> value;
265 nsresult rv = Get(aProp, NS_GET_IID(nsIFile), getter_AddRefs(value));
266 if (NS_FAILED(rv)) {
267 return NS_OK;
270 if (value) {
271 *aResult = true;
274 return rv;
277 NS_IMETHODIMP
278 nsDirectoryService::RegisterProvider(nsIDirectoryServiceProvider* aProv) {
279 if (!aProv) {
280 return NS_ERROR_FAILURE;
283 mProviders.AppendElement(aProv);
284 return NS_OK;
287 void nsDirectoryService::RegisterCategoryProviders() {
288 nsCOMPtr<nsICategoryManager> catman(
289 do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
290 if (!catman) {
291 return;
294 nsCOMPtr<nsISimpleEnumerator> entries;
295 catman->EnumerateCategory(XPCOM_DIRECTORY_PROVIDER_CATEGORY,
296 getter_AddRefs(entries));
298 for (auto& categoryEntry : SimpleEnumerator<nsICategoryEntry>(entries)) {
299 nsAutoCString contractID;
300 categoryEntry->GetValue(contractID);
302 if (nsCOMPtr<nsIDirectoryServiceProvider> provider =
303 do_GetService(contractID.get())) {
304 RegisterProvider(provider);
309 NS_IMETHODIMP
310 nsDirectoryService::UnregisterProvider(nsIDirectoryServiceProvider* aProv) {
311 if (!aProv) {
312 return NS_ERROR_FAILURE;
315 mProviders.RemoveElement(aProv);
316 return NS_OK;
319 // DO NOT ADD ANY LOCATIONS TO THIS FUNCTION UNTIL YOU TALK TO:
320 // dougt@netscape.com. This is meant to be a place of xpcom or system specific
321 // file locations, not application specific locations. If you need the later,
322 // register a callback for your application.
324 NS_IMETHODIMP
325 nsDirectoryService::GetFile(const char* aProp, bool* aPersistent,
326 nsIFile** aResult) {
327 nsCOMPtr<nsIFile> localFile;
328 nsresult rv = NS_ERROR_FAILURE;
330 *aResult = nullptr;
331 *aPersistent = true;
333 RefPtr<nsAtom> inAtom = NS_Atomize(aProp);
335 // check to see if it is one of our defaults
337 if (inAtom == nsGkAtoms::DirectoryService_CurrentProcess ||
338 inAtom == nsGkAtoms::DirectoryService_OS_CurrentProcessDirectory) {
339 rv = GetCurrentProcessDirectory(getter_AddRefs(localFile));
342 // Unless otherwise set, the core pieces of the GRE exist
343 // in the current process directory.
344 else if (inAtom == nsGkAtoms::DirectoryService_GRE_Directory ||
345 inAtom == nsGkAtoms::DirectoryService_GRE_BinDirectory) {
346 rv = GetCurrentProcessDirectory(getter_AddRefs(localFile));
347 } else if (inAtom == nsGkAtoms::DirectoryService_OS_TemporaryDirectory) {
348 rv = GetSpecialSystemDirectory(OS_TemporaryDirectory,
349 getter_AddRefs(localFile));
350 } else if (inAtom == nsGkAtoms::DirectoryService_OS_CurrentWorkingDirectory) {
351 rv = GetSpecialSystemDirectory(OS_CurrentWorkingDirectory,
352 getter_AddRefs(localFile));
354 #if defined(MOZ_WIDGET_COCOA)
355 else if (inAtom == nsGkAtoms::DirectoryService_SystemDirectory) {
356 rv = GetSpecialSystemDirectory(Mac_SystemDirectory,
357 getter_AddRefs(localFile));
358 } else if (inAtom == nsGkAtoms::DirectoryService_UserLibDirectory) {
359 rv = GetSpecialSystemDirectory(Mac_UserLibDirectory,
360 getter_AddRefs(localFile));
361 } else if (inAtom == nsGkAtoms::Home) {
362 rv =
363 GetSpecialSystemDirectory(Mac_HomeDirectory, getter_AddRefs(localFile));
364 } else if (inAtom == nsGkAtoms::DirectoryService_DefaultDownloadDirectory) {
365 rv = GetSpecialSystemDirectory(Mac_DefaultDownloadDirectory,
366 getter_AddRefs(localFile));
367 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DesktopDirectory) {
368 rv = GetSpecialSystemDirectory(Mac_UserDesktopDirectory,
369 getter_AddRefs(localFile));
370 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DocumentsDirectory) {
371 rv = GetSpecialSystemDirectory(Mac_UserDocumentsDirectory,
372 getter_AddRefs(localFile));
373 } else if (inAtom == nsGkAtoms::DirectoryService_LocalApplicationsDirectory) {
374 rv = GetSpecialSystemDirectory(Mac_LocalApplicationsDirectory,
375 getter_AddRefs(localFile));
376 } else if (inAtom == nsGkAtoms::DirectoryService_UserPreferencesDirectory) {
377 rv = GetSpecialSystemDirectory(Mac_UserPreferencesDirectory,
378 getter_AddRefs(localFile));
379 } else if (inAtom == nsGkAtoms::DirectoryService_PictureDocumentsDirectory) {
380 rv = GetSpecialSystemDirectory(Mac_PictureDocumentsDirectory,
381 getter_AddRefs(localFile));
382 } else if (inAtom == nsGkAtoms::DirectoryService_DefaultScreenshotDirectory) {
383 rv = GetSpecialSystemDirectory(Mac_DefaultScreenshotDirectory,
384 getter_AddRefs(localFile));
386 #elif defined(XP_WIN)
387 else if (inAtom == nsGkAtoms::DirectoryService_SystemDirectory) {
388 rv = GetSpecialSystemDirectory(Win_SystemDirectory,
389 getter_AddRefs(localFile));
390 } else if (inAtom == nsGkAtoms::DirectoryService_WindowsDirectory) {
391 rv = GetSpecialSystemDirectory(Win_WindowsDirectory,
392 getter_AddRefs(localFile));
393 } else if (inAtom == nsGkAtoms::DirectoryService_WindowsProgramFiles) {
394 rv = GetSpecialSystemDirectory(Win_ProgramFiles, getter_AddRefs(localFile));
395 } else if (inAtom == nsGkAtoms::Home) {
396 rv =
397 GetSpecialSystemDirectory(Win_HomeDirectory, getter_AddRefs(localFile));
398 } else if (inAtom == nsGkAtoms::DirectoryService_Programs) {
399 rv = GetSpecialSystemDirectory(Win_Programs, getter_AddRefs(localFile));
400 } else if (inAtom == nsGkAtoms::DirectoryService_Favorites) {
401 rv = GetSpecialSystemDirectory(Win_Favorites, getter_AddRefs(localFile));
402 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DesktopDirectory) {
403 rv = GetSpecialSystemDirectory(Win_Desktopdirectory,
404 getter_AddRefs(localFile));
405 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DocumentsDirectory) {
406 rv = GetSpecialSystemDirectory(Win_Documents, getter_AddRefs(localFile));
407 } else if (inAtom == nsGkAtoms::DirectoryService_Appdata) {
408 rv = GetSpecialSystemDirectory(Win_Appdata, getter_AddRefs(localFile));
409 } else if (inAtom == nsGkAtoms::DirectoryService_LocalAppdata) {
410 rv = GetSpecialSystemDirectory(Win_LocalAppdata, getter_AddRefs(localFile));
411 } else if (inAtom == nsGkAtoms::DirectoryService_WinCookiesDirectory) {
412 rv = GetSpecialSystemDirectory(Win_Cookies, getter_AddRefs(localFile));
413 } else if (inAtom == nsGkAtoms::DirectoryService_DefaultDownloadDirectory) {
414 rv = GetSpecialSystemDirectory(Win_Downloads, getter_AddRefs(localFile));
416 #elif defined(XP_UNIX)
417 else if (inAtom == nsGkAtoms::Home) {
418 rv = GetSpecialSystemDirectory(Unix_HomeDirectory,
419 getter_AddRefs(localFile));
420 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DesktopDirectory) {
421 rv = GetSpecialSystemDirectory(Unix_XDG_Desktop, getter_AddRefs(localFile));
422 *aPersistent = false;
423 } else if (inAtom == nsGkAtoms::DirectoryService_DefaultDownloadDirectory) {
424 rv =
425 GetSpecialSystemDirectory(Unix_XDG_Download, getter_AddRefs(localFile));
426 *aPersistent = false;
427 } else if (inAtom == nsGkAtoms::DirectoryService_OS_SystemConfigDir) {
428 rv = GetSpecialSystemDirectory(Unix_SystemConfigDirectory,
429 getter_AddRefs(localFile));
430 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DocumentsDirectory) {
431 rv = GetSpecialSystemDirectory(Unix_XDG_Documents,
432 getter_AddRefs(localFile));
434 #endif
436 if (NS_FAILED(rv)) {
437 return rv;
440 if (!localFile) {
441 return NS_ERROR_FAILURE;
444 localFile.forget(aResult);
445 return NS_OK;
448 NS_IMETHODIMP
449 nsDirectoryService::GetFiles(const char* aProp, nsISimpleEnumerator** aResult) {
450 if (NS_WARN_IF(!aResult)) {
451 return NS_ERROR_INVALID_ARG;
453 *aResult = nullptr;
455 return NS_ERROR_FAILURE;