mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
Add impl of APIs to get user directories on Win32
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>
This commit is contained in:
parent
517368a377
commit
076f200689
@ -1131,6 +1131,7 @@ virFileBuildPath;
|
|||||||
virFileExists;
|
virFileExists;
|
||||||
virFileFindMountPoint;
|
virFileFindMountPoint;
|
||||||
virFileHasSuffix;
|
virFileHasSuffix;
|
||||||
|
virFileIsAbsPath;
|
||||||
virFileIsExecutable;
|
virFileIsExecutable;
|
||||||
virFileIsLink;
|
virFileIsLink;
|
||||||
virFileIsDir;
|
virFileIsDir;
|
||||||
@ -1145,6 +1146,7 @@ virFileReadLimFD;
|
|||||||
virFileResolveAllLinks;
|
virFileResolveAllLinks;
|
||||||
virFileResolveLink;
|
virFileResolveLink;
|
||||||
virFileSanitizePath;
|
virFileSanitizePath;
|
||||||
|
virFileSkipRoot;
|
||||||
virFileStripSuffix;
|
virFileStripSuffix;
|
||||||
virFileUnlock;
|
virFileUnlock;
|
||||||
virFileWaitForDevices;
|
virFileWaitForDevices;
|
||||||
|
251
src/util/util.c
251
src/util/util.c
@ -64,6 +64,11 @@
|
|||||||
# include <mntent.h>
|
# include <mntent.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# include <windows.h>
|
||||||
|
# include <shlobj.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "c-ctype.h"
|
#include "c-ctype.h"
|
||||||
#include "dirname.h"
|
#include "dirname.h"
|
||||||
#include "virterror_internal.h"
|
#include "virterror_internal.h"
|
||||||
@ -1411,6 +1416,77 @@ int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED,
|
|||||||
}
|
}
|
||||||
#endif /* WIN32 */
|
#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.
|
* Creates an absolute path for a potentially relative path.
|
||||||
* Return 0 if the path was not relative, or on success.
|
* Return 0 if the path was not relative, or on success.
|
||||||
@ -2542,8 +2618,153 @@ error:
|
|||||||
return -1;
|
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 *
|
char *
|
||||||
virGetUserDirectory(void)
|
virGetUserDirectory(void)
|
||||||
{
|
{
|
||||||
@ -2553,6 +2774,34 @@ virGetUserDirectory(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 *
|
char *
|
||||||
virGetUserName(uid_t uid ATTRIBUTE_UNUSED)
|
virGetUserName(uid_t uid ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
|
@ -120,8 +120,32 @@ char *virFileBuildPath(const char *dir,
|
|||||||
const char *name,
|
const char *name,
|
||||||
const char *ext) ATTRIBUTE_RETURN_CHECK;
|
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,
|
int virFileAbsPath(const char *path,
|
||||||
char **abspath) ATTRIBUTE_RETURN_CHECK;
|
char **abspath) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
const char *virFileSkipRoot(const char *path);
|
||||||
|
|
||||||
int virFileOpenTty(int *ttymaster,
|
int virFileOpenTty(int *ttymaster,
|
||||||
char **ttyName,
|
char **ttyName,
|
||||||
|
Loading…
Reference in New Issue
Block a user