#include "lib/fs/path.h"
#include "lib/malloc/malloc.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/string/printf.h"
#include "lib/string/util_string.h"
#include "lib/string/compat_ctype.h"
#include "lib/fs/userdb.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include <string.h>
char *
get_unquoted_path(const char *path)
{
size_t len = strlen(path);
if (len == 0) {
return tor_strdup("");
}
int has_start_quote = (path[0] == '\"');
int has_end_quote = (len > 0 && path[len-1] == '\"');
if (has_start_quote != has_end_quote || (len == 1 && has_start_quote)) {
return NULL;
}
char *unquoted_path = tor_malloc(len - has_start_quote - has_end_quote + 1);
char *s = unquoted_path;
size_t i;
for (i = has_start_quote; i < len - has_end_quote; i++) {
if (path[i] == '\"' && (i > 0 && path[i-1] == '\\')) {
*(s-1) = path[i];
} else if (path[i] != '\"') {
*s++ = path[i];
} else {
tor_free(unquoted_path);
return NULL;
}
}
*s = '\0';
return unquoted_path;
}
char *
expand_filename(const char *filename)
{
tor_assert(filename);
#ifdef _WIN32
return tor_strdup(filename);
#else
if (*filename == '~') {
char *home, *result=NULL;
const char *rest;
if (filename[1] == '/' || filename[1] == '\0') {
home = getenv("HOME");
if (!home) {
log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while "
"expanding \"%s\"; defaulting to \"\".", filename);
home = tor_strdup("");
} else {
home = tor_strdup(home);
}
rest = strlen(filename)>=2?(filename+2):"";
} else {
#ifdef HAVE_PWD_H
char *username, *slash;
slash = strchr(filename, '/');
if (slash)
username = tor_strndup(filename+1,slash-filename-1);
else
username = tor_strdup(filename+1);
if (!(home = get_user_homedir(username))) {
log_warn(LD_CONFIG,"Couldn't get homedir for \"%s\"",username);
tor_free(username);
return NULL;
}
tor_free(username);
rest = slash ? (slash+1) : "";
#else
log_warn(LD_CONFIG, "Couldn't expand homedir on system without pwd.h");
return tor_strdup(filename);
#endif
}
tor_assert(home);
if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) {
home[strlen(home)-1] = '\0';
}
tor_asprintf(&result,"%s"PATH_SEPARATOR"%s",home,rest);
tor_free(home);
return result;
} else {
return tor_strdup(filename);
}
#endif
}
int
path_is_relative(const char *filename)
{
if (filename && filename[0] == '/')
return 0;
#ifdef _WIN32
else if (filename && filename[0] == '\\')
return 0;
else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) &&
filename[1] == ':' && filename[2] == '\\')
return 0;
#endif
else
return 1;
}
void
clean_fname_for_stat(char *name)
{
#ifdef _WIN32
size_t len = strlen(name);
if (!len)
return;
if (name[len-1]=='\\' || name[len-1]=='/') {
if (len == 1 || (len==3 && name[1]==':'))
return;
name[len-1]='\0';
}
#else
(void)name;
#endif
}
int
get_parent_directory(char *fname)
{
char *cp;
int at_end = 1;
tor_assert(fname);
#ifdef _WIN32
if (fname[0] && fname[1] == ':') {
fname += 2;
}
#endif
cp = fname + strlen(fname);
at_end = 1;
while (--cp >= fname) {
int is_sep = (*cp == '/'
#ifdef _WIN32
|| *cp == '\\'
#endif
);
if (is_sep) {
if (cp == fname) {
cp[1] = '\0';
return 0;
}
*cp = '\0';
if (! at_end)
return 0;
} else {
at_end = 0;
}
}
return -1;
}
#ifndef _WIN32
static char *
alloc_getcwd(void)
{
#ifdef HAVE_GET_CURRENT_DIR_NAME
char *cwd = get_current_dir_name();
char *result = NULL;
if (cwd) {
result = tor_strdup(cwd);
raw_free(cwd); }
return result;
#else
size_t size = 1024;
char *buf = NULL;
char *ptr = NULL;
while (ptr == NULL) {
buf = tor_realloc(buf, size);
ptr = getcwd(buf, size);
if (ptr == NULL && errno != ERANGE) {
tor_free(buf);
return NULL;
}
size *= 2;
}
return buf;
#endif
}
#endif
char *
make_path_absolute(const char *fname)
{
#ifdef _WIN32
char *absfname_malloced = _fullpath(NULL, fname, 1);
char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname);
if (absfname_malloced) raw_free(absfname_malloced);
return absfname;
#else
char *absfname = NULL, *path = NULL;
tor_assert(fname);
if (fname[0] == '/') {
absfname = tor_strdup(fname);
} else {
path = alloc_getcwd();
if (path) {
tor_asprintf(&absfname, "%s/%s", path, fname);
tor_free(path);
} else {
log_warn(LD_GENERAL, "Unable to find current working directory: %s",
strerror(errno));
absfname = tor_strdup(fname);
}
}
return absfname;
#endif
}