From 3faaa5dab98b9fd9a09db16ec41809de28d9fab7 Mon Sep 17 00:00:00 2001 From: "reed%reedloden.com" Date: Wed, 12 Mar 2008 22:35:56 +0000 Subject: [PATCH] Bug 399500 - "support XDG user dirs in the directory service" [p=chpe@gnome.org (Christian Persch) r=caillon sr=bsmedberg a1.9=damons] git-svn-id: svn://10.0.0.236/trunk@247688 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/io/SpecialSystemDirectory.cpp | 244 ++++++++++++++++++-- mozilla/xpcom/io/SpecialSystemDirectory.h | 11 +- mozilla/xpcom/io/nsDirectoryService.cpp | 60 ++++- mozilla/xpcom/io/nsDirectoryService.h | 9 + mozilla/xpcom/io/nsDirectoryServiceDefs.h | 8 + 5 files changed, 309 insertions(+), 23 deletions(-) diff --git a/mozilla/xpcom/io/SpecialSystemDirectory.cpp b/mozilla/xpcom/io/SpecialSystemDirectory.cpp index 5ceea5ed105..df38acb744b 100644 --- a/mozilla/xpcom/io/SpecialSystemDirectory.cpp +++ b/mozilla/xpcom/io/SpecialSystemDirectory.cpp @@ -238,6 +238,222 @@ GetUnixHomeDir(nsILocalFile** aFile) PR_TRUE, aFile); #endif } + +/* + The following licence 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 *type) +{ + FILE *file; + char *home_dir, *config_home, *config_file; + char buffer[512]; + char *user_dir; + char *p, *d; + int len; + int relative; + + home_dir = getenv ("HOME"); + + if (home_dir == NULL) + goto error; + + config_home = getenv ("XDG_CONFIG_HOME"); + if (config_home == NULL || config_home[0] == 0) + { + config_file = (char*) malloc (strlen (home_dir) + strlen ("/.config/user-dirs.dirs") + 1); + if (config_file == NULL) + 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 == NULL) + goto error; + + strcpy (config_file, config_home); + strcat (config_file, "/user-dirs.dirs"); + } + + file = fopen (config_file, "r"); + free (config_file); + if (file == NULL) + goto error; + + user_dir = NULL; + 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, type, strlen (type)) != 0) + continue; + p += strlen (type); + 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 == NULL) + goto error2; + + strcpy (user_dir, home_dir); + strcat (user_dir, "/"); + } + else + { + user_dir = (char*) malloc (strlen (p) + 1); + if (user_dir == NULL) + 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 NULL; +} + +static const char xdg_user_dirs[] = + "DESKTOP\0" + "DOCUMENTS\0" + "DOWNLOAD\0" + "MUSIC\0" + "PICTURES\0" + "PUBLICSHARE\0" + "TEMPLATES\0" + "VIDEOS"; + +static const PRUint8 xdg_user_dir_offsets[] = { + 0, + 8, + 18, + 27, + 33, + 42, + 54, + 64 +}; + +static nsresult +GetUnixXDGUserDirectory(SystemDirectories aSystemDirectory, + nsILocalFile** aFile) +{ + char *dir = xdg_user_dir_lookup + (xdg_user_dirs + xdg_user_dir_offsets[aSystemDirectory - + Unix_XDG_Desktop]); + + nsresult rv; + nsCOMPtr file; + if (dir) { + rv = NS_NewNativeLocalFile(nsDependentCString(dir), PR_TRUE, + getter_AddRefs(file)); + free(dir); + } else if (Unix_XDG_Desktop == aSystemDirectory) { + // for the XDG desktop dir, fall back to HOME/Desktop + // (for historical compatibility) + rv = GetUnixHomeDir(getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + rv = file->AppendNative(NS_LITERAL_CSTRING("Desktop")); + } else { + // no fallback for the other XDG dirs + rv = NS_ERROR_FAILURE; + } + + if (NS_FAILED(rv)) + return rv; + + PRBool exists; + 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; + } + + *aFile = nsnull; + file.swap(*aFile); + + return NS_OK; +} #endif nsresult @@ -575,25 +791,15 @@ GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory, case Unix_HomeDirectory: return GetUnixHomeDir(aFile); - case Unix_DesktopDirectory: - { - nsCOMPtr home; - nsresult rv = GetUnixHomeDir(getter_AddRefs(home)); - if (NS_FAILED(rv)) - return rv; - rv = home->AppendNative(NS_LITERAL_CSTRING("Desktop")); - if (NS_FAILED(rv)) - return rv; - PRBool exists; - rv = home->Exists(&exists); - if (NS_FAILED(rv)) - return rv; - if (!exists) - return GetUnixHomeDir(aFile); - - NS_ADDREF(*aFile = home); - return NS_OK; - } + case Unix_XDG_Desktop: + case Unix_XDG_Documents: + case Unix_XDG_Download: + case Unix_XDG_Music: + case Unix_XDG_Pictures: + case Unix_XDG_PublicShare: + case Unix_XDG_Templates: + case Unix_XDG_Videos: + return GetUnixXDGUserDirectory(aSystemSystemDirectory, aFile); #endif #ifdef XP_BEOS diff --git a/mozilla/xpcom/io/SpecialSystemDirectory.h b/mozilla/xpcom/io/SpecialSystemDirectory.h index b7c37211285..673b5961a5c 100644 --- a/mozilla/xpcom/io/SpecialSystemDirectory.h +++ b/mozilla/xpcom/io/SpecialSystemDirectory.h @@ -114,8 +114,15 @@ enum SystemDirectories { Unix_LocalDirectory = 301, Unix_LibDirectory = 302, Unix_HomeDirectory = 303, - Unix_DesktopDirectory = 304, - + Unix_XDG_Desktop = 304, + Unix_XDG_Documents = 305, + Unix_XDG_Download = 306, + Unix_XDG_Music = 307, + Unix_XDG_Pictures = 308, + Unix_XDG_PublicShare = 309, + Unix_XDG_Templates = 310, + Unix_XDG_Videos = 311, + BeOS_SettingsDirectory = 401, BeOS_HomeDirectory = 402, BeOS_DesktopDirectory = 403, diff --git a/mozilla/xpcom/io/nsDirectoryService.cpp b/mozilla/xpcom/io/nsDirectoryService.cpp index d99f8a4a0cd..31f8b0533c4 100644 --- a/mozilla/xpcom/io/nsDirectoryService.cpp +++ b/mozilla/xpcom/io/nsDirectoryService.cpp @@ -358,6 +358,15 @@ nsIAtom* nsDirectoryService::sDefaultDownloadDirectory = nsnull; #elif defined (XP_UNIX) nsIAtom* nsDirectoryService::sLocalDirectory = nsnull; nsIAtom* nsDirectoryService::sLibDirectory = nsnull; +nsIAtom* nsDirectoryService::sDefaultDownloadDirectory = nsnull; +nsIAtom* nsDirectoryService::sXDGDesktop = nsnull; +nsIAtom* nsDirectoryService::sXDGDocuments = nsnull; +nsIAtom* nsDirectoryService::sXDGDownload = nsnull; +nsIAtom* nsDirectoryService::sXDGMusic = nsnull; +nsIAtom* nsDirectoryService::sXDGPictures = nsnull; +nsIAtom* nsDirectoryService::sXDGPublicShare = nsnull; +nsIAtom* nsDirectoryService::sXDGTemplates = nsnull; +nsIAtom* nsDirectoryService::sXDGVideos = nsnull; #elif defined (XP_OS2) nsIAtom* nsDirectoryService::sSystemDirectory = nsnull; nsIAtom* nsDirectoryService::sOS2Directory = nsnull; @@ -465,6 +474,15 @@ static const nsStaticAtom directory_atoms[] = { #elif defined (XP_UNIX) { NS_UNIX_LOCAL_DIR, &nsDirectoryService::sLocalDirectory }, { NS_UNIX_LIB_DIR, &nsDirectoryService::sLibDirectory }, + { NS_UNIX_DEFAULT_DOWNLOAD_DIR, &nsDirectoryService::sDefaultDownloadDirectory }, + { NS_UNIX_XDG_DESKTOP_DIR, &nsDirectoryService::sXDGDesktop }, + { NS_UNIX_XDG_DOCUMENTS_DIR, &nsDirectoryService::sXDGDocuments }, + { NS_UNIX_XDG_DOWNLOAD_DIR, &nsDirectoryService::sXDGDownload }, + { NS_UNIX_XDG_MUSIC_DIR, &nsDirectoryService::sXDGMusic }, + { NS_UNIX_XDG_PICTURES_DIR, &nsDirectoryService::sXDGPictures }, + { NS_UNIX_XDG_PUBLIC_SHARE_DIR, &nsDirectoryService::sXDGPublicShare }, + { NS_UNIX_XDG_TEMPLATES_DIR, &nsDirectoryService::sXDGTemplates }, + { NS_UNIX_XDG_VIDEOS_DIR, &nsDirectoryService::sXDGVideos }, #elif defined (XP_OS2) { NS_OS_SYSTEM_DIR, &nsDirectoryService::sSystemDirectory }, { NS_OS2_DIR, &nsDirectoryService::sOS2Directory }, @@ -1150,9 +1168,47 @@ nsDirectoryService::GetFile(const char *prop, PRBool *persistent, nsIFile **_ret { rv = GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(localFile)); } - else if (inAtom == nsDirectoryService::sOS_DesktopDirectory) + else if (inAtom == nsDirectoryService::sXDGDesktop || + inAtom == nsDirectoryService::sOS_DesktopDirectory) { - rv = GetSpecialSystemDirectory(Unix_DesktopDirectory, getter_AddRefs(localFile)); + rv = GetSpecialSystemDirectory(Unix_XDG_Desktop, getter_AddRefs(localFile)); + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sXDGDocuments) + { + rv = GetSpecialSystemDirectory(Unix_XDG_Documents, getter_AddRefs(localFile)); + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sXDGDownload || + inAtom == nsDirectoryService::sDefaultDownloadDirectory) + { + rv = GetSpecialSystemDirectory(Unix_XDG_Download, getter_AddRefs(localFile)); + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sXDGMusic) + { + rv = GetSpecialSystemDirectory(Unix_XDG_Music, getter_AddRefs(localFile)); + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sXDGPictures) + { + rv = GetSpecialSystemDirectory(Unix_XDG_Pictures, getter_AddRefs(localFile)); + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sXDGPublicShare) + { + rv = GetSpecialSystemDirectory(Unix_XDG_PublicShare, getter_AddRefs(localFile)); + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sXDGTemplates) + { + rv = GetSpecialSystemDirectory(Unix_XDG_Templates, getter_AddRefs(localFile)); + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sXDGVideos) + { + rv = GetSpecialSystemDirectory(Unix_XDG_Videos, getter_AddRefs(localFile)); + *persistent = PR_FALSE; } #elif defined (XP_OS2) else if (inAtom == nsDirectoryService::sSystemDirectory) diff --git a/mozilla/xpcom/io/nsDirectoryService.h b/mozilla/xpcom/io/nsDirectoryService.h index 6c176cb6273..10979e5d6ea 100644 --- a/mozilla/xpcom/io/nsDirectoryService.h +++ b/mozilla/xpcom/io/nsDirectoryService.h @@ -160,6 +160,15 @@ public: #elif defined (XP_UNIX) static nsIAtom *sLocalDirectory; static nsIAtom *sLibDirectory; + static nsIAtom *sXDGDesktop; + static nsIAtom *sXDGDocuments; + static nsIAtom *sXDGDownload; + static nsIAtom *sXDGMusic; + static nsIAtom *sXDGPictures; + static nsIAtom *sXDGPublicShare; + static nsIAtom *sXDGTemplates; + static nsIAtom *sXDGVideos; + static nsIAtom *sDefaultDownloadDirectory; #elif defined (XP_OS2) static nsIAtom *sSystemDirectory; static nsIAtom *sOS2Directory; diff --git a/mozilla/xpcom/io/nsDirectoryServiceDefs.h b/mozilla/xpcom/io/nsDirectoryServiceDefs.h index e72717b6eab..1ec7f2772ef 100755 --- a/mozilla/xpcom/io/nsDirectoryServiceDefs.h +++ b/mozilla/xpcom/io/nsDirectoryServiceDefs.h @@ -186,6 +186,14 @@ #define NS_UNIX_LOCAL_DIR "Locl" #define NS_UNIX_LIB_DIR "LibD" #define NS_UNIX_HOME_DIR NS_OS_HOME_DIR + #define NS_UNIX_XDG_DESKTOP_DIR "XDGDesk" + #define NS_UNIX_XDG_DOCUMENTS_DIR "XDGDocs" + #define NS_UNIX_XDG_DOWNLOAD_DIR "XDGDwnld" + #define NS_UNIX_XDG_MUSIC_DIR "XDGMusic" + #define NS_UNIX_XDG_PICTURES_DIR "XDGPict" + #define NS_UNIX_XDG_PUBLIC_SHARE_DIR "XDGPubSh" + #define NS_UNIX_XDG_TEMPLATES_DIR "XDGTempl" + #define NS_UNIX_XDG_VIDEOS_DIR "XDGVids" #elif defined (XP_OS2) #define NS_OS2_DIR "OS2Dir" #define NS_OS2_HOME_DIR NS_OS_HOME_DIR