From 498f679adc396c412bb84fb043023ec12794f032 Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 22 May 2015 15:20:21 +0200 Subject: [PATCH] config.c: create missing parent directories when modifying config files 'git config' (--add / --unset etc.) automatically creates missing config files. However, it fails with a misleading error message "could not lock config file" if the parent directory doesn't exist. Also create missing parent directories. This is particularly important when calling git config -f /non/existing/directory/config ... We *must not* create the leading directories when locking a config file. It is the caller's responsibility to ensure that the directory exists, just like it is the caller's responsibility to call `git init` before running repository operations. Point in case: if we simply create all leading directories, calling `git config user.name me` *outside* of a Git worktree will *create* .git/! This fixes https://github.com/git-for-windows/git/issues/643 and https://groups.google.com/forum/#!topic/git-for-windows/fVRdnDIKVuw [jes: prevented bogus .git/ directories from being created] Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin --- config.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/config.c b/config.c index 70b1e00489..165b6cfcbd 100644 --- a/config.c +++ b/config.c @@ -1971,6 +1971,20 @@ int git_config_key_is_valid(const char *key) return !git_config_parse_key_1(key, NULL, NULL, 1); } +static int lock_config_file(const char *config_filename, + struct lock_file **result) +{ + int fd; + + *result = xcalloc(1, sizeof(struct lock_file)); + fd = hold_lock_file_for_update(*result, config_filename, 0); + if (fd < 0) + error("could not lock config file %s: %s", config_filename, + strerror(errno)); + + return fd; +} + /* * If value==NULL, unset in (remove from) config, * if value_regex!=NULL, disregard key/value pairs where value does not match. @@ -2022,8 +2036,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, * The lock serves a purpose in addition to locking: the new * contents of .git/config will be written into it. */ - lock = xcalloc(1, sizeof(struct lock_file)); - fd = hold_lock_file_for_update(lock, config_filename, 0); + fd = lock_config_file(config_filename, &lock); if (fd < 0) { error_errno("could not lock config file %s", config_filename); free(store.key); @@ -2324,12 +2337,9 @@ int git_config_rename_section_in_file(const char *config_filename, if (!config_filename) config_filename = filename_buf = git_pathdup("config"); - lock = xcalloc(1, sizeof(struct lock_file)); - out_fd = hold_lock_file_for_update(lock, config_filename, 0); - if (out_fd < 0) { - ret = error("could not lock config file %s", config_filename); + out_fd = lock_config_file(config_filename, &lock); + if (out_fd < 0) goto out; - } if (!(config_file = fopen(config_filename, "rb"))) { /* no config file means nothing to rename, no error */