Module: wine
Branch: master
Commit: 78f5db2b511cb8b558f1198dbf640781e929de8f
URL: http://source.winehq.org/git/wine.git/?a=commit;h=78f5db2b511cb8b558f1198db…
Author: Lei Zhang <thestig(a)google.com>
Date: Tue Mar 11 13:51:43 2008 -0700
shell32: Use xdg well known directories for my_xxx folder symbolic links.
---
dlls/shell32/shellpath.c | 31 +++++++++++++++++++++++++++----
1 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index d3d3b75..dd7eb0c 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -46,6 +46,7 @@
#include "pidl.h"
#include "wine/unicode.h"
#include "shlwapi.h"
+#include "xdg.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
@@ -1993,8 +1994,9 @@ static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) {
* point directly to $HOME. We assume the user to be a unix hacker who does not
* want wine to create anything anywhere besides the .wine directory. So, if
* there already is a 'My Music' directory in $HOME, we symlink the 'My Music'
- * shell folder to it. But if not, we symlink it to $HOME directly. The same
- * holds fo 'My Pictures' and 'My Video'.
+ * shell folder to it. But if not, then we check XDG_MUSIC_DIR - "well known"
+ * directory, and try to link to that. If that fails, then we symlink to
+ * $HOME directly. The same holds fo 'My Pictures' and 'My Video'.
* - The Desktop shell folder is symlinked to '$HOME/Desktop', if that does
* exists and left alone if not.
* ('My Music',... above in fact means LoadString(IDS_MYMUSIC))
@@ -2003,6 +2005,7 @@ static void _SHCreateSymbolicLinks(void)
{
UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEO, IDS_MYMUSIC }, i;
int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC };
+ static const char * xdg_dirs[] = { "PICTURES", "VIDEOS", "MUSIC" };
WCHAR wszTempPath[MAX_PATH];
char szPersonalTarget[FILENAME_MAX], *pszPersonal;
char szMyStuffTarget[FILENAME_MAX], *pszMyStuff;
@@ -2010,6 +2013,8 @@ static void _SHCreateSymbolicLinks(void)
struct stat statFolder;
const char *pszHome;
HRESULT hr;
+ const unsigned int num = sizeof(xdg_dirs) / sizeof(xdg_dirs[0]);
+ char ** xdg_results = NULL;
/* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */
hr = SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL,
@@ -2018,6 +2023,8 @@ static void _SHCreateSymbolicLinks(void)
pszPersonal = wine_get_unix_file_name(wszTempPath);
if (!pszPersonal) return;
+ XDG_UserDirLookup(xdg_dirs, num, &xdg_results);
+
pszHome = getenv("HOME");
if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode)) {
strcpy(szPersonalTarget, pszHome);
@@ -2073,9 +2080,17 @@ static void _SHCreateSymbolicLinks(void)
}
else
{
- /* Else link to where 'My Documents' itself links to. */
rmdir(pszMyStuff);
- symlink(szPersonalTarget, pszMyStuff);
+ if (xdg_results && xdg_results[i])
+ {
+ /* the folder specified by XDG_XXX_DIR exists, link to it. */
+ symlink(xdg_results[i], pszMyStuff);
+ }
+ else
+ {
+ /* Else link to where 'My Documents' itself links to. */
+ symlink(szPersonalTarget, pszMyStuff);
+ }
}
HeapFree(GetProcessHeap(), 0, pszMyStuff);
}
@@ -2099,6 +2114,14 @@ static void _SHCreateSymbolicLinks(void)
HeapFree(GetProcessHeap(), 0, pszDesktop);
}
}
+
+ /* Free resources allocated by XDG_UserDirLookup() */
+ if (xdg_results)
+ {
+ for (i = 0; i < num; i++)
+ HeapFree(GetProcessHeap(), 0, xdg_results[i]);
+ HeapFree(GetProcessHeap(), 0, xdg_results);
+ }
}
/* Register the default values in the registry, as some apps seem to depend
Module: wine
Branch: master
Commit: f5ba1c21bea6a66455a478910575fcad9c9024a4
URL: http://source.winehq.org/git/wine.git/?a=commit;h=f5ba1c21bea6a66455a478910…
Author: Lei Zhang <thestig(a)google.com>
Date: Mon Mar 10 17:59:48 2008 -0700
shell32: Add xdg-user-dirs lookup code.
---
dlls/shell32/xdg.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++++
dlls/shell32/xdg.h | 1 +
2 files changed, 256 insertions(+), 0 deletions(-)
diff --git a/dlls/shell32/xdg.c b/dlls/shell32/xdg.c
index 3b1a1bc..b541aa7 100644
--- a/dlls/shell32/xdg.c
+++ b/dlls/shell32/xdg.c
@@ -16,10 +16,38 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *
+ * XDG_UserDirLookup() and helper functions are based on code from:
+ * http://www.freedesktop.org/wiki/Software/xdg-user-dirs
+ *
+ * Copyright (c) 2007 Red Hat, inc
+ *
+ * From the xdg-user-dirs license:
+ * 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.
*/
#include "config.h"
+#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@@ -712,3 +740,230 @@ char *XDG_GetStringValue(XDG_PARSED_FILE *file, const char *group_name, const ch
return NULL;
}
+
+/* Get the name of the xdg configuration file.
+ *
+ * [in] home_dir - $HOME
+ * [out] config_file - the name of the configuration file
+ */
+static HRESULT get_xdg_config_file(char * home_dir, char ** config_file)
+{
+ char *config_home;
+
+ config_home = getenv("XDG_CONFIG_HOME");
+ if (!config_home || !config_home[0])
+ {
+ *config_file = HeapAlloc(GetProcessHeap(), 0, strlen(home_dir) + strlen("/.config/user-dirs.dirs") + 1);
+ if (!*config_file)
+ return E_OUTOFMEMORY;
+
+ strcpy(*config_file, home_dir);
+ strcat(*config_file, "/.config/user-dirs.dirs");
+ }
+ else
+ {
+ *config_file = HeapAlloc(GetProcessHeap(), 0, strlen(config_home) + strlen("/user-dirs.dirs") + 1);
+ if (!*config_file)
+ return E_OUTOFMEMORY;
+
+ strcpy(*config_file, config_home);
+ strcat(*config_file, "/user-dirs.dirs");
+ }
+ return S_OK;
+}
+
+/* Parse the key in a line in the xdg-user-dir config file.
+ * i.e. XDG_PICTURES_DIR="$HOME/Pictures"
+ * ^ ^
+ *
+ * [in] xdg_dirs - array of xdg directories to look for
+ * [in] num_dirs - number of elements in xdg_dirs
+ * [in/out] p_ptr - pointer to where we are in the buffer
+ * Returns the index to xdg_dirs if we find the key, or -1 on error.
+ */
+static int parse_config1(const char ** xdg_dirs, const unsigned int num_dirs, char ** p_ptr)
+{
+ char *p;
+ int i;
+
+ p = *p_ptr;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (strncmp(p, "XDG_", 4))
+ return -1;
+
+ p += 4;
+ for (i = 0; i < num_dirs; i++)
+ {
+ if (!strncmp(p, xdg_dirs[i], strlen(xdg_dirs[i])))
+ {
+ p += strlen(xdg_dirs[i]);
+ break;
+ }
+ }
+ if (i == num_dirs)
+ return -1;
+ if (strncmp(p, "_DIR", 4))
+ return -1;
+ p += 4;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p != '=')
+ return -1;
+ p++;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p != '"')
+ return -1;
+ p++;
+
+ *p_ptr = p;
+ return i;
+}
+
+/* Parse the value in a line in the xdg-user-dir config file.
+ * i.e. XDG_PICTURES_DIR="$HOME/Pictures"
+ * ^ ^
+ *
+ * [in] p - pointer to the buffer
+ * [in] home_dir - $HOME
+ * [out] out_ptr - the directory name
+ */
+static HRESULT parse_config2(char * p, const char * home_dir, char ** out_ptr)
+{
+ BOOL relative;
+ char *out, *d;
+
+ relative = FALSE;
+
+ if (!strncmp(p, "$HOME/", 6))
+ {
+ p += 6;
+ relative = TRUE;
+ }
+ else if (*p != '/')
+ return E_FAIL;
+
+ if (relative)
+ {
+ out = HeapAlloc(GetProcessHeap(), 0, strlen(home_dir) + strlen(p) + 2);
+ if (!out)
+ return E_OUTOFMEMORY;
+
+ strcpy(out, home_dir);
+ strcat(out, "/");
+ }
+ else
+ {
+ out = HeapAlloc(GetProcessHeap(), 0, strlen(p) + 1);
+ if (!out)
+ return E_OUTOFMEMORY;
+ *out = 0;
+ }
+
+ d = out + strlen(out);
+ while (*p && *p != '"')
+ {
+ if ((*p == '\\') && (*(p + 1) != 0))
+ p++;
+ *d++ = *p++;
+ }
+ *d = 0;
+ *out_ptr = out;
+ return S_OK;
+}
+
+/* Parse part of a line in the xdg-user-dir config file.
+ * i.e. XDG_PICTURES_DIR="$HOME/Pictures"
+ * ^ ^
+ *
+ * The calling function is responsible for freeing all elements of out_ptr as
+ * well as out_ptr itself.
+ *
+ * [in] xdg_dirs - array of xdg directories to look for
+ * [in] num_dirs - number of elements in xdg_dirs
+ * [out] out_ptr - an array of the xdg directories names
+ */
+HRESULT XDG_UserDirLookup(const char ** xdg_dirs, const unsigned int num_dirs, char *** out_ptr)
+{
+ FILE *file;
+ char **out;
+ char *home_dir, *config_file;
+ char buffer[512];
+ int i, len;
+ HRESULT hr;
+
+ *out_ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_dirs * sizeof(char *));
+ out = *out_ptr;
+ if (!out)
+ return E_OUTOFMEMORY;
+
+ home_dir = getenv("HOME");
+ if (!home_dir)
+ {
+ hr = E_FAIL;
+ goto xdg_user_dir_lookup_error;
+ }
+
+ hr = get_xdg_config_file(home_dir, &config_file);
+ if (FAILED(hr))
+ goto xdg_user_dir_lookup_error;
+
+ file = fopen(config_file, "r");
+ HeapFree(GetProcessHeap(), 0, config_file);
+ if (!file)
+ {
+ hr = E_HANDLE;
+ goto xdg_user_dir_lookup_error;
+ }
+
+ while (fgets(buffer, sizeof(buffer), file))
+ {
+ int idx;
+ char *p;
+
+ /* Remove newline at end */
+ len = strlen(buffer);
+ if (len > 0 && buffer[len-1] == '\n')
+ buffer[len-1] = 0;
+
+ /* Parse the key */
+ p = buffer;
+ idx = parse_config1(xdg_dirs, num_dirs, &p);
+ if (idx < 0)
+ continue;
+ if (out[idx])
+ continue;
+
+ /* Parse the value */
+ hr = parse_config2(p, home_dir, &out[idx]);
+ if (FAILED(hr))
+ {
+ if (hr == E_OUTOFMEMORY)
+ goto xdg_user_dir_lookup_error;
+ continue;
+ }
+ }
+ hr = S_OK;
+
+ /* Remove entries for directories that do no exist */
+ for (i = 0; i < num_dirs; i++)
+ {
+ struct stat statFolder;
+
+ if (!out[i])
+ continue;
+ if (!stat(out[i], &statFolder) && S_ISDIR(statFolder.st_mode))
+ continue;
+ HeapFree(GetProcessHeap(), 0, out[i]);
+ out[i] = NULL;
+ }
+
+xdg_user_dir_lookup_error:
+ if (FAILED(hr))
+ {
+ for (i = 0; i < num_dirs; i++) HeapFree(GetProcessHeap(), 0, out[i]);
+ HeapFree(GetProcessHeap(), 0, out_ptr);
+ }
+ return hr;
+}
diff --git a/dlls/shell32/xdg.h b/dlls/shell32/xdg.h
index 6c083c6..9ae2872 100644
--- a/dlls/shell32/xdg.h
+++ b/dlls/shell32/xdg.h
@@ -47,5 +47,6 @@ HRESULT TRASH_UnpackItemID(LPCSHITEMID id, TRASH_ELEMENT *element, WIN32_FIND_DA
HRESULT TRASH_EnumItems(LPITEMIDLIST **pidls, int *count);
void TRASH_DisposeElement(TRASH_ELEMENT *element);
+HRESULT XDG_UserDirLookup(const char ** xdg_dirs, const unsigned int num_dirs, char *** out_ptr);
#endif /* ndef __XDG_H__ */