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>

Nguyễn Thái Ngọc Duy committed Nov 30, 2014 at 15:24 UTC 4ef9caf5431dbbd23f240a25b69a989aeb9840a4
1 file changed +51 -69
path.c
+51 -69
@@ -16,11 +16,15 @@ static int get_st_mode_bits(const char *path, int *mode)
16
17 static char bad_path[] = "/bad-path/";
18
19 -static char *get_pathname(void)
19 +static struct strbuf *get_pathname(void)
20 {
21 - static char pathname_array[4][PATH_MAX];
21 + static struct strbuf pathname_array[4] = {
22 + STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
23 + };
24 static int index;
23 - return pathname_array[3 & ++index];
25 + struct strbuf *sb = &pathname_array[3 & ++index];
26 + strbuf_reset(sb);
27 + return sb;
28 }
29
30 static char *cleanup_path(char *path)
@@ -34,6 +38,13 @@ static char *cleanup_path(char *path)
38 return path;
39 }
40
41 +static void strbuf_cleanup_path(struct strbuf *sb)
42 +{
43 + char *path = cleanup_path(sb->buf);
44 + if (path > sb->buf)
45 + strbuf_remove(sb, 0, path - sb->buf);
46 +}
47 +
48 char *mksnpath(char *buf, size_t n, const char *fmt, ...)
49 {
50 va_list args;
@@ -49,85 +60,70 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
60 return cleanup_path(buf);
61 }
62
52 -static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args)
63 +static void vsnpath(struct strbuf *buf, const char *fmt, va_list args)
64 {
65 const char *git_dir = get_git_dir();
55 - size_t len;
56 -
57 - len = strlen(git_dir);
58 - if (n < len + 1)
59 - goto bad;
60 - memcpy(buf, git_dir, len);
61 - if (len && !is_dir_sep(git_dir[len-1]))
62 - buf[len++] = '/';
63 - len += vsnprintf(buf + len, n - len, fmt, args);
64 - if (len >= n)
65 - goto bad;
66 - return cleanup_path(buf);
67 -bad:
68 - strlcpy(buf, bad_path, n);
69 - return buf;
66 + strbuf_addstr(buf, git_dir);
67 + if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
68 + strbuf_addch(buf, '/');
69 + strbuf_vaddf(buf, fmt, args);
70 + strbuf_cleanup_path(buf);
71 }
72
73 char *git_snpath(char *buf, size_t n, const char *fmt, ...)
74 {
74 - char *ret;
75 + struct strbuf sb = STRBUF_INIT;
76 va_list args;
77 va_start(args, fmt);
77 - ret = vsnpath(buf, n, fmt, args);
78 + vsnpath(&sb, fmt, args);
79 va_end(args);
79 - return ret;
80 + if (sb.len >= n)
81 + strlcpy(buf, bad_path, n);
82 + else
83 + memcpy(buf, sb.buf, sb.len + 1);
84 + strbuf_release(&sb);
85 + return buf;
86 }
87
88 char *git_pathdup(const char *fmt, ...)
89 {
84 - char path[PATH_MAX], *ret;
90 + struct strbuf path = STRBUF_INIT;
91 va_list args;
92 va_start(args, fmt);
87 - ret = vsnpath(path, sizeof(path), fmt, args);
93 + vsnpath(&path, fmt, args);
94 va_end(args);
89 - return xstrdup(ret);
95 + return strbuf_detach(&path, NULL);
96 }
97
98 char *mkpathdup(const char *fmt, ...)
99 {
94 - char *path;
100 struct strbuf sb = STRBUF_INIT;
101 va_list args;
97 -
102 va_start(args, fmt);
103 strbuf_vaddf(&sb, fmt, args);
104 va_end(args);
101 - path = xstrdup(cleanup_path(sb.buf));
102 -
103 - strbuf_release(&sb);
104 - return path;
105 + strbuf_cleanup_path(&sb);
106 + return strbuf_detach(&sb, NULL);
107 }
108
109 char *mkpath(const char *fmt, ...)
110 {
111 va_list args;
110 - unsigned len;
111 - char *pathname = get_pathname();
112 -
112 + struct strbuf *pathname = get_pathname();
113 va_start(args, fmt);
114 - len = vsnprintf(pathname, PATH_MAX, fmt, args);
114 + strbuf_vaddf(pathname, fmt, args);
115 va_end(args);
116 - if (len >= PATH_MAX)
117 - return bad_path;
118 - return cleanup_path(pathname);
116 + return cleanup_path(pathname->buf);
117 }
118
119 char *git_path(const char *fmt, ...)
120 {
123 - char *pathname = get_pathname();
121 + struct strbuf *pathname = get_pathname();
122 va_list args;
125 - char *ret;
126 -
123 va_start(args, fmt);
128 - ret = vsnpath(pathname, PATH_MAX, fmt, args);
124 + vsnpath(pathname, fmt, args);
125 va_end(args);
130 - return ret;
126 + return pathname->buf;
127 }
128
129 void home_config_paths(char **global, char **xdg, char *file)
@@ -160,41 +156,27 @@ void home_config_paths(char **global, char **xdg, char *file)
156
157 char *git_path_submodule(const char *path, const char *fmt, ...)
158 {
163 - char *pathname = get_pathname();
164 - struct strbuf buf = STRBUF_INIT;
159 + struct strbuf *buf = get_pathname();
160 const char *git_dir;
161 va_list args;
167 - unsigned len;
168 -
169 - len = strlen(path);
170 - if (len > PATH_MAX-100)
171 - return bad_path;
162
173 - strbuf_addstr(&buf, path);
174 - if (len && path[len-1] != '/')
175 - strbuf_addch(&buf, '/');
176 - strbuf_addstr(&buf, ".git");
163 + strbuf_addstr(buf, path);
164 + if (buf->len && buf->buf[buf->len - 1] != '/')
165 + strbuf_addch(buf, '/');
166 + strbuf_addstr(buf, ".git");
167
178 - git_dir = read_gitfile(buf.buf);
168 + git_dir = read_gitfile(buf->buf);
169 if (git_dir) {
180 - strbuf_reset(&buf);
181 - strbuf_addstr(&buf, git_dir);
170 + strbuf_reset(buf);
171 + strbuf_addstr(buf, git_dir);
172 }
183 - strbuf_addch(&buf, '/');
184 -
185 - if (buf.len >= PATH_MAX)
186 - return bad_path;
187 - memcpy(pathname, buf.buf, buf.len + 1);
188 -
189 - strbuf_release(&buf);
190 - len = strlen(pathname);
173 + strbuf_addch(buf, '/');
174
175 va_start(args, fmt);
193 - len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
176 + strbuf_vaddf(buf, fmt, args);
177 va_end(args);
195 - if (len >= PATH_MAX)
196 - return bad_path;
197 - return cleanup_path(pathname);
178 + strbuf_cleanup_path(buf);
179 + return buf->buf;
180 }
181
182 int validate_headref(const char *path)