blob: 0e88e5c4ec5e3e3c0662735a6b25529322806110 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2013-2014 Google, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Google, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include "share.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "dr_frontend_private.h" /* for debuglevel/abortlevel */
#include "dr_frontend.h"
#ifdef WINDOWS
# include <direct.h>
/* It looks better to consistently use the same separator */
# define DIRSEP '\\'
# define snprintf _snprintf
#else
# include <unistd.h>
# define DIRSEP '/'
#endif
#include <sys/types.h>
#include <sys/stat.h> /* for _stat */
drfront_status_t
drfront_bufprint(char *buf, size_t bufsz, INOUT size_t *sofar, OUT ssize_t *len,
char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
/* XXX i#1397: We would like to use our_vsnprintf() instead of depending
* on libc/winapi.
*/
*len = vsnprintf(buf + *sofar, bufsz - *sofar, fmt, ap);
*sofar += (*len < 0 ? 0 : *len);
if (bufsz <= *sofar) {
va_end(ap);
return DRFRONT_ERROR_INVALID_SIZE;
}
/* be paranoid: though usually many calls in a row and could delay until end */
buf[bufsz - 1] = '\0';
va_end(ap);
return DRFRONT_SUCCESS;
}
/* Always null-terminates.
* No conversion on UNIX, just copy the data.
*/
drfront_status_t
drfront_convert_args(const TCHAR **targv, OUT char ***argv, int argc)
{
int i = 0;
drfront_status_t ret = DRFRONT_ERROR;
*argv = (char **) calloc(argc + 1/*null*/, sizeof(**argv));
for (i = 0; i < argc; i++) {
size_t len = 0;
ret = drfront_tchar_to_char_size_needed(targv[i], &len);
if (ret != DRFRONT_SUCCESS)
return ret;
(*argv)[i] = (char *) malloc(len); /* len includes terminating null */
ret = drfront_tchar_to_char(targv[i], (*argv)[i], len);
if (ret != DRFRONT_SUCCESS)
return ret;
}
(*argv)[i] = NULL;
return DRFRONT_SUCCESS;
}
drfront_status_t
drfront_cleanup_args(char **argv, int argc)
{
int i = 0;
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
return DRFRONT_SUCCESS;
}
static bool
drfront_is_system_install_dir(const char *dir)
{
#ifdef WINDOWS
return (strstr(dir, "Program Files") != NULL);
#else
return (strstr(dir, "/usr/") == dir);
#endif
}
drfront_status_t
drfront_appdata_logdir(const char *root, const char *subdir,
OUT bool *use_root,
OUT char *buf, size_t buflen/*# elements*/)
{
drfront_status_t res = DRFRONT_ERROR;
bool writable = false;
char env[MAXIMUM_PATH];
if (use_root == NULL || buf == NULL)
return DRFRONT_ERROR_INVALID_PARAMETER;
/* On Vista+ we can't write to Program Files; plus better to not store
* logs there on 2K or XP either.
*/
if (drfront_is_system_install_dir(root) ||
drfront_access(root, DRFRONT_WRITE, &writable) != DRFRONT_SUCCESS ||
!writable) {
bool have_env = false;
drfront_status_t sc;
*use_root = false;
#ifdef WINDOWS
sc = drfront_get_env_var("APPDATA", env, BUFFER_SIZE_ELEMENTS(env));
if (sc == DRFRONT_SUCCESS)
have_env = true;
if (have_env) {
snprintf(buf, buflen, "%s%c%s", env, DIRSEP, subdir);
buf[buflen - 1] = '\0';
} else {
sc = drfront_get_env_var("USERPROFILE", env, BUFFER_SIZE_ELEMENTS(env));
if (sc == DRFRONT_SUCCESS)
have_env = true;
if (have_env) {
snprintf(buf, buflen,
"%s%cApplication Data%c%s", env, DIRSEP, DIRSEP, subdir);
buf[buflen - 1] = '\0';
}
}
#endif
if (!have_env) {
sc = drfront_get_env_var("TMPDIR", env, BUFFER_SIZE_ELEMENTS(env));
if (sc != DRFRONT_SUCCESS)
sc = drfront_get_env_var("TEMP", env, BUFFER_SIZE_ELEMENTS(env));
if (sc != DRFRONT_SUCCESS)
sc = drfront_get_env_var("TMP", env, BUFFER_SIZE_ELEMENTS(env));
if (sc != DRFRONT_SUCCESS) {
#ifdef WINDOWS
/* bail */
#else
have_env = true;
snprintf(env, BUFFER_SIZE_ELEMENTS(env), "%s", "/tmp");
NULL_TERMINATE_BUFFER(env);
#endif
} else
have_env = true;
if (have_env) {
snprintf(buf, buflen, "%s%c%s", env, DIRSEP, subdir);
buf[buflen - 1] = '\0';
}
}
if (have_env) {
/* XXX: I would create the dir, or check for existence, here --
* but currently this lib has no reliance on DR so I can't
* easily use dr_create_dir() or dr_directory_exists().
*/
res = DRFRONT_SUCCESS;
}
} else {
*use_root = true;
res = DRFRONT_SUCCESS;
}
return res;
}
void
drfront_string_replace_character(OUT char *str, char old_char, char new_char)
{
while (*str != '\0') {
if (*str == old_char) {
*str = new_char;
}
str++;
}
}
void
drfront_string_replace_character_wide(OUT TCHAR *str, TCHAR old_char, TCHAR new_char)
{
while (*str != _T('\0')) {
if (*str == old_char) {
*str = new_char;
}
str++;
}
}
/* XXX: Since we can't simply use dr_* routines, we implement create/remove/exists
* directory here as a short-term solution (xref i#1409).
*/
drfront_status_t
drfront_create_dir(const char *dir)
{
uint res;
if (dir == NULL)
return DRFRONT_ERROR_INVALID_PARAMETER;
/* FIXME i#1530: we should not use libc on Windows,
* which breaks the internationalization support
*/
#ifdef WINDOWS
res = _mkdir(dir);
#else
res = mkdir(dir, 0777);
#endif
if (res != 0) {
if(errno == EEXIST) {
return DRFRONT_ERROR_FILE_EXISTS;
} else if(errno == EACCES) {
return DRFRONT_ERROR_ACCESS_DENIED;
} else {
DO_DEBUG(DL_WARN,
printf("mkdir failed %d", errno);
);
return DRFRONT_ERROR;
}
}
return DRFRONT_SUCCESS;
}
drfront_status_t
drfront_remove_dir(const char *dir)
{
uint res;
if (dir == NULL)
return DRFRONT_ERROR_INVALID_PARAMETER;
/* FIXME i#1530: we should not use libc on Windows,
* which breaks the internationalization support
*/
#ifdef WINDOWS
res = _rmdir(dir);
#else
res = rmdir(dir);
#endif
if (res != 0) {
if(errno == ENOENT) {
return DRFRONT_ERROR_INVALID_PATH;
} else if(errno == EACCES) {
return DRFRONT_ERROR_ACCESS_DENIED;
} else {
DO_DEBUG(DL_WARN,
printf("rmdir failed %d", errno);
);
return DRFRONT_ERROR;
}
}
return DRFRONT_SUCCESS;
}