Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/io/nsDirectoryService.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#include "mozilla/ArrayUtils.h"
8
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"
16
17
#include "mozilla/SimpleEnumerator.h"
18
#include "nsICategoryManager.h"
19
#include "nsISimpleEnumerator.h"
20
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
36
37
#include "SpecialSystemDirectory.h"
38
#include "nsAppFileLocationProvider.h"
39
#include "BinaryPath.h"
40
41
using namespace mozilla;
42
43
//----------------------------------------------------------------------------------------
44
nsresult
45
nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile)
46
//----------------------------------------------------------------------------------------
47
12
{
48
12
  if (NS_WARN_IF(!aFile)) {
49
0
    return NS_ERROR_INVALID_ARG;
50
0
  }
51
12
  *aFile = nullptr;
52
12
53
12
  //  Set the component registry location:
54
12
  if (!gService) {
55
0
    return NS_ERROR_FAILURE;
56
0
  }
57
12
58
12
  nsCOMPtr<nsIFile> file;
59
12
  gService->Get(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
60
12
                getter_AddRefs(file));
61
12
  if (file) {
62
0
    file.forget(aFile);
63
0
    return NS_OK;
64
0
  }
65
12
66
12
  if (NS_SUCCEEDED(BinaryPath::GetFile(getter_AddRefs(file)))) {
67
12
    return file->GetParent(aFile);
68
12
  }
69
0
  NS_ERROR("unable to get current process directory");
70
0
  return NS_ERROR_FAILURE;
71
0
} // GetCurrentProcessDirectory()
72
73
StaticRefPtr<nsDirectoryService> nsDirectoryService::gService;
74
75
nsDirectoryService::nsDirectoryService()
76
  : mHashtable(128)
77
3
{
78
3
}
79
80
nsresult
81
nsDirectoryService::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
82
9
{
83
9
  if (NS_WARN_IF(!aResult)) {
84
0
    return NS_ERROR_INVALID_ARG;
85
0
  }
86
9
  if (NS_WARN_IF(aOuter)) {
87
0
    return NS_ERROR_NO_AGGREGATION;
88
0
  }
89
9
90
9
  if (!gService) {
91
0
    return NS_ERROR_NOT_INITIALIZED;
92
0
  }
93
9
94
9
  return gService->QueryInterface(aIID, aResult);
95
9
}
96
97
NS_IMETHODIMP
98
nsDirectoryService::Init()
99
0
{
100
0
  MOZ_ASSERT_UNREACHABLE("nsDirectoryService::Init() for internal use only!");
101
0
  return NS_OK;
102
0
}
103
104
void
105
nsDirectoryService::RealInit()
106
3
{
107
3
  NS_ASSERTION(!gService,
108
3
               "nsDirectoryService::RealInit Mustn't initialize twice!");
109
3
110
3
  gService = new nsDirectoryService();
111
3
112
3
  // Let the list hold the only reference to the provider.
113
3
  nsAppFileLocationProvider* defaultProvider = new nsAppFileLocationProvider;
114
3
  gService->mProviders.AppendElement(defaultProvider);
115
3
}
116
117
nsDirectoryService::~nsDirectoryService()
118
0
{
119
0
}
120
121
NS_IMPL_ISUPPORTS(nsDirectoryService,
122
                  nsIProperties,
123
                  nsIDirectoryService,
124
                  nsIDirectoryServiceProvider,
125
                  nsIDirectoryServiceProvider2)
