X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=refs.c;h=aff02cd09d4e40b04f6764a6f6ab43240b736a08;hb=e2b7eaf0ca3897940961d23392d4ff718867ea9f;hp=4dc7e8b47659b75cc0dcf334f1bf33798b2e5157;hpb=5c054a985a5b7e758f48353ac03582c9b2a9f919;p=git.git diff --git a/refs.c b/refs.c index 4dc7e8b47..aff02cd09 100644 --- a/refs.c +++ b/refs.c @@ -2,6 +2,7 @@ #include "refs.h" #include "object.h" #include "tag.h" +#include "dir.h" /* ISSYMREF=01 and ISPACKED=02 are public interfaces */ #define REF_KNOWS_PEELED 04 @@ -671,57 +672,23 @@ static struct ref_lock *verify_lock(struct ref_lock *lock, return lock; } -static int remove_empty_dir_recursive(char *path, int len) -{ - DIR *dir = opendir(path); - struct dirent *e; - int ret = 0; - - if (!dir) - return -1; - if (path[len-1] != '/') - path[len++] = '/'; - while ((e = readdir(dir)) != NULL) { - struct stat st; - int namlen; - if ((e->d_name[0] == '.') && - ((e->d_name[1] == 0) || - ((e->d_name[1] == '.') && e->d_name[2] == 0))) - continue; /* "." and ".." */ - - namlen = strlen(e->d_name); - if ((len + namlen < PATH_MAX) && - strcpy(path + len, e->d_name) && - !lstat(path, &st) && - S_ISDIR(st.st_mode) && - !remove_empty_dir_recursive(path, len + namlen)) - continue; /* happy */ - - /* path too long, stat fails, or non-directory still exists */ - ret = -1; - break; - } - closedir(dir); - if (!ret) { - path[len] = 0; - ret = rmdir(path); - } - return ret; -} - -static int remove_empty_directories(char *file) +static int remove_empty_directories(const char *file) { /* we want to create a file but there is a directory there; * if that is an empty directory (or a directory that contains * only empty directories), remove them. */ - char path[PATH_MAX]; - int len = strlen(file); + struct strbuf path; + int result; - if (len >= PATH_MAX) /* path too long ;-) */ - return -1; - strcpy(path, file); - return remove_empty_dir_recursive(path, len); + strbuf_init(&path, 20); + strbuf_addstr(&path, file); + + result = remove_dir_recursively(&path, 1); + + strbuf_release(&path); + + return result; } static int is_refname_available(const char *ref, const char *oldref, @@ -869,6 +836,7 @@ static int repack_without_ref(const char *refname) die("too long a refname '%s'", list->name); write_or_die(fd, line, len); } + close(fd); return commit_lock_file(&packlock); } @@ -1036,6 +1004,32 @@ void unlock_ref(struct ref_lock *lock) free(lock); } +/* + * copy the reflog message msg to buf, which has been allocated sufficiently + * large, while cleaning up the whitespaces. Especially, convert LF to space, + * because reflog file is one line per entry. + */ +static int copy_msg(char *buf, const char *msg) +{ + char *cp = buf; + char c; + int wasspace = 1; + + *cp++ = '\t'; + while ((c = *msg++)) { + if (wasspace && isspace(c)) + continue; + wasspace = isspace(c); + if (wasspace) + c = ' '; + *cp++ = c; + } + while (buf < cp && isspace(cp[-1])) + cp--; + *cp++ = '\n'; + return cp - buf; +} + static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, const unsigned char *new_sha1, const char *msg) { @@ -1080,21 +1074,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, adjust_shared_perm(log_file); - msglen = 0; - if (msg) { - /* clean up the message and make sure it is a single line */ - for ( ; *msg; msg++) - if (!isspace(*msg)) - break; - if (*msg) { - const char *ep = strchr(msg, '\n'); - if (ep) - msglen = ep - msg; - else - msglen = strlen(msg); - } - } - + msglen = msg ? strlen(msg) : 0; committer = git_committer_info(-1); maxlen = strlen(committer) + msglen + 100; logrec = xmalloc(maxlen); @@ -1103,7 +1083,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, sha1_to_hex(new_sha1), committer); if (msglen) - len += sprintf(logrec + len - 1, "\t%.*s\n", msglen, msg) - 1; + len += copy_msg(logrec + len - 1, msg) - 1; written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1; free(logrec); if (close(logfd) != 0 || written != len) @@ -1233,15 +1213,11 @@ int create_symref(const char *ref_target, const char *refs_heads_master, static char *ref_msg(const char *line, const char *endp) { const char *ep; - char *msg; - line += 82; - for (ep = line; ep < endp && *ep != '\n'; ep++) - ; - msg = xmalloc(ep - line + 1); - memcpy(msg, line, ep - line); - msg[ep - line] = 0; - return msg; + ep = memchr(line, '\n', endp - line); + if (!ep) + ep = endp; + return xmemdupz(line, ep - line); } int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *sha1, char **msg, unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt) @@ -1300,7 +1276,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * if (hashcmp(logged_sha1, sha1)) { fprintf(stderr, "warning: Log %s has gap after %s.\n", - logfile, show_rfc2822_date(date, tz)); + logfile, show_date(date, tz, DATE_RFC2822)); } } else if (date == at_time) { @@ -1313,7 +1289,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * if (hashcmp(logged_sha1, sha1)) { fprintf(stderr, "warning: Log %s unexpectedly ended on %s.\n", - logfile, show_rfc2822_date(date, tz)); + logfile, show_date(date, tz, DATE_RFC2822)); } } munmap(log_mapped, mapsz); @@ -1442,3 +1418,30 @@ int for_each_reflog(each_ref_fn fn, void *cb_data) { return do_for_each_reflog("", fn, cb_data); } + +int update_ref(const char *action, const char *refname, + const unsigned char *sha1, const unsigned char *oldval, + int flags, enum action_on_err onerr) +{ + static struct ref_lock *lock; + lock = lock_any_ref_for_update(refname, oldval, flags); + if (!lock) { + const char *str = "Cannot lock the ref '%s'."; + switch (onerr) { + case MSG_ON_ERR: error(str, refname); break; + case DIE_ON_ERR: die(str, refname); break; + case QUIET_ON_ERR: break; + } + return 1; + } + if (write_ref_sha1(lock, sha1, action) < 0) { + const char *str = "Cannot update the ref '%s'."; + switch (onerr) { + case MSG_ON_ERR: error(str, refname); break; + case DIE_ON_ERR: die(str, refname); break; + case QUIET_ON_ERR: break; + } + return 1; + } + return 0; +}