1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code, released
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Doug Turner <dougt@netscape.com>
26 * Fredrik Holmqvist <thesuckiestemail@yahoo.se>
27 * Jungshik Shin <jshin@i18nl10n.com>
29 * Alternatively, the contents of this file may be used under the terms of
30 * either of the GNU General Public License Version 2 or later (the "GPL"),
31 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
43 #include "SpecialSystemDirectory.h"
45 #include "nsDependentString.h"
56 // These are not defined by VC6.
57 #ifndef CSIDL_LOCAL_APPDATA
58 #define CSIDL_LOCAL_APPDATA 0x001C
60 #ifndef CSIDL_PROGRAM_FILES
61 #define CSIDL_PROGRAM_FILES 0x0026
66 #define MAX_PATH _MAX_PATH
67 #define INCL_WINWORKPLACE
69 #define INCL_DOSMODULEMGR
70 #define INCL_DOSPROCESS
71 #define INCL_WINSHELLDATA
77 #elif defined(XP_UNIX)
81 #include <sys/param.h>
84 #elif defined(XP_BEOS)
86 #include <FindDirectory.h>
91 #include <sys/param.h>
104 #define MAXPATHLEN MAX_PATH
105 #elif defined(_MAX_PATH)
106 #define MAXPATHLEN _MAX_PATH
107 #elif defined(CCHMAXPATH)
108 #define MAXPATHLEN CCHMAXPATH
110 #define MAXPATHLEN 1024
115 typedef HRESULT (WINAPI
* nsGetKnownFolderPath
)(GUID
& rfid
,
120 static nsGetKnownFolderPath gGetKnownFolderPath
= NULL
;
122 static HINSTANCE gShell32DLLInst
= NULL
;
125 NS_COM
void StartupSpecialSystemDirectory()
127 #if defined (XP_WIN) && !defined (WINCE)
128 // SHGetKnownFolderPath is only available on Windows Vista
129 // so that we need to use GetProcAddress to get the pointer.
130 gShell32DLLInst
= LoadLibrary("Shell32.dll");
133 gGetKnownFolderPath
= (nsGetKnownFolderPath
)
134 GetProcAddress(gShell32DLLInst
, "SHGetKnownFolderPath");
139 NS_COM
void ShutdownSpecialSystemDirectory()
144 FreeLibrary(gShell32DLLInst
);
145 gShell32DLLInst
= NULL
;
146 gGetKnownFolderPath
= NULL
;
153 static nsresult
GetKnownFolder(GUID
* guid
, nsILocalFile
** aFile
)
155 if (!guid
|| !gGetKnownFolderPath
)
156 return NS_ERROR_FAILURE
;
159 gGetKnownFolderPath(*guid
, 0, NULL
, &path
);
162 return NS_ERROR_FAILURE
;
164 nsresult rv
= NS_NewLocalFile(nsDependentString(path
),
172 //----------------------------------------------------------------------------------------
173 static nsresult
GetWindowsFolder(int folder
, nsILocalFile
** aFile
)
174 //----------------------------------------------------------------------------------------
176 WCHAR path
[MAX_PATH
+ 2];
177 HRESULT result
= SHGetSpecialFolderPathW(NULL
, path
, folder
, true);
179 if (!SUCCEEDED(result
))
180 return NS_ERROR_FAILURE
;
182 // Append the trailing slash
183 int len
= wcslen(path
);
184 if (len
> 1 && path
[len
- 1] != L
'\\')
190 return NS_NewLocalFile(nsDependentString(path
, len
), PR_TRUE
, aFile
);
195 #if defined (XP_BEOS)
197 GetBeOSFolder( directory_which which
, dev_t volume
, nsILocalFile
** aFile
)
199 char path
[MAXPATHLEN
];
201 return NS_ERROR_FAILURE
;
203 status_t result
= find_directory(which
, volume
, false, path
, MAXPATHLEN
- 2);
205 return NS_ERROR_FAILURE
;
207 int len
= strlen(path
);
209 return NS_ERROR_FAILURE
;
211 if (path
[len
-1] != '/')
216 return NS_NewNativeLocalFile(nsDependentCString(path
), PR_TRUE
, aFile
);
222 GetUnixHomeDir(nsILocalFile
** aFile
)
226 pHome
= getenv("HOME");
228 return NS_NewNativeLocalFile(nsDependentCString(pHome
),
232 return NS_NewNativeLocalFile(nsDependentCString(decc$
translate_vms(pHome
)),
237 return NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")),
243 The following license applies to the xdg_user_dir_lookup function:
245 Copyright (c) 2007 Red Hat, Inc.
247 Permission is hereby granted, free of charge, to any person
248 obtaining a copy of this software and associated documentation files
249 (the "Software"), to deal in the Software without restriction,
250 including without limitation the rights to use, copy, modify, merge,
251 publish, distribute, sublicense, and/or sell copies of the Software,
252 and to permit persons to whom the Software is furnished to do so,
253 subject to the following conditions:
255 The above copyright notice and this permission notice shall be
256 included in all copies or substantial portions of the Software.
258 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
259 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
260 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
261 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
262 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
263 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
264 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
269 xdg_user_dir_lookup (const char *type
)
272 char *home_dir
, *config_home
, *config_file
;
279 home_dir
= getenv ("HOME");
281 if (home_dir
== NULL
)
284 config_home
= getenv ("XDG_CONFIG_HOME");
285 if (config_home
== NULL
|| config_home
[0] == 0)
287 config_file
= (char*) malloc (strlen (home_dir
) + strlen ("/.config/user-dirs.dirs") + 1);
288 if (config_file
== NULL
)
291 strcpy (config_file
, home_dir
);
292 strcat (config_file
, "/.config/user-dirs.dirs");
296 config_file
= (char*) malloc (strlen (config_home
) + strlen ("/user-dirs.dirs") + 1);
297 if (config_file
== NULL
)
300 strcpy (config_file
, config_home
);
301 strcat (config_file
, "/user-dirs.dirs");
304 file
= fopen (config_file
, "r");
310 while (fgets (buffer
, sizeof (buffer
), file
))
312 /* Remove newline at end */
313 len
= strlen (buffer
);
314 if (len
> 0 && buffer
[len
-1] == '\n')
318 while (*p
== ' ' || *p
== '\t')
321 if (strncmp (p
, "XDG_", 4) != 0)
324 if (strncmp (p
, type
, strlen (type
)) != 0)
327 if (strncmp (p
, "_DIR", 4) != 0)
331 while (*p
== ' ' || *p
== '\t')
338 while (*p
== ' ' || *p
== '\t')
346 if (strncmp (p
, "$HOME/", 6) == 0)
356 user_dir
= (char*) malloc (strlen (home_dir
) + 1 + strlen (p
) + 1);
357 if (user_dir
== NULL
)
360 strcpy (user_dir
, home_dir
);
361 strcat (user_dir
, "/");
365 user_dir
= (char*) malloc (strlen (p
) + 1);
366 if (user_dir
== NULL
)
372 d
= user_dir
+ strlen (user_dir
);
373 while (*p
&& *p
!= '"')
375 if ((*p
== '\\') && (*(p
+1) != 0))
391 static const char xdg_user_dirs
[] =
401 static const PRUint8 xdg_user_dir_offsets
[] = {
413 GetUnixXDGUserDirectory(SystemDirectories aSystemDirectory
,
414 nsILocalFile
** aFile
)
416 char *dir
= xdg_user_dir_lookup
417 (xdg_user_dirs
+ xdg_user_dir_offsets
[aSystemDirectory
-
421 nsCOMPtr
<nsILocalFile
> file
;
423 rv
= NS_NewNativeLocalFile(nsDependentCString(dir
), PR_TRUE
,
424 getter_AddRefs(file
));
426 } else if (Unix_XDG_Desktop
== aSystemDirectory
) {
427 // for the XDG desktop dir, fall back to HOME/Desktop
428 // (for historical compatibility)
429 rv
= GetUnixHomeDir(getter_AddRefs(file
));
433 rv
= file
->AppendNative(NS_LITERAL_CSTRING("Desktop"));
435 // no fallback for the other XDG dirs
436 rv
= NS_ERROR_FAILURE
;
443 rv
= file
->Exists(&exists
);
447 rv
= file
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
460 GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory
,
461 nsILocalFile
** aFile
)
464 WCHAR path
[MAX_PATH
];
466 char path
[MAXPATHLEN
];
469 switch (aSystemSystemDirectory
)
471 case OS_CurrentWorkingDirectory
:
473 if (!_wgetcwd(path
, MAX_PATH
))
474 return NS_ERROR_FAILURE
;
475 return NS_NewLocalFile(nsDependentString(path
),
478 #elif defined(XP_OS2)
479 if (DosQueryPathInfo( ".", FIL_QUERYFULLNAME
, path
, MAXPATHLEN
))
480 return NS_ERROR_FAILURE
;
482 if(!getcwd(path
, MAXPATHLEN
))
483 return NS_ERROR_FAILURE
;
487 return NS_NewNativeLocalFile(nsDependentCString(path
),
492 case OS_DriveDirectory
:
495 PRInt32 len
= ::GetWindowsDirectoryW(path
, MAX_PATH
);
498 if (path
[1] == PRUnichar(':') && path
[2] == PRUnichar('\\'))
501 return NS_NewLocalFile(nsDependentString(path
),
505 #elif defined(XP_OS2)
507 ULONG ulBootDrive
= 0;
508 char buffer
[] = " :\\OS2\\";
509 DosQuerySysInfo( QSV_BOOT_DRIVE
, QSV_BOOT_DRIVE
,
510 &ulBootDrive
, sizeof ulBootDrive
);
511 buffer
[0] = 'A' - 1 + ulBootDrive
; // duh, 1-based index...
513 return NS_NewNativeLocalFile(nsDependentCString(buffer
),
518 return NS_NewNativeLocalFile(nsDependentCString("/"),
524 case OS_TemporaryDirectory
:
525 #if defined (XP_WIN) && !defined (WINCE)
527 DWORD len
= ::GetTempPathW(MAX_PATH
, path
);
530 return NS_NewLocalFile(nsDependentString(path
, len
),
534 #elif defined (WINCE)
536 return NS_NewNativeLocalFile(NS_LITERAL_CSTRING("\\Temp"),
540 #elif defined(XP_OS2)
542 char *tPath
= PR_GetEnv("TMP");
543 if (!tPath
|| !*tPath
) {
544 tPath
= PR_GetEnv("TEMP");
545 if (!tPath
|| !*tPath
) {
546 // if an OS/2 system has neither TMP nor TEMP defined
547 // then it is severely broken, so this will never happen.
548 return NS_ERROR_UNEXPECTED
;
551 nsCString tString
= nsDependentCString(tPath
);
552 if (tString
.Find("/", PR_FALSE
, 0, -1)) {
553 tString
.ReplaceChar('/','\\');
555 return NS_NewNativeLocalFile(tString
, PR_TRUE
, aFile
);
557 #elif defined(XP_MACOSX)
559 return GetOSXFolderType(kUserDomain
, kTemporaryFolderType
, aFile
);
562 #elif defined(XP_UNIX) || defined(XP_BEOS)
564 static const char *tPath
= nsnull
;
566 tPath
= PR_GetEnv("TMPDIR");
567 if (!tPath
|| !*tPath
) {
568 tPath
= PR_GetEnv("TMP");
569 if (!tPath
|| !*tPath
) {
570 tPath
= PR_GetEnv("TEMP");
571 if (!tPath
|| !*tPath
) {
577 return NS_NewNativeLocalFile(nsDependentCString(tPath
),
585 case Win_SystemDirectory
:
587 PRInt32 len
= ::GetSystemDirectoryW(path
, MAX_PATH
);
589 // Need enough space to add the trailing backslash
590 if (!len
|| len
> MAX_PATH
- 2)
595 return NS_NewLocalFile(nsDependentString(path
, len
),
600 case Win_WindowsDirectory
:
602 PRInt32 len
= ::GetWindowsDirectoryW(path
, MAX_PATH
);
604 // Need enough space to add the trailing backslash
605 if (!len
|| len
> MAX_PATH
- 2)
611 return NS_NewLocalFile(nsDependentString(path
, len
),
616 case Win_ProgramFiles
:
618 return GetWindowsFolder(CSIDL_PROGRAM_FILES
, aFile
);
621 case Win_HomeDirectory
:
624 if ((len
= ::GetEnvironmentVariableW(L
"HOME", path
, MAX_PATH
)) > 0)
626 // Need enough space to add the trailing backslash
627 if (len
> MAX_PATH
- 2)
633 return NS_NewLocalFile(nsDependentString(path
, len
),
638 len
= ::GetEnvironmentVariableW(L
"HOMEDRIVE", path
, MAX_PATH
);
639 if (0 < len
&& len
< MAX_PATH
)
641 WCHAR temp
[MAX_PATH
];
642 DWORD len2
= ::GetEnvironmentVariableW(L
"HOMEPATH", temp
, MAX_PATH
);
643 if (0 < len2
&& len
+ len2
< MAX_PATH
)
644 wcsncat(path
, temp
, len2
);
648 // Need enough space to add the trailing backslash
649 if (len
> MAX_PATH
- 2)
655 return NS_NewLocalFile(nsDependentString(path
, len
),
662 return GetWindowsFolder(CSIDL_DESKTOP
, aFile
);
666 return GetWindowsFolder(CSIDL_PROGRAMS
, aFile
);
671 // Defined in KnownFolders.h.
672 GUID folderid_downloads
= {0x374de290, 0x123f, 0x4565, {0x91, 0x64,
673 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}};
674 nsresult rv
= GetKnownFolder(&folderid_downloads
, aFile
);
675 // On WinXP and 2k, there is no downloads folder, default
677 if(NS_ERROR_FAILURE
== rv
)
679 rv
= GetWindowsFolder(CSIDL_DESKTOP
, aFile
);
686 return GetWindowsFolder(CSIDL_CONTROLS
, aFile
);
690 return GetWindowsFolder(CSIDL_PRINTERS
, aFile
);
694 return GetWindowsFolder(CSIDL_PERSONAL
, aFile
);
698 return GetWindowsFolder(CSIDL_FAVORITES
, aFile
);
702 return GetWindowsFolder(CSIDL_STARTUP
, aFile
);
706 return GetWindowsFolder(CSIDL_RECENT
, aFile
);
710 return GetWindowsFolder(CSIDL_SENDTO
, aFile
);
714 return GetWindowsFolder(CSIDL_BITBUCKET
, aFile
);
718 return GetWindowsFolder(CSIDL_STARTMENU
, aFile
);
720 case Win_Desktopdirectory
:
722 return GetWindowsFolder(CSIDL_DESKTOPDIRECTORY
, aFile
);
726 return GetWindowsFolder(CSIDL_DRIVES
, aFile
);
730 return GetWindowsFolder(CSIDL_NETWORK
, aFile
);
734 return GetWindowsFolder(CSIDL_NETHOOD
, aFile
);
738 return GetWindowsFolder(CSIDL_FONTS
, aFile
);
742 return GetWindowsFolder(CSIDL_TEMPLATES
, aFile
);
745 case Win_Common_Startmenu
:
747 return GetWindowsFolder(CSIDL_COMMON_STARTMENU
, aFile
);
749 case Win_Common_Programs
:
751 return GetWindowsFolder(CSIDL_COMMON_PROGRAMS
, aFile
);
753 case Win_Common_Startup
:
755 return GetWindowsFolder(CSIDL_COMMON_STARTUP
, aFile
);
757 case Win_Common_Desktopdirectory
:
759 return GetWindowsFolder(CSIDL_COMMON_DESKTOPDIRECTORY
, aFile
);
763 return GetWindowsFolder(CSIDL_PRINTHOOD
, aFile
);
767 return GetWindowsFolder(CSIDL_COOKIES
, aFile
);
772 return GetWindowsFolder(CSIDL_APPDATA
, aFile
);
775 case Win_LocalAppdata
:
777 return GetWindowsFolder(CSIDL_LOCAL_APPDATA
, aFile
);
782 case Unix_LocalDirectory
:
783 return NS_NewNativeLocalFile(nsDependentCString("/usr/local/netscape/"),
786 case Unix_LibDirectory
:
787 return NS_NewNativeLocalFile(nsDependentCString("/usr/local/lib/netscape/"),
791 case Unix_HomeDirectory
:
792 return GetUnixHomeDir(aFile
);
794 case Unix_XDG_Desktop
:
795 case Unix_XDG_Documents
:
796 case Unix_XDG_Download
:
798 case Unix_XDG_Pictures
:
799 case Unix_XDG_PublicShare
:
800 case Unix_XDG_Templates
:
801 case Unix_XDG_Videos
:
802 return GetUnixXDGUserDirectory(aSystemSystemDirectory
, aFile
);
806 case BeOS_SettingsDirectory
:
808 return GetBeOSFolder(B_USER_SETTINGS_DIRECTORY
,0, aFile
);
811 case BeOS_HomeDirectory
:
813 return GetBeOSFolder(B_USER_DIRECTORY
,0, aFile
);
816 case BeOS_DesktopDirectory
:
818 /* Get the user's desktop folder, which in the future may differ from the boot desktop */
819 char path
[MAXPATHLEN
];
820 if (find_directory(B_USER_DIRECTORY
, 0, false, path
, MAXPATHLEN
) != B_OK
)
822 return GetBeOSFolder(B_DESKTOP_DIRECTORY
, dev_for_path(path
), aFile
);
825 case BeOS_SystemDirectory
:
827 return GetBeOSFolder(B_BEOS_DIRECTORY
,0, aFile
);
831 case OS2_SystemDirectory
:
833 ULONG ulBootDrive
= 0;
834 char buffer
[] = " :\\OS2\\System\\";
835 DosQuerySysInfo( QSV_BOOT_DRIVE
, QSV_BOOT_DRIVE
,
836 &ulBootDrive
, sizeof ulBootDrive
);
837 buffer
[0] = 'A' - 1 + ulBootDrive
; // duh, 1-based index...
839 return NS_NewNativeLocalFile(nsDependentCString(buffer
),
844 case OS2_OS2Directory
:
846 ULONG ulBootDrive
= 0;
847 char buffer
[] = " :\\OS2\\";
848 DosQuerySysInfo( QSV_BOOT_DRIVE
, QSV_BOOT_DRIVE
,
849 &ulBootDrive
, sizeof ulBootDrive
);
850 buffer
[0] = 'A' - 1 + ulBootDrive
; // duh, 1-based index...
852 return NS_NewNativeLocalFile(nsDependentCString(buffer
),
857 case OS2_HomeDirectory
:
860 char *tPath
= PR_GetEnv("MOZILLA_HOME");
861 char buffer
[CCHMAXPATH
];
862 /* If MOZILLA_HOME is not set, use GetCurrentProcessDirectory */
863 /* To ensure we get a long filename system */
864 if (!tPath
|| !*tPath
) {
867 DosGetInfoBlocks( &ptib
, &ppib
);
868 DosQueryModuleName( ppib
->pib_hmte
, CCHMAXPATH
, buffer
);
869 *strrchr( buffer
, '\\') = '\0'; // XXX DBCS misery
872 rv
= NS_NewNativeLocalFile(nsDependentCString(tPath
),
876 PrfWriteProfileString(HINI_USERPROFILE
, "Mozilla", "Home", tPath
);
880 case OS2_DesktopDirectory
:
882 char szPath
[CCHMAXPATH
+ 1];
884 fSuccess
= WinQueryActiveDesktopPathname (szPath
, sizeof(szPath
));
886 // this could happen if we are running without the WPS, return
887 // the Home directory instead
888 return GetSpecialSystemDirectory(OS2_HomeDirectory
, aFile
);
890 int len
= strlen (szPath
);
891 if (len
> CCHMAXPATH
-1)
894 szPath
[len
+ 1] = '\0';
896 return NS_NewNativeLocalFile(nsDependentCString(szPath
),
904 return NS_ERROR_NOT_AVAILABLE
;
907 #if defined (XP_MACOSX)
909 GetOSXFolderType(short aDomain
, OSType aFolderType
, nsILocalFile
**localFile
)
913 nsresult rv
= NS_ERROR_FAILURE
;
915 err
= ::FSFindFolder(aDomain
, aFolderType
, kCreateFolder
, &fsRef
);
918 NS_NewLocalFile(EmptyString(), PR_TRUE
, localFile
);
919 nsCOMPtr
<nsILocalFileMac
> localMacFile(do_QueryInterface(*localFile
));
921 rv
= localMacFile
->InitWithFSRef(&fsRef
);