126
127
128
NS_IMETHODIMP
129
nsDirectoryService::Undefine(const char* aProp)
130
0
{
131
0
  if (NS_WARN_IF(!aProp)) {
132
0
    return NS_ERROR_INVALID_ARG;
133
0
  }
134
0
135
0
  nsDependentCString key(aProp);
136
0
  return mHashtable.Remove(key) ? NS_OK : NS_ERROR_FAILURE;
137
0
}
138
139
NS_IMETHODIMP
140
nsDirectoryService::GetKeys(uint32_t* aCount, char*** aKeys)
141
0
{
142
0
  return NS_ERROR_NOT_IMPLEMENTED;
143
0
}
144
145
struct MOZ_STACK_CLASS FileData
146
{
147
  FileData(const char* aProperty, const nsIID& aUUID)
148
    : property(aProperty)
149
    , data(nullptr)
150
    , persistent(true)
151
    , uuid(aUUID)
152
39
  {
153
39
  }
154
155
  const char*   property;
156
  nsCOMPtr<nsISupports> data;
157
  bool          persistent;
158
  const nsIID&  uuid;
159
};
160
161
static bool
162
FindProviderFile(nsIDirectoryServiceProvider* aElement, FileData* aData)
163
123
{
164
123
  nsresult rv;
165
123
  if (aData->uuid.Equals(NS_GET_IID(nsISimpleEnumerator))) {
166
9
    // Not all providers implement this iface
167
9
    nsCOMPtr<nsIDirectoryServiceProvider2> prov2 = do_QueryInterface(aElement);
168
9
    if (prov2) {
169
9
      nsCOMPtr<nsISimpleEnumerator> newFiles;
170
9
      rv = prov2->GetFiles(aData->property, getter_AddRefs(newFiles));
171
9
      if (NS_SUCCEEDED(rv) && newFiles) {
172
0
        if (aData->data) {
173
0
          nsCOMPtr<nsISimpleEnumerator> unionFiles;
174
0
175
0
          NS_NewUnionEnumerator(getter_AddRefs(unionFiles),
176
0
                                (nsISimpleEnumerator*)aData->data.get(), newFiles);
177
0
178
0
          if (unionFiles) {
179
0
            unionFiles.swap(*(nsISimpleEnumerator**)&aData->data);
180
0
          }
181
0
        } else {
182
0
          aData->data = newFiles;
183
0
        }
184
0
185
0
        aData->persistent = false; // Enumerators can never be persistent
186
0
        return rv == NS_SUCCESS_AGGREGATE_RESULT;
187
0
      }
188
114
    }
189
114
  } else {
190
114
    rv = aElement->GetFile(aData->property, &aData->persistent,
191
114
                           (nsIFile**)&aData->data);
192
114
    if (NS_SUCCEEDED(rv) && aData->data) {
193
18
      return false;
194
18
    }
195
105
  }
196
105
197
105
  return true;
198
105
}
199
200
NS_IMETHODIMP
201
nsDirectoryService::Get(const char* aProp, const nsIID& aUuid, void** aResult)
202
60
{
203
60
  if (NS_WARN_IF(!aProp)) {
204
0
    return NS_ERROR_INVALID_ARG;
205
0
  }
206
60
207
60
  nsDependentCString key(aProp);
208
60
209
60
  nsCOMPtr<nsIFile> cachedFile = mHashtable.Get(key);
210
60
211
60
  if (cachedFile) {
212
21
    nsCOMPtr<nsIFile> cloneFile;
213
21
    cachedFile->Clone(getter_AddRefs(cloneFile));
214
21
    return cloneFile->QueryInterface(aUuid, aResult);
215
21
  }
216
39
217
39
  // it is not one of our defaults, lets check any providers
218
39
  FileData fileData(aProp, aUuid);
219
39
220
123
  for (int32_t i = mProviders.Length() - 1; i >= 0; i--) {
221
90
    if (!FindProviderFile(mProviders[i], &fileData)) {
222
6
      break;
223
6
    }
224
90
  }
225
39
  if (fileData.data) {
226
6
    if (fileData.persistent) {
227
6
      Set(aProp, static_cast<nsIFile*>(fileData.data.get()));
228
6
    }
229
6
    nsresult rv = (fileData.data)->QueryInterface(aUuid, aResult);
230
6
    fileData.data = nullptr; // AddRef occurs in FindProviderFile()
231
6
    return rv;
232
6
  }
233
33
234
33
  FindProviderFile(static_cast<nsIDirectoryServiceProvider*>(this), &fileData);
235
33
  if (fileData.data) {
236
12
    if (fileData.persistent) {
237
12
      Set(aProp, static_cast<nsIFile*>(fileData.data.get()));
238
12
    }
239
12
    nsresult rv = (fileData.data)->QueryInterface(aUuid, aResult);
240
12
    fileData.data = nullptr; // AddRef occurs in FindProviderFile()
241
12
    return rv;
242
12
  }
243
21
244
21
  return NS_ERROR_FAILURE;
245
21
}
246
247
NS_IMETHODIMP
248
nsDirectoryService::Set(const char* aProp, nsISupports* aValue)
249
21
{
250
21
  if (NS_WARN_IF(!aProp)) {
251
0
    return NS_ERROR_INVALID_ARG;
252
0
  }
253
21
  if (!aValue) {
254
0
    return NS_ERROR_FAILURE;
255
0
  }
256
21
257
21
  nsDependentCString key(aProp);
258
21
  if (auto entry = mHashtable.LookupForAdd(key)) {
259
0
    return NS_ERROR_FAILURE;
260
21
  } else {
261
21
    nsCOMPtr<nsIFile> ourFile = do_QueryInterface(aValue);
262
21
    if (ourFile) {
263
21
      nsCOMPtr<nsIFile> cloneFile;
264
21
      ourFile->Clone(getter_AddRefs(cloneFile));
265
21
      entry.OrInsert([&cloneFile] () { return cloneFile.forget(); });
266
21
      return NS_OK;
267
21
    }
268
0
    mHashtable.Remove(key); // another hashtable lookup, but should be rare
269
0
  }
270
21
  return NS_ERROR_FAILURE;
271
21
}
272
273
NS_IMETHODIMP
274
nsDirectoryService::Has(const char* aProp, bool* aResult)
275
0
{
276
0
  if (NS_WARN_IF(!aProp)) {
277
0
    return NS_ERROR_INVALID_ARG;
278
0
  }
279
0
280
0
  *aResult = false;
281
0
  nsCOMPtr<nsIFile> value;
282
0
  nsresult rv = Get(aProp, NS_GET_IID(nsIFile), getter_AddRefs(value));
283
0
  if (NS_FAILED(rv)) {
284
0
    return NS_OK;
285
0
  }
286
0
287
0
  if (value) {
288
0
    *aResult = true;
289
0
  }
290
0
291
0
  return rv;
292
0
}
293
294
NS_IMETHODIMP
295
nsDirectoryService::RegisterProvider(nsIDirectoryServiceProvider* aProv)
296
6
{
297
6
  if (!aProv) {
298
0
    return NS_ERROR_FAILURE;
299
0
  }
300
6
301
6
  mProviders.AppendElement(aProv);
302
6
  return NS_OK;
303
6
}
304
305
void
306
nsDirectoryService::RegisterCategoryProviders()
307
3
{
308
3
  nsCOMPtr<nsICategoryManager> catman
309
3
  (do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
310
3
  if (!catman) {
311
0
    return;
312
0
  }
313
3
314
3
  nsCOMPtr<nsISimpleEnumerator> entries;
315
3
  catman->EnumerateCategory(XPCOM_DIRECTORY_PROVIDER_CATEGORY,
316
3
                            getter_AddRefs(entries));
317
3
318
3
  for (auto& categoryEntry : SimpleEnumerator<nsICategoryEntry>(entries)) {
319
3
    nsAutoCString contractID;
320
3
    categoryEntry->GetValue(contractID);
321
3
322
3
    if (nsCOMPtr<nsIDirectoryServiceProvider> provider = do_GetService(contractID.get())) {
323
3
      RegisterProvider(provider);
324
3
    }
325
3
  }
326
3
}
327
328
NS_IMETHODIMP
329
nsDirectoryService::UnregisterProvider(nsIDirectoryServiceProvider* aProv)
330
0
{
331
0
  if (!aProv) {
332
0
    return NS_ERROR_FAILURE;
333
0
  }
334
0
335
0
  mProviders.RemoveElement(aProv);
336
0
  return NS_OK;
337
0
}
338
339
#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
340
static nsresult
341
GetLowIntegrityTempBase(nsIFile** aLowIntegrityTempBase)
342
{
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;
348
  }
349
350
  rv = localFile->Append(NS_LITERAL_STRING(MOZ_USER_DIR));
351
  if (NS_WARN_IF(NS_FAILED(rv))) {
352
    return rv;
353
  }
354
355
  localFile.forget(aLowIntegrityTempBase);
356
  return rv;
357
}
358
#endif
359
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.
364
365
NS_IMETHODIMP
366
nsDirectoryService::GetFile(const char* aProp, bool* aPersistent,
367
                            nsIFile** aResult)
