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"
10 #include "nsAutoPtr.h"
11 #include "nsDirectoryService.h"
12 #include "nsLocalFile.h"
14 #include "nsGkAtoms.h"
15 #include "nsEnumeratorUtils.h"
17 #include "mozilla/SimpleEnumerator.h"
18 #include "nsICategoryManager.h"
19 #include "nsISimpleEnumerator.h"
26 #elif defined(XP_UNIX)
29 #include <sys/param.h>
31 #ifdef MOZ_WIDGET_COCOA
32 #include <CoreServices/CoreServices.h>
33 #include <Carbon/Carbon.h>
37 #include "SpecialSystemDirectory.h"
38 #include "nsAppFileLocationProvider.h"
39 #include "BinaryPath.h"
41 using namespace mozilla
;
43 //----------------------------------------------------------------------------------------
45 nsDirectoryService::GetCurrentProcessDirectory(nsIFile
** aFile
)
46 //----------------------------------------------------------------------------------------
48 if (NS_WARN_IF(!aFile
)) {
49 return NS_ERROR_INVALID_ARG
;
53 // Set the component registry location:
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
));
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()
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
;
91 return NS_ERROR_NOT_INITIALIZED
;
94 return gService
->QueryInterface(aIID
, aResult
);
98 nsDirectoryService::Init()
100 MOZ_ASSERT_UNREACHABLE("nsDirectoryService::Init() for internal use only!");
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
,
124 nsIDirectoryServiceProvider
,
125 nsIDirectoryServiceProvider2
)
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
;
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
)
155 const char* property
;
156 nsCOMPtr
<nsISupports
> data
;
162 FindProviderFile(nsIDirectoryServiceProvider
* aElement
, FileData
* aData
)
165 if (aData
->uuid
.Equals(NS_GET_IID(nsISimpleEnumerator
))) {
166 // Not all providers implement this iface
167 nsCOMPtr
<nsIDirectoryServiceProvider2
> prov2
= do_QueryInterface(aElement
);
169 nsCOMPtr
<nsISimpleEnumerator
> newFiles
;
170 rv
= prov2
->GetFiles(aData
->property
, getter_AddRefs(newFiles
));
171 if (NS_SUCCEEDED(rv
) && newFiles
) {
173 nsCOMPtr
<nsISimpleEnumerator
> unionFiles
;
175 NS_NewUnionEnumerator(getter_AddRefs(unionFiles
),
176 (nsISimpleEnumerator
*)aData
->data
.get(), newFiles
);
179 unionFiles
.swap(*(nsISimpleEnumerator
**)&aData
->data
);
182 aData
->data
= newFiles
;
185 aData
->persistent
= false; // Enumerators can never be persistent
186 return rv
== NS_SUCCESS_AGGREGATE_RESULT
;
190 rv
= aElement
->GetFile(aData
->property
, &aData
->persistent
,
191 (nsIFile
**)&aData
->data
);
192 if (NS_SUCCEEDED(rv
) && aData
->data
) {
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
);
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
)) {
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()
234 FindProviderFile(static_cast<nsIDirectoryServiceProvider
*>(this), &fileData
);
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()
244 return NS_ERROR_FAILURE
;
248 nsDirectoryService::Set(const char* aProp
, nsISupports
* aValue
)
250 if (NS_WARN_IF(!aProp
)) {
251 return NS_ERROR_INVALID_ARG
;
254 return NS_ERROR_FAILURE
;
257 nsDependentCString
key(aProp
);
258 if (auto entry
= mHashtable
.LookupForAdd(key
)) {
259 return NS_ERROR_FAILURE
;
261 nsCOMPtr
<nsIFile
> ourFile
= do_QueryInterface(aValue
);
263 nsCOMPtr
<nsIFile
> cloneFile
;
264 ourFile
->Clone(getter_AddRefs(cloneFile
));
265 entry
.OrInsert([&cloneFile
] () { return cloneFile
.forget(); });
268 mHashtable
.Remove(key
); // another hashtable lookup, but should be rare
270 return NS_ERROR_FAILURE
;
274 nsDirectoryService::Has(const char* aProp
, bool* aResult
)
276 if (NS_WARN_IF(!aProp
)) {
277 return NS_ERROR_INVALID_ARG
;
281 nsCOMPtr
<nsIFile
> value
;
282 nsresult rv
= Get(aProp
, NS_GET_IID(nsIFile
), getter_AddRefs(value
));
295 nsDirectoryService::RegisterProvider(nsIDirectoryServiceProvider
* aProv
)
298 return NS_ERROR_FAILURE
;
301 mProviders
.AppendElement(aProv
);
306 nsDirectoryService::RegisterCategoryProviders()
308 nsCOMPtr
<nsICategoryManager
> catman
309 (do_GetService(NS_CATEGORYMANAGER_CONTRACTID
));
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
);
329 nsDirectoryService::UnregisterProvider(nsIDirectoryServiceProvider
* aProv
)
332 return NS_ERROR_FAILURE
;
335 mProviders
.RemoveElement(aProv
);
339 #if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
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
))) {
350 rv
= localFile
->Append(NS_LITERAL_STRING(MOZ_USER_DIR
));
351 if (NS_WARN_IF(NS_FAILED(rv
))) {
355 localFile
.forget(aLowIntegrityTempBase
);
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
366 nsDirectoryService::GetFile(const char* aProp
, bool* aPersistent
,
369 nsCOMPtr
<nsIFile
> localFile
;
370 nsresult rv
= NS_ERROR_FAILURE
;
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
));
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
));
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;
467 return NS_ERROR_FAILURE
;
470 localFile
.forget(aResult
);
475 nsDirectoryService::GetFiles(const char* aProp
, nsISimpleEnumerator
** aResult
)
477 if (NS_WARN_IF(!aResult
)) {
478 return NS_ERROR_INVALID_ARG
;
482 return NS_ERROR_FAILURE
;