|
Packit Service |
3749ba |
/*
|
|
Packit Service |
3749ba |
* Copyright (c) 2005 Stefan Walter
|
|
Packit Service |
3749ba |
* Copyright (c) 2011 Collabora Ltd.
|
|
Packit Service |
3749ba |
* Copyright (c) 2013 Red Hat Inc.
|
|
Packit Service |
3749ba |
*
|
|
Packit Service |
3749ba |
* Redistribution and use in source and binary forms, with or without
|
|
Packit Service |
3749ba |
* modification, are permitted provided that the following conditions
|
|
Packit Service |
3749ba |
* are met:
|
|
Packit Service |
3749ba |
*
|
|
Packit Service |
3749ba |
* * Redistributions of source code must retain the above
|
|
Packit Service |
3749ba |
* copyright notice, this list of conditions and the
|
|
Packit Service |
3749ba |
* following disclaimer.
|
|
Packit Service |
3749ba |
* * Redistributions in binary form must reproduce the
|
|
Packit Service |
3749ba |
* above copyright notice, this list of conditions and
|
|
Packit Service |
3749ba |
* the following disclaimer in the documentation and/or
|
|
Packit Service |
3749ba |
* other materials provided with the distribution.
|
|
Packit Service |
3749ba |
* * The names of contributors to this software may not be
|
|
Packit Service |
3749ba |
* used to endorse or promote products derived from this
|
|
Packit Service |
3749ba |
* software without specific prior written permission.
|
|
Packit Service |
3749ba |
*
|
|
Packit Service |
3749ba |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit Service |
3749ba |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit Service |
3749ba |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
Packit Service |
3749ba |
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
Packit Service |
3749ba |
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
Packit Service |
3749ba |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
Packit Service |
3749ba |
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
Packit Service |
3749ba |
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
Packit Service |
3749ba |
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
Packit Service |
3749ba |
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
Packit Service |
3749ba |
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
Packit Service |
3749ba |
* DAMAGE.
|
|
Packit Service |
3749ba |
*
|
|
Packit Service |
3749ba |
*
|
|
Packit Service |
3749ba |
* CONTRIBUTORS
|
|
Packit Service |
3749ba |
* Stef Walter <stefw@redhat.com>
|
|
Packit Service |
3749ba |
*/
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
#include "config.h"
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
#include "buffer.h"
|
|
Packit Service |
3749ba |
#include "debug.h"
|
|
Packit Service |
3749ba |
#include "message.h"
|
|
Packit Service |
3749ba |
#include "path.h"
|
|
Packit Service |
3749ba |
#include "url.h"
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
#include <assert.h>
|
|
Packit Service |
3749ba |
#include <errno.h>
|
|
Packit Service |
3749ba |
#include <stdarg.h>
|
|
Packit Service |
3749ba |
#include <stdlib.h>
|
|
Packit Service |
3749ba |
#include <string.h>
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
#ifdef OS_UNIX
|
|
Packit Service |
3749ba |
#include <pwd.h>
|
|
Packit Service |
3749ba |
#include <unistd.h>
|
|
Packit Service |
3749ba |
#endif
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
#ifdef OS_WIN32
|
|
Packit Service |
3749ba |
#include <shlobj.h>
|
|
Packit Service |
3749ba |
#endif
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
char *
|
|
Packit Service |
3749ba |
p11_path_base (const char *path)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
#ifdef OS_WIN32
|
|
Packit Service |
3749ba |
const char *delims = "/\\";
|
|
Packit Service |
3749ba |
#else
|
|
Packit Service |
3749ba |
const char *delims = "/";
|
|
Packit Service |
3749ba |
#endif
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
const char *end;
|
|
Packit Service |
3749ba |
const char *beg;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return_val_if_fail (path != NULL, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
/* Any trailing slashes */
|
|
Packit Service |
3749ba |
end = path + strlen (path);
|
|
Packit Service |
3749ba |
while (end != path) {
|
|
Packit Service |
3749ba |
if (!strchr (delims, *(end - 1)))
|
|
Packit Service |
3749ba |
break;
|
|
Packit Service |
3749ba |
end--;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
/* Find the last slash after those */
|
|
Packit Service |
3749ba |
beg = end;
|
|
Packit Service |
3749ba |
while (beg != path) {
|
|
Packit Service |
3749ba |
if (strchr (delims, *(beg - 1)))
|
|
Packit Service |
3749ba |
break;
|
|
Packit Service |
3749ba |
beg--;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return strndup (beg, end - beg);
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
static inline bool
|
|
Packit Service |
a29e5c |
is_path_component_or_null (char ch)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
a29e5c |
return (ch == '\0' || ch == '/'
|
|
Packit Service |
3749ba |
#ifdef OS_WIN32
|
|
Packit Service |
3749ba |
|| ch == '\\'
|
|
Packit Service |
3749ba |
#endif
|
|
Packit Service |
3749ba |
);
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
static char *
|
|
Packit Service |
3749ba |
expand_homedir (const char *remainder)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
const char *env;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
if (getauxval (AT_SECURE)) {
|
|
Packit Service |
3749ba |
errno = EPERM;
|
|
Packit Service |
3749ba |
return NULL;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
a29e5c |
while (remainder[0] && is_path_component_or_null (remainder[0]))
|
|
Packit Service |
3749ba |
remainder++;
|
|
Packit Service |
3749ba |
if (remainder[0] == '\0')
|
|
Packit Service |
3749ba |
remainder = NULL;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
/* Expand $XDG_CONFIG_HOME */
|
|
Packit Service |
3749ba |
if (remainder != NULL &&
|
|
Packit Service |
3749ba |
strncmp (remainder, ".config", 7) == 0 &&
|
|
Packit Service |
a29e5c |
is_path_component_or_null (remainder[7])) {
|
|
Packit Service |
3749ba |
env = getenv ("XDG_CONFIG_HOME");
|
|
Packit Service |
3749ba |
if (env && env[0])
|
|
Packit Service |
3749ba |
return p11_path_build (env, remainder + 8, NULL);
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
env = getenv ("HOME");
|
|
Packit Service |
3749ba |
if (env && env[0]) {
|
|
Packit Service |
3749ba |
return p11_path_build (env, remainder, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
} else {
|
|
Packit Service |
3749ba |
#ifdef OS_UNIX
|
|
Packit Service |
3749ba |
char buf[1024];
|
|
Packit Service |
3749ba |
struct passwd pws;
|
|
Packit Service |
3749ba |
struct passwd *pwd = NULL;
|
|
Packit Service |
3749ba |
int error;
|
|
Packit Service |
3749ba |
int ret;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
errno = 0;
|
|
Packit Service |
3749ba |
ret = getpwuid_r (getuid (), &pws, buf, sizeof (buf), &pwd);
|
|
Packit Service |
3749ba |
if (pwd == NULL) {
|
|
Packit Service |
3749ba |
if (ret == 0)
|
|
Packit Service |
3749ba |
error = ESRCH;
|
|
Packit Service |
3749ba |
else
|
|
Packit Service |
3749ba |
error = errno;
|
|
Packit Service |
3749ba |
p11_message_err (error, "couldn't lookup home directory for user %d", getuid ());
|
|
Packit Service |
3749ba |
errno = error;
|
|
Packit Service |
3749ba |
return NULL;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return p11_path_build (pwd->pw_dir, remainder, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
#else /* OS_WIN32 */
|
|
Packit Service |
3749ba |
char directory[MAX_PATH + 1];
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
if (!SHGetSpecialFolderPathA (NULL, directory, CSIDL_PROFILE, TRUE)) {
|
|
Packit Service |
3749ba |
p11_message ("couldn't lookup home directory for user");
|
|
Packit Service |
3749ba |
errno = ENOTDIR;
|
|
Packit Service |
3749ba |
return NULL;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return p11_path_build (directory, remainder, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
#endif /* OS_WIN32 */
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
char *
|
|
Packit Service |
3749ba |
p11_path_expand (const char *path)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
return_val_if_fail (path != NULL, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
if (strncmp (path, "~", 1) == 0 &&
|
|
Packit Service |
a29e5c |
is_path_component_or_null (path[1])) {
|
|
Packit Service |
3749ba |
return expand_homedir (path + 1);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
} else {
|
|
Packit Service |
3749ba |
return strdup (path);
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
bool
|
|
Packit Service |
3749ba |
p11_path_absolute (const char *path)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
return_val_if_fail (path != NULL, false);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return (path[0] == '/')
|
|
Packit Service |
3749ba |
#ifdef OS_WIN32
|
|
Packit Service |
3749ba |
|| (path[0] != '\0' && path[1] == ':' && path[2] == '\\')
|
|
Packit Service |
3749ba |
#endif
|
|
Packit Service |
3749ba |
;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
char *
|
|
Packit Service |
3749ba |
p11_path_build (const char *path,
|
|
Packit Service |
3749ba |
...)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
#ifdef OS_WIN32
|
|
Packit Service |
3749ba |
const char delim = '\\';
|
|
Packit Service |
3749ba |
#else
|
|
Packit Service |
3749ba |
const char delim = '/';
|
|
Packit Service |
3749ba |
#endif
|
|
Packit Service |
3749ba |
const char *first = path;
|
|
Packit Service |
3749ba |
char *built;
|
|
Packit Service |
3749ba |
size_t len;
|
|
Packit Service |
3749ba |
size_t at;
|
|
Packit Service |
3749ba |
size_t num;
|
|
Packit Service |
3749ba |
size_t until;
|
|
Packit Service |
3749ba |
va_list va;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return_val_if_fail (path != NULL, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
len = 1;
|
|
Packit Service |
3749ba |
va_start (va, path);
|
|
Packit Service |
3749ba |
while (path != NULL) {
|
|
Packit Service |
3749ba |
size_t old_len = len;
|
|
Packit Service |
3749ba |
len += strlen (path) + 1;
|
|
Packit Service |
3749ba |
if (len < old_len) {
|
|
Packit Service |
3749ba |
va_end (va);
|
|
Packit Service |
3749ba |
return_val_if_reached (NULL);
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
path = va_arg (va, const char *);
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
va_end (va);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
built = malloc (len + 1);
|
|
Packit Service |
3749ba |
return_val_if_fail (built != NULL, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
at = 0;
|
|
Packit Service |
3749ba |
path = first;
|
|
Packit Service |
3749ba |
va_start (va, path);
|
|
Packit Service |
3749ba |
while (path != NULL) {
|
|
Packit Service |
3749ba |
num = strlen (path);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
/* Trim end of the path */
|
|
Packit Service |
3749ba |
until = (at > 0) ? 0 : 1;
|
|
Packit Service |
a29e5c |
while (num > until && is_path_component_or_null (path[num - 1]))
|
|
Packit Service |
3749ba |
num--;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
if (at != 0) {
|
|
Packit Service |
a29e5c |
if (num == 0)
|
|
Packit Service |
3749ba |
continue;
|
|
Packit Service |
a29e5c |
built[at++] = delim;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
assert (at + num < len);
|
|
Packit Service |
3749ba |
memcpy (built + at, path, num);
|
|
Packit Service |
3749ba |
at += num;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
path = va_arg (va, const char *);
|
|
Packit Service |
a29e5c |
|
|
Packit Service |
a29e5c |
/* Trim beginning of path */
|
|
Packit Service |
a29e5c |
while (path && path[0] && is_path_component_or_null (path[0]))
|
|
Packit Service |
a29e5c |
path++;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
va_end (va);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
assert (at < len);
|
|
Packit Service |
3749ba |
built[at] = '\0';
|
|
Packit Service |
3749ba |
return built;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
char *
|
|
Packit Service |
3749ba |
p11_path_parent (const char *path)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
const char *e;
|
|
Packit Service |
3749ba |
char *parent;
|
|
Packit Service |
3749ba |
bool had = false;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return_val_if_fail (path != NULL, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
/* Find the end of the last component */
|
|
Packit Service |
3749ba |
e = path + strlen (path);
|
|
Packit Service |
a29e5c |
while (e != path && is_path_component_or_null (*e))
|
|
Packit Service |
3749ba |
e--;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
/* Find the beginning of the last component */
|
|
Packit Service |
a29e5c |
while (e != path && !is_path_component_or_null (*e)) {
|
|
Packit Service |
3749ba |
had = true;
|
|
Packit Service |
3749ba |
e--;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
/* Find the end of the last component */
|
|
Packit Service |
a29e5c |
while (e != path && is_path_component_or_null (*e))
|
|
Packit Service |
3749ba |
e--;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
if (e == path) {
|
|
Packit Service |
3749ba |
if (!had)
|
|
Packit Service |
3749ba |
return NULL;
|
|
Packit Service |
3749ba |
parent = strdup ("/");
|
|
Packit Service |
3749ba |
} else {
|
|
Packit Service |
3749ba |
parent = strndup (path, (e - path) + 1);
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return_val_if_fail (parent != NULL, NULL);
|
|
Packit Service |
3749ba |
return parent;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
bool
|
|
Packit Service |
3749ba |
p11_path_prefix (const char *string,
|
|
Packit Service |
3749ba |
const char *prefix)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
int a, b;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return_val_if_fail (string != NULL, false);
|
|
Packit Service |
3749ba |
return_val_if_fail (prefix != NULL, false);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
a = strlen (string);
|
|
Packit Service |
3749ba |
b = strlen (prefix);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return a > b &&
|
|
Packit Service |
3749ba |
strncmp (string, prefix, b) == 0 &&
|
|
Packit Service |
a29e5c |
is_path_component_or_null (string[b]);
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
void
|
|
Packit Service |
3749ba |
p11_path_canon (char *name)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
static const char *VALID =
|
|
Packit Service |
3749ba |
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_";
|
|
Packit Service |
3749ba |
int i;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return_if_fail (name != NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
for (i = 0; name[i] != '\0'; i++) {
|
|
Packit Service |
3749ba |
if (strchr (VALID, name[i]) == NULL)
|
|
Packit Service |
3749ba |
name[i] = '_';
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
char *
|
|
Packit Service |
3749ba |
p11_path_encode (const char *path)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
static const char *VALID =
|
|
Packit Service |
3749ba |
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/\\";
|
|
Packit Service |
3749ba |
p11_buffer buf;
|
|
Packit Service |
3749ba |
char *result;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return_val_if_fail (path != NULL, NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
if (!p11_buffer_init_null (&buf, strlen (path)))
|
|
Packit Service |
3749ba |
return_val_if_reached (NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
p11_url_encode ((unsigned char *)path,
|
|
Packit Service |
3749ba |
(unsigned char *)path + strlen (path),
|
|
Packit Service |
3749ba |
VALID,
|
|
Packit Service |
3749ba |
&buf;;
|
|
Packit Service |
3749ba |
return_val_if_fail (p11_buffer_ok (&buf), NULL);
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
result = p11_buffer_steal (&buf, NULL);
|
|
Packit Service |
3749ba |
p11_buffer_uninit (&buf;;
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
return result;
|
|
Packit Service |
3749ba |
}
|
|
Packit Service |
3749ba |
|
|
Packit Service |
3749ba |
char *
|
|
Packit Service |
3749ba |
p11_path_decode (const char *path)
|
|
Packit Service |
3749ba |
{
|
|
Packit Service |
3749ba |
return (char *) p11_url_decode (path, path + strlen (path), "", NULL);
|
|
Packit Service |
3749ba |
}
|