368
30
{
369
30
  nsCOMPtr<nsIFile> localFile;
370
30
  nsresult rv = NS_ERROR_FAILURE;
371
30
372
30
  *aResult = nullptr;
373
30
  *aPersistent = true;
374
30
375
30
  RefPtr<nsAtom> inAtom = NS_Atomize(aProp);
376
30
377
30
  // check to see if it is one of our defaults
378
30
379
30
  if (inAtom == nsGkAtoms::DirectoryService_CurrentProcess ||
380
30
      inAtom == nsGkAtoms::DirectoryService_OS_CurrentProcessDirectory) {
381
6
    rv = GetCurrentProcessDirectory(getter_AddRefs(localFile));
382
6
  }
383
24
384
24
  // Unless otherwise set, the core pieces of the GRE exist
385
24
  // in the current process directory.
386
24
  else if (inAtom == nsGkAtoms::DirectoryService_GRE_Directory ||
387
24
           inAtom == nsGkAtoms::DirectoryService_GRE_BinDirectory) {
388
6
    rv = GetCurrentProcessDirectory(getter_AddRefs(localFile));
389
18
  } else if (inAtom == nsGkAtoms::DirectoryService_OS_TemporaryDirectory) {
390
0
    rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(localFile));
391
18
  } else if (inAtom == nsGkAtoms::DirectoryService_OS_CurrentProcessDirectory) {
392
0
    rv = GetSpecialSystemDirectory(OS_CurrentProcessDirectory, getter_AddRefs(localFile));
393
18
  } else if (inAtom == nsGkAtoms::DirectoryService_OS_CurrentWorkingDirectory) {
394
0
    rv = GetSpecialSystemDirectory(OS_CurrentWorkingDirectory, getter_AddRefs(localFile));
395
0
  }
