Expand ~ and ~user in core.excludesfile, commit.template
These config variables are parsed to substitute ~ and ~user with getpw entries. user_path() refactored into new function expand_user_path(), to allow dynamically allocating the return buffer. Original patch by Karl Chen, modified by Matthieu Moy, and further amended by Junio C Hamano. Signed-off-by: Karl Chen <quarl@quarl.org> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Matthieu Moy committed
Nov 17, 2009 at 18:24 UTC
395de250d9d9762b8ac1ce98b297d60d0b5bd643
5 files changed
+63
-37
Documentation/config.txt
+3
-1
@@ -380,7 +380,8 @@ Common unit suffixes of 'k', 'm', or 'g' are supported.
380
core.excludesfile::
381
In addition to '.gitignore' (per-directory) and
382
'.git/info/exclude', git looks into this file for patterns
383
- of files which are not meant to be tracked. See
383
+ of files which are not meant to be tracked. "~/" and "~user/"
384
+ are expanded to the specified user's home directory. See
385
linkgit:gitignore[5].
386
387
core.editor::
@@ -666,6 +667,7 @@ color.ui::
667
668
commit.template::
669
Specify a file to use as the template for new commit messages.
670
+ "~/" and "~user/" are expanded to the specified user's home directory.
671
672
diff.autorefreshindex::
673
When using 'git-diff' to compare with work tree
builtin-commit.c
+1
-1
@@ -954,7 +954,7 @@ static int git_commit_config(const char *k, const char *v, void *cb)
954
struct wt_status *s = cb;
955
956
if (!strcmp(k, "commit.template"))
957
- return git_config_string(&template_file, k, v);
957
+ return git_config_pathname(&template_file, k, v);
958
959
return git_status_config(k, v, s);
960
}
cache.h
+2
@@ -644,6 +644,7 @@ int set_shared_perm(const char *path, int mode);
644
#define adjust_shared_perm(path) set_shared_perm((path), 0)
645
int safe_create_leading_directories(char *path);
646
int safe_create_leading_directories_const(const char *path);
647
+extern char *expand_user_path(const char *path);
648
char *enter_repo(char *path, int strict);
649
static inline int is_absolute_path(const char *path)
650
{
@@ -902,6 +903,7 @@ extern unsigned long git_config_ulong(const char *, const char *);
903
extern int git_config_bool_or_int(const char *, const char *, int *);
904
extern int git_config_bool(const char *, const char *);
905
extern int git_config_string(const char **, const char *, const char *);
906
+extern int git_config_pathname(const char **, const char *, const char *);
907
extern int git_config_set(const char *, const char *);
908
extern int git_config_set_multivar(const char *, const char *, const char *, int);
909
extern int git_config_rename_section(const char *, const char *);
config.c
+11
-1
@@ -351,6 +351,16 @@ int git_config_string(const char **dest, const char *var, const char *value)
351
return 0;
352
}
353
354
+int git_config_pathname(const char **dest, const char *var, const char *value)
355
+{
356
+ if (!value)
357
+ return config_error_nonbool(var);
358
+ *dest = expand_user_path(value);
359
+ if (!*dest)
360
+ die("Failed to expand user dir in: '%s'", value);
361
+ return 0;
362
+}
363
+
364
static int git_default_core_config(const char *var, const char *value)
365
{
366
/* This needs a better name */
@@ -474,7 +484,7 @@ static int git_default_core_config(const char *var, const char *value)
484
return git_config_string(&editor_program, var, value);
485
486
if (!strcmp(var, "core.excludesfile"))
477
- return git_config_string(&excludes_file, var, value);
487
+ return git_config_pathname(&excludes_file, var, value);
488
489
if (!strcmp(var, "core.whitespace")) {
490
if (!value)
path.c
+46
-34
@@ -11,6 +11,7 @@
11
* which is what it's designed for.
12
*/
13
#include "cache.h"
14
+#include "strbuf.h"
15
16
static char bad_path[] = "/bad-path/";
17
@@ -207,43 +208,44 @@ int validate_headref(const char *path)
208
return -1;
209
}
210
210
-static char *user_path(char *buf, char *path, int sz)
211
+static struct passwd *getpw_str(const char *username, size_t len)
212
{
213
struct passwd *pw;
213
- char *slash;
214
- int len, baselen;
214
+ char *username_z = xmalloc(len + 1);
215
+ memcpy(username_z, username, len);
216
+ username_z[len] = '\0';
217
+ pw = getpwnam(username_z);
218
+ free(username_z);
219
+ return pw;
220
+}
221
216
- if (!path || path[0] != '~')
217
- return NULL;
218
- path++;
219
- slash = strchr(path, '/');
220
- if (path[0] == '/' || !path[0]) {
221
- pw = getpwuid(getuid());
222
- }
223
- else {
224
- if (slash) {
225
- *slash = 0;
226
- pw = getpwnam(path);
227
- *slash = '/';
228
- }
229
- else
230
- pw = getpwnam(path);
231
- }
232
- if (!pw || !pw->pw_dir || sz <= strlen(pw->pw_dir))
233
- return NULL;
234
- baselen = strlen(pw->pw_dir);
235
- memcpy(buf, pw->pw_dir, baselen);
236
- while ((1 < baselen) && (buf[baselen-1] == '/')) {
237
- buf[baselen-1] = 0;
238
- baselen--;
239
- }
240
- if (slash && slash[1]) {
241
- len = strlen(slash);
242
- if (sz <= baselen + len)
243
- return NULL;
244
- memcpy(buf + baselen, slash, len + 1);
222
+/*
223
+ * Return a string with ~ and ~user expanded via getpw*. If buf != NULL,
224
+ * then it is a newly allocated string. Returns NULL on getpw failure or
225
+ * if path is NULL.
226
+ */
227
+char *expand_user_path(const char *path)
228
+{
229
+ struct strbuf user_path = STRBUF_INIT;
230
+ const char *first_slash = strchrnul(path, '/');
231
+ const char *to_copy = path;
232
+
233
+ if (path == NULL)
234
+ goto return_null;
235
+ if (path[0] == '~') {
236
+ const char *username = path + 1;
237
+ size_t username_len = first_slash - username;
238
+ struct passwd *pw = getpw_str(username, username_len);
239
+ if (!pw)
240
+ goto return_null;
241
+ strbuf_add(&user_path, pw->pw_dir, strlen(pw->pw_dir));
242
+ to_copy = first_slash;
243
}
246
- return buf;
244
+ strbuf_add(&user_path, to_copy, strlen(to_copy));
245
+ return strbuf_detach(&user_path, NULL);
246
+return_null:
247
+ strbuf_release(&user_path);
248
+ return NULL;
249
}
250
251
/*
@@ -291,8 +293,18 @@ char *enter_repo(char *path, int strict)
293
if (PATH_MAX <= len)
294
return NULL;
295
if (path[0] == '~') {
294
- if (!user_path(used_path, path, PATH_MAX))
296
+ char *newpath = expand_user_path(path);
297
+ if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
298
+ free(newpath);
299
return NULL;
300
+ }
301
+ /*
302
+ * Copy back into the static buffer. A pity
303
+ * since newpath was not bounded, but other
304
+ * branches of the if are limited by PATH_MAX
305
+ * anyway.
306
+ */
307
+ strcpy(used_path, newpath); free(newpath);
308
strcpy(validated_path, path);
309
path = used_path;
310
}