mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
41a9498074
Differential Revision: https://phabricator.services.mozilla.com/D197607
731 lines
19 KiB
C++
731 lines
19 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "SpecialSystemDirectory.h"
|
|
#include "mozilla/Try.h"
|
|
#include "nsString.h"
|
|
#include "nsDependentString.h"
|
|
#include "nsIXULAppInfo.h"
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
# include <windows.h>
|
|
# include <stdlib.h>
|
|
# include <stdio.h>
|
|
# include <string.h>
|
|
# include <direct.h>
|
|
# include <shlobj.h>
|
|
# include <knownfolders.h>
|
|
# include <guiddef.h>
|
|
|
|
#elif defined(XP_UNIX)
|
|
|
|
# include <limits.h>
|
|
# include <unistd.h>
|
|
# include <stdlib.h>
|
|
# include <sys/param.h>
|
|
# include "prenv.h"
|
|
# if defined(MOZ_WIDGET_COCOA)
|
|
# include "CFTypeRefPtr.h"
|
|
# include "CocoaFileUtils.h"
|
|
# endif
|
|
# if defined(MOZ_WIDGET_GTK)
|
|
# include "mozilla/WidgetUtilsGtk.h"
|
|
# endif
|
|
|
|
#endif
|
|
|
|
#ifndef MAXPATHLEN
|
|
# ifdef PATH_MAX
|
|
# define MAXPATHLEN PATH_MAX
|
|
# elif defined(MAX_PATH)
|
|
# define MAXPATHLEN MAX_PATH
|
|
# elif defined(_MAX_PATH)
|
|
# define MAXPATHLEN _MAX_PATH
|
|
# elif defined(CCHMAXPATH)
|
|
# define MAXPATHLEN CCHMAXPATH
|
|
# else
|
|
# define MAXPATHLEN 1024
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
static nsresult GetKnownFolder(GUID* aGuid, nsIFile** aFile) {
|
|
if (!aGuid) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
PWSTR path = nullptr;
|
|
SHGetKnownFolderPath(*aGuid, 0, nullptr, &path);
|
|
|
|
if (!path) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult rv = NS_NewLocalFile(nsDependentString(path), true, aFile);
|
|
|
|
CoTaskMemFree(path);
|
|
return rv;
|
|
}
|
|
|
|
static nsresult GetWindowsFolder(int aFolder, nsIFile** aFile) {
|
|
WCHAR path_orig[MAX_PATH + 3];
|
|
WCHAR* path = path_orig + 1;
|
|
BOOL result = SHGetSpecialFolderPathW(nullptr, path, aFolder, true);
|
|
|
|
if (!result) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// Append the trailing slash
|
|
int len = wcslen(path);
|
|
if (len == 0) {
|
|
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
|
}
|
|
if (len > 1 && path[len - 1] != L'\\') {
|
|
path[len] = L'\\';
|
|
path[++len] = L'\0';
|
|
}
|
|
|
|
return NS_NewLocalFile(nsDependentString(path, len), true, aFile);
|
|
}
|
|
|
|
# if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
|
|
/*
|
|
* Return the default save-to location for the Windows Library passed in
|
|
* through aFolderId.
|
|
*/
|
|
static nsresult GetLibrarySaveToPath(int aFallbackFolderId,
|
|
REFKNOWNFOLDERID aFolderId,
|
|
nsIFile** aFile) {
|
|
RefPtr<IShellLibrary> shellLib;
|
|
RefPtr<IShellItem> savePath;
|
|
SHLoadLibraryFromKnownFolder(aFolderId, STGM_READ, IID_IShellLibrary,
|
|
getter_AddRefs(shellLib));
|
|
|
|
if (shellLib && SUCCEEDED(shellLib->GetDefaultSaveFolder(
|
|
DSFT_DETECT, IID_IShellItem, getter_AddRefs(savePath)))) {
|
|
wchar_t* str = nullptr;
|
|
if (SUCCEEDED(savePath->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
|
|
nsAutoString path;
|
|
path.Assign(str);
|
|
path.Append('\\');
|
|
nsresult rv = NS_NewLocalFile(path, false, aFile);
|
|
CoTaskMemFree(str);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
return GetWindowsFolder(aFallbackFolderId, aFile);
|
|
}
|
|
# endif
|
|
|
|
/**
|
|
* Provides a fallback for getting the path to APPDATA or LOCALAPPDATA by
|
|
* querying the registry when the call to SHGetSpecialFolderPathW is unable to
|
|
* provide these paths (Bug 513958).
|
|
*/
|
|
static nsresult GetRegWindowsAppDataFolder(bool aLocal, nsIFile** aFile) {
|
|
HKEY key;
|
|
LPCWSTR keyName =
|
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
|
|
DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName, 0, KEY_READ, &key);
|
|
if (res != ERROR_SUCCESS) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
WCHAR path[MAX_PATH + 2];
|
|
DWORD type, size;
|
|
res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"), nullptr,
|
|
&type, (LPBYTE)&path, &size);
|
|
::RegCloseKey(key);
|
|
// The call to RegQueryValueExW must succeed, the type must be REG_SZ, the
|
|
// buffer size must not equal 0, and the buffer size be a multiple of 2.
|
|
if (res != ERROR_SUCCESS || type != REG_SZ || size == 0 || size % 2 != 0) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// Append the trailing slash
|
|
int len = wcslen(path);
|
|
if (len > 1 && path[len - 1] != L'\\') {
|
|
path[len] = L'\\';
|
|
path[++len] = L'\0';
|
|
}
|
|
|
|
return NS_NewLocalFile(nsDependentString(path, len), true, aFile);
|
|
}
|
|
|
|
#endif // XP_WIN
|
|
|
|
#if defined(XP_UNIX)
|
|
static nsresult GetUnixHomeDir(nsIFile** aFile) {
|
|
# if defined(ANDROID)
|
|
// XXX no home dir on android; maybe we should return the sdcard if present?
|
|
return NS_ERROR_FAILURE;
|
|
# else
|
|
return NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), true,
|
|
aFile);
|
|
# endif
|
|
}
|
|
|
|
static nsresult GetUnixSystemConfigDir(nsIFile** aFile) {
|
|
# if defined(ANDROID)
|
|
return NS_ERROR_FAILURE;
|
|
# else
|
|
nsAutoCString appName;
|
|
if (nsCOMPtr<nsIXULAppInfo> appInfo =
|
|
do_GetService("@mozilla.org/xre/app-info;1")) {
|
|
MOZ_TRY(appInfo->GetName(appName));
|
|
} else {
|
|
appName.AssignLiteral(MOZ_APP_BASENAME);
|
|
}
|
|
|
|
ToLowerCase(appName);
|
|
|
|
nsDependentCString sysConfigDir;
|
|
if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
|
|
const char* mozSystemConfigDir = PR_GetEnv("MOZ_SYSTEM_CONFIG_DIR");
|
|
if (mozSystemConfigDir) {
|
|
sysConfigDir.Assign(nsDependentCString(mozSystemConfigDir));
|
|
}
|
|
}
|
|
# if defined(MOZ_WIDGET_GTK)
|
|
if (sysConfigDir.IsEmpty() && mozilla::widget::IsRunningUnderFlatpak()) {
|
|
sysConfigDir.Assign(nsLiteralCString("/app/etc"));
|
|
}
|
|
# endif
|
|
if (sysConfigDir.IsEmpty()) {
|
|
sysConfigDir.Assign(nsLiteralCString("/etc"));
|
|
}
|
|
MOZ_TRY(NS_NewNativeLocalFile(sysConfigDir, true, aFile));
|
|
MOZ_TRY((*aFile)->AppendNative(appName));
|
|
return NS_OK;
|
|
# endif
|
|
}
|
|
|
|
/*
|
|
The following license applies to the xdg_user_dir_lookup function:
|
|
|
|
Copyright (c) 2007 Red Hat, Inc.
|
|
|
|
Permission is hereby granted, free of charge, to any person
|
|
obtaining a copy of this software and associated documentation files
|
|
(the "Software"), to deal in the Software without restriction,
|
|
including without limitation the rights to use, copy, modify, merge,
|
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
|
and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
static char* xdg_user_dir_lookup(const char* aType) {
|
|
FILE* file;
|
|
char* home_dir;
|
|
char* config_home;
|
|
char* config_file;
|
|
char buffer[512];
|
|
char* user_dir;
|
|
char* p;
|
|
char* d;
|
|
int len;
|
|
int relative;
|
|
|
|
home_dir = getenv("HOME");
|
|
|
|
if (!home_dir) {
|
|
goto error;
|
|
}
|
|
|
|
config_home = getenv("XDG_CONFIG_HOME");
|
|
if (!config_home || config_home[0] == 0) {
|
|
config_file =
|
|
(char*)malloc(strlen(home_dir) + strlen("/.config/user-dirs.dirs") + 1);
|
|
if (!config_file) {
|
|
goto error;
|
|
}
|
|
|
|
strcpy(config_file, home_dir);
|
|
strcat(config_file, "/.config/user-dirs.dirs");
|
|
} else {
|
|
config_file =
|
|
(char*)malloc(strlen(config_home) + strlen("/user-dirs.dirs") + 1);
|
|
if (!config_file) {
|
|
goto error;
|
|
}
|
|
|
|
strcpy(config_file, config_home);
|
|
strcat(config_file, "/user-dirs.dirs");
|
|
}
|
|
|
|
file = fopen(config_file, "r");
|
|
free(config_file);
|
|
if (!file) {
|
|
goto error;
|
|
}
|
|
|
|
user_dir = nullptr;
|
|
while (fgets(buffer, sizeof(buffer), file)) {
|
|
/* Remove newline at end */
|
|
len = strlen(buffer);
|
|
if (len > 0 && buffer[len - 1] == '\n') {
|
|
buffer[len - 1] = 0;
|
|
}
|
|
|
|
p = buffer;
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
if (strncmp(p, "XDG_", 4) != 0) {
|
|
continue;
|
|
}
|
|
p += 4;
|
|
if (strncmp(p, aType, strlen(aType)) != 0) {
|
|
continue;
|
|
}
|
|
p += strlen(aType);
|
|
if (strncmp(p, "_DIR", 4) != 0) {
|
|
continue;
|
|
}
|
|
p += 4;
|
|
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
if (*p != '=') {
|
|
continue;
|
|
}
|
|
p++;
|
|
|
|
while (*p == ' ' || *p == '\t') {
|
|
p++;
|
|
}
|
|
|
|
if (*p != '"') {
|
|
continue;
|
|
}
|
|
p++;
|
|
|
|
relative = 0;
|
|
if (strncmp(p, "$HOME/", 6) == 0) {
|
|
p += 6;
|
|
relative = 1;
|
|
} else if (*p != '/') {
|
|
continue;
|
|
}
|
|
|
|
if (relative) {
|
|
user_dir = (char*)malloc(strlen(home_dir) + 1 + strlen(p) + 1);
|
|
if (!user_dir) {
|
|
goto error2;
|
|
}
|
|
|
|
strcpy(user_dir, home_dir);
|
|
strcat(user_dir, "/");
|
|
} else {
|
|
user_dir = (char*)malloc(strlen(p) + 1);
|
|
if (!user_dir) {
|
|
goto error2;
|
|
}
|
|
|
|
*user_dir = 0;
|
|
}
|
|
|
|
d = user_dir + strlen(user_dir);
|
|
while (*p && *p != '"') {
|
|
if ((*p == '\\') && (*(p + 1) != 0)) {
|
|
p++;
|
|
}
|
|
*d++ = *p++;
|
|
}
|
|
*d = 0;
|
|
}
|
|
error2:
|
|
fclose(file);
|
|
|
|
if (user_dir) {
|
|
return user_dir;
|
|
}
|
|
|
|
error:
|
|
return nullptr;
|
|
}
|
|
|
|
static const char xdg_user_dirs[] =
|
|
"DESKTOP\0"
|
|
"DOCUMENTS\0"
|
|
"DOWNLOAD\0"
|
|
"MUSIC\0"
|
|
"PICTURES\0"
|
|
"PUBLICSHARE\0"
|
|
"TEMPLATES\0"
|
|
"VIDEOS";
|
|
|
|
static const uint8_t xdg_user_dir_offsets[] = {0, 8, 18, 27, 33, 42, 54, 64};
|
|
|
|
static nsresult GetUnixXDGUserDirectory(SystemDirectories aSystemDirectory,
|
|
nsIFile** aFile) {
|
|
char* dir = xdg_user_dir_lookup(
|
|
xdg_user_dirs +
|
|
xdg_user_dir_offsets[aSystemDirectory - Unix_XDG_Desktop]);
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIFile> file;
|
|
bool exists;
|
|
if (dir) {
|
|
rv = NS_NewNativeLocalFile(nsDependentCString(dir), true,
|
|
getter_AddRefs(file));
|
|
free(dir);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
rv = file->Exists(&exists);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
if (!exists) {
|
|
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0755);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
} else if (Unix_XDG_Desktop == aSystemDirectory) {
|
|
// for the XDG desktop dir, fall back to HOME/Desktop
|
|
// (for historical compatibility)
|
|
nsCOMPtr<nsIFile> home;
|
|
rv = GetUnixHomeDir(getter_AddRefs(home));
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
rv = home->Clone(getter_AddRefs(file));
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
rv = file->AppendNative("Desktop"_ns);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
rv = file->Exists(&exists);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
// fallback to HOME only if HOME/Desktop doesn't exist
|
|
if (!exists) {
|
|
file = home;
|
|
}
|
|
} else {
|
|
// no fallback for the other XDG dirs
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
*aFile = nullptr;
|
|
file.swap(*aFile);
|
|
|
|
return NS_OK;
|
|
}
|
|
#endif
|
|
|
|
nsresult GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory,
|
|
nsIFile** aFile) {
|
|
#if defined(XP_WIN)
|
|
WCHAR path[MAX_PATH];
|
|
#else
|
|
char path[MAXPATHLEN];
|
|
#endif
|
|
|
|
switch (aSystemSystemDirectory) {
|
|
case OS_CurrentWorkingDirectory:
|
|
#if defined(XP_WIN)
|
|
if (!_wgetcwd(path, MAX_PATH)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
return NS_NewLocalFile(nsDependentString(path), true, aFile);
|
|
#else
|
|
if (!getcwd(path, MAXPATHLEN)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(XP_WIN)
|
|
return NS_NewNativeLocalFile(nsDependentCString(path), true, aFile);
|
|
#endif
|
|
|
|
case OS_TemporaryDirectory:
|
|
#if defined(XP_WIN)
|
|
{
|
|
DWORD len = ::GetTempPathW(MAX_PATH, path);
|
|
if (len == 0) {
|
|
break;
|
|
}
|
|
return NS_NewLocalFile(nsDependentString(path, len), true, aFile);
|
|
}
|
|
#elif defined(MOZ_WIDGET_COCOA)
|
|
{
|
|
return GetOSXFolderType(kUserDomain, kTemporaryFolderType, aFile);
|
|
}
|
|
|
|
#elif defined(XP_UNIX)
|
|
{
|
|
static const char* tPath = nullptr;
|
|
if (!tPath) {
|
|
tPath = PR_GetEnv("TMPDIR");
|
|
if (!tPath || !*tPath) {
|
|
tPath = PR_GetEnv("TMP");
|
|
if (!tPath || !*tPath) {
|
|
tPath = PR_GetEnv("TEMP");
|
|
if (!tPath || !*tPath) {
|
|
tPath = "/tmp/";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NS_NewNativeLocalFile(nsDependentCString(tPath), true, aFile);
|
|
}
|
|
#else
|
|
break;
|
|
#endif
|
|
#if defined(MOZ_WIDGET_COCOA)
|
|
case Mac_SystemDirectory: {
|
|
return GetOSXFolderType(kClassicDomain, kSystemFolderType, aFile);
|
|
}
|
|
case Mac_UserLibDirectory: {
|
|
return GetOSXFolderType(kUserDomain, kDomainLibraryFolderType, aFile);
|
|
}
|
|
case Mac_HomeDirectory: {
|
|
return GetOSXFolderType(kUserDomain, kDomainTopLevelFolderType, aFile);
|
|
}
|
|
case Mac_DefaultDownloadDirectory: {
|
|
nsresult rv = GetOSXFolderType(kUserDomain, kDownloadsFolderType, aFile);
|
|
if (NS_FAILED(rv)) {
|
|
return GetOSXFolderType(kUserDomain, kDesktopFolderType, aFile);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
case Mac_UserDesktopDirectory: {
|
|
return GetOSXFolderType(kUserDomain, kDesktopFolderType, aFile);
|
|
}
|
|
case Mac_LocalApplicationsDirectory: {
|
|
return GetOSXFolderType(kLocalDomain, kApplicationsFolderType, aFile);
|
|
}
|
|
case Mac_UserPreferencesDirectory: {
|
|
return GetOSXFolderType(kUserDomain, kPreferencesFolderType, aFile);
|
|
}
|
|
case Mac_PictureDocumentsDirectory: {
|
|
return GetOSXFolderType(kUserDomain, kPictureDocumentsFolderType, aFile);
|
|
}
|
|
case Mac_DefaultScreenshotDirectory: {
|
|
auto prefValue = CFTypeRefPtr<CFPropertyListRef>::WrapUnderCreateRule(
|
|
CFPreferencesCopyAppValue(CFSTR("location"),
|
|
CFSTR("com.apple.screencapture")));
|
|
|
|
if (!prefValue || CFGetTypeID(prefValue.get()) != CFStringGetTypeID()) {
|
|
return GetOSXFolderType(kUserDomain, kPictureDocumentsFolderType,
|
|
aFile);
|
|
}
|
|
|
|
nsAutoString path;
|
|
mozilla::Span<char16_t> data =
|
|
path.GetMutableData(CFStringGetLength((CFStringRef)prefValue.get()));
|
|
CFStringGetCharacters((CFStringRef)prefValue.get(),
|
|
CFRangeMake(0, data.Length()),
|
|
reinterpret_cast<UniChar*>(data.Elements()));
|
|
|
|
return NS_NewLocalFile(path, true, aFile);
|
|
}
|
|
#elif defined(XP_WIN)
|
|
case Win_SystemDirectory: {
|
|
int32_t len = ::GetSystemDirectoryW(path, MAX_PATH);
|
|
|
|
// Need enough space to add the trailing backslash
|
|
if (!len || len > MAX_PATH - 2) {
|
|
break;
|
|
}
|
|
path[len] = L'\\';
|
|
path[++len] = L'\0';
|
|
|
|
return NS_NewLocalFile(nsDependentString(path, len), true, aFile);
|
|
}
|
|
|
|
case Win_WindowsDirectory: {
|
|
int32_t len = ::GetWindowsDirectoryW(path, MAX_PATH);
|
|
|
|
// Need enough space to add the trailing backslash
|
|
if (!len || len > MAX_PATH - 2) {
|
|
break;
|
|
}
|
|
|
|
path[len] = L'\\';
|
|
path[++len] = L'\0';
|
|
|
|
return NS_NewLocalFile(nsDependentString(path, len), true, aFile);
|
|
}
|
|
|
|
case Win_ProgramFiles: {
|
|
return GetWindowsFolder(CSIDL_PROGRAM_FILES, aFile);
|
|
}
|
|
|
|
case Win_HomeDirectory: {
|
|
nsresult rv = GetWindowsFolder(CSIDL_PROFILE, aFile);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
int32_t len;
|
|
if ((len = ::GetEnvironmentVariableW(L"HOME", path, MAX_PATH)) > 0) {
|
|
// Need enough space to add the trailing backslash
|
|
if (len > MAX_PATH - 2) {
|
|
break;
|
|
}
|
|
|
|
path[len] = L'\\';
|
|
path[++len] = L'\0';
|
|
|
|
rv = NS_NewLocalFile(nsDependentString(path, len), true, aFile);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
len = ::GetEnvironmentVariableW(L"HOMEDRIVE", path, MAX_PATH);
|
|
if (0 < len && len < MAX_PATH) {
|
|
WCHAR temp[MAX_PATH];
|
|
DWORD len2 = ::GetEnvironmentVariableW(L"HOMEPATH", temp, MAX_PATH);
|
|
if (0 < len2 && len + len2 < MAX_PATH) {
|
|
wcsncat(path, temp, len2);
|
|
}
|
|
|
|
len = wcslen(path);
|
|
|
|
// Need enough space to add the trailing backslash
|
|
if (len > MAX_PATH - 2) {
|
|
break;
|
|
}
|
|
|
|
path[len] = L'\\';
|
|
path[++len] = L'\0';
|
|
|
|
return NS_NewLocalFile(nsDependentString(path, len), true, aFile);
|
|
}
|
|
break;
|
|
}
|
|
case Win_Programs: {
|
|
return GetWindowsFolder(CSIDL_PROGRAMS, aFile);
|
|
}
|
|
|
|
case Win_Downloads: {
|
|
// Defined in KnownFolders.h.
|
|
GUID folderid_downloads = {
|
|
0x374de290,
|
|
0x123f,
|
|
0x4565,
|
|
{0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}};
|
|
nsresult rv = GetKnownFolder(&folderid_downloads, aFile);
|
|
// On WinXP, there is no downloads folder, default
|
|
// to 'Desktop'.
|
|
if (NS_ERROR_FAILURE == rv) {
|
|
rv = GetWindowsFolder(CSIDL_DESKTOP, aFile);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
case Win_Favorites: {
|
|
return GetWindowsFolder(CSIDL_FAVORITES, aFile);
|
|
}
|
|
case Win_Desktopdirectory: {
|
|
return GetWindowsFolder(CSIDL_DESKTOPDIRECTORY, aFile);
|
|
}
|
|
case Win_Cookies: {
|
|
return GetWindowsFolder(CSIDL_COOKIES, aFile);
|
|
}
|
|
case Win_Appdata: {
|
|
nsresult rv = GetWindowsFolder(CSIDL_APPDATA, aFile);
|
|
if (NS_FAILED(rv)) {
|
|
rv = GetRegWindowsAppDataFolder(false, aFile);
|
|
}
|
|
return rv;
|
|
}
|
|
case Win_LocalAppdata: {
|
|
nsresult rv = GetWindowsFolder(CSIDL_LOCAL_APPDATA, aFile);
|
|
if (NS_FAILED(rv)) {
|
|
rv = GetRegWindowsAppDataFolder(true, aFile);
|
|
}
|
|
return rv;
|
|
}
|
|
# if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
|
|
case Win_Documents: {
|
|
return GetLibrarySaveToPath(CSIDL_MYDOCUMENTS, FOLDERID_DocumentsLibrary,
|
|
aFile);
|
|
}
|
|
# endif
|
|
#endif // XP_WIN
|
|
|
|
#if defined(XP_UNIX)
|
|
case Unix_HomeDirectory:
|
|
return GetUnixHomeDir(aFile);
|
|
|
|
case Unix_XDG_Desktop:
|
|
case Unix_XDG_Download:
|
|
return GetUnixXDGUserDirectory(aSystemSystemDirectory, aFile);
|
|
|
|
case Unix_SystemConfigDirectory:
|
|
return GetUnixSystemConfigDir(aFile);
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
#if defined(MOZ_WIDGET_COCOA)
|
|
nsresult GetOSXFolderType(short aDomain, OSType aFolderType,
|
|
nsIFile** aLocalFile) {
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
if (aFolderType == kTemporaryFolderType) {
|
|
NS_NewLocalFile(u""_ns, true, aLocalFile);
|
|
nsCOMPtr<nsILocalFileMac> localMacFile(do_QueryInterface(*aLocalFile));
|
|
if (localMacFile) {
|
|
rv = localMacFile->InitWithCFURL(
|
|
CocoaFileUtils::GetTemporaryFolder().get());
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
OSErr err;
|
|
FSRef fsRef;
|
|
err = ::FSFindFolder(aDomain, aFolderType, kCreateFolder, &fsRef);
|
|
if (err == noErr) {
|
|
NS_NewLocalFile(u""_ns, true, aLocalFile);
|
|
nsCOMPtr<nsILocalFileMac> localMacFile(do_QueryInterface(*aLocalFile));
|
|
if (localMacFile) {
|
|
rv = localMacFile->InitWithFSRef(&fsRef);
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
#endif
|