Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'rs/strbuf-getcwd'
Reduce the use of fixed sized buffer passed to getcwd() calls
by introducing xgetcwd() helper.

* rs/strbuf-getcwd:
  use strbuf_add_absolute_path() to add absolute paths
  abspath: convert absolute_path() to strbuf
  use xgetcwd() to set $GIT_DIR
  use xgetcwd() to get the current directory or die
  wrapper: add xgetcwd()
  abspath: convert real_path_internal() to strbuf
  abspath: use strbuf_getcwd() to remember original working directory
  setup: convert setup_git_directory_gently_1 et al. to strbuf
  unix-sockets: use strbuf_getcwd()
  strbuf: add strbuf_getcwd()
  • Loading branch information
Junio C Hamano committed Sep 2, 2014
2 parents 51eeaea + 9610dec commit f655651
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 178 deletions.
10 changes: 10 additions & 0 deletions Documentation/technical/api-strbuf.txt
Expand Up @@ -307,6 +307,16 @@ same behaviour as well.
use it unless you need the correct position in the file
descriptor.

`strbuf_getcwd`::

Set the buffer to the path of the current working directory.

`strbuf_add_absolute_path`

Add a path to a buffer, converting a relative path to an
absolute one in the process. Symbolic links are not
resolved.

`stripspace`::

Strip whitespace from a buffer. The second parameter controls if
Expand Down
124 changes: 34 additions & 90 deletions abspath.c
Expand Up @@ -33,24 +33,22 @@ int is_directory(const char *path)
*/
static const char *real_path_internal(const char *path, int die_on_error)
{
static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
static struct strbuf sb = STRBUF_INIT;
char *retval = NULL;

/*
* If we have to temporarily chdir(), store the original CWD
* here so that we can chdir() back to it at the end of the
* function:
*/
char cwd[1024] = "";

int buf_index = 1;
struct strbuf cwd = STRBUF_INIT;

int depth = MAXDEPTH;
char *last_elem = NULL;
struct stat st;

/* We've already done it */
if (path == buf || path == next_buf)
if (path == sb.buf)
return path;

if (!*path) {
Expand All @@ -60,90 +58,74 @@ static const char *real_path_internal(const char *path, int die_on_error)
goto error_out;
}

if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) {
if (die_on_error)
die("Too long path: %.*s", 60, path);
else
goto error_out;
}
strbuf_reset(&sb);
strbuf_addstr(&sb, path);

