path.c: make get_pathname() return strbuf instead of static buffer

We've been avoiding PATH_MAX whenever possible. This patch makes
get_pathname() return a strbuf and updates the callers to take
advantage of this. The code is simplified as we no longer need to
worry about buffer overflow.

vsnpath() behavior is changed slightly: previously it always clears
the buffer before writing, now it just appends. Fortunately this is a
static function and all of its callers prepare the buffer properly:
git_path() gets the buffer from get_pathname() which resets the
buffer, the remaining call sites start with STRBUF_INIT'd buffer.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nguyễn Thái Ngọc Duy 2014-11-30 15:24:26 +07:00 коммит произвёл Junio C Hamano
Родитель b260d265e1
Коммит 4ef9caf543
1 изменённых файлов: 51 добавлений и 69 удалений

120
path.c
Просмотреть файл

@ -16,11 +16,15 @@ static int get_st_mode_bits(const char *path, int *mode)
static char bad_path[] = "/bad-path/"; static char bad_path[] = "/bad-path/";
static char *get_pathname(void) static struct strbuf *get_pathname(void)
{ {
static char pathname_array[4][PATH_MAX]; static struct strbuf pathname_array[4] = {
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
};
static int index; static int index;
return pathname_array[3 & ++index]; struct strbuf *sb = &pathname_array[3 & ++index];
strbuf_reset(sb);
return sb;
} }
static char *cleanup_path(char *path) static char *cleanup_path(char *path)
@ -34,6 +38,13 @@ static char *cleanup_path(char *path)
return path; return path;
} }
static void strbuf_cleanup_path(struct strbuf *sb)
{
char *path = cleanup_path(sb->buf);
if (path > sb->buf)
strbuf_remove(sb, 0, path - sb->buf);
}
char *mksnpath(char *buf, size_t n, const char *fmt, ...) char *mksnpath(char *buf, size_t n, const char *fmt, ...)
{ {
va_list args; va_list args;
@ -49,85 +60,70 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
return cleanup_path(buf); return cleanup_path(buf);
} }
static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args) static void vsnpath(struct strbuf *buf, const char *fmt, va_list args)
{ {
const char *git_dir = get_git_dir(); const char *git_dir = get_git_dir();
size_t len; strbuf_addstr(buf, git_dir);
if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
len = strlen(git_dir); strbuf_addch(buf, '/');
if (n < len + 1) strbuf_vaddf(buf, fmt, args);
goto bad; strbuf_cleanup_path(buf);
memcpy(buf, git_dir, len);
if (len && !is_dir_sep(git_dir[len-1]))
buf[len++] = '/';
len += vsnprintf(buf + len, n - len, fmt, args);
if (len >= n)
goto bad;
return cleanup_path(buf);
bad:
strlcpy(buf, bad_path, n);
return buf;
} }
char *git_snpath(char *buf, size_t n, const char *fmt, ...) char *git_snpath(char *buf, size_t n, const char *fmt, ...)
{ {
char *ret; struct strbuf sb = STRBUF_INIT;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ret = vsnpath(buf, n, fmt, args); vsnpath(&sb, fmt, args);
va_end(args); va_end(args);
return ret; if (sb.len >= n)
strlcpy(buf, bad_path, n);
else
memcpy(buf, sb.buf, sb.len + 1);
strbuf_release(&sb);
return buf;
} }
char *git_pathdup(const char *fmt, ...) char *git_pathdup(const char *fmt, ...)
{ {
char path[PATH_MAX], *ret; struct strbuf path = STRBUF_INIT;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ret = vsnpath(path, sizeof(path), fmt, args); vsnpath(&path, fmt, args);
va_end(args); va_end(args);
return xstrdup(ret); return strbuf_detach(&path, NULL);
} }
char *mkpathdup(const char *fmt, ...) char *mkpathdup(const char *fmt, ...)
{ {
char *path;
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
strbuf_vaddf(&sb, fmt, args); strbuf_vaddf(&sb, fmt, args);
va_end(args); va_end(args);
path = xstrdup(cleanup_path(sb.buf)); strbuf_cleanup_path(&sb);
return strbuf_detach(&sb, NULL);
strbuf_release(&sb);
return path;
} }
char *mkpath(const char *fmt, ...) char *mkpath(const char *fmt, ...)
{ {
va_list args; va_list args;
unsigned len; struct strbuf *pathname = get_pathname();
char *pathname = get_pathname();
va_start(args, fmt); va_start(args, fmt);
len = vsnprintf(pathname, PATH_MAX, fmt, args); strbuf_vaddf(pathname, fmt, args);
va_end(args); va_end(args);
if (len >= PATH_MAX) return cleanup_path(pathname->buf);
return bad_path;
return cleanup_path(pathname);
} }
char *git_path(const char *fmt, ...) char *git_path(const char *fmt, ...)
{ {
char *pathname = get_pathname(); struct strbuf *pathname = get_pathname();
va_list args; va_list args;
char *ret;
va_start(args, fmt); va_start(args, fmt);
ret = vsnpath(pathname, PATH_MAX, fmt, args); vsnpath(pathname, fmt, args);
va_end(args); va_end(args);
return ret; return pathname->buf;
} }
void home_config_paths(char **global, char **xdg, char *file) void home_config_paths(char **global, char **xdg, char *file)
@ -160,41 +156,27 @@ void home_config_paths(char **global, char **xdg, char *file)
char *git_path_submodule(const char *path, const char *fmt, ...) char *git_path_submodule(const char *path, const char *fmt, ...)
{ {
char *pathname = get_pathname(); struct strbuf *buf = get_pathname();
struct strbuf buf = STRBUF_INIT;
const char *git_dir; const char *git_dir;
va_list args; va_list args;
unsigned len;
len = strlen(path); strbuf_addstr(buf, path);
if (len > PATH_MAX-100) if (buf->len && buf->buf[buf->len - 1] != '/')
return bad_path; strbuf_addch(buf, '/');
strbuf_addstr(buf, ".git");
strbuf_addstr(&buf, path); git_dir = read_gitfile(buf->buf);
if (len && path[len-1] != '/')
strbuf_addch(&buf, '/');
strbuf_addstr(&buf, ".git");
git_dir = read_gitfile(buf.buf);
if (git_dir) { if (git_dir) {
strbuf_reset(&buf); strbuf_reset(buf);
strbuf_addstr(&buf, git_dir); strbuf_addstr(buf, git_dir);
} }
strbuf_addch(&buf, '/'); strbuf_addch(buf, '/');
if (buf.len >= PATH_MAX)
return bad_path;
memcpy(pathname, buf.buf, buf.len + 1);
strbuf_release(&buf);
len = strlen(pathname);
va_start(args, fmt); va_start(args, fmt);
len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args); strbuf_vaddf(buf, fmt, args);
va_end(args); va_end(args);
if (len >= PATH_MAX) strbuf_cleanup_path(buf);
return bad_path; return buf->buf;
return cleanup_path(pathname);
} }
int validate_headref(const char *path) int validate_headref(const char *path)