From: Junio C Hamano Date: Sun, 9 Nov 2008 00:13:19 +0000 (-0800) Subject: Merge branch 'ar/maint-mksnpath' into maint X-Git-Tag: v1.6.0.4~4 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/8b1981d32b41f1b4e26d8d96a3c6e63b9bc746b0?hp=-c Merge branch 'ar/maint-mksnpath' into maint * ar/maint-mksnpath: Use git_pathdup instead of xstrdup(git_path(...)) git_pathdup: returns xstrdup-ed copy of the formatted path Fix potentially dangerous use of git_path in ref.c Add git_snpath: a .git path formatting routine with output buffer Fix potentially dangerous uses of mkpath and git_path Fix mkpath abuse in dwim_ref and dwim_log of sha1_name.c Add mksnpath which allows you to specify the output buffer Conflicts: builtin-revert.c rerere.c --- 8b1981d32b41f1b4e26d8d96a3c6e63b9bc746b0 diff --combined builtin-revert.c index 786a956f26,5c4ab58f46..74845ef8e6 --- a/builtin-revert.c +++ b/builtin-revert.c @@@ -269,7 -269,7 +269,7 @@@ static int revert_or_cherry_pick(int ar int i; char *oneline, *reencoded_message = NULL; const char *message, *encoding; - char *defmsg = xstrdup(git_path("MERGE_MSG")); - const char *defmsg = git_pathdup("MERGE_MSG"); ++ char *defmsg = git_pathdup("MERGE_MSG"); git_config(git_default_config, NULL); me = action == REVERT ? "revert" : "cherry-pick"; @@@ -338,8 -338,7 +338,8 @@@ * reverse of it if we are revert. */ - msg_fd = hold_lock_file_for_update(&msg_file, defmsg, 1); + msg_fd = hold_lock_file_for_update(&msg_file, defmsg, + LOCK_DIE_ON_ERROR); encoding = get_encoding(message); if (!encoding) @@@ -427,7 -426,6 +427,7 @@@ return execv_git_cmd(args); } free(reencoded_message); + free(defmsg); return 0; } diff --combined builtin-tag.c index 5b141c5846,6c6c35176e..843e9ac056 --- a/builtin-tag.c +++ b/builtin-tag.c @@@ -125,7 -125,7 +125,7 @@@ static int for_each_tag_name(const cha static int delete_tag(const char *name, const char *ref, const unsigned char *sha1) { - if (delete_ref(ref, sha1)) + if (delete_ref(ref, sha1, 0)) return 1; printf("Deleted tag '%s'\n", name); return 0; @@@ -283,7 -283,7 +283,7 @@@ static void create_tag(const unsigned c int fd; /* write the template message before editing: */ - path = xstrdup(git_path("TAG_EDITMSG")); + path = git_pathdup("TAG_EDITMSG"); fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (fd < 0) die("could not create file '%s': %s", diff --combined cache.h index 39f24ad827,eaacd6dd9f..a1e4982cd4 --- a/cache.h +++ b/cache.h @@@ -270,7 -270,6 +270,7 @@@ static inline void remove_name_hash(str #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options)) #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options)) #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase)) +#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen)) #endif enum object_type { @@@ -383,7 -382,6 +383,7 @@@ extern int add_to_index(struct index_st extern int add_file_to_index(struct index_state *, const char *path, int flags); extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh); extern int ce_same_name(struct cache_entry *a, struct cache_entry *b); +extern int index_name_is_other(const struct index_state *, const char *, int); /* do stat comparison even if CE_VALID is true */ #define CE_MATCH_IGNORE_VALID 01 @@@ -413,8 -411,6 +413,8 @@@ struct lock_file char on_list; char filename[PATH_MAX]; }; +#define LOCK_DIE_ON_ERROR 1 +#define LOCK_NODEREF 2 extern int hold_lock_file_for_update(struct lock_file *, const char *path, int); extern int hold_lock_file_for_append(struct lock_file *, const char *path, int); extern int commit_lock_file(struct lock_file *); @@@ -424,7 -420,7 +424,7 @@@ extern int commit_locked_index(struct l extern void set_alternate_index_output(const char *); extern int close_lock_file(struct lock_file *); extern void rollback_lock_file(struct lock_file *); -extern int delete_ref(const char *, const unsigned char *sha1); +extern int delete_ref(const char *, const unsigned char *sha1, int delopt); /* Environment bits from configuration mechanism */ extern int trust_executable_bit; @@@ -484,6 -480,13 +484,13 @@@ extern int check_repository_format(void #define DATA_CHANGED 0x0020 #define TYPE_CHANGED 0x0040 + extern char *mksnpath(char *buf, size_t n, const char *fmt, ...) + __attribute__((format (printf, 3, 4))); + extern char *git_snpath(char *buf, size_t n, const char *fmt, ...) + __attribute__((format (printf, 3, 4))); + extern char *git_pathdup(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); + /* Return a statically allocated filename matching the sha1 signature */ extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); diff --combined path.c index c1cb54b7b8,092ce57190..eb24017535 --- a/path.c +++ b/path.c @@@ -32,6 -32,60 +32,60 @@@ static char *cleanup_path(char *path return path; } + char *mksnpath(char *buf, size_t n, const char *fmt, ...) + { + va_list args; + unsigned len; + + va_start(args, fmt); + len = vsnprintf(buf, n, fmt, args); + va_end(args); + if (len >= n) { + snprintf(buf, n, bad_path); + return buf; + } + return cleanup_path(buf); + } + + static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args) + { + const char *git_dir = get_git_dir(); + size_t len; + + len = strlen(git_dir); + if (n < len + 1) + goto bad; + 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: + snprintf(buf, n, bad_path); + return buf; + } + + char *git_snpath(char *buf, size_t n, const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + (void)git_vsnpath(buf, n, fmt, args); + va_end(args); + return buf; + } + + char *git_pathdup(const char *fmt, ...) + { + char path[PATH_MAX]; + va_list args; + va_start(args, fmt); + (void)git_vsnpath(path, sizeof(path), fmt, args); + va_end(args); + return xstrdup(path); + } + char *mkpath(const char *fmt, ...) { va_list args; @@@ -348,7 -402,7 +402,7 @@@ int normalize_absolute_path(char *buf, goto next; } - memcpy(dst, comp_start, comp_len); + memmove(dst, comp_start, comp_len); dst += comp_len; next: comp_start = comp_end; diff --combined refs.c index 156714e54e,d589b25562..48271a99ab --- a/refs.c +++ b/refs.c @@@ -401,7 -401,7 +401,7 @@@ const char *resolve_ref(const char *ref *flag = 0; for (;;) { - const char *path = git_path("%s", ref); + char path[PATH_MAX]; struct stat st; char *buf; int fd; @@@ -409,6 -409,7 +409,7 @@@ if (--depth < 0) return NULL; + git_snpath(path, sizeof(path), "%s", ref); /* Special case: non-existing file. * Not having the refs/heads/new-branch is OK * if we are writing into it, so is .git/HEAD @@@ -790,7 -791,7 +791,7 @@@ static struct ref_lock *lock_ref_sha1_b struct ref_lock *lock; struct stat st; int last_errno = 0; - int type; + int type, lflags; int mustexist = (old_sha1 && !is_null_sha1(old_sha1)); lock = xcalloc(1, sizeof(struct ref_lock)); @@@ -830,11 -831,8 +831,11 @@@ lock->lk = xcalloc(1, sizeof(struct lock_file)); - if (flags & REF_NODEREF) + lflags = LOCK_DIE_ON_ERROR; + if (flags & REF_NODEREF) { ref = orig_ref; + lflags |= LOCK_NODEREF; + } lock->ref_name = xstrdup(ref); lock->orig_ref_name = xstrdup(orig_ref); ref_file = git_path("%s", ref); @@@ -848,8 -846,8 +849,8 @@@ error("unable to create directory for %s", ref_file); goto error_return; } - lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, 1); + lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, lflags); return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock; error_return: @@@ -915,33 -913,25 +916,33 @@@ static int repack_without_ref(const cha return commit_lock_file(&packlock); } -int delete_ref(const char *refname, const unsigned char *sha1) +int delete_ref(const char *refname, const unsigned char *sha1, int delopt) { struct ref_lock *lock; - int err, i, ret = 0, flag = 0; + int err, i = 0, ret = 0, flag = 0; lock = lock_ref_sha1_basic(refname, sha1, 0, &flag); if (!lock) return 1; - if (!(flag & REF_ISPACKED)) { + if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) { /* loose */ - i = strlen(lock->lk->filename) - 5; /* .lock */ - lock->lk->filename[i] = 0; - err = unlink(lock->lk->filename); + const char *path; + + if (!(delopt & REF_NODEREF)) { + i = strlen(lock->lk->filename) - 5; /* .lock */ + lock->lk->filename[i] = 0; + path = lock->lk->filename; + } else { + path = git_path(refname); + } + err = unlink(path); if (err && errno != ENOENT) { ret = 1; error("unlink(%s) failed: %s", - lock->lk->filename, strerror(errno)); + path, strerror(errno)); } - lock->lk->filename[i] = '.'; + if (!(delopt & REF_NODEREF)) + lock->lk->filename[i] = '.'; } /* removing the loose one could have resurrected an earlier * packed one. Also, if it was not loose we need to repack @@@ -966,16 -956,11 +967,16 @@@ int rename_ref(const char *oldref, cons struct ref_lock *lock; struct stat loginfo; int log = !lstat(git_path("logs/%s", oldref), &loginfo); + const char *symref = NULL; - if (S_ISLNK(loginfo.st_mode)) + if (log && S_ISLNK(loginfo.st_mode)) return error("reflog for %s is a symlink", oldref); - if (!resolve_ref(oldref, orig_sha1, 1, &flag)) + symref = resolve_ref(oldref, orig_sha1, 1, &flag); + if (flag & REF_ISSYMREF) + return error("refname %s is a symbolic ref, renaming it is not supported", + oldref); + if (!symref) return error("refname %s not found", oldref); if (!is_refname_available(newref, oldref, get_packed_refs(), 0)) @@@ -995,12 -980,12 +996,12 @@@ return error("unable to move logfile logs/%s to tmp-renamed-log: %s", oldref, strerror(errno)); - if (delete_ref(oldref, orig_sha1)) { + if (delete_ref(oldref, orig_sha1, REF_NODEREF)) { error("unable to delete old %s", oldref); goto rollback; } - if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1)) { + if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1, REF_NODEREF)) { if (errno==EISDIR) { if (remove_empty_directories(git_path("%s", newref))) { error("Directory not empty: %s", newref); @@@ -1043,6 -1028,7 +1044,6 @@@ error("unable to lock %s for update", newref); goto rollback; } - lock->force_write = 1; hashcpy(lock->old_sha1, orig_sha1); if (write_ref_sha1(lock, orig_sha1, logmsg)) { @@@ -1136,13 -1122,14 +1137,14 @@@ static int log_ref_write(const char *re int logfd, written, oflags = O_APPEND | O_WRONLY; unsigned maxlen, len; int msglen; - char *log_file, *logrec; + char log_file[PATH_MAX]; + char *logrec; const char *committer; if (log_all_ref_updates < 0) log_all_ref_updates = !is_bare_repository(); - log_file = git_path("logs/%s", ref_name); + git_snpath(log_file, sizeof(log_file), "logs/%s", ref_name); if (log_all_ref_updates && (!prefixcmp(ref_name, "refs/heads/") || @@@ -1271,7 -1258,7 +1273,7 @@@ int create_symref(const char *ref_targe const char *lockpath; char ref[1000]; int fd, len, written; - char *git_HEAD = xstrdup(git_path("%s", ref_target)); + char *git_HEAD = git_pathdup("%s", ref_target); unsigned char old_sha1[20], new_sha1[20]; if (logmsg && read_ref(ref_target, old_sha1)) diff --combined rerere.c index 2b7a99d729,3d6ee8fa2a..a0d477aaca --- a/rerere.c +++ b/rerere.c @@@ -345,9 -345,8 +345,9 @@@ int setup_rerere(struct string_list *me if (!is_rerere_enabled()) return -1; - merge_rr_path = xstrdup(git_path("MERGE_RR")); + merge_rr_path = git_pathdup("MERGE_RR"); - fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1); + fd = hold_lock_file_for_update(&write_lock, merge_rr_path, + LOCK_DIE_ON_ERROR); read_rr(merge_rr); return fd; }