while (depth--) {
if (!is_directory(buf)) {
char *last_slash = find_last_dir_sep(buf);
if (!is_directory(sb.buf)) {
char *last_slash = find_last_dir_sep(sb.buf);
if (last_slash) {
last_elem = xstrdup(last_slash + 1);
last_slash[1] = '\0';
strbuf_setlen(&sb, last_slash - sb.buf + 1);
} else {
last_elem = xstrdup(buf);
*buf = '\0';
last_elem = xmemdupz(sb.buf, sb.len);
strbuf_reset(&sb);
}
}

if (*buf) {
if (!*cwd && !getcwd(cwd, sizeof(cwd))) {
if (sb.len) {
if (!cwd.len && strbuf_getcwd(&cwd)) {
if (die_on_error)
die_errno("Could not get current working directory");
else
goto error_out;
}

if (chdir(buf)) {
if (chdir(sb.buf)) {
if (die_on_error)
die_errno("Could not switch to '%s'", buf);
die_errno("Could not switch to '%s'",
sb.buf);
else
goto error_out;
}
}
if (!getcwd(buf, PATH_MAX)) {
if (strbuf_getcwd(&sb)) {
if (die_on_error)
die_errno("Could not get current working directory");
else
goto error_out;
}

if (last_elem) {
size_t len = strlen(buf);
if (len + strlen(last_elem) + 2 > PATH_MAX) {
if (die_on_error)
die("Too long path name: '%s/%s'",
buf, last_elem);
else
goto error_out;
}
if (len && !is_dir_sep(buf[len - 1]))
buf[len++] = '/';
strcpy(buf + len, last_elem);
if (sb.len && !is_dir_sep(sb.buf[sb.len - 1]))
strbuf_addch(&sb, '/');
strbuf_addstr(&sb, last_elem);
free(last_elem);
last_elem = NULL;
}

if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
ssize_t len = readlink(buf, next_buf, PATH_MAX);
if (!lstat(sb.buf, &st) && S_ISLNK(st.st_mode)) {
struct strbuf next_sb = STRBUF_INIT;
ssize_t len = strbuf_readlink(&next_sb, sb.buf, 0);
if (len < 0) {
if (die_on_error)
die_errno("Invalid symlink '%s'", buf);
else
goto error_out;
}
if (PATH_MAX <= len) {
if (die_on_error)
die("symbolic link too long: %s", buf);
die_errno("Invalid symlink '%s'",
sb.buf);
else
goto error_out;
}
next_buf[len] = '\0';
buf = next_buf;
buf_index = 1 - buf_index;
next_buf = bufs[buf_index];
strbuf_swap(&sb, &next_sb);
strbuf_release(&next_sb);
} else
break;
}

retval = buf;
retval = sb.buf;
error_out:
free(last_elem);
if (*cwd && chdir(cwd))
die_errno("Could not change back to '%s'", cwd);
if (cwd.len && chdir(cwd.buf))
die_errno("Could not change back to '%s'", cwd.buf);
strbuf_release(&cwd);

return retval;
}
Expand All @@ -158,54 +140,16 @@ const char *real_path_if_valid(const char *path)
return real_path_internal(path, 0);
}

static const char *get_pwd_cwd(void)
{
static char cwd[PATH_MAX + 1];
char *pwd;
struct stat cwd_stat, pwd_stat;
if (getcwd(cwd, PATH_MAX) == NULL)
return NULL;
pwd = getenv("PWD");
if (pwd && strcmp(pwd, cwd)) {
stat(cwd, &cwd_stat);
if ((cwd_stat.st_dev || cwd_stat.st_ino) &&
!stat(pwd, &pwd_stat) &&
pwd_stat.st_dev == cwd_stat.st_dev &&
pwd_stat.st_ino == cwd_stat.st_ino) {
strlcpy(cwd, pwd, PATH_MAX);
}
}
return cwd;
}

/*
* Use this to get an absolute path from a relative one. If you want
* to resolve links, you should use real_path.
*
* If the path is already absolute, then return path. As the user is
* never meant to free the return value, we're safe.
*/
const char *absolute_path(const char *path)
{
static char buf[PATH_MAX + 1];

if (!*path) {
die("The empty string is not a valid path");
} else if (is_absolute_path(path)) {
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
die("Too long path: %.*s", 60, path);
} else {
size_t len;
const char *fmt;
const char *cwd = get_pwd_cwd();
if (!cwd)
die_errno("Cannot determine the current working directory");
len = strlen(cwd);
fmt = (len > 0 && is_dir_sep(cwd[len - 1])) ? "%s%s" : "%s/%s";
if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX)
die("Too long path: %.*s", 60, path);
}
return buf;
static struct strbuf sb = STRBUF_INIT;
strbuf_reset(&sb);
strbuf_add_absolute_path(&sb, path);
return sb.buf;
}

/*
Expand Down
24 changes: 11 additions & 13 deletions builtin/init-db.c
Expand Up @@ -426,18 +426,20 @@ int init_db(const char *template_dir, unsigned int flags)

static int guess_repository_type(const char *git_dir)
{
char cwd[PATH_MAX];
const char *slash;
char *cwd;
int cwd_is_git_dir;

/*
* "GIT_DIR=. git init" is always bare.
* "GIT_DIR=`pwd` git init" too.
*/
if (!strcmp(".", git_dir))
return 1;
if (!getcwd(cwd, sizeof(cwd)))
die_errno(_("cannot tell cwd"));
if (!strcmp(git_dir, cwd))
cwd = xgetcwd();
cwd_is_git_dir = !strcmp(git_dir, cwd);
free(cwd);
if (cwd_is_git_dir)
return 1;
/*
* "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
Expand Down Expand Up @@ -535,10 +537,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
usage(init_db_usage[0]);
}
if (is_bare_repository_cfg == 1) {
static char git_dir[PATH_MAX+1];

setenv(GIT_DIR_ENVIRONMENT,
getcwd(git_dir, sizeof(git_dir)), argc > 0);
char *cwd = xgetcwd();
setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
free(cwd);
}

if (init_shared_repository != -1)
Expand Down Expand Up @@ -572,11 +573,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
git_work_tree_cfg = xstrdup(real_path(rel));
free(rel);
}
if (!git_work_tree_cfg) {
git_work_tree_cfg = xcalloc(PATH_MAX, 1);
if (!getcwd(git_work_tree_cfg, PATH_MAX))
die_errno (_("Cannot access current working directory"));
}
if (!git_work_tree_cfg)
git_work_tree_cfg = xgetcwd();
if (work_tree)
set_git_work_tree(work_tree);
else
Expand Down
6 changes: 3 additions & 3 deletions builtin/rev-parse.c
Expand Up @@ -736,7 +736,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!strcmp(arg, "--git-dir")) {
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
static char cwd[PATH_MAX];
char *cwd;
int len;
if (gitdir) {
puts(gitdir);
Expand All @@ -746,10 +746,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(".git");
continue;
}
if (!getcwd(cwd, PATH_MAX))
die_errno("unable to get current working directory");
cwd = xgetcwd();
len = strlen(cwd);
printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
free(cwd);
continue;
}
if (!strcmp(arg, "--resolve-git-dir")) {
Expand Down
12 changes: 8 additions & 4 deletions dir.c
Expand Up @@ -1507,12 +1507,16 @@ int dir_inside_of(const char *subdir, const char *dir)

int is_inside_dir(const char *dir)
{
char cwd[PATH_MAX];
char *cwd;
int rc;

if (!dir)
return 0;
if (!getcwd(cwd, sizeof(cwd)))
die_errno("can't find the current directory");
return dir_inside_of(cwd, dir) >= 0;

cwd = xgetcwd();
rc = (dir_inside_of(cwd, dir) >= 0);
free(cwd);
return rc;
}

int is_empty_dir(const char *path)
Expand Down
6 changes: 1 addition & 5 deletions exec_cmd.c
Expand Up @@ -86,11 +86,7 @@ const char *git_exec_path(void)
static void add_path(struct strbuf *out, const char *path)
{
if (path && *path) {
if (is_absolute_path(path))
strbuf_addstr(out, path);
else
strbuf_addstr(out, absolute_path(path));

strbuf_add_absolute_path(out, path);
strbuf_addch(out, PATH_SEP);
}
}
Expand Down
1 change: 1 addition & 0 deletions git-compat-util.h
Expand Up @@ -607,6 +607,7 @@ extern int xmkstemp(char *template);
extern int xmkstemp_mode(char *template, int mode);
extern int odb_mkstemp(char *template, size_t limit, const char *pattern);
extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);
extern char *xgetcwd(void);

static inline size_t xsize_t(off_t len)
{
Expand Down
13 changes: 7 additions & 6 deletions git.c
Expand Up @@ -20,7 +20,7 @@ const char git_more_info_string[] =

static struct startup_info git_startup_info;
static int use_pager = -1;
static char orig_cwd[PATH_MAX];
static char *orig_cwd;
static const char *env_names[] = {
GIT_DIR_ENVIRONMENT,
GIT_WORK_TREE_ENVIRONMENT,
Expand All @@ -36,8 +36,7 @@ static void save_env(void)
if (saved_environment)
return;
saved_environment = 1;
if (!getcwd(orig_cwd, sizeof(orig_cwd)))
die_errno("cannot getcwd");
orig_cwd = xgetcwd();
for (i = 0; i < ARRAY_SIZE(env_names); i++) {
orig_env[i] = getenv(env_names[i]);
if (orig_env[i])
Expand All @@ -48,8 +47,9 @@ static void save_env(void)
static void restore_env(void)
{
int i;
if (*orig_cwd && chdir(orig_cwd))
if (orig_cwd && chdir(orig_cwd))
die_errno("could not move to %s", orig_cwd);
free(orig_cwd);
for (i = 0; i < ARRAY_SIZE(env_names); i++) {
if (orig_env[i])
setenv(env_names[i], orig_env[i], 1);
Expand Down Expand Up @@ -161,9 +161,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--bare")) {
static char git_dir[PATH_MAX+1];
char *cwd = xgetcwd();
is_bare_repository_cfg = 1;
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
setenv(GIT_DIR_ENVIRONMENT, cwd, 0);
free(cwd);
setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
if (envchanged)
*envchanged = 1;
Expand Down

0 comments on commit f655651

Please sign in to comment.