396
18
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));
410
    }
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));
419
  }
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));
449
  }
450
#elif defined (XP_UNIX)
451
18
  else if (inAtom == nsGkAtoms::Home) {
452
0
    rv = GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(localFile));
453
18
  } else if (inAtom == nsGkAtoms::DirectoryService_OS_DesktopDirectory) {
454
0
    rv = GetSpecialSystemDirectory(Unix_XDG_Desktop, getter_AddRefs(localFile));
455
0
    *aPersistent = false;
456
18
  } else if (inAtom == nsGkAtoms::DirectoryService_DefaultDownloadDirectory) {
457
0
    rv = GetSpecialSystemDirectory(Unix_XDG_Download, getter_AddRefs(localFile));
458
0
    *aPersistent = false;
459
0
  }
460
30
#endif
461
30
462
30
  if (NS_FAILED(rv)) {
463
18
    return rv;
464
18
  }
465
12
466
12
  if (!localFile) {
467
0
    return NS_ERROR_FAILURE;
468
0
  }
469
12
470
12
  localFile.forget(aResult);
471
12
  return NS_OK;
472
12
}
473
474
NS_IMETHODIMP
475
nsDirectoryService::GetFiles(const char* aProp, nsISimpleEnumerator** aResult)
476
3
{
477
3
  if (NS_WARN_IF(!aResult)) {
478
0
    return NS_ERROR_INVALID_ARG;
479
0
  }
480
3
  *aResult = nullptr;
481
3
482
3
  return NS_ERROR_FAILURE;
483
3
}