In the previous patch, git_snpath() is modified to allocate a new strbuf buffer because vsnpath() needs that. But that makes it awkward because git_snpath() receives a pre-allocated buffer from outside and has to copy data back. Rename it to strbuf_git_path() and make it receive strbuf directly. Using git_path() in update_refs_for_switch() which used to call git_snpath() is safe because that function and all of its callers do not keep any pointer to the round-robin buffer pool allocated by get_pathname(). Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx> --- builtin/checkout.c | 13 +++++---- cache.h | 4 +-- path.c | 11 ++------ refs.c | 78 +++++++++++++++++++++++++++++++++--------------------- refs.h | 2 +- 5 files changed, 61 insertions(+), 47 deletions(-) diff --git a/builtin/checkout.c b/builtin/checkout.c index d402d7a..220f80e 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -588,18 +588,21 @@ static void update_refs_for_switch(const struct checkout_opts *opts, if (opts->new_orphan_branch) { if (opts->new_branch_log && !log_all_ref_updates) { int temp; - char log_file[PATH_MAX]; - const char *ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch); + struct strbuf log_file = STRBUF_INIT; + int ret; + const char *ref_name; + ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch); temp = log_all_ref_updates; log_all_ref_updates = 1; - if (log_ref_setup(ref_name, log_file, sizeof(log_file))) { + ret = log_ref_setup(ref_name, &log_file); + log_all_ref_updates = temp; + strbuf_release(&log_file); + if (ret) { fprintf(stderr, _("Can not do reflog for '%s'\n"), opts->new_orphan_branch); - log_all_ref_updates = temp; return; } - log_all_ref_updates = temp; } } else diff --git a/cache.h b/cache.h index 2e4d88f..f487c0e 100644 --- a/cache.h +++ b/cache.h @@ -697,8 +697,8 @@ extern int check_repository_format(void); 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 void strbuf_git_path(struct strbuf *sb, const char *fmt, ...) + __attribute__((format (printf, 2, 3))); extern char *git_pathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); extern char *mkpathdup(const char *fmt, ...) diff --git a/path.c b/path.c index a7ceea2..47753aa 100644 --- a/path.c +++ b/path.c @@ -70,19 +70,12 @@ static void vsnpath(struct strbuf *buf, const char *fmt, va_list args) strbuf_cleanup_path(buf); } -char *git_snpath(char *buf, size_t n, const char *fmt, ...) +void strbuf_git_path(struct strbuf *sb, const char *fmt, ...) { - struct strbuf sb = STRBUF_INIT; va_list args; va_start(args, fmt); - vsnpath(&sb, fmt, args); + vsnpath(sb, fmt, args); va_end(args); - 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, ...) diff --git a/refs.c b/refs.c index f616adc..3cefbd3 100644 --- a/refs.c +++ b/refs.c @@ -1400,10 +1400,12 @@ static const char *handle_missing_loose_ref(const char *refname, /* This function needs to return a meaningful errno on failure */ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag) { + struct strbuf sb_path = STRBUF_INIT; int depth = MAXDEPTH; ssize_t len; char buffer[256]; static char refname_buffer[256]; + const char *ret; if (flag) *flag = 0; @@ -1414,17 +1416,19 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea } for (;;) { - char path[PATH_MAX]; + const char *path; struct stat st; char *buf; int fd; if (--depth < 0) { errno = ELOOP; - return NULL; + goto fail; } - git_snpath(path, sizeof(path), "%s", refname); + strbuf_reset(&sb_path); + strbuf_git_path(&sb_path, "%s", refname); + path = sb_path.buf; /* * We might have to loop back here to avoid a race @@ -1438,10 +1442,11 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea stat_ref: if (lstat(path, &st) < 0) { if (errno == ENOENT) - return handle_missing_loose_ref(refname, sha1, - reading, flag); + ret = handle_missing_loose_ref(refname, sha1, + reading, flag); else - return NULL; + ret = NULL; + goto done; } /* Follow "normalized" - ie "refs/.." symlinks by hand */ @@ -1452,7 +1457,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea /* inconsistent with lstat; retry */ goto stat_ref; else - return NULL; + goto fail; } buffer[len] = 0; if (starts_with(buffer, "refs/") && @@ -1468,7 +1473,7 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea /* Is it a directory? */ if (S_ISDIR(st.st_mode)) { errno = EISDIR; - return NULL; + goto fail; } /* @@ -1481,14 +1486,15 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea /* inconsistent with lstat; retry */ goto stat_ref; else - return NULL; + goto fail; } + len = read_in_full(fd, buffer, sizeof(buffer)-1); if (len < 0) { int save_errno = errno; close(fd); errno = save_errno; - return NULL; + goto fail; } close(fd); while (len && isspace(buffer[len-1])) @@ -1508,9 +1514,10 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea if (flag) *flag |= REF_ISBROKEN; errno = EINVAL; - return NULL; + goto fail; } - return refname; + ret = refname; + goto done; } if (flag) *flag |= REF_ISSYMREF; @@ -1521,10 +1528,15 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea if (flag) *flag |= REF_ISBROKEN; errno = EINVAL; - return NULL; + goto fail; } refname = strcpy(refname_buffer, buf); } +fail: + ret = NULL; +done: + strbuf_release(&sb_path); + return ret; } char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag) @@ -2832,51 +2844,51 @@ static int copy_msg(char *buf, const char *msg) } /* This function must set a meaningful errno on failure */ -int log_ref_setup(const char *refname, char *logfile, int bufsize) +int log_ref_setup(const char *refname, struct strbuf *logfile) { int logfd, oflags = O_APPEND | O_WRONLY; - git_snpath(logfile, bufsize, "logs/%s", refname); + strbuf_git_path(logfile, "logs/%s", refname); if (log_all_ref_updates && (starts_with(refname, "refs/heads/") || starts_with(refname, "refs/remotes/") || starts_with(refname, "refs/notes/") || !strcmp(refname, "HEAD"))) { - if (safe_create_leading_directories(logfile) < 0) { + if (safe_create_leading_directories(logfile->buf) < 0) { int save_errno = errno; - error("unable to create directory for %s", logfile); + error("unable to create directory for %s", logfile->buf); errno = save_errno; return -1; } oflags |= O_CREAT; } - logfd = open(logfile, oflags, 0666); + logfd = open(logfile->buf, oflags, 0666); if (logfd < 0) { if (!(oflags & O_CREAT) && errno == ENOENT) return 0; if ((oflags & O_CREAT) && errno == EISDIR) { - if (remove_empty_directories(logfile)) { + if (remove_empty_directories(logfile->buf)) { int save_errno = errno; error("There are still logs under '%s'", - logfile); + logfile->buf); errno = save_errno; return -1; } - logfd = open(logfile, oflags, 0666); + logfd = open(logfile->buf, oflags, 0666); } if (logfd < 0) { int save_errno = errno; - error("Unable to append to %s: %s", logfile, + error("Unable to append to %s: %s", logfile->buf, strerror(errno)); errno = save_errno; return -1; } } - adjust_shared_perm(logfile); + adjust_shared_perm(logfile->buf); close(logfd); return 0; } @@ -2887,20 +2899,22 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1, int logfd, result, written, oflags = O_APPEND | O_WRONLY; unsigned maxlen, len; int msglen; - char log_file[PATH_MAX]; + struct strbuf sb_log_file = STRBUF_INIT; + const char *log_file; char *logrec; const char *committer; if (log_all_ref_updates < 0) log_all_ref_updates = !is_bare_repository(); - result = log_ref_setup(refname, log_file, sizeof(log_file)); + result = log_ref_setup(refname, &sb_log_file); if (result) - return result; + goto done; + log_file = sb_log_file.buf; logfd = open(log_file, oflags); if (logfd < 0) - return 0; + goto done; msglen = msg ? strlen(msg) : 0; committer = git_committer_info(0); maxlen = strlen(committer) + msglen + 100; @@ -2918,15 +2932,19 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1, close(logfd); error("Unable to append to %s", log_file); errno = save_errno; - return -1; + result = -1; + goto done; } if (close(logfd)) { int save_errno = errno; error("Unable to append to %s", log_file); errno = save_errno; - return -1; + result = -1; + goto done; } - return 0; +done: + strbuf_release(&sb_log_file); + return result; } int is_branch(const char *refname) diff --git a/refs.h b/refs.h index 10fc3a2..c990a85 100644 --- a/refs.h +++ b/refs.h @@ -203,7 +203,7 @@ extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, cons /* * Setup reflog before using. Set errno to something meaningful on failure. */ -int log_ref_setup(const char *refname, char *logfile, int bufsize); +int log_ref_setup(const char *refname, struct strbuf *logfile); /** Reads log for the value of ref during at_time. **/ extern int read_ref_at(const char *refname, unsigned long at_time, int cnt, -- 2.1.0.rc0.78.gc0d8480 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html