Bug 1431441 - Part 6 - Start middleman WebReplay process sandbox later r=Alex_Gaynor
[gecko.git] / xpcom / io / nsDirectoryService.cpp
blob903bc4edd0c5948365998be9fce21c91e0590a9d
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 "nsAutoPtr.h"
11 #include "nsDirectoryService.h"
12 #include "nsLocalFile.h"
13 #include "nsDebug.h"
14 #include "nsGkAtoms.h"
15 #include "nsEnumeratorUtils.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
45 nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile)
46 //----------------------------------------------------------------------------------------
48 if (NS_WARN_IF(!aFile)) {
49 return NS_ERROR_INVALID_ARG;
51 *aFile = nullptr;
53 // Set the component registry location:
54 if (!gService) {
55 return NS_ERROR_FAILURE;
58 nsCOMPtr<nsIFile> file;
59 gService->Get(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
60 getter_AddRefs(file));
61 if (file) {
62 file.forget(aFile);
63 return NS_OK;
66 if (NS_SUCCEEDED(BinaryPath::GetFile(getter_AddRefs(file)))) {
67 return file->GetParent(aFile);
69 NS_ERROR("unable to get current process directory");
70 return NS_ERROR_FAILURE;
71 } // GetCurrentProcessDirectory()
73 StaticRefPtr<nsDirectoryService> nsDirectoryService::gService;
75 nsDirectoryService::nsDirectoryService()
76 : mHashtable(128)
80 nsresult
81 nsDirectoryService::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
83 if (NS_WARN_IF(!aResult)) {
84 return NS_ERROR_INVALID_ARG;
86 if (NS_WARN_IF(aOuter)) {
87 return NS_ERROR_NO_AGGREGATION;
90 if (!gService) {
91 return NS_ERROR_NOT_INITIALIZED;
94 return gService->QueryInterface(aIID, aResult);
97 NS_IMETHODIMP
98 nsDirectoryService::Init()
100 MOZ_ASSERT_UNREACHABLE("nsDirectoryService::Init() for internal use only!");
101 return NS_OK;
104 void
105 nsDirectoryService::RealInit()
107 NS_ASSERTION(!gService,
108 "nsDirectoryService::RealInit Mustn't initialize twice!");
110 gService = new nsDirectoryService();
112 // Let the list hold the only reference to the provider.
113 nsAppFileLocationProvider* defaultProvider = new nsAppFileLocationProvider;
114 gService->mProviders.AppendElement(defaultProvider);
117 nsDirectoryService::~nsDirectoryService()
121 NS_IMPL_ISUPPORTS(nsDirectoryService,
122 nsIProperties,
123 nsIDirectoryService,
124 nsIDirectoryServiceProvider,
125 nsIDirectoryServiceProvider2)
128 NS_IMETHODIMP
129 nsDirectoryService::Undefine(const char* aProp)
131 if (NS_WARN_IF(!aProp)) {
132 return NS_ERROR_INVALID_ARG;
135 nsDependentCString key(aProp);
136 return mHashtable.Remove(key) ? NS_OK : NS_ERROR_FAILURE;
139 NS_IMETHODIMP
140 nsDirectoryService::GetKeys(uint32_t* aCount, char*** aKeys)
142 return NS_ERROR_NOT_IMPLEMENTED;
145 struct MOZ_STACK_CLASS FileData
147 FileData(const char* aProperty, const nsIID& aUUID)
148 : property(aProperty)
149 , data(nullptr)
150 , persistent(true)
151 , uuid(aUUID)
155 const char* property;
156 nsCOMPtr<nsISupports> data;
157 bool persistent;
158 const nsIID& uuid;
161 static bool
162 FindProviderFile(nsIDirectoryServiceProvider* aElement, FileData* aData)
164 nsresult rv;
165 if (aData->uuid.Equals(NS_GET_IID(nsISimpleEnumerator))) {
166 // Not all providers implement this iface
167 nsCOMPtr<nsIDirectoryServiceProvider2> prov2 = do_QueryInterface(aElement);
168 if (prov2) {
169 nsCOMPtr<nsISimpleEnumerator> newFiles;
170 rv = prov2->GetFiles(aData->property, getter_AddRefs(newFiles));
171 if (NS_SUCCEEDED(rv) && newFiles) {
172 if (aData->data) {
173 nsCOMPtr<nsISimpleEnumerator> unionFiles;
175 NS_NewUnionEnumerator(getter_AddRefs(unionFiles),
176 (nsISimpleEnumerator*)aData->data.get(), newFiles);
178 if (unionFiles) {
179 unionFiles.swap(*(nsISimpleEnumerator**)&aData->data);
181 } else {
182 aData->data = newFiles;
185 aData->persistent = false; // Enumerators can never be persistent
186 return rv == NS_SUCCESS_AGGREGATE_RESULT;
189 } else {
190 rv = aElement->GetFile(aData->property, &aData->persistent,
191 (nsIFile**)&aData->data);
192 if (NS_SUCCEEDED(rv) && aData->data) {
193 return false;
197 return true;
200 NS_IMETHODIMP
201 nsDirectoryService::Get(const char* aProp, const nsIID& aUuid, void** aResult)
203 if (NS_WARN_IF(!aProp)) {
204 return NS_ERROR_INVALID_ARG;
207 nsDependentCString key(aProp);
209 nsCOMPtr<nsIFile> cachedFile = mHashtable.Get(key);
211 if (cachedFile) {
212 nsCOMPtr<nsIFile> cloneFile;
213 cachedFile->Clone(getter_AddRefs(cloneFile));
214 return cloneFile->QueryInterface(aUuid, aResult);
217 // it is not one of our defaults, lets check any providers
218 FileData fileData(aProp, aUuid);
220 for (int32_t i = mProviders.Length() - 1; i >= 0; i--) {
221 if (!FindProviderFile(mProviders[i], &fileData)) {
222 break;
225 if (fileData.data) {
226 if (fileData.persistent) {
227 Set(aProp, static_cast<nsIFile*>(fileData.data.get()));
229 nsresult rv = (fileData.data)->QueryInterface(aUuid, aResult);
230 fileData.data = nullptr; // AddRef occurs in FindProviderFile()
231 return rv;
234 FindProviderFile(static_cast<nsIDirectoryServiceProvider*>(this), &fileData);
235 if (fileData.data) {
236 if (fileData.persistent) {
237 Set(aProp, static_cast<nsIFile*>(fileData.data.get()));
239 nsresult rv = (fileData.data)->QueryInterface(aUuid, aResult);
240 fileData.data = nullptr; // AddRef occurs in FindProviderFile()
241 return rv;
244 return NS_ERROR_FAILURE;
247 NS_IMETHODIMP
248 nsDirectoryService::Set(const char* aProp, nsISupports* aValue)
250 if (NS_WARN_IF(!aProp)) {
251 return NS_ERROR_INVALID_ARG;
253 if (!aValue) {
254 return NS_ERROR_FAILURE;
257 nsDependentCString key(aProp);
258 if (auto entry = mHashtable.LookupForAdd(key)) {
259 return NS_ERROR_FAILURE;
260 } else {
261 nsCOMPtr<nsIFile> ourFile = do_QueryInterface(aValue);
262 if (ourFile) {
263 nsCOMPtr<nsIFile> cloneFile;
264 ourFile->Clone(getter_AddRefs(cloneFile));
265 entry.OrInsert([&cloneFile] () { return cloneFile.forget(); });
266 return NS_OK;
268 mHashtable.Remove(key); // another hashtable lookup, but should be rare
270 return NS_ERROR_FAILURE;
273 NS_IMETHODIMP
274 nsDirectoryService::Has(const char* aProp, bool* aResult)
276 if (NS_WARN_IF(!aProp)) {
277 return NS_ERROR_INVALID_ARG;
280 *aResult = false;
281 nsCOMPtr<nsIFile> value;
282 nsresult rv = Get(aProp, NS_GET_IID(nsIFile), getter_AddRefs(value));
283 if (NS_FAILED(rv)) {
284 return NS_OK;
287 if (value) {
288 *aResult = true;
291 return rv;
294 NS_IMETHODIMP
295 nsDirectoryService::RegisterProvider(nsIDirectoryServiceProvider* aProv)
297 if (!aProv) {
298 return NS_ERROR_FAILURE;
301 mProviders.AppendElement(aProv);
302 return NS_OK;
305 void
306 nsDirectoryService::RegisterCategoryProviders()
308 nsCOMPtr<nsICategoryManager> catman
309 (do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
310 if (!catman) {
311 return;
314 nsCOMPtr<nsISimpleEnumerator> entries;
315 catman->EnumerateCategory(XPCOM_DIRECTORY_PROVIDER_CATEGORY,
316 getter_AddRefs(entries));
318 for (auto& categoryEntry : SimpleEnumerator<nsICategoryEntry>(entries)) {
319 nsAutoCString contractID;
320 categoryEntry->GetValue(contractID);
322 if (nsCOMPtr<nsIDirectoryServiceProvider> provider = do_GetService(contractID.get())) {
323 RegisterProvider(provider);
328 NS_IMETHODIMP
329 nsDirectoryService::UnregisterProvider(nsIDirectoryServiceProvider* aProv)
331 if (!aProv) {
332 return NS_ERROR_FAILURE;
335 mProviders.RemoveElement(aProv);
336 return NS_OK;
339 #if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
340 static nsresult
341 GetLowIntegrityTempBase(nsIFile** aLowIntegrityTempBase)
343 nsCOMPtr<nsIFile> localFile;
344 nsresult rv = GetSpecialSystemDirectory(Win_LocalAppdataLow,
345 getter_AddRefs(localFile));
346 if (NS_WARN_IF(NS_FAILED(rv))) {
347 return rv;
350 rv = localFile->Append(NS_LITERAL_STRING(MOZ_USER_DIR));
351 if (NS_WARN_IF(NS_FAILED(rv))) {
352 return rv;
355 localFile.forget(aLowIntegrityTempBase);
356 return rv;
358 #endif
360 // DO NOT ADD ANY LOCATIONS TO THIS FUNCTION UNTIL YOU TALK TO: dougt@netscape.com.
361 // This is meant to be a place of xpcom or system specific file locations, not
362 // application specific locations. If you need the later, register a callback for
363 // your application.
365 NS_IMETHODIMP
366 nsDirectoryService::GetFile(const char* aProp, bool* aPersistent,
367 nsIFile** aResult)
369 nsCOMPtr<nsIFile> localFile;
370 nsresult rv = NS_ERROR_FAILURE;
372 *aResult = nullptr;
373 *aPersistent = true;
375 RefPtr<nsAtom> inAtom = NS_Atomize(aProp);
377 // check to see if it is one of our defaults
379 if (inAtom == nsGkAtoms::DirectoryService_CurrentProcess ||
380 inAtom == nsGkAtoms::DirectoryService_OS_CurrentProcessDirectory) {
381 rv = GetCurrentProcessDirectory(getter_AddRefs(localFile));
384 // Unless otherwise set, the core pieces of the GRE exist
385 // in the current process directory.
386 else if (inAtom == nsGkAtoms::DirectoryService_GRE_Directory ||
387 inAtom == nsGkAtoms::DirectoryService_GRE_BinDirectory) {
388 rv = GetCurrentProcessDirectory(getter_AddRefs(localFile));
389 } else if (inAtom == nsGkAtoms::DirectoryService_OS_TemporaryDirectory) {
390 rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(localFile));
391 } else if (inAtom == nsGkAtoms::DirectoryService_OS_CurrentProcessDirectory) {
392 rv = GetSpecialSystemDirectory(OS_CurrentProcessDirectory, getter_AddRefs(localFile));
393 } else if (inAtom == nsGkAtoms::DirectoryService_OS_CurrentWorkingDirectory) {
394 rv = GetSpecialSystemDirectory(OS_CurrentWorkingDirectory, getter_AddRefs(localFile));
397 #if defined(MOZ_WIDGET_COCOA)
398 else if (inAtom == nsGkAtoms::DirectoryService_SystemDirectory) {
399 rv = GetOSXFolderType(kClassicDomain, kSystemFolderType, getter_AddRefs(localFile));
400 } else if (inAtom == nsGkAtoms::DirectoryService_UserLibDirectory) {
401 rv = GetOSXFolderType(kUserDomain, kDomainLibraryFolderType, getter_AddRefs(localFile));
402 } else if (inAtom == nsGkAtoms::Home) {
403 rv = GetOSXFolderType(kUserDomain, kDomainTopLevelFolderType, getter_AddRefs(localFile));
404 } else if (inAtom == nsGkAtoms::DirectoryService_DefaultDownloadDirectory) {
405 rv = GetOSXFolderType(kUserDomain, kDownloadsFolderType,
406 getter_AddRefs(localFile));
407 if (NS_FAILED(rv)) {
408 rv = GetOSXFolderType(kUserDomain, kDesktopFolderType,
409 getter_AddRefs(localFile));
411 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DesktopDirectory) {
412 rv = GetOSXFolderType(kUserDomain, kDesktopFolderType, getter_AddRefs(localFile));
413 } else if (inAtom == nsGkAtoms::DirectoryService_LocalApplicationsDirectory) {
414 rv = GetOSXFolderType(kLocalDomain, kApplicationsFolderType, getter_AddRefs(localFile));
415 } else if (inAtom == nsGkAtoms::DirectoryService_UserPreferencesDirectory) {
416 rv = GetOSXFolderType(kUserDomain, kPreferencesFolderType, getter_AddRefs(localFile));
417 } else if (inAtom == nsGkAtoms::DirectoryService_PictureDocumentsDirectory) {
418 rv = GetOSXFolderType(kUserDomain, kPictureDocumentsFolderType, getter_AddRefs(localFile));
420 #elif defined (XP_WIN)
421 else if (inAtom == nsGkAtoms::DirectoryService_SystemDirectory) {
422 rv = GetSpecialSystemDirectory(Win_SystemDirectory, getter_AddRefs(localFile));
423 } else if (inAtom == nsGkAtoms::DirectoryService_WindowsDirectory) {
424 rv = GetSpecialSystemDirectory(Win_WindowsDirectory, getter_AddRefs(localFile));
425 } else if (inAtom == nsGkAtoms::DirectoryService_WindowsProgramFiles) {
426 rv = GetSpecialSystemDirectory(Win_ProgramFiles, getter_AddRefs(localFile));
427 } else if (inAtom == nsGkAtoms::Home) {
428 rv = GetSpecialSystemDirectory(Win_HomeDirectory, getter_AddRefs(localFile));
429 } else if (inAtom == nsGkAtoms::DirectoryService_Programs) {
430 rv = GetSpecialSystemDirectory(Win_Programs, getter_AddRefs(localFile));
431 } else if (inAtom == nsGkAtoms::DirectoryService_Favorites) {
432 rv = GetSpecialSystemDirectory(Win_Favorites, getter_AddRefs(localFile));
433 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DesktopDirectory) {
434 rv = GetSpecialSystemDirectory(Win_Desktopdirectory, getter_AddRefs(localFile));
435 } else if (inAtom == nsGkAtoms::DirectoryService_Appdata) {
436 rv = GetSpecialSystemDirectory(Win_Appdata, getter_AddRefs(localFile));
437 } else if (inAtom == nsGkAtoms::DirectoryService_LocalAppdata) {
438 rv = GetSpecialSystemDirectory(Win_LocalAppdata, getter_AddRefs(localFile));
439 #if defined(MOZ_CONTENT_SANDBOX)
440 } else if (inAtom == nsGkAtoms::DirectoryService_LocalAppdataLow) {
441 rv = GetSpecialSystemDirectory(Win_LocalAppdataLow, getter_AddRefs(localFile));
442 } else if (inAtom == nsGkAtoms::DirectoryService_LowIntegrityTempBase) {
443 rv = GetLowIntegrityTempBase(getter_AddRefs(localFile));
444 #endif
445 } else if (inAtom == nsGkAtoms::DirectoryService_WinCookiesDirectory) {
446 rv = GetSpecialSystemDirectory(Win_Cookies, getter_AddRefs(localFile));
447 } else if (inAtom == nsGkAtoms::DirectoryService_DefaultDownloadDirectory) {
448 rv = GetSpecialSystemDirectory(Win_Downloads, getter_AddRefs(localFile));
450 #elif defined (XP_UNIX)
451 else if (inAtom == nsGkAtoms::Home) {
452 rv = GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(localFile));
453 } else if (inAtom == nsGkAtoms::DirectoryService_OS_DesktopDirectory) {
454 rv = GetSpecialSystemDirectory(Unix_XDG_Desktop, getter_AddRefs(localFile));
455 *aPersistent = false;
456 } else if (inAtom == nsGkAtoms::DirectoryService_DefaultDownloadDirectory) {
457 rv = GetSpecialSystemDirectory(Unix_XDG_Download, getter_AddRefs(localFile));
458 *aPersistent = false;
460 #endif
462 if (NS_FAILED(rv)) {
463 return rv;
466 if (!localFile) {
467 return NS_ERROR_FAILURE;
470 localFile.forget(aResult);
471 return NS_OK;
474 NS_IMETHODIMP
475 nsDirectoryService::GetFiles(const char* aProp, nsISimpleEnumerator** aResult)
477 if (NS_WARN_IF(!aResult)) {
478 return NS_ERROR_INVALID_ARG;
480 *aResult = nullptr;
482 return NS_ERROR_FAILURE;