From f63272a35e03a9895c468d1a698dabaa4c3d9273 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Thu, 13 Mar 2014 10:19:07 +0100 Subject: checkout_entry(): use the strbuf throughout the function There is no need to break out the "buf" and "len" members into separate temporary variables. Rename path_buf to path and use path.buf and path.len directly. This makes it easier to reason about the data flow in the function. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- entry.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'entry.c') diff --git a/entry.c b/entry.c index fbb486310..20d291918 100644 --- a/entry.c +++ b/entry.c @@ -237,27 +237,25 @@ static int check_path(const char *path, int len, struct stat *st, int skiplen) int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath) { - static struct strbuf path_buf = STRBUF_INIT; - char *path; + static struct strbuf path = STRBUF_INIT; struct stat st; - int len; if (topath) return write_entry(ce, topath, state, 1); - strbuf_reset(&path_buf); - strbuf_add(&path_buf, state->base_dir, state->base_dir_len); - strbuf_add(&path_buf, ce->name, ce_namelen(ce)); - path = path_buf.buf; - len = path_buf.len; + strbuf_reset(&path); + strbuf_add(&path, state->base_dir, state->base_dir_len); + strbuf_add(&path, ce->name, ce_namelen(ce)); - if (!check_path(path, len, &st, state->base_dir_len)) { + if (!check_path(path.buf, path.len, &st, state->base_dir_len)) { unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE); if (!changed) return 0; if (!state->force) { if (!state->quiet) - fprintf(stderr, "%s already exists, no checkout\n", path); + fprintf(stderr, + "%s already exists, no checkout\n", + path.buf); return -1; } @@ -272,12 +270,14 @@ int checkout_entry(struct cache_entry *ce, if (S_ISGITLINK(ce->ce_mode)) return 0; if (!state->force) - return error("%s is a directory", path); - remove_subtree(path); - } else if (unlink(path)) - return error("unable to unlink old '%s' (%s)", path, strerror(errno)); + return error("%s is a directory", path.buf); + remove_subtree(path.buf); + } else if (unlink(path.buf)) + return error("unable to unlink old '%s' (%s)", + path.buf, strerror(errno)); } else if (state->not_new) return 0; - create_directories(path, len, state); - return write_entry(ce, path, state, 0); + + create_directories(path.buf, path.len, state); + return write_entry(ce, path.buf, state, 0); } -- cgit v1.2.1 From 2f29e0c6fa5d312c4e0675b0dd23d3126b9f55fa Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Thu, 13 Mar 2014 10:19:08 +0100 Subject: entry.c: fix possible buffer overflow in remove_subtree() remove_subtree() manipulated path in a fixed-size buffer even though the length of the input, let alone the length of entries within the directory, were not known in advance. Change the function to take a strbuf argument and use that object as its scratch space. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- entry.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'entry.c') diff --git a/entry.c b/entry.c index 20d291918..fa0e5ec8a 100644 --- a/entry.c +++ b/entry.c @@ -44,33 +44,33 @@ static void create_directories(const char *path, int path_len, free(buf); } -static void remove_subtree(const char *path) +static void remove_subtree(struct strbuf *path) { - DIR *dir = opendir(path); + DIR *dir = opendir(path->buf); struct dirent *de; - char pathbuf[PATH_MAX]; - char *name; + int origlen = path->len; if (!dir) - die_errno("cannot opendir '%s'", path); - strcpy(pathbuf, path); - name = pathbuf + strlen(path); - *name++ = '/'; + die_errno("cannot opendir '%s'", path->buf); while ((de = readdir(dir)) != NULL) { struct stat st; + if (is_dot_or_dotdot(de->d_name)) continue; - strcpy(name, de->d_name); - if (lstat(pathbuf, &st)) - die_errno("cannot lstat '%s'", pathbuf); + + strbuf_addch(path, '/'); + strbuf_addstr(path, de->d_name); + if (lstat(path->buf, &st)) + die_errno("cannot lstat '%s'", path->buf); if (S_ISDIR(st.st_mode)) - remove_subtree(pathbuf); - else if (unlink(pathbuf)) - die_errno("cannot unlink '%s'", pathbuf); + remove_subtree(path); + else if (unlink(path->buf)) + die_errno("cannot unlink '%s'", path->buf); + strbuf_setlen(path, origlen); } closedir(dir); - if (rmdir(path)) - die_errno("cannot rmdir '%s'", path); + if (rmdir(path->buf)) + die_errno("cannot rmdir '%s'", path->buf); } static int create_file(const char *path, unsigned int mode) @@ -271,7 +271,7 @@ int checkout_entry(struct cache_entry *ce, return 0; if (!state->force) return error("%s is a directory", path.buf); - remove_subtree(path.buf); + remove_subtree(&path); } else if (unlink(path.buf)) return error("unable to unlink old '%s' (%s)", path.buf, strerror(errno)); -- cgit v1.2.1