apply patch from Christophe Gisquet <christophe dot gisquet at free.fr> with some modifications

-don't use access with X_OK, it won't work on Vista
http://lists.samba.org/archive/ccache/2006q3/000242.html

svn path=/trunk/tools/RosBE/; revision=684
This commit is contained in:
Christoph von Wittich 2008-03-06 16:36:43 +00:00
parent 127da9910c
commit 60196c1e4c
9 changed files with 332 additions and 102 deletions

View File

@ -38,7 +38,7 @@ ARGS *args_init(int init_argc, char **init_args)
void args_add(ARGS *args, const char *s)
{
args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char *));
args->argv[args->argc] = x_strdup(s);
args->argv[args->argc] = x_quote_strdup(s);
args->argc++;
args->argv[args->argc] = NULL;
}
@ -69,7 +69,7 @@ void args_add_prefix(ARGS *args, const char *s)
args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char *));
memmove(&args->argv[1], &args->argv[0],
(args->argc+1) * sizeof(args->argv[0]));
args->argv[0] = x_strdup(s);
args->argv[0] = x_quote_strdup(s);
args->argc++;
}

View File

@ -87,6 +87,38 @@ static struct {
{"ii", "ii"},
{NULL, NULL}};
static int first_is_meh(const char* first)
{
const char* exe = strrchr(first, PATH_SEP_CHAR);
const size_t len = strlen(MYNAME);
if (exe) exe++;
else exe=first;
return (strlen(exe) >= len && strncmp(exe, MYNAME, len) == 0 &&
(exe[len]==0 || strcmp(exe+len, ".exe")==0) );
}
char *build_command(char **argv)
{
char *cmd;
int i, length = 0;
for(i = 0; argv[i]; i++) {
length++;
length += (int)strlen(argv[i]);
}
cmd = (char *)malloc(length);
strcpy(cmd, argv[0]);
for(i = 1; argv[i]; i++) {
strcat(cmd, " ");
strcat(cmd, argv[i]);
}
return cmd;
}
/*
something went badly wrong - just execute the real compiler
*/
@ -155,12 +187,15 @@ static void to_cache(ARGS *args)
{
char *path_stderr;
char *tmp_stdout, *tmp_stderr, *tmp_hashname;
struct stat st1, st2;
struct stat st;
int status;
off_t size = 0;
x_asprintf(&tmp_stdout, "%s/tmp.stdout.%s", temp_dir, tmp_string());
x_asprintf(&tmp_stderr, "%s/tmp.stderr.%s", temp_dir, tmp_string());
x_asprintf(&tmp_hashname, "%s/tmp.hash.%s.o", temp_dir, tmp_string());
/* No quoting, unique arguments */
x_asprintf(&tmp_stdout, "%s"PATH_SEP"tmp.stdout.%s", temp_dir, tmp_string());
x_asprintf(&tmp_stderr, "%s"PATH_SEP"tmp.stderr.%s", temp_dir, tmp_string());
/* Must be quoted as it will belong to a command-line */
x_asprintf(&tmp_hashname, "%s"PATH_SEP"tmp.hash.%s.o", temp_dir, tmp_string());
args_add(args, "-o");
args_add(args, tmp_hashname);
@ -181,7 +216,7 @@ static void to_cache(ARGS *args)
status = execute(args->argv, tmp_stdout, tmp_stderr);
args_pop(args, 3);
if (stat(tmp_stdout, &st1) != 0 || st1.st_size != 0) {
if (stat(tmp_stdout, &st) != 0 || st.st_size != 0) {
cc_log("compiler produced stdout for %s\n", output_file);
stats_update(STATS_STDOUT);
unlink(tmp_stdout);
@ -198,7 +233,7 @@ static void to_cache(ARGS *args)
fd = open(tmp_stderr, O_RDONLY | O_BINARY);
if (fd != -1) {
if (strcmp(output_file, "/dev/null") == 0 ||
if (strcmp(output_file, DEV_NULL) == 0 ||
rename(tmp_hashname, output_file) == 0 || errno == ENOENT) {
if (cpp_stderr) {
/* we might have some stderr from cpp */
@ -211,8 +246,7 @@ static void to_cache(ARGS *args)
}
}
/* we can use a quick method of
getting the failed output */
/* we can use a quick method of getting the failed output */
copy_fd(fd, 2);
close(fd);
unlink(tmp_stderr);
@ -228,19 +262,32 @@ static void to_cache(ARGS *args)
failed();
}
x_asprintf(&path_stderr, "%s.stderr", hashname);
if (stat(tmp_hashname, &st) != 0 || rename(tmp_hashname, hashname) != 0) {
cc_log("failed to rename output: %s\n"
" '%s'\n"
" -> '%s': \n",
strerror(errno), tmp_hashname, hashname);
stats_update(STATS_ERROR);
failed();
}
cc_log("Moved '%s' to '%s'\n", tmp_hashname, hashname);
size += file_size(&st);
if (stat(tmp_stderr, &st1) != 0 ||
stat(tmp_hashname, &st2) != 0 ||
rename(tmp_hashname, hashname) != 0 ||
rename(tmp_stderr, path_stderr) != 0) {
cc_log("failed to rename tmp files - %s\n", strerror(errno));
x_asprintf(&path_stderr, "%s.stderr", hashname);
if (stat(tmp_stderr, &st) != 0 || rename(tmp_stderr, path_stderr) != 0) {
cc_log("failed to rename stderr: %s\n"
" '%s'\n"
" -> '%s': \n",
strerror(errno), tmp_stderr, path_stderr);
stats_update(STATS_ERROR);
failed();
}
cc_log("Moved '%s' to '%s'\n", tmp_stderr, path_stderr);
size += file_size(&st);
cc_log("Placed %s into cache\n", output_file);
stats_tocache(file_size(&st1) + file_size(&st2));
stats_tocache(size);
free(tmp_hashname);
free(tmp_stderr);
@ -331,8 +378,8 @@ static void find_hash(ARGS *args)
hash_string(str_basename(args->argv[0]));
}
hash_int(st.st_size);
hash_int(st.st_mtime);
hash_int((int)st.st_size);
hash_int((int)st.st_mtime);
/* possibly hash the current working directory */
if (getenv("CCACHE_HASHDIR")) {
@ -356,11 +403,11 @@ static void find_hash(ARGS *args)
input_base[10] = 0;
}
/* now the run */
x_asprintf(&path_stdout, "%s/%s.tmp.%s.%s", temp_dir,
input_base, tmp_string(),
i_extension);
x_asprintf(&path_stderr, "%s/tmp.cpp_stderr.%s", temp_dir, tmp_string());
/* now the run - path_std* are unique args => no quoting */
x_asprintf(&path_stdout, "%s"PATH_SEP"%s.tmp.%s.%s", temp_dir,
input_base, tmp_string(),
i_extension);
x_asprintf(&path_stderr, "%s"PATH_SEP"tmp.cpp_stderr.%s", temp_dir, tmp_string());
if (!direct_i_file) {
/* run cpp on the input file to obtain the .i */
@ -423,17 +470,18 @@ static void find_hash(ARGS *args)
/* we use a N level subdir for the cache path to reduce the impact
on filesystems which are slow for large directories
Quoting not necessary because unique argument, or not used yet.
*/
s = hash_result();
x_asprintf(&hash_dir, "%s/%c", cache_dir, s[0]);
x_asprintf(&stats_file, "%s/stats", hash_dir);
x_asprintf(&hash_dir, "%s"PATH_SEP"%c", cache_dir, s[0]);
x_asprintf(&stats_file, "%s"PATH_SEP"stats", hash_dir);
for (i=1; i<nlevels; i++) {
char *p;
if (create_dir(hash_dir) != 0) {
cc_log("failed to create %s\n", hash_dir);
failed();
}
x_asprintf(&p, "%s/%c", hash_dir, s[i]);
x_asprintf(&p, "%s"PATH_SEP"%c", hash_dir, s[i]);
free(hash_dir);
hash_dir = p;
}
@ -441,7 +489,7 @@ static void find_hash(ARGS *args)
cc_log("failed to create %s\n", hash_dir);
failed();
}
x_asprintf(&hashname, "%s/%s", hash_dir, s+nlevels);
x_asprintf(&hashname, "%s"PATH_SEP"%s", hash_dir, s+nlevels);
free(hash_dir);
}
@ -483,7 +531,7 @@ static void from_cache(int first)
utime(stderr_file, NULL);
if (strcmp(output_file, "/dev/null") == 0) {
if (strcmp(output_file, DEV_NULL) == 0) {
ret = 0;
} else {
unlink(output_file);
@ -562,10 +610,10 @@ static void find_compiler(int argc, char **argv)
base = str_basename(argv[0]);
/* we might be being invoked like "ccache gcc -c foo.c" */
if (strcmp(base, MYNAME) == 0) {
if (first_is_meh(argv[0])) {
args_remove_first(orig_args);
free(base);
if (strchr(argv[1],'/')) {
if (strchr(argv[1],PATH_SEP_CHAR)) {
/* a full path was given */
return;
}
@ -801,7 +849,7 @@ static void process_args(int argc, char **argv)
if (!output_file) {
char *p;
output_file = x_strdup(input_file);
if ((p = strrchr(output_file, '/'))) {
if ((p = strrchr(output_file, PATH_SEP_CHAR))) {
output_file = p+1;
}
p = strrchr(output_file, '.');
@ -815,7 +863,7 @@ static void process_args(int argc, char **argv)
}
/* cope with -o /dev/null */
if (strcmp(output_file,"/dev/null") != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) {
if (strcmp(output_file, DEV_NULL) != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) {
cc_log("Not a regular file %s\n", output_file);
stats_update(STATS_DEVICE);
failed();
@ -934,14 +982,15 @@ static int ccache_main(int argc, char *argv[])
case 'F':
v = atoi(optarg);
stats_set_limits(v, -1);
stats_set_limits((long)v, -1);
printf("Set cache file limit to %u\n", (unsigned)v);
break;
case 'M':
v = value_units(optarg);
stats_set_limits(-1, v);
stats_set_limits(-1, (long) v);
printf("Set cache size limit to %uk\n", (unsigned)v);
printf("not implemented");
break;
default:
@ -983,7 +1032,7 @@ int main(int argc, char *argv[])
cache_dir = getenv("CCACHE_DIR");
if (!cache_dir) {
x_asprintf(&cache_dir, "%s/.ccache", get_home_directory());
x_asprintf(&cache_dir, "%s"PATH_SEP".ccache", get_home_directory());
}
temp_dir = getenv("CCACHE_TEMPDIR");
@ -1009,8 +1058,8 @@ int main(int argc, char *argv[])
/* check if we are being invoked as "ccache" */
if (strlen(argv[0]) >= strlen(MYNAME) &&
strcmp(argv[0] + strlen(argv[0]) - strlen(MYNAME), MYNAME) == 0) {
if (first_is_meh(argv[0]))
{
if (argc < 2) {
usage();
exit(1);

View File

@ -1,23 +1,38 @@
#define CCACHE_VERSION "2.4"
#include "config.h"
#define USUAL_PATH_SEP_CHAR '/'
#define USUAL_PATH_SEP "/"
#define WIN32_PATH_SEP_CHAR '\\'
#define WIN32_PATH_SEP "\\"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <windows.h>
#include <sys/locking.h>
#define PATH_SEP WIN32_PATH_SEP
#define PATH_SEP_CHAR WIN32_PATH_SEP_CHAR
#define DEV_NULL "NUL"
#else
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <utime.h>
#include <dirent.h>
#define PATH_SEP USUAL_PATH_SEP
#define PATH_SEP_CHAR USUAL_PATH_SEP_CHAR
#define DEV_NULL "/dev/null"
#endif
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <utime.h>
#include <stdarg.h>
#include <dirent.h>
#include <limits.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
@ -83,6 +98,7 @@ int copy_file(const char *src, const char *dest);
int create_dir(const char *dir);
void x_asprintf(char **ptr, const char *format, ...);
char *x_strdup(const char *s);
char *x_quote_strdup(const char* s);
void *x_realloc(void *ptr, size_t size);
void *x_malloc(size_t size);
void traverse(const char *dir, void (*fn)(const char *, struct stat *));

View File

@ -50,7 +50,9 @@ static void traverse_fn(const char *fname, struct stat *st)
{
char *p;
#ifndef WIN32
if (!S_ISREG(st->st_mode)) return;
#endif
p = str_basename(fname);
if (strcmp(p, "stats") == 0) {
@ -107,8 +109,8 @@ void cleanup_dir(const char *dir, size_t maxfiles, size_t maxsize)
{
unsigned i;
size_threshold = maxsize * LIMIT_MULTIPLE;
files_threshold = maxfiles * LIMIT_MULTIPLE;
size_threshold = maxsize * (size_t) LIMIT_MULTIPLE;
files_threshold = maxfiles * (size_t) LIMIT_MULTIPLE;
num_files = 0;
total_size = 0;
@ -143,8 +145,9 @@ void cleanup_all(const char *dir)
int i;
for (i=0;i<=0xF;i++) {
x_asprintf(&dname, "%s/%1x", dir, i);
x_asprintf(&sfile, "%s/%1x/stats", dir, i);
/* No need to quote, unique argument */
x_asprintf(&dname, "%s"PATH_SEP"%1x", dir, i);
x_asprintf(&sfile, "%s"PATH_SEP"%1x"PATH_SEP"stats", dir, i);
memset(counters, 0, sizeof(counters));
stats_read(sfile, counters);
@ -183,7 +186,7 @@ void wipe_all(const char *dir)
int i;
for (i=0;i<=0xF;i++) {
x_asprintf(&dname, "%s/%1x", dir, i);
x_asprintf(&dname, "%s"PATH_SEP"%1x", dir, i);
traverse(dir, wipe_fn);
free(dname);
}

View File

@ -27,6 +27,7 @@ int execute(char **argv,
const char *path_stdout,
const char *path_stderr)
{
#ifndef _WIN32
pid_t pid;
int status;
@ -64,9 +65,88 @@ int execute(char **argv,
}
return WEXITSTATUS(status);
#else /* Should be portable */
int status = -2;
int fd, std_od = -1, std_ed = -1;
unlink(path_stdout);
std_od = _dup(1);
fd = _open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
if (fd == -1) {
status = STATUS_NOCACHE;
cc_log("stdout error: failed to open %s\n", path_stdout);
goto out;
}
/*std_od = */ _dup2(fd, 1);
_close(fd);
unlink(path_stderr);
fd = _open(path_stderr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
std_ed = _dup(2);
if (fd == -1) {
status = STATUS_NOCACHE;
cc_log("stderr error: failed to open %s\n", path_stderr);
goto out;
}
/*std_ed =*/ _dup2(fd, 2);
_close(fd);
/* Spawn process (_exec* familly doesn't return) */
status = _spawnv(_P_WAIT, argv[0], argv);
out:
cc_log("%s:\n stdout -> %s\n stderr -> %s\n process status=%i\n",
argv[0], path_stdout, path_stderr, status);
if (status == -1) cc_log("Error %i: %s\n", errno, strerror(errno));
/* Restore descriptors */
if (std_od != -1) _dup2(std_od, 1);
if (std_ed != -1) _dup2(std_ed, 2);
_flushall();
return (status>0);
#endif
}
/*
Check that the executable exists
*/
char is_exec_file(const char *fname, const char *exclude_name)
{
struct stat st1, st2;
if (access(fname, 0) == 0 &&
#ifndef _WIN32 /* Symlinks not used under windows */
lstat(fname, &st1) == 0 &&
#endif
stat(fname, &st2) == 0 &&
S_ISREG(st2.st_mode)) {
#ifndef _WIN32 /* Symlinks not used under windows */
/* if its a symlink then ensure it doesn't
point at something called exclude_name */
if (S_ISLNK(st1.st_mode)) {
char *buf = x_realpath(fname);
if (buf) {
char *p = str_basename(buf);
if (strcmp(p, exclude_name) == 0) {
/* its a link to "ccache" ! */
free(p);
free(buf);
return -1;
}
free(buf);
free(p);
}
}
#endif
/* found it! */
return 1;
}
return -1;
}
/*
find an executable by name in $PATH. Exclude any that are links to exclude_name
*/
@ -74,9 +154,9 @@ char *find_executable(const char *name, const char *exclude_name)
{
char *path;
char *tok;
struct stat st1, st2;
const char *sep = ":";
if (*name == '/') {
if (*name == PATH_SEP_CHAR) {
return x_strdup(name);
}
@ -91,39 +171,37 @@ char *find_executable(const char *name, const char *exclude_name)
path = x_strdup(path);
/* Determine path separator */
if (strchr(path, ';')) sep = ";";
/* search the path looking for the first compiler of the right name
that isn't us */
for (tok=strtok(path,":"); tok; tok = strtok(NULL, ":")) {
for (tok=strtok(path, sep); tok; tok = strtok(NULL, sep)) {
char *fname;
x_asprintf(&fname, "%s/%s", tok, name);
x_asprintf(&fname, "%s"PATH_SEP"%s", tok, name);
/* look for a normal executable file */
if (access(fname, X_OK) == 0 &&
lstat(fname, &st1) == 0 &&
stat(fname, &st2) == 0 &&
S_ISREG(st2.st_mode)) {
/* if its a symlink then ensure it doesn't
point at something called exclude_name */
if (S_ISLNK(st1.st_mode)) {
char *buf = x_realpath(fname);
if (buf) {
char *p = str_basename(buf);
if (strcmp(p, exclude_name) == 0) {
/* its a link to "ccache" ! */
free(p);
free(buf);
continue;
}
free(buf);
free(p);
}
}
/* found it! */
if (is_exec_file(fname, exclude_name) > 0)
{
free(path);
return fname;
}
free(fname);
}
/* found it! */
#ifdef _WIN32 /* Add .exe under win32 */
x_asprintf(&fname, "%s"PATH_SEP"%s.exe", tok, name);
/* look for a normal executable file */
if (is_exec_file(fname, exclude_name) > 0)
{
free(path);
return fname;
}
free(fname);
#endif
}
free(path);
return NULL;
}

View File

@ -35,7 +35,7 @@ void hash_start(void)
void hash_string(const char *s)
{
hash_buffer(s, strlen(s));
hash_buffer(s, (int)strlen(s));
}
void hash_int(int x)

View File

@ -126,7 +126,7 @@ static void stats_update_size(enum stats stat, size_t size)
if (!stats_file) {
if (!cache_dir) return;
x_asprintf(&stats_file, "%s/stats", cache_dir);
x_asprintf(&stats_file, "%s"PATH_SEP"stats", cache_dir);
}
/* open safely to try to prevent symlink races */
@ -215,9 +215,9 @@ void stats_summary(void)
char *fname;
if (dir == -1) {
x_asprintf(&fname, "%s/stats", cache_dir);
x_asprintf(&fname, "%s"PATH_SEP"stats", cache_dir);
} else {
x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir);
x_asprintf(&fname, "%s"PATH_SEP"%1x"PATH_SEP"stats", cache_dir, dir);
}
stats_read(fname, counters);
@ -259,12 +259,12 @@ void stats_zero(void)
char *fname;
unsigned counters[STATS_END];
x_asprintf(&fname, "%s/stats", cache_dir);
x_asprintf(&fname, "%s"PATH_SEP"stats", cache_dir);
unlink(fname);
free(fname);
for (dir=0;dir<=0xF;dir++) {
x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir);
x_asprintf(&fname, "%s"PATH_SEP"%1x"PATH_SEP"stats", cache_dir, dir);
fd = safe_open(fname);
if (fd == -1) {
free(fname);
@ -305,9 +305,9 @@ void stats_set_limits(long maxfiles, long maxsize)
char *fname, *cdir;
int fd;
x_asprintf(&cdir, "%s/%1x", cache_dir, dir);
x_asprintf(&cdir, "%s"PATH_SEP"%1x", cache_dir, dir);
create_dir(cdir);
x_asprintf(&fname, "%s/stats", cdir);
x_asprintf(&fname, "%s"PATH_SEP"stats", cdir);
free(cdir);
memset(counters, 0, sizeof(counters));
@ -336,7 +336,7 @@ void stats_set_sizes(const char *dir, size_t num_files, size_t total_size)
char *stats_file;
create_dir(dir);
x_asprintf(&stats_file, "%s/stats", dir);
x_asprintf(&stats_file, "%s"PATH_SEP"stats", dir);
memset(counters, 0, sizeof(counters));

View File

@ -209,7 +209,7 @@ static void unify(unsigned char *p, size_t size)
q = p[ofs];
for (i=0;i<tokens[q].num_toks;i++) {
unsigned char *s = (unsigned char *)tokens[q].toks[i];
int len = strlen((char *)s);
int len = (int) strlen((char *)s);
if (size >= ofs+len && memcmp(&p[ofs], s, len) == 0) {
int j;
for (j=0;s[j];j++) {
@ -241,6 +241,7 @@ int unify_hash(const char *fname)
int fd;
struct stat st;
char *map;
HANDLE view;
fd = open(fname, O_RDONLY|O_BINARY);
if (fd == -1 || fstat(fd, &st) != 0) {
@ -249,6 +250,33 @@ int unify_hash(const char *fname)
return -1;
}
#ifdef _WIN32
/* win32 equivalent of mmap is ViewMapOfFile, but malloc+read
may be better */
view = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL,
PAGE_READONLY|SEC_COMMIT, 0,0 , NULL);
if (NULL == view) {
cc_log("Failed to create file mapping %s: %s\n",
fname, strerror(errno));
stats_update(STATS_PREPROCESSOR);
return -1;
}
map = MapViewOfFile(view, FILE_MAP_READ, 0, 0, st.st_size);
if (NULL == map) {
cc_log("Failed to map view of file %s: %s\n",
fname, strerror(errno));
stats_update(STATS_PREPROCESSOR);
return -1;
}
/* pass it through the unifier */
unify((unsigned char *)map, st.st_size);
UnmapViewOfFile(map);
CloseHandle(view);
close(fd);
#else
/* we use mmap() to make it easy to handle arbitrarily long
lines in preprocessor output. I have seen lines of over
100k in length, so this is well worth it */
@ -263,7 +291,7 @@ int unify_hash(const char *fname)
unify((unsigned char *)map, st.st_size);
munmap(map, st.st_size);
#endif
return 0;
}

View File

@ -20,6 +20,22 @@
static FILE *logfile;
#ifdef _WIN32
int fchmod(int fildes, mode_t mode)
{
return 0;
}
#endif
#ifndef HAVE_MKSTEMP
/* cheap and nasty mkstemp replacement */
int mkstemp(char *template)
{
_mktemp(template);
return open(template, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0600);
}
#endif
/* log a message to the CCACHE_LOGFILE location */
void cc_log(const char *format, ...)
{
@ -154,6 +170,34 @@ void x_asprintf(char **ptr, const char *format, ...)
if (!ptr) fatal("out of memory in x_asprintf");
}
/*
this is like strdup() but dies if the malloc fails and add quotes
around the argument if it contains spaces.
*/
char*
x_quote_strdup(const char* s)
{
/* Protect against args containing spaces in them - unicode-able ? */
if (strchr(s, ' ') != NULL) {
size_t len = strlen(s); /* at least 1 as it holds ' ' */
char *new_arg = x_malloc(len+2*1+1); /* Make room for quoting */
/* Quote */
new_arg[0] = '"';
memcpy(new_arg+1, s, len);
new_arg[len+1] = '"';
new_arg[len+2] = 0;
/* Done */
cc_log("Quoted %s\n", new_arg);
return new_arg;
}
else
return x_strdup(s);
}
/*
this is like strdup() but dies if the malloc fails
*/
@ -220,7 +264,7 @@ void traverse(const char *dir, void (*fn)(const char *, struct stat *))
if (strlen(de->d_name) == 0) continue;
x_asprintf(&fname, "%s/%s", dir, de->d_name);
x_asprintf(&fname, "%s"PATH_SEP"%s", dir, de->d_name);
if (lstat(fname, &st)) {
if (errno != ENOENT) {
perror(fname);
@ -244,7 +288,7 @@ void traverse(const char *dir, void (*fn)(const char *, struct stat *))
/* return the base name of a file - caller frees */
char *str_basename(const char *s)
{
char *p = strrchr(s, '/');
char *p = strrchr(s, PATH_SEP_CHAR);
if (p) {
return x_strdup(p+1);
}
@ -257,7 +301,7 @@ char *dirname(char *s)
{
char *p;
s = x_strdup(s);
p = strrchr(s, '/');
p = strrchr(s, PATH_SEP_CHAR);
if (p) {
*p = 0;
}
@ -266,6 +310,9 @@ char *dirname(char *s)
int lock_fd(int fd)
{
#ifdef _WIN32
return _locking(fd, _LK_NBLCK, 1);
#else
struct flock fl;
int ret;
@ -281,17 +328,23 @@ int lock_fd(int fd)
ret = fcntl(fd, F_SETLKW, &fl);
} while (ret == -1 && errno == EINTR);
return ret;
#endif
}
/* return size on disk of a file */
size_t file_size(struct stat *st)
{
#ifdef _WIN32
return st->st_size;
#else
size_t size = st->st_blocks * 512;
if ((size_t)st->st_size > size) {
/* probably a broken stat() call ... */
size = (st->st_size + 1023) & ~1023;
}
return size;
#endif
}
@ -351,6 +404,7 @@ size_t value_units(const char *s)
a sane realpath() function, trying to cope with stupid path limits and
a broken API
*/
#ifndef WIN32
char *x_realpath(const char *path)
{
int maxlen;
@ -389,6 +443,7 @@ char *x_realpath(const char *path)
free(ret);
return NULL;
}
#endif
/* a getcwd that will returns an allocated buffer */
char *gnu_getcwd(void)
@ -397,7 +452,7 @@ char *gnu_getcwd(void)
while (1) {
char *buffer = (char *)x_malloc(size);
if (getcwd(buffer, size) == buffer) {
if (_getcwd(buffer, size) == buffer) {
return buffer;
}
free(buffer);
@ -408,16 +463,6 @@ char *gnu_getcwd(void)
}
}
#ifndef HAVE_MKSTEMP
/* cheap and nasty mkstemp replacement */
int mkstemp(char *template)
{
mktemp(template);
return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
}
#endif
/* create an empty file */
int create_empty_file(const char *fname)
{
@ -436,7 +481,18 @@ int create_empty_file(const char *fname)
*/
const char *get_home_directory(void)
{
const char *p = getenv("HOME");
const char *p = NULL;
#ifdef _WIN32
static char szPath[MAX_PATH];
// "Documents and Settings\user\Application Data" is CSIDL_APPDATA
if(SHGetSpecialFolderPathA(NULL, szPath, CSIDL_PROFILE, FALSE))
{
return szPath;
}
#endif
p = getenv("HOME");
if (p) {
return p;
}