[libvirt] [PATCH 0/2] Fix virGetUserXXXDirectory on Win32

The newly added APIs for getting user directories were causing a win32 build failure, due to export of non-existing APIs. The build fix is complicated enough that it needs review.

From: "Daniel P. Berrange" <berrange@redhat.com> Remove the uid param from virGetUserConfigDirectory, virGetUserCacheDirectory, virGetUserRuntimeDirectory, and virGetUserDirectory These functions were universally called with the results of getuid() or geteuid(). To make it practical to port to Win32, remove the uid parameter and hardcode geteuid() Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- daemon/libvirtd-config.c | 2 +- daemon/libvirtd.c | 12 ++++++------ src/libvirt.c | 2 +- src/network/bridge_driver.c | 5 ++--- src/nwfilter/nwfilter_driver.c | 3 +-- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_driver.c | 7 +++---- src/remote/remote_driver.c | 2 +- src/rpc/virnettlscontext.c | 2 +- src/secret/secret_driver.c | 3 +-- src/storage/storage_driver.c | 3 +-- src/uml/uml_driver.c | 5 ++--- src/util/util.c | 32 +++++++++++++------------------- src/util/util.h | 8 ++++---- src/util/virauth.c | 2 +- tools/virsh.c | 5 ++--- 16 files changed, 41 insertions(+), 54 deletions(-) diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c index 8b95969..6781e05 100644 --- a/daemon/libvirtd-config.c +++ b/daemon/libvirtd-config.c @@ -207,7 +207,7 @@ daemonConfigFilePath(bool privileged, char **configfile) } else { char *configdir = NULL; - if (!(configdir = virGetUserConfigDirectory(geteuid()))) + if (!(configdir = virGetUserConfigDirectory())) goto error; if (virAsprintf(configfile, "%s/libvirtd.conf", configdir) < 0) { diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 943fef4..c74cd43 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -242,7 +242,7 @@ daemonPidFilePath(bool privileged, char *rundir = NULL; mode_t old_umask; - if (!(rundir = virGetUserRuntimeDirectory(geteuid()))) + if (!(rundir = virGetUserRuntimeDirectory())) goto error; old_umask = umask(077); @@ -290,7 +290,7 @@ daemonUnixSocketPaths(struct daemonConfig *config, char *rundir = NULL; mode_t old_umask; - if (!(rundir = virGetUserRuntimeDirectory(geteuid()))) + if (!(rundir = virGetUserRuntimeDirectory())) goto error; old_umask = umask(077); @@ -634,7 +634,7 @@ daemonSetupLogging(struct daemonConfig *config, LOCALSTATEDIR) == -1) goto no_memory; } else { - char *logdir = virGetUserCacheDirectory(geteuid()); + char *logdir = virGetUserCacheDirectory(); mode_t old_umask; if (!logdir) @@ -783,7 +783,7 @@ static int migrateProfile(void) int ret = -1; mode_t old_umask; - if (!(home = virGetUserDirectory(geteuid()))) + if (!(home = virGetUserDirectory())) goto cleanup; if (virAsprintf(&old_base, "%s/.libvirt", home) < 0) { @@ -791,7 +791,7 @@ static int migrateProfile(void) } /* if the new directory is there or the old one is not: do nothing */ - if (!(config_dir = virGetUserConfigDirectory(geteuid()))) + if (!(config_dir = virGetUserConfigDirectory())) goto cleanup; if (!virFileIsDir(old_base) || virFileExists(config_dir)) { @@ -1112,7 +1112,7 @@ int main(int argc, char **argv) { if (privileged) { run_dir = strdup(LOCALSTATEDIR "/run/libvirt"); } else { - run_dir = virGetUserRuntimeDirectory(geteuid()); + run_dir = virGetUserRuntimeDirectory(); if (!run_dir) { VIR_ERROR(_("Can't determine user directory")); diff --git a/src/libvirt.c b/src/libvirt.c index 8900011..ba504c0 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -926,7 +926,7 @@ virConnectGetConfigFilePath(void) SYSCONFDIR) < 0) goto no_memory; } else { - char *userdir = virGetUserConfigDirectory(geteuid()); + char *userdir = virGetUserConfigDirectory(); if (!userdir) goto error; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index cea87c2..5f3132c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -260,7 +260,6 @@ networkAutostartConfigs(struct network_driver *driver) { */ static int networkStartup(int privileged) { - uid_t uid = geteuid(); char *base = NULL; if (VIR_ALLOC(driverState) < 0) @@ -280,7 +279,7 @@ networkStartup(int privileged) { if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL) goto out_of_memory; } else { - char *userdir = virGetUserCacheDirectory(uid); + char *userdir = virGetUserCacheDirectory(); if (!userdir) goto error; @@ -292,7 +291,7 @@ networkStartup(int privileged) { } VIR_FREE(userdir); - userdir = virGetUserConfigDirectory(uid); + userdir = virGetUserConfigDirectory(); if (virAsprintf(&base, "%s", userdir) == -1) { VIR_FREE(userdir); goto out_of_memory; diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c index 3d732ab..efb9182 100644 --- a/src/nwfilter/nwfilter_driver.c +++ b/src/nwfilter/nwfilter_driver.c @@ -86,8 +86,7 @@ nwfilterDriverStartup(int privileged) { if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL) goto out_of_memory; } else { - uid_t uid = geteuid(); - base = virGetUserConfigDirectory(uid); + base = virGetUserConfigDirectory(); if (!base) goto error; } diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index dc2a95f..5136fbc 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -977,7 +977,7 @@ openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, int ret; char *pubkey = NULL; char *pvtkey = NULL; - char *userhome = virGetUserDirectory(geteuid()); + char *userhome = virGetUserDirectory(); struct stat pvt_stat, pub_stat; if (userhome == NULL) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 39b27b1..1864959 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -523,11 +523,10 @@ qemudStartup(int privileged) { "%s/lib/libvirt/qemu/dump", LOCALSTATEDIR) == -1) goto out_of_memory; } else { - uid_t uid = geteuid(); char *rundir; char *cachedir; - cachedir = virGetUserCacheDirectory(uid); + cachedir = virGetUserCacheDirectory(); if (!cachedir) goto error; @@ -542,7 +541,7 @@ qemudStartup(int privileged) { } VIR_FREE(cachedir); - rundir = virGetUserRuntimeDirectory(uid); + rundir = virGetUserRuntimeDirectory(); if (!rundir) goto error; if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", rundir) == -1) { @@ -551,7 +550,7 @@ qemudStartup(int privileged) { } VIR_FREE(rundir); - base = virGetUserConfigDirectory(uid); + base = virGetUserConfigDirectory(); if (!base) goto error; if (virAsprintf(&qemu_driver->libDir, "%s/qemu/lib", base) == -1) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 5c87561..299cd69 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -578,7 +578,7 @@ doRemoteOpen (virConnectPtr conn, case trans_unix: if (!sockname) { if (flags & VIR_DRV_OPEN_REMOTE_USER) { - char *userdir = virGetUserRuntimeDirectory(getuid()); + char *userdir = virGetUserRuntimeDirectory(); if (!userdir) goto failed; diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index 7440c7a..bf92088 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -774,7 +774,7 @@ static int virNetTLSContextLocateCredentials(const char *pkipath, /* Check to see if $HOME/.pki contains at least one of the * files and if so, use that */ - userdir = virGetUserDirectory(getuid()); + userdir = virGetUserDirectory(); if (!userdir) goto out_of_memory; diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index f3fcce2..49ca29b 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -1012,8 +1012,7 @@ secretDriverStartup(int privileged) if (base == NULL) goto out_of_memory; } else { - uid_t uid = geteuid(); - base = virGetUserConfigDirectory(uid); + base = virGetUserConfigDirectory(); if (!base) goto error; } diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index fd762c0..88f3809 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -145,8 +145,7 @@ storageDriverStartup(int privileged) if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL) goto out_of_memory; } else { - uid_t uid = geteuid(); - base = virGetUserConfigDirectory(uid); + base = virGetUserConfigDirectory(); if (!base) goto error; } diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 65f9cbc..219246d 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -392,7 +392,6 @@ cleanup: static int umlStartup(int privileged) { - uid_t uid = geteuid(); char *base = NULL; char *userdir = NULL; @@ -418,7 +417,7 @@ umlStartup(int privileged) if (!uml_driver->domainEventState) goto error; - userdir = virGetUserDirectory(uid); + userdir = virGetUserDirectory(); if (!userdir) goto error; @@ -434,7 +433,7 @@ umlStartup(int privileged) "%s/run/libvirt/uml-guest", LOCALSTATEDIR) == -1) goto out_of_memory; } else { - base = virGetUserConfigDirectory(uid); + base = virGetUserConfigDirectory(); if (!base) goto error; diff --git a/src/util/util.c b/src/util/util.c index ee48504..afe5a8c 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -2305,19 +2305,16 @@ static char *virGetGroupEnt(gid_t gid) return ret; } -char *virGetUserDirectory(uid_t uid) +char *virGetUserDirectory() { - return virGetUserEnt(uid, VIR_USER_ENT_DIRECTORY); + return virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); } -static char *virGetXDGDirectory(uid_t uid, const char *xdgenvname, const char *xdgdefdir) +static char *virGetXDGDirectory(const char *xdgenvname, const char *xdgdefdir) { - const char *path = NULL; + const char *path = getenv(xdgenvname); char *ret = NULL; - char *home = virGetUserEnt(uid, VIR_USER_ENT_DIRECTORY); - - if (uid == getuid()) - path = getenv(xdgenvname); + char *home = virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); if (path && path[0]) { if (virAsprintf(&ret, "%s/libvirt", path) < 0) @@ -2335,25 +2332,22 @@ static char *virGetXDGDirectory(uid_t uid, const char *xdgenvname, const char *x goto cleanup; } -char *virGetUserConfigDirectory(uid_t uid) +char *virGetUserConfigDirectory(void) { - return virGetXDGDirectory(uid, "XDG_CONFIG_HOME", ".config"); + return virGetXDGDirectory("XDG_CONFIG_HOME", ".config"); } -char *virGetUserCacheDirectory(uid_t uid) +char *virGetUserCacheDirectory(void) { - return virGetXDGDirectory(uid, "XDG_CACHE_HOME", ".cache"); + return virGetXDGDirectory("XDG_CACHE_HOME", ".cache"); } -char *virGetUserRuntimeDirectory(uid_t uid) +char *virGetUserRuntimeDirectory(void) { - const char *path = NULL; - - if (uid == getuid ()) - path = getenv("XDG_RUNTIME_DIR"); + const char *path = getenv("XDG_RUNTIME_DIR"); if (!path || !path[0]) { - return virGetUserCacheDirectory(uid); + return virGetUserCacheDirectory(); } else { char *ret; @@ -2551,7 +2545,7 @@ error: #else /* HAVE_GETPWUID_R */ char * -virGetUserDirectory(uid_t uid ATTRIBUTE_UNUSED) +virGetUserDirectory(void) { virUtilError(VIR_ERR_INTERNAL_ERROR, "%s", _("virGetUserDirectory is not available")); diff --git a/src/util/util.h b/src/util/util.h index f5fa876..b45f2b9 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -228,10 +228,10 @@ char *virGetHostname(virConnectPtr conn); int virKillProcess(pid_t pid, int sig); -char *virGetUserDirectory(uid_t uid); -char *virGetUserConfigDirectory(uid_t uid); -char *virGetUserCacheDirectory(uid_t uid); -char *virGetUserRuntimeDirectory(uid_t uid); +char *virGetUserDirectory(void); +char *virGetUserConfigDirectory(void); +char *virGetUserCacheDirectory(void); +char *virGetUserRuntimeDirectory(void); char *virGetUserName(uid_t uid); char *virGetGroupName(gid_t gid); int virGetUserID(const char *name, diff --git a/src/util/virauth.c b/src/util/virauth.c index 92ecb7c..5412ca6 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -65,7 +65,7 @@ int virAuthGetConfigFilePath(virConnectPtr conn, } } - if (!(userdir = virGetUserConfigDirectory(geteuid()))) + if (!(userdir = virGetUserConfigDirectory())) goto cleanup; if (virAsprintf(path, "%s/auth.conf", userdir) < 0) diff --git a/tools/virsh.c b/tools/virsh.c index ffe6ed2..1cfa004 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -15673,8 +15673,7 @@ cmdCd(vshControl *ctl, const vshCmd *cmd) } if (vshCommandOptString(cmd, "dir", &dir) <= 0) { - uid_t uid = geteuid(); - dir = dir_malloced = virGetUserDirectory(uid); + dir = dir_malloced = virGetUserDirectory(); } if (!dir) dir = "/"; @@ -19871,7 +19870,7 @@ vshReadlineInit(vshControl *ctl) stifle_history(500); /* Prepare to read/write history from/to the $XDG_CACHE_HOME/virsh/history file */ - userdir = virGetUserCacheDirectory(getuid()); + userdir = virGetUserCacheDirectory(); if (userdir == NULL) { vshError(ctl, "%s", _("Could not determine home directory")); -- 1.7.7.6

On 05/24/2012 07:44 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Remove the uid param from virGetUserConfigDirectory, virGetUserCacheDirectory, virGetUserRuntimeDirectory, and virGetUserDirectory
These functions were universally called with the results of getuid() or geteuid(). To make it practical to port to Win32, remove the uid parameter and hardcode geteuid()
Confirmed that we were universally using a current id, and that blindly using geteuid() is the best approach. ACK.
+++ b/src/remote/remote_driver.c @@ -578,7 +578,7 @@ doRemoteOpen (virConnectPtr conn, case trans_unix: if (!sockname) { if (flags & VIR_DRV_OPEN_REMOTE_USER) { - char *userdir = virGetUserRuntimeDirectory(getuid()); + char *userdir = virGetUserRuntimeDirectory();
There's probably a subtle difference for the effects if getuid() and geteuid() differed in value if you ever got here while linking to libvirt.so from a setuid binary, but I think that is unlikely enough and that our switch to geteuid() feels safer anyways. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Thu, May 24, 2012 at 08:18:55AM -0600, Eric Blake wrote:
On 05/24/2012 07:44 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Remove the uid param from virGetUserConfigDirectory, virGetUserCacheDirectory, virGetUserRuntimeDirectory, and virGetUserDirectory
These functions were universally called with the results of getuid() or geteuid(). To make it practical to port to Win32, remove the uid parameter and hardcode geteuid()
Confirmed that we were universally using a current id, and that blindly using geteuid() is the best approach.
ACK.
+++ b/src/remote/remote_driver.c @@ -578,7 +578,7 @@ doRemoteOpen (virConnectPtr conn, case trans_unix: if (!sockname) { if (flags & VIR_DRV_OPEN_REMOTE_USER) { - char *userdir = virGetUserRuntimeDirectory(getuid()); + char *userdir = virGetUserRuntimeDirectory();
There's probably a subtle difference for the effects if getuid() and geteuid() differed in value if you ever got here while linking to libvirt.so from a setuid binary, but I think that is unlikely enough and that our switch to geteuid() feels safer anyways.
And if the difference did matter, I'm fairly sure that our existing code would be broken, since the choice is getuid() vs geteuid() in our code appears to be completely random. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

From: "Daniel P. Berrange" <berrange@redhat.com> Add an impl of +virGetUserRuntimeDirectory, virGetUserCacheDirectory virGetUserConfigDirectory and virGetUserDirectory for Win32 platform. Also create stubs for non-Win32 platforms which lack getpwuid_r() In adding these two helpers were added virFileIsAbsPath and virFileSkipRoot, along with some macros VIR_FILE_DIR_SEPARATOR, VIR_FILE_DIR_SEPARATOR_S, VIR_FILE_IS_DIR_SEPARATOR, VIR_FILE_PATH_SEPARATOR, VIR_FILE_PATH_SEPARATOR_S All this code was adapted from GLib2 under terms of LGPLv2+ license. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/libvirt_private.syms | 2 + src/util/util.c | 253 +++++++++++++++++++++++++++++++++++++++++++++- src/util/util.h | 24 +++++ 3 files changed, 277 insertions(+), 2 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3bf0794..c6fe0e3 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1131,6 +1131,7 @@ virFileBuildPath; virFileExists; virFileFindMountPoint; virFileHasSuffix; +virFileIsAbsPath; virFileIsExecutable; virFileIsLink; virFileIsDir; @@ -1145,6 +1146,7 @@ virFileReadLimFD; virFileResolveAllLinks; virFileResolveLink; virFileSanitizePath; +virFileSkipRoot; virFileStripSuffix; virFileUnlock; virFileWaitForDevices; diff --git a/src/util/util.c b/src/util/util.c index afe5a8c..28a4fe7 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -64,6 +64,11 @@ # include <mntent.h> #endif +#ifdef WIN32 +# include <windows.h> +# include <shlobj.h> +#endif + #include "c-ctype.h" #include "dirname.h" #include "virterror_internal.h" @@ -1411,6 +1416,77 @@ int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED, } #endif /* WIN32 */ +bool virFileIsAbsPath(const char *path) +{ + if (!path) + return false; + + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + return true; + +#ifdef WIN32 + if (c_isalpha(path[0]) && + path[1] == ':' && + VIR_FILE_IS_DIR_SEPARATOR(path[2])) + return true; +#endif + + return false; +} + + +const char *virFileSkipRoot(const char *path) +{ +#ifdef WIN32 + /* Skip \\server\share or //server/share */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0]) && + VIR_FILE_IS_DIR_SEPARATOR(path[1]) && + path[2] && + !VIR_FILE_IS_DIR_SEPARATOR(path[2])) + { + const char *p = strchr(path + 2, VIR_FILE_DIR_SEPARATOR); + const char *q = strchr(path + 2, '/'); + + if (p == NULL || (q != NULL && q < p)) + p = q; + + if (p && p > path + 2 && p[1]) { + path = p + 1; + + while (path[0] && + !VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + /* Possibly skip a backslash after the share name */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + return path; + } + } +#endif + + /* Skip initial slashes */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) { + while (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + return path; + } + +#ifdef WIN32 + /* Skip X:\ */ + if (c_isalpha(path[0]) && + path[1] == ':' && + VIR_FILE_IS_DIR_SEPARATOR(path[2])) + return path + 3; +#endif + + return path; +} + + + /* * Creates an absolute path for a potentially relative path. * Return 0 if the path was not relative, or on success. @@ -2305,7 +2381,7 @@ static char *virGetGroupEnt(gid_t gid) return ret; } -char *virGetUserDirectory() +char *virGetUserDirectory(void) { return virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); } @@ -2542,11 +2618,156 @@ error: return -1; } -#else /* HAVE_GETPWUID_R */ +#else /* ! HAVE_GETPWUID_R */ + +# ifdef WIN32 +/* These methods are adapted from GLib2 under terms of LGPLv2+ */ +static int +virGetWin32SpecialFolder(int csidl, char **path) +{ + char buf[MAX_PATH+1]; + LPITEMIDLIST pidl = NULL; + int ret = 0; + + *path = NULL; + + if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) == S_OK) { + if (SHGetPathFromIDList(pidl, buf)) { + if (!(*path = strdup(buf))) { + virReportOOMError(); + ret = -1; + } + } + CoTaskMemFree(pidl); + } + return ret; +} + +static int +virGetWin32DirectoryRoot(char **path) +{ + char windowsdir[MAX_PATH]; + int ret = 0; + + *path = NULL; + + if (GetWindowsDirectory(windowsdir, ARRAY_CARDINALITY(windowsdir))) + { + const char *tmp; + /* Usually X:\Windows, but in terminal server environments + * might be an UNC path, AFAIK. + */ + tmp = virFileSkipRoot(windowsdir); + if (VIR_FILE_IS_DIR_SEPARATOR(tmp[-1]) && + tmp[-2] != ':') + tmp--; + + windowsdir[tmp - windowsdir] = '\0'; + } else { + strcpy(windowsdir, "C:\\"); + } + + if (!(*path = strdup(windowsdir))) { + virReportOOMError(); + ret = -1; + } + + return ret; +} + + char * virGetUserDirectory(void) { + const char *dir; + char *ret; + + dir = getenv("HOME"); + + /* Only believe HOME if it is an absolute path and exists */ + if (dir) { + if (!virFileIsAbsPath(dir) || + !virFileExists(dir)) + dir = NULL; + } + + /* In case HOME is Unix-style (it happens), convert it to + * Windows style. + */ + if (dir) { + char *p; + while ((p = strchr (dir, '/')) != NULL) + *p = '\\'; + } + + if (!dir) + /* USERPROFILE is probably the closest equivalent to $HOME? */ + dir = getenv("USERPROFILE"); + + if (dir) { + if (!(ret = strdup(dir))) { + virReportOOMError(); + return NULL; + } + } + + if (!ret && + virGetWin32SpecialFolder(CSIDL_PROFILE, &ret) < 0) + return NULL; + + if (!ret && + virGetWin32DirectoryRoot(&ret) < 0) + return NULL; + + if (!ret) { + virUtilError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine home directory")); + return NULL; + } + + return ret; +} + +char * +virGetUserConfigDirectory(void) +{ + char *ret; + if (virGetWin32SpecialFolder(CSIDL_LOCAL_APPDATA, &ret) < 0) + return NULL; + + if (!ret) { + virUtilError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine config directory")); + return NULL; + } + return ret; +} + +char * +virGetUserCacheDirectory(void) +{ + char *ret; + if (virGetWin32SpecialFolder(CSIDL_INTERNET_CACHE, &ret) < 0) + return NULL; + + if (!ret) { + virUtilError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine config directory")); + return NULL; + } + return ret; +} + +char * +virGetUserRuntimeDirectory(void) +{ + return virGetUserCacheDirectory(); +} +# else /* !HAVE_GETPWUID_R && !WIN32 */ +char * +virGetUserDirectory(void) +{ virUtilError(VIR_ERR_INTERNAL_ERROR, "%s", _("virGetUserDirectory is not available")); @@ -2554,6 +2775,34 @@ virGetUserDirectory(void) } char * +virGetUserConfigDirectory(void) +{ + virUtilError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserConfigDirectory is not available")); + + return NULL; +} + +char * +virGetUserCacheDirectory(void) +{ + virUtilError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserCacheDirectory is not available")); + + return NULL; +} + +char * +virGetUserRuntimeDirectory(void) +{ + virUtilError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserRuntimeDirectory is not available")); + + return NULL; +} +# endif /* ! HAVE_GETPWUID_R && ! WIN32 */ + +char * virGetUserName(uid_t uid ATTRIBUTE_UNUSED) { virUtilError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/util/util.h b/src/util/util.h index b45f2b9..0af7e6d 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -120,8 +120,32 @@ char *virFileBuildPath(const char *dir, const char *name, const char *ext) ATTRIBUTE_RETURN_CHECK; + +# ifdef WIN32 +/* On Win32, the canonical directory separator is the backslash, and + * the search path separator is the semicolon. Note that also the + * (forward) slash works as directory separator. + */ +# define VIR_FILE_DIR_SEPARATOR '\\' +# define VIR_FILE_DIR_SEPARATOR_S "\\" +# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR || (c) == '/') +# define VIR_FILE_PATH_SEPARATOR ';' +# define VIR_FILE_PATH_SEPARATOR_S ";" + +# else /* !WIN32 */ + +# define VIR_FILE_DIR_SEPARATOR '/' +# define VIR_FILE_DIR_SEPARATOR_S "/" +# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR) +# define VIR_FILE_PATH_SEPARATOR ':' +# define VIR_FILE_PATH_SEPARATOR_S ":" + +# endif /* !WIN32 */ + +bool virFileIsAbsPath(const char *path); int virFileAbsPath(const char *path, char **abspath) ATTRIBUTE_RETURN_CHECK; +const char *virFileSkipRoot(const char *path); int virFileOpenTty(int *ttymaster, char **ttyName, -- 1.7.7.6

On 05/24/2012 07:44 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Add an impl of +virGetUserRuntimeDirectory, virGetUserCacheDirectory virGetUserConfigDirectory and virGetUserDirectory for Win32 platform. Also create stubs for non-Win32 platforms which lack getpwuid_r()
In adding these two helpers were added virFileIsAbsPath and virFileSkipRoot, along with some macros VIR_FILE_DIR_SEPARATOR, VIR_FILE_DIR_SEPARATOR_S, VIR_FILE_IS_DIR_SEPARATOR, VIR_FILE_PATH_SEPARATOR, VIR_FILE_PATH_SEPARATOR_S
All this code was adapted from GLib2 under terms of LGPLv2+ license.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/libvirt_private.syms | 2 + src/util/util.c | 253 +++++++++++++++++++++++++++++++++++++++++++++- src/util/util.h | 24 +++++ 3 files changed, 277 insertions(+), 2 deletions(-)
@@ -2305,7 +2381,7 @@ static char *virGetGroupEnt(gid_t gid) return ret; }
-char *virGetUserDirectory() +char *virGetUserDirectory(void)
This particular hunk should be squashed into 1/2. ACK; the code looked generally reasonable. I note that on WIN32, it didn't treat 'c:file' as absolute (it's anchored to the C drive, but is relative to the current directory of that drive, and yes, Windows really does have 26 current directories, one per drive letter, in addition to the global current working directory). But while this might mess up unusual situations, I'm not sure it is worth worrying about, and this addition is a strict improvement over the previous behavior of no support at all. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Daniel P. Berrange
-
Eric Blake