Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "SpecialSystemDirectory.h" |
michael@0 | 7 | #include "nsString.h" |
michael@0 | 8 | #include "nsDependentString.h" |
michael@0 | 9 | #include "nsAutoPtr.h" |
michael@0 | 10 | |
michael@0 | 11 | #if defined(XP_WIN) |
michael@0 | 12 | |
michael@0 | 13 | #include <windows.h> |
michael@0 | 14 | #include <shlobj.h> |
michael@0 | 15 | #include <stdlib.h> |
michael@0 | 16 | #include <stdio.h> |
michael@0 | 17 | #include <string.h> |
michael@0 | 18 | #include <direct.h> |
michael@0 | 19 | #include <shlobj.h> |
michael@0 | 20 | #include <knownfolders.h> |
michael@0 | 21 | #include <guiddef.h> |
michael@0 | 22 | #include "mozilla/WindowsVersion.h" |
michael@0 | 23 | |
michael@0 | 24 | using mozilla::IsWin7OrLater; |
michael@0 | 25 | |
michael@0 | 26 | #elif defined(XP_UNIX) |
michael@0 | 27 | |
michael@0 | 28 | #include <limits.h> |
michael@0 | 29 | #include <unistd.h> |
michael@0 | 30 | #include <stdlib.h> |
michael@0 | 31 | #include <sys/param.h> |
michael@0 | 32 | #include "prenv.h" |
michael@0 | 33 | |
michael@0 | 34 | #endif |
michael@0 | 35 | |
michael@0 | 36 | #if defined(VMS) |
michael@0 | 37 | #include <unixlib.h> |
michael@0 | 38 | #endif |
michael@0 | 39 | |
michael@0 | 40 | #ifndef MAXPATHLEN |
michael@0 | 41 | #ifdef PATH_MAX |
michael@0 | 42 | #define MAXPATHLEN PATH_MAX |
michael@0 | 43 | #elif defined(MAX_PATH) |
michael@0 | 44 | #define MAXPATHLEN MAX_PATH |
michael@0 | 45 | #elif defined(_MAX_PATH) |
michael@0 | 46 | #define MAXPATHLEN _MAX_PATH |
michael@0 | 47 | #elif defined(CCHMAXPATH) |
michael@0 | 48 | #define MAXPATHLEN CCHMAXPATH |
michael@0 | 49 | #else |
michael@0 | 50 | #define MAXPATHLEN 1024 |
michael@0 | 51 | #endif |
michael@0 | 52 | #endif |
michael@0 | 53 | |
michael@0 | 54 | #ifdef XP_WIN |
michael@0 | 55 | typedef HRESULT (WINAPI* nsGetKnownFolderPath)(GUID& rfid, |
michael@0 | 56 | DWORD dwFlags, |
michael@0 | 57 | HANDLE hToken, |
michael@0 | 58 | PWSTR *ppszPath); |
michael@0 | 59 | |
michael@0 | 60 | static nsGetKnownFolderPath gGetKnownFolderPath = nullptr; |
michael@0 | 61 | #endif |
michael@0 | 62 | |
michael@0 | 63 | void StartupSpecialSystemDirectory() |
michael@0 | 64 | { |
michael@0 | 65 | #if defined (XP_WIN) |
michael@0 | 66 | // SHGetKnownFolderPath is only available on Windows Vista |
michael@0 | 67 | // so that we need to use GetProcAddress to get the pointer. |
michael@0 | 68 | HMODULE hShell32DLLInst = GetModuleHandleW(L"shell32.dll"); |
michael@0 | 69 | if(hShell32DLLInst) |
michael@0 | 70 | { |
michael@0 | 71 | gGetKnownFolderPath = (nsGetKnownFolderPath) |
michael@0 | 72 | GetProcAddress(hShell32DLLInst, "SHGetKnownFolderPath"); |
michael@0 | 73 | } |
michael@0 | 74 | #endif |
michael@0 | 75 | } |
michael@0 | 76 | |
michael@0 | 77 | #if defined (XP_WIN) |
michael@0 | 78 | |
michael@0 | 79 | static nsresult GetKnownFolder(GUID* guid, nsIFile** aFile) |
michael@0 | 80 | { |
michael@0 | 81 | if (!guid || !gGetKnownFolderPath) |
michael@0 | 82 | return NS_ERROR_FAILURE; |
michael@0 | 83 | |
michael@0 | 84 | PWSTR path = nullptr; |
michael@0 | 85 | gGetKnownFolderPath(*guid, 0, nullptr, &path); |
michael@0 | 86 | |
michael@0 | 87 | if (!path) |
michael@0 | 88 | return NS_ERROR_FAILURE; |
michael@0 | 89 | |
michael@0 | 90 | nsresult rv = NS_NewLocalFile(nsDependentString(path), |
michael@0 | 91 | true, |
michael@0 | 92 | aFile); |
michael@0 | 93 | |
michael@0 | 94 | CoTaskMemFree(path); |
michael@0 | 95 | return rv; |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | static nsresult |
michael@0 | 99 | GetWindowsFolder(int folder, nsIFile** aFile) |
michael@0 | 100 | { |
michael@0 | 101 | WCHAR path_orig[MAX_PATH + 3]; |
michael@0 | 102 | WCHAR *path = path_orig+1; |
michael@0 | 103 | HRESULT result = SHGetSpecialFolderPathW(nullptr, path, folder, true); |
michael@0 | 104 | |
michael@0 | 105 | if (!SUCCEEDED(result)) |
michael@0 | 106 | return NS_ERROR_FAILURE; |
michael@0 | 107 | |
michael@0 | 108 | // Append the trailing slash |
michael@0 | 109 | int len = wcslen(path); |
michael@0 | 110 | if (len > 1 && path[len - 1] != L'\\') |
michael@0 | 111 | { |
michael@0 | 112 | path[len] = L'\\'; |
michael@0 | 113 | path[++len] = L'\0'; |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | return NS_NewLocalFile(nsDependentString(path, len), true, aFile); |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | __inline HRESULT |
michael@0 | 120 | SHLoadLibraryFromKnownFolder(REFKNOWNFOLDERID aFolderId, DWORD aMode, |
michael@0 | 121 | REFIID riid, void **ppv) |
michael@0 | 122 | { |
michael@0 | 123 | *ppv = nullptr; |
michael@0 | 124 | IShellLibrary *plib; |
michael@0 | 125 | HRESULT hr = CoCreateInstance(CLSID_ShellLibrary, nullptr, |
michael@0 | 126 | CLSCTX_INPROC_SERVER, |
michael@0 | 127 | IID_PPV_ARGS(&plib)); |
michael@0 | 128 | if (SUCCEEDED(hr)) { |
michael@0 | 129 | hr = plib->LoadLibraryFromKnownFolder(aFolderId, aMode); |
michael@0 | 130 | if (SUCCEEDED(hr)) { |
michael@0 | 131 | hr = plib->QueryInterface(riid, ppv); |
michael@0 | 132 | } |
michael@0 | 133 | plib->Release(); |
michael@0 | 134 | } |
michael@0 | 135 | return hr; |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | /* |
michael@0 | 139 | * Check to see if we're on Win7 and up, and if so, returns the default |
michael@0 | 140 | * save-to location for the Windows Library passed in through aFolderId. |
michael@0 | 141 | * Otherwise falls back on pre-win7 GetWindowsFolder. |
michael@0 | 142 | */ |
michael@0 | 143 | static nsresult |
michael@0 | 144 | GetLibrarySaveToPath(int aFallbackFolderId, REFKNOWNFOLDERID aFolderId, |
michael@0 | 145 | nsIFile** aFile) |
michael@0 | 146 | { |
michael@0 | 147 | // Skip off checking for library support if the os is Vista or lower. |
michael@0 | 148 | if (!IsWin7OrLater()) |
michael@0 | 149 | return GetWindowsFolder(aFallbackFolderId, aFile); |
michael@0 | 150 | |
michael@0 | 151 | nsRefPtr<IShellLibrary> shellLib; |
michael@0 | 152 | nsRefPtr<IShellItem> savePath; |
michael@0 | 153 | HRESULT hr = |
michael@0 | 154 | SHLoadLibraryFromKnownFolder(aFolderId, STGM_READ, |
michael@0 | 155 | IID_IShellLibrary, getter_AddRefs(shellLib)); |
michael@0 | 156 | |
michael@0 | 157 | if (shellLib && |
michael@0 | 158 | SUCCEEDED(shellLib->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, |
michael@0 | 159 | getter_AddRefs(savePath)))) { |
michael@0 | 160 | wchar_t* str = nullptr; |
michael@0 | 161 | if (SUCCEEDED(savePath->GetDisplayName(SIGDN_FILESYSPATH, &str))) { |
michael@0 | 162 | nsAutoString path; |
michael@0 | 163 | path.Assign(str); |
michael@0 | 164 | path.AppendLiteral("\\"); |
michael@0 | 165 | nsresult rv = |
michael@0 | 166 | NS_NewLocalFile(path, false, aFile); |
michael@0 | 167 | CoTaskMemFree(str); |
michael@0 | 168 | return rv; |
michael@0 | 169 | } |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | return GetWindowsFolder(aFallbackFolderId, aFile); |
michael@0 | 173 | } |
michael@0 | 174 | |
michael@0 | 175 | /** |
michael@0 | 176 | * Provides a fallback for getting the path to APPDATA or LOCALAPPDATA by |
michael@0 | 177 | * querying the registry when the call to SHGetSpecialFolderPathW is unable to |
michael@0 | 178 | * provide these paths (Bug 513958). |
michael@0 | 179 | */ |
michael@0 | 180 | static nsresult GetRegWindowsAppDataFolder(bool aLocal, nsIFile** aFile) |
michael@0 | 181 | { |
michael@0 | 182 | HKEY key; |
michael@0 | 183 | NS_NAMED_LITERAL_STRING(keyName, |
michael@0 | 184 | "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); |
michael@0 | 185 | DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName.get(), 0, KEY_READ, |
michael@0 | 186 | &key); |
michael@0 | 187 | if (res != ERROR_SUCCESS) |
michael@0 | 188 | return NS_ERROR_FAILURE; |
michael@0 | 189 | |
michael@0 | 190 | WCHAR path[MAX_PATH + 2]; |
michael@0 | 191 | DWORD type, size; |
michael@0 | 192 | res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"), |
michael@0 | 193 | nullptr, &type, (LPBYTE)&path, &size); |
michael@0 | 194 | ::RegCloseKey(key); |
michael@0 | 195 | // The call to RegQueryValueExW must succeed, the type must be REG_SZ, the |
michael@0 | 196 | // buffer size must not equal 0, and the buffer size be a multiple of 2. |
michael@0 | 197 | if (res != ERROR_SUCCESS || type != REG_SZ || size == 0 || size % 2 != 0) |
michael@0 | 198 | return NS_ERROR_FAILURE; |
michael@0 | 199 | |
michael@0 | 200 | // Append the trailing slash |
michael@0 | 201 | int len = wcslen(path); |
michael@0 | 202 | if (len > 1 && path[len - 1] != L'\\') |
michael@0 | 203 | { |
michael@0 | 204 | path[len] = L'\\'; |
michael@0 | 205 | path[++len] = L'\0'; |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | return NS_NewLocalFile(nsDependentString(path, len), true, aFile); |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | #endif // XP_WIN |
michael@0 | 212 | |
michael@0 | 213 | #if defined(XP_UNIX) |
michael@0 | 214 | static nsresult |
michael@0 | 215 | GetUnixHomeDir(nsIFile** aFile) |
michael@0 | 216 | { |
michael@0 | 217 | #ifdef VMS |
michael@0 | 218 | char *pHome; |
michael@0 | 219 | pHome = getenv("HOME"); |
michael@0 | 220 | if (*pHome == '/') { |
michael@0 | 221 | return NS_NewNativeLocalFile(nsDependentCString(pHome), |
michael@0 | 222 | true, |
michael@0 | 223 | aFile); |
michael@0 | 224 | } else { |
michael@0 | 225 | return NS_NewNativeLocalFile(nsDependentCString(decc$translate_vms(pHome)), |
michael@0 | 226 | true, |
michael@0 | 227 | aFile); |
michael@0 | 228 | } |
michael@0 | 229 | #elif defined(ANDROID) |
michael@0 | 230 | // XXX no home dir on android; maybe we should return the sdcard if present? |
michael@0 | 231 | return NS_ERROR_FAILURE; |
michael@0 | 232 | #else |
michael@0 | 233 | return NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), |
michael@0 | 234 | true, aFile); |
michael@0 | 235 | #endif |
michael@0 | 236 | } |
michael@0 | 237 | |
michael@0 | 238 | /* |
michael@0 | 239 | The following license applies to the xdg_user_dir_lookup function: |
michael@0 | 240 | |
michael@0 | 241 | Copyright (c) 2007 Red Hat, Inc. |
michael@0 | 242 | |
michael@0 | 243 | Permission is hereby granted, free of charge, to any person |
michael@0 | 244 | obtaining a copy of this software and associated documentation files |
michael@0 | 245 | (the "Software"), to deal in the Software without restriction, |
michael@0 | 246 | including without limitation the rights to use, copy, modify, merge, |
michael@0 | 247 | publish, distribute, sublicense, and/or sell copies of the Software, |
michael@0 | 248 | and to permit persons to whom the Software is furnished to do so, |
michael@0 | 249 | subject to the following conditions: |
michael@0 | 250 | |
michael@0 | 251 | The above copyright notice and this permission notice shall be |
michael@0 | 252 | included in all copies or substantial portions of the Software. |
michael@0 | 253 | |
michael@0 | 254 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
michael@0 | 255 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
michael@0 | 256 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
michael@0 | 257 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
michael@0 | 258 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
michael@0 | 259 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
michael@0 | 260 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
michael@0 | 261 | SOFTWARE. |
michael@0 | 262 | */ |
michael@0 | 263 | |
michael@0 | 264 | static char * |
michael@0 | 265 | xdg_user_dir_lookup (const char *type) |
michael@0 | 266 | { |
michael@0 | 267 | FILE *file; |
michael@0 | 268 | char *home_dir, *config_home, *config_file; |
michael@0 | 269 | char buffer[512]; |
michael@0 | 270 | char *user_dir; |
michael@0 | 271 | char *p, *d; |
michael@0 | 272 | int len; |
michael@0 | 273 | int relative; |
michael@0 | 274 | |
michael@0 | 275 | home_dir = getenv ("HOME"); |
michael@0 | 276 | |
michael@0 | 277 | if (home_dir == nullptr) |
michael@0 | 278 | goto error; |
michael@0 | 279 | |
michael@0 | 280 | config_home = getenv ("XDG_CONFIG_HOME"); |
michael@0 | 281 | if (config_home == nullptr || config_home[0] == 0) |
michael@0 | 282 | { |
michael@0 | 283 | config_file = (char*) malloc (strlen (home_dir) + strlen ("/.config/user-dirs.dirs") + 1); |
michael@0 | 284 | if (config_file == nullptr) |
michael@0 | 285 | goto error; |
michael@0 | 286 | |
michael@0 | 287 | strcpy (config_file, home_dir); |
michael@0 | 288 | strcat (config_file, "/.config/user-dirs.dirs"); |
michael@0 | 289 | } |
michael@0 | 290 | else |
michael@0 | 291 | { |
michael@0 | 292 | config_file = (char*) malloc (strlen (config_home) + strlen ("/user-dirs.dirs") + 1); |
michael@0 | 293 | if (config_file == nullptr) |
michael@0 | 294 | goto error; |
michael@0 | 295 | |
michael@0 | 296 | strcpy (config_file, config_home); |
michael@0 | 297 | strcat (config_file, "/user-dirs.dirs"); |
michael@0 | 298 | } |
michael@0 | 299 | |
michael@0 | 300 | file = fopen (config_file, "r"); |
michael@0 | 301 | free (config_file); |
michael@0 | 302 | if (file == nullptr) |
michael@0 | 303 | goto error; |
michael@0 | 304 | |
michael@0 | 305 | user_dir = nullptr; |
michael@0 | 306 | while (fgets (buffer, sizeof (buffer), file)) |
michael@0 | 307 | { |
michael@0 | 308 | /* Remove newline at end */ |
michael@0 | 309 | len = strlen (buffer); |
michael@0 | 310 | if (len > 0 && buffer[len-1] == '\n') |
michael@0 | 311 | buffer[len-1] = 0; |
michael@0 | 312 | |
michael@0 | 313 | p = buffer; |
michael@0 | 314 | while (*p == ' ' || *p == '\t') |
michael@0 | 315 | p++; |
michael@0 | 316 | |
michael@0 | 317 | if (strncmp (p, "XDG_", 4) != 0) |
michael@0 | 318 | continue; |
michael@0 | 319 | p += 4; |
michael@0 | 320 | if (strncmp (p, type, strlen (type)) != 0) |
michael@0 | 321 | continue; |
michael@0 | 322 | p += strlen (type); |
michael@0 | 323 | if (strncmp (p, "_DIR", 4) != 0) |
michael@0 | 324 | continue; |
michael@0 | 325 | p += 4; |
michael@0 | 326 | |
michael@0 | 327 | while (*p == ' ' || *p == '\t') |
michael@0 | 328 | p++; |
michael@0 | 329 | |
michael@0 | 330 | if (*p != '=') |
michael@0 | 331 | continue; |
michael@0 | 332 | p++; |
michael@0 | 333 | |
michael@0 | 334 | while (*p == ' ' || *p == '\t') |
michael@0 | 335 | p++; |
michael@0 | 336 | |
michael@0 | 337 | if (*p != '"') |
michael@0 | 338 | continue; |
michael@0 | 339 | p++; |
michael@0 | 340 | |
michael@0 | 341 | relative = 0; |
michael@0 | 342 | if (strncmp (p, "$HOME/", 6) == 0) |
michael@0 | 343 | { |
michael@0 | 344 | p += 6; |
michael@0 | 345 | relative = 1; |
michael@0 | 346 | } |
michael@0 | 347 | else if (*p != '/') |
michael@0 | 348 | continue; |
michael@0 | 349 | |
michael@0 | 350 | if (relative) |
michael@0 | 351 | { |
michael@0 | 352 | user_dir = (char*) malloc (strlen (home_dir) + 1 + strlen (p) + 1); |
michael@0 | 353 | if (user_dir == nullptr) |
michael@0 | 354 | goto error2; |
michael@0 | 355 | |
michael@0 | 356 | strcpy (user_dir, home_dir); |
michael@0 | 357 | strcat (user_dir, "/"); |
michael@0 | 358 | } |
michael@0 | 359 | else |
michael@0 | 360 | { |
michael@0 | 361 | user_dir = (char*) malloc (strlen (p) + 1); |
michael@0 | 362 | if (user_dir == nullptr) |
michael@0 | 363 | goto error2; |
michael@0 | 364 | |
michael@0 | 365 | *user_dir = 0; |
michael@0 | 366 | } |
michael@0 | 367 | |
michael@0 | 368 | d = user_dir + strlen (user_dir); |
michael@0 | 369 | while (*p && *p != '"') |
michael@0 | 370 | { |
michael@0 | 371 | if ((*p == '\\') && (*(p+1) != 0)) |
michael@0 | 372 | p++; |
michael@0 | 373 | *d++ = *p++; |
michael@0 | 374 | } |
michael@0 | 375 | *d = 0; |
michael@0 | 376 | } |
michael@0 | 377 | error2: |
michael@0 | 378 | fclose (file); |
michael@0 | 379 | |
michael@0 | 380 | if (user_dir) |
michael@0 | 381 | return user_dir; |
michael@0 | 382 | |
michael@0 | 383 | error: |
michael@0 | 384 | return nullptr; |
michael@0 | 385 | } |
michael@0 | 386 | |
michael@0 | 387 | static const char xdg_user_dirs[] = |
michael@0 | 388 | "DESKTOP\0" |
michael@0 | 389 | "DOCUMENTS\0" |
michael@0 | 390 | "DOWNLOAD\0" |
michael@0 | 391 | "MUSIC\0" |
michael@0 | 392 | "PICTURES\0" |
michael@0 | 393 | "PUBLICSHARE\0" |
michael@0 | 394 | "TEMPLATES\0" |
michael@0 | 395 | "VIDEOS"; |
michael@0 | 396 | |
michael@0 | 397 | static const uint8_t xdg_user_dir_offsets[] = { |
michael@0 | 398 | 0, |
michael@0 | 399 | 8, |
michael@0 | 400 | 18, |
michael@0 | 401 | 27, |
michael@0 | 402 | 33, |
michael@0 | 403 | 42, |
michael@0 | 404 | 54, |
michael@0 | 405 | 64 |
michael@0 | 406 | }; |
michael@0 | 407 | |
michael@0 | 408 | static nsresult |
michael@0 | 409 | GetUnixXDGUserDirectory(SystemDirectories aSystemDirectory, |
michael@0 | 410 | nsIFile** aFile) |
michael@0 | 411 | { |
michael@0 | 412 | char *dir = xdg_user_dir_lookup |
michael@0 | 413 | (xdg_user_dirs + xdg_user_dir_offsets[aSystemDirectory - |
michael@0 | 414 | Unix_XDG_Desktop]); |
michael@0 | 415 | |
michael@0 | 416 | nsresult rv; |
michael@0 | 417 | nsCOMPtr<nsIFile> file; |
michael@0 | 418 | if (dir) { |
michael@0 | 419 | rv = NS_NewNativeLocalFile(nsDependentCString(dir), true, |
michael@0 | 420 | getter_AddRefs(file)); |
michael@0 | 421 | free(dir); |
michael@0 | 422 | } else if (Unix_XDG_Desktop == aSystemDirectory) { |
michael@0 | 423 | // for the XDG desktop dir, fall back to HOME/Desktop |
michael@0 | 424 | // (for historical compatibility) |
michael@0 | 425 | rv = GetUnixHomeDir(getter_AddRefs(file)); |
michael@0 | 426 | if (NS_FAILED(rv)) |
michael@0 | 427 | return rv; |
michael@0 | 428 | |
michael@0 | 429 | rv = file->AppendNative(NS_LITERAL_CSTRING("Desktop")); |
michael@0 | 430 | } |
michael@0 | 431 | else { |
michael@0 | 432 | // no fallback for the other XDG dirs |
michael@0 | 433 | rv = NS_ERROR_FAILURE; |
michael@0 | 434 | } |
michael@0 | 435 | |
michael@0 | 436 | if (NS_FAILED(rv)) |
michael@0 | 437 | return rv; |
michael@0 | 438 | |
michael@0 | 439 | bool exists; |
michael@0 | 440 | rv = file->Exists(&exists); |
michael@0 | 441 | if (NS_FAILED(rv)) |
michael@0 | 442 | return rv; |
michael@0 | 443 | if (!exists) { |
michael@0 | 444 | rv = file->Create(nsIFile::DIRECTORY_TYPE, 0755); |
michael@0 | 445 | if (NS_FAILED(rv)) |
michael@0 | 446 | return rv; |
michael@0 | 447 | } |
michael@0 | 448 | |
michael@0 | 449 | *aFile = nullptr; |
michael@0 | 450 | file.swap(*aFile); |
michael@0 | 451 | |
michael@0 | 452 | return NS_OK; |
michael@0 | 453 | } |
michael@0 | 454 | #endif |
michael@0 | 455 | |
michael@0 | 456 | nsresult |
michael@0 | 457 | GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory, |
michael@0 | 458 | nsIFile** aFile) |
michael@0 | 459 | { |
michael@0 | 460 | #if defined(XP_WIN) |
michael@0 | 461 | WCHAR path[MAX_PATH]; |
michael@0 | 462 | #else |
michael@0 | 463 | char path[MAXPATHLEN]; |
michael@0 | 464 | #endif |
michael@0 | 465 | |
michael@0 | 466 | switch (aSystemSystemDirectory) |
michael@0 | 467 | { |
michael@0 | 468 | case OS_CurrentWorkingDirectory: |
michael@0 | 469 | #if defined(XP_WIN) |
michael@0 | 470 | if (!_wgetcwd(path, MAX_PATH)) |
michael@0 | 471 | return NS_ERROR_FAILURE; |
michael@0 | 472 | return NS_NewLocalFile(nsDependentString(path), |
michael@0 | 473 | true, |
michael@0 | 474 | aFile); |
michael@0 | 475 | #else |
michael@0 | 476 | if(!getcwd(path, MAXPATHLEN)) |
michael@0 | 477 | return NS_ERROR_FAILURE; |
michael@0 | 478 | #endif |
michael@0 | 479 | |
michael@0 | 480 | #if !defined(XP_WIN) |
michael@0 | 481 | return NS_NewNativeLocalFile(nsDependentCString(path), |
michael@0 | 482 | true, |
michael@0 | 483 | aFile); |
michael@0 | 484 | #endif |
michael@0 | 485 | |
michael@0 | 486 | case OS_DriveDirectory: |
michael@0 | 487 | #if defined (XP_WIN) |
michael@0 | 488 | { |
michael@0 | 489 | int32_t len = ::GetWindowsDirectoryW(path, MAX_PATH); |
michael@0 | 490 | if (len == 0) |
michael@0 | 491 | break; |
michael@0 | 492 | if (path[1] == char16_t(':') && path[2] == char16_t('\\')) |
michael@0 | 493 | path[3] = 0; |
michael@0 | 494 | |
michael@0 | 495 | return NS_NewLocalFile(nsDependentString(path), |
michael@0 | 496 | true, |
michael@0 | 497 | aFile); |
michael@0 | 498 | } |
michael@0 | 499 | #else |
michael@0 | 500 | return NS_NewNativeLocalFile(nsDependentCString("/"), |
michael@0 | 501 | true, |
michael@0 | 502 | aFile); |
michael@0 | 503 | |
michael@0 | 504 | #endif |
michael@0 | 505 | |
michael@0 | 506 | case OS_TemporaryDirectory: |
michael@0 | 507 | #if defined (XP_WIN) |
michael@0 | 508 | { |
michael@0 | 509 | DWORD len = ::GetTempPathW(MAX_PATH, path); |
michael@0 | 510 | if (len == 0) |
michael@0 | 511 | break; |
michael@0 | 512 | return NS_NewLocalFile(nsDependentString(path, len), |
michael@0 | 513 | true, |
michael@0 | 514 | aFile); |
michael@0 | 515 | } |
michael@0 | 516 | #elif defined(MOZ_WIDGET_COCOA) |
michael@0 | 517 | { |
michael@0 | 518 | return GetOSXFolderType(kUserDomain, kTemporaryFolderType, aFile); |
michael@0 | 519 | } |
michael@0 | 520 | |
michael@0 | 521 | #elif defined(XP_UNIX) |
michael@0 | 522 | { |
michael@0 | 523 | static const char *tPath = nullptr; |
michael@0 | 524 | if (!tPath) { |
michael@0 | 525 | tPath = PR_GetEnv("TMPDIR"); |
michael@0 | 526 | if (!tPath || !*tPath) { |
michael@0 | 527 | tPath = PR_GetEnv("TMP"); |
michael@0 | 528 | if (!tPath || !*tPath) { |
michael@0 | 529 | tPath = PR_GetEnv("TEMP"); |
michael@0 | 530 | if (!tPath || !*tPath) { |
michael@0 | 531 | tPath = "/tmp/"; |
michael@0 | 532 | } |
michael@0 | 533 | } |
michael@0 | 534 | } |
michael@0 | 535 | } |
michael@0 | 536 | return NS_NewNativeLocalFile(nsDependentCString(tPath), |
michael@0 | 537 | true, |
michael@0 | 538 | aFile); |
michael@0 | 539 | } |
michael@0 | 540 | #else |
michael@0 | 541 | break; |
michael@0 | 542 | #endif |
michael@0 | 543 | #if defined (XP_WIN) |
michael@0 | 544 | case Win_SystemDirectory: |
michael@0 | 545 | { |
michael@0 | 546 | int32_t len = ::GetSystemDirectoryW(path, MAX_PATH); |
michael@0 | 547 | |
michael@0 | 548 | // Need enough space to add the trailing backslash |
michael@0 | 549 | if (!len || len > MAX_PATH - 2) |
michael@0 | 550 | break; |
michael@0 | 551 | path[len] = L'\\'; |
michael@0 | 552 | path[++len] = L'\0'; |
michael@0 | 553 | |
michael@0 | 554 | return NS_NewLocalFile(nsDependentString(path, len), |
michael@0 | 555 | true, |
michael@0 | 556 | aFile); |
michael@0 | 557 | } |
michael@0 | 558 | |
michael@0 | 559 | case Win_WindowsDirectory: |
michael@0 | 560 | { |
michael@0 | 561 | int32_t len = ::GetWindowsDirectoryW(path, MAX_PATH); |
michael@0 | 562 | |
michael@0 | 563 | // Need enough space to add the trailing backslash |
michael@0 | 564 | if (!len || len > MAX_PATH - 2) |
michael@0 | 565 | break; |
michael@0 | 566 | |
michael@0 | 567 | path[len] = L'\\'; |
michael@0 | 568 | path[++len] = L'\0'; |
michael@0 | 569 | |
michael@0 | 570 | return NS_NewLocalFile(nsDependentString(path, len), |
michael@0 | 571 | true, |
michael@0 | 572 | aFile); |
michael@0 | 573 | } |
michael@0 | 574 | |
michael@0 | 575 | case Win_ProgramFiles: |
michael@0 | 576 | { |
michael@0 | 577 | return GetWindowsFolder(CSIDL_PROGRAM_FILES, aFile); |
michael@0 | 578 | } |
michael@0 | 579 | |
michael@0 | 580 | case Win_HomeDirectory: |
michael@0 | 581 | { |
michael@0 | 582 | nsresult rv = GetWindowsFolder(CSIDL_PROFILE, aFile); |
michael@0 | 583 | if (NS_SUCCEEDED(rv)) |
michael@0 | 584 | return rv; |
michael@0 | 585 | |
michael@0 | 586 | int32_t len; |
michael@0 | 587 | if ((len = ::GetEnvironmentVariableW(L"HOME", path, MAX_PATH)) > 0) |
michael@0 | 588 | { |
michael@0 | 589 | // Need enough space to add the trailing backslash |
michael@0 | 590 | if (len > MAX_PATH - 2) |
michael@0 | 591 | break; |
michael@0 | 592 | |
michael@0 | 593 | path[len] = L'\\'; |
michael@0 | 594 | path[++len] = L'\0'; |
michael@0 | 595 | |
michael@0 | 596 | rv = NS_NewLocalFile(nsDependentString(path, len), |
michael@0 | 597 | true, |
michael@0 | 598 | aFile); |
michael@0 | 599 | if (NS_SUCCEEDED(rv)) |
michael@0 | 600 | return rv; |
michael@0 | 601 | } |
michael@0 | 602 | |
michael@0 | 603 | len = ::GetEnvironmentVariableW(L"HOMEDRIVE", path, MAX_PATH); |
michael@0 | 604 | if (0 < len && len < MAX_PATH) |
michael@0 | 605 | { |
michael@0 | 606 | WCHAR temp[MAX_PATH]; |
michael@0 | 607 | DWORD len2 = ::GetEnvironmentVariableW(L"HOMEPATH", temp, MAX_PATH); |
michael@0 | 608 | if (0 < len2 && len + len2 < MAX_PATH) |
michael@0 | 609 | wcsncat(path, temp, len2); |
michael@0 | 610 | |
michael@0 | 611 | len = wcslen(path); |
michael@0 | 612 | |
michael@0 | 613 | // Need enough space to add the trailing backslash |
michael@0 | 614 | if (len > MAX_PATH - 2) |
michael@0 | 615 | break; |
michael@0 | 616 | |
michael@0 | 617 | path[len] = L'\\'; |
michael@0 | 618 | path[++len] = L'\0'; |
michael@0 | 619 | |
michael@0 | 620 | return NS_NewLocalFile(nsDependentString(path, len), |
michael@0 | 621 | true, |
michael@0 | 622 | aFile); |
michael@0 | 623 | } |
michael@0 | 624 | } |
michael@0 | 625 | case Win_Desktop: |
michael@0 | 626 | { |
michael@0 | 627 | return GetWindowsFolder(CSIDL_DESKTOP, aFile); |
michael@0 | 628 | } |
michael@0 | 629 | case Win_Programs: |
michael@0 | 630 | { |
michael@0 | 631 | return GetWindowsFolder(CSIDL_PROGRAMS, aFile); |
michael@0 | 632 | } |
michael@0 | 633 | |
michael@0 | 634 | case Win_Downloads: |
michael@0 | 635 | { |
michael@0 | 636 | // Defined in KnownFolders.h. |
michael@0 | 637 | GUID folderid_downloads = {0x374de290, 0x123f, 0x4565, {0x91, 0x64, |
michael@0 | 638 | 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}}; |
michael@0 | 639 | nsresult rv = GetKnownFolder(&folderid_downloads, aFile); |
michael@0 | 640 | // On WinXP, there is no downloads folder, default |
michael@0 | 641 | // to 'Desktop'. |
michael@0 | 642 | if(NS_ERROR_FAILURE == rv) |
michael@0 | 643 | { |
michael@0 | 644 | rv = GetWindowsFolder(CSIDL_DESKTOP, aFile); |
michael@0 | 645 | } |
michael@0 | 646 | return rv; |
michael@0 | 647 | } |
michael@0 | 648 | |
michael@0 | 649 | case Win_Controls: |
michael@0 | 650 | { |
michael@0 | 651 | return GetWindowsFolder(CSIDL_CONTROLS, aFile); |
michael@0 | 652 | } |
michael@0 | 653 | case Win_Printers: |
michael@0 | 654 | { |
michael@0 | 655 | return GetWindowsFolder(CSIDL_PRINTERS, aFile); |
michael@0 | 656 | } |
michael@0 | 657 | case Win_Personal: |
michael@0 | 658 | { |
michael@0 | 659 | return GetWindowsFolder(CSIDL_PERSONAL, aFile); |
michael@0 | 660 | } |
michael@0 | 661 | case Win_Favorites: |
michael@0 | 662 | { |
michael@0 | 663 | return GetWindowsFolder(CSIDL_FAVORITES, aFile); |
michael@0 | 664 | } |
michael@0 | 665 | case Win_Startup: |
michael@0 | 666 | { |
michael@0 | 667 | return GetWindowsFolder(CSIDL_STARTUP, aFile); |
michael@0 | 668 | } |
michael@0 | 669 | case Win_Recent: |
michael@0 | 670 | { |
michael@0 | 671 | return GetWindowsFolder(CSIDL_RECENT, aFile); |
michael@0 | 672 | } |
michael@0 | 673 | case Win_Sendto: |
michael@0 | 674 | { |
michael@0 | 675 | return GetWindowsFolder(CSIDL_SENDTO, aFile); |
michael@0 | 676 | } |
michael@0 | 677 | case Win_Bitbucket: |
michael@0 | 678 | { |
michael@0 | 679 | return GetWindowsFolder(CSIDL_BITBUCKET, aFile); |
michael@0 | 680 | } |
michael@0 | 681 | case Win_Startmenu: |
michael@0 | 682 | { |
michael@0 | 683 | return GetWindowsFolder(CSIDL_STARTMENU, aFile); |
michael@0 | 684 | } |
michael@0 | 685 | case Win_Desktopdirectory: |
michael@0 | 686 | { |
michael@0 | 687 | return GetWindowsFolder(CSIDL_DESKTOPDIRECTORY, aFile); |
michael@0 | 688 | } |
michael@0 | 689 | case Win_Drives: |
michael@0 | 690 | { |
michael@0 | 691 | return GetWindowsFolder(CSIDL_DRIVES, aFile); |
michael@0 | 692 | } |
michael@0 | 693 | case Win_Network: |
michael@0 | 694 | { |
michael@0 | 695 | return GetWindowsFolder(CSIDL_NETWORK, aFile); |
michael@0 | 696 | } |
michael@0 | 697 | case Win_Nethood: |
michael@0 | 698 | { |
michael@0 | 699 | return GetWindowsFolder(CSIDL_NETHOOD, aFile); |
michael@0 | 700 | } |
michael@0 | 701 | case Win_Fonts: |
michael@0 | 702 | { |
michael@0 | 703 | return GetWindowsFolder(CSIDL_FONTS, aFile); |
michael@0 | 704 | } |
michael@0 | 705 | case Win_Templates: |
michael@0 | 706 | { |
michael@0 | 707 | return GetWindowsFolder(CSIDL_TEMPLATES, aFile); |
michael@0 | 708 | } |
michael@0 | 709 | case Win_Common_Startmenu: |
michael@0 | 710 | { |
michael@0 | 711 | return GetWindowsFolder(CSIDL_COMMON_STARTMENU, aFile); |
michael@0 | 712 | } |
michael@0 | 713 | case Win_Common_Programs: |
michael@0 | 714 | { |
michael@0 | 715 | return GetWindowsFolder(CSIDL_COMMON_PROGRAMS, aFile); |
michael@0 | 716 | } |
michael@0 | 717 | case Win_Common_Startup: |
michael@0 | 718 | { |
michael@0 | 719 | return GetWindowsFolder(CSIDL_COMMON_STARTUP, aFile); |
michael@0 | 720 | } |
michael@0 | 721 | case Win_Common_Desktopdirectory: |
michael@0 | 722 | { |
michael@0 | 723 | return GetWindowsFolder(CSIDL_COMMON_DESKTOPDIRECTORY, aFile); |
michael@0 | 724 | } |
michael@0 | 725 | case Win_Common_AppData: |
michael@0 | 726 | { |
michael@0 | 727 | return GetWindowsFolder(CSIDL_COMMON_APPDATA, aFile); |
michael@0 | 728 | } |
michael@0 | 729 | case Win_Printhood: |
michael@0 | 730 | { |
michael@0 | 731 | return GetWindowsFolder(CSIDL_PRINTHOOD, aFile); |
michael@0 | 732 | } |
michael@0 | 733 | case Win_Cookies: |
michael@0 | 734 | { |
michael@0 | 735 | return GetWindowsFolder(CSIDL_COOKIES, aFile); |
michael@0 | 736 | } |
michael@0 | 737 | case Win_Appdata: |
michael@0 | 738 | { |
michael@0 | 739 | nsresult rv = GetWindowsFolder(CSIDL_APPDATA, aFile); |
michael@0 | 740 | if (NS_FAILED(rv)) |
michael@0 | 741 | rv = GetRegWindowsAppDataFolder(false, aFile); |
michael@0 | 742 | return rv; |
michael@0 | 743 | } |
michael@0 | 744 | case Win_LocalAppdata: |
michael@0 | 745 | { |
michael@0 | 746 | nsresult rv = GetWindowsFolder(CSIDL_LOCAL_APPDATA, aFile); |
michael@0 | 747 | if (NS_FAILED(rv)) |
michael@0 | 748 | rv = GetRegWindowsAppDataFolder(true, aFile); |
michael@0 | 749 | return rv; |
michael@0 | 750 | } |
michael@0 | 751 | case Win_Documents: |
michael@0 | 752 | { |
michael@0 | 753 | return GetLibrarySaveToPath(CSIDL_MYDOCUMENTS, |
michael@0 | 754 | FOLDERID_DocumentsLibrary, |
michael@0 | 755 | aFile); |
michael@0 | 756 | } |
michael@0 | 757 | case Win_Pictures: |
michael@0 | 758 | { |
michael@0 | 759 | return GetLibrarySaveToPath(CSIDL_MYPICTURES, |
michael@0 | 760 | FOLDERID_PicturesLibrary, |
michael@0 | 761 | aFile); |
michael@0 | 762 | } |
michael@0 | 763 | case Win_Music: |
michael@0 | 764 | { |
michael@0 | 765 | return GetLibrarySaveToPath(CSIDL_MYMUSIC, |
michael@0 | 766 | FOLDERID_MusicLibrary, |
michael@0 | 767 | aFile); |
michael@0 | 768 | } |
michael@0 | 769 | case Win_Videos: |
michael@0 | 770 | { |
michael@0 | 771 | return GetLibrarySaveToPath(CSIDL_MYVIDEO, |
michael@0 | 772 | FOLDERID_VideosLibrary, |
michael@0 | 773 | aFile); |
michael@0 | 774 | } |
michael@0 | 775 | #endif // XP_WIN |
michael@0 | 776 | |
michael@0 | 777 | #if defined(XP_UNIX) |
michael@0 | 778 | case Unix_LocalDirectory: |
michael@0 | 779 | return NS_NewNativeLocalFile(nsDependentCString("/usr/local/netscape/"), |
michael@0 | 780 | true, |
michael@0 | 781 | aFile); |
michael@0 | 782 | case Unix_LibDirectory: |
michael@0 | 783 | return NS_NewNativeLocalFile(nsDependentCString("/usr/local/lib/netscape/"), |
michael@0 | 784 | true, |
michael@0 | 785 | aFile); |
michael@0 | 786 | |
michael@0 | 787 | case Unix_HomeDirectory: |
michael@0 | 788 | return GetUnixHomeDir(aFile); |
michael@0 | 789 | |
michael@0 | 790 | case Unix_XDG_Desktop: |
michael@0 | 791 | case Unix_XDG_Documents: |
michael@0 | 792 | case Unix_XDG_Download: |
michael@0 | 793 | case Unix_XDG_Music: |
michael@0 | 794 | case Unix_XDG_Pictures: |
michael@0 | 795 | case Unix_XDG_PublicShare: |
michael@0 | 796 | case Unix_XDG_Templates: |
michael@0 | 797 | case Unix_XDG_Videos: |
michael@0 | 798 | return GetUnixXDGUserDirectory(aSystemSystemDirectory, aFile); |
michael@0 | 799 | #endif |
michael@0 | 800 | |
michael@0 | 801 | default: |
michael@0 | 802 | break; |
michael@0 | 803 | } |
michael@0 | 804 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 805 | } |
michael@0 | 806 | |
michael@0 | 807 | #if defined (MOZ_WIDGET_COCOA) |
michael@0 | 808 | nsresult |
michael@0 | 809 | GetOSXFolderType(short aDomain, OSType aFolderType, nsIFile **localFile) |
michael@0 | 810 | { |
michael@0 | 811 | OSErr err; |
michael@0 | 812 | FSRef fsRef; |
michael@0 | 813 | nsresult rv = NS_ERROR_FAILURE; |
michael@0 | 814 | |
michael@0 | 815 | err = ::FSFindFolder(aDomain, aFolderType, kCreateFolder, &fsRef); |
michael@0 | 816 | if (err == noErr) |
michael@0 | 817 | { |
michael@0 | 818 | NS_NewLocalFile(EmptyString(), true, localFile); |
michael@0 | 819 | nsCOMPtr<nsILocalFileMac> localMacFile(do_QueryInterface(*localFile)); |
michael@0 | 820 | if (localMacFile) |
michael@0 | 821 | rv = localMacFile->InitWithFSRef(&fsRef); |
michael@0 | 822 | } |
michael@0 | 823 | return rv; |
michael@0 | 824 | } |
michael@0 | 825 | #endif |
michael@0 | 826 |