X-Git-Url: https://git.octo.it/?p=git.git;a=blobdiff_plain;f=refs.c;h=713ca467368e24f6112663b7b96921f9d1bbc145;hp=ae9825deadeda63c7ebc2d775ad59bd66256a6a4;hb=HEAD;hpb=70e34b2dc88e28f09903b85932ea679992da62ff diff --git a/refs.c b/refs.c index ae9825de..713ca467 100644 --- a/refs.c +++ b/refs.c @@ -104,6 +104,11 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master) error("Unable to create %s", git_HEAD); return -3; } + if (adjust_shared_perm(git_HEAD)) { + unlink(lockpath); + error("Unable to fix permissions on %s", lockpath); + return -4; + } return 0; } @@ -142,6 +147,8 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u namelen = strlen(de->d_name); if (namelen > 255) continue; + if (namelen>5 && !strcmp(de->d_name+namelen-5,".lock")) + continue; memcpy(path + baselen, de->d_name, namelen+1); if (stat(git_path("%s", path), &st) < 0) continue; @@ -257,7 +264,7 @@ int check_ref_format(const char *ref) } } -static struct ref_lock* verify_lock(struct ref_lock *lock, +static struct ref_lock *verify_lock(struct ref_lock *lock, const unsigned char *old_sha1, int mustexist) { char buf[40]; @@ -283,11 +290,12 @@ static struct ref_lock* verify_lock(struct ref_lock *lock, return lock; } -static struct ref_lock* lock_ref_sha1_basic(const char *path, +static struct ref_lock *lock_ref_sha1_basic(const char *path, int plen, const unsigned char *old_sha1, int mustexist) { struct ref_lock *lock; + struct stat st; lock = xcalloc(1, sizeof(struct ref_lock)); lock->lock_fd = -1; @@ -295,22 +303,21 @@ static struct ref_lock* lock_ref_sha1_basic(const char *path, plen = strlen(path) - plen; path = resolve_ref(path, lock->old_sha1, mustexist); if (!path) { - error("Can't read ref %s", path); unlock_ref(lock); return NULL; } + lock->lk = xcalloc(1, sizeof(struct lock_file)); lock->ref_file = strdup(path); - lock->lock_file = strdup(mkpath("%s.lock", lock->ref_file)); lock->log_file = strdup(git_path("logs/%s", lock->ref_file + plen)); + lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT; - if (safe_create_leading_directories(lock->lock_file)) - die("unable to create directory for %s", lock->lock_file); - lock->lock_fd = open(lock->lock_file, - O_WRONLY | O_CREAT | O_EXCL, 0666); + if (safe_create_leading_directories(lock->ref_file)) + die("unable to create directory for %s", lock->ref_file); + lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file); if (lock->lock_fd < 0) { error("Couldn't open lock file %s: %s", - lock->lock_file, strerror(errno)); + lock->lk->filename, strerror(errno)); unlock_ref(lock); return NULL; } @@ -318,32 +325,32 @@ static struct ref_lock* lock_ref_sha1_basic(const char *path, return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock; } -struct ref_lock* lock_ref_sha1(const char *ref, +struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1, int mustexist) { if (check_ref_format(ref)) return NULL; return lock_ref_sha1_basic(git_path("refs/%s", ref), - strlen(ref), old_sha1, mustexist); + 5 + strlen(ref), old_sha1, mustexist); } -struct ref_lock* lock_any_ref_for_update(const char *ref, +struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int mustexist) { return lock_ref_sha1_basic(git_path("%s", ref), strlen(ref), old_sha1, mustexist); } -void unlock_ref (struct ref_lock *lock) +void unlock_ref(struct ref_lock *lock) { if (lock->lock_fd >= 0) { close(lock->lock_fd); - unlink(lock->lock_file); + /* Do not free lock->lk -- atexit() still looks at them */ + if (lock->lk) + rollback_lock_file(lock->lk); } if (lock->ref_file) free(lock->ref_file); - if (lock->lock_file) - free(lock->lock_file); if (lock->log_file) free(lock->log_file); free(lock); @@ -382,7 +389,8 @@ static int log_ref_write(struct ref_lock *lock, sha1_to_hex(sha1), comitter, msg); - } else { + } + else { maxlen = strlen(comitter) + 2*40 + 4; logrec = xmalloc(maxlen); len = snprintf(logrec, maxlen, "%s %s %s\n", @@ -405,14 +413,14 @@ int write_ref_sha1(struct ref_lock *lock, if (!lock) return -1; - if (!memcmp(lock->old_sha1, sha1, 20)) { + if (!lock->force_write && !memcmp(lock->old_sha1, sha1, 20)) { unlock_ref(lock); return 0; } if (write(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 || write(lock->lock_fd, &term, 1) != 1 || close(lock->lock_fd) < 0) { - error("Couldn't write %s", lock->lock_file); + error("Couldn't write %s", lock->lk->filename); unlock_ref(lock); return -1; } @@ -420,7 +428,7 @@ int write_ref_sha1(struct ref_lock *lock, unlock_ref(lock); return -1; } - if (rename(lock->lock_file, lock->ref_file) < 0) { + if (commit_lock_file(lock->lk)) { error("Couldn't set %s", lock->ref_file); unlock_ref(lock); return -1; @@ -432,11 +440,12 @@ int write_ref_sha1(struct ref_lock *lock, int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1) { - const char *logfile, *logdata, *logend, *rec, *c; + const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec; char *tz_c; int logfd, tz; struct stat st; unsigned long date; + unsigned char logged_sha1[20]; logfile = git_path("logs/%s", ref); logfd = open(logfile, O_RDONLY, 0); @@ -448,32 +457,59 @@ int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1) logdata = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, logfd, 0); close(logfd); + lastrec = NULL; rec = logend = logdata + st.st_size; while (logdata < rec) { if (logdata < rec && *(rec-1) == '\n') rec--; - while (logdata < rec && *(rec-1) != '\n') + lastgt = NULL; + while (logdata < rec && *(rec-1) != '\n') { rec--; - c = rec; - while (c < logend && *c != '>' && *c != '\n') - c++; - if (c == logend || *c == '\n') + if (*rec == '>') + lastgt = rec; + } + if (!lastgt) die("Log %s is corrupt.", logfile); - date = strtoul(c + 1, NULL, 10); + date = strtoul(lastgt + 1, &tz_c, 10); if (date <= at_time) { - if (get_sha1_hex(rec + 41, sha1)) - die("Log %s is corrupt.", logfile); + if (lastrec) { + if (get_sha1_hex(lastrec, logged_sha1)) + die("Log %s is corrupt.", logfile); + if (get_sha1_hex(rec + 41, sha1)) + die("Log %s is corrupt.", logfile); + if (memcmp(logged_sha1, sha1, 20)) { + tz = strtoul(tz_c, NULL, 10); + fprintf(stderr, + "warning: Log %s has gap after %s.\n", + logfile, show_rfc2822_date(date, tz)); + } + } + else if (date == at_time) { + if (get_sha1_hex(rec + 41, sha1)) + die("Log %s is corrupt.", logfile); + } + else { + if (get_sha1_hex(rec + 41, logged_sha1)) + die("Log %s is corrupt.", logfile); + if (memcmp(logged_sha1, sha1, 20)) { + tz = strtoul(tz_c, NULL, 10); + fprintf(stderr, + "warning: Log %s unexpectedly ended on %s.\n", + logfile, show_rfc2822_date(date, tz)); + } + } munmap((void*)logdata, st.st_size); return 0; } + lastrec = rec; } - c = logdata; - while (c < logend && *c != '>' && *c != '\n') - c++; - if (c == logend || *c == '\n') + rec = logdata; + while (rec < logend && *rec != '>' && *rec != '\n') + rec++; + if (rec == logend || *rec == '\n') die("Log %s is corrupt.", logfile); - date = strtoul(c, &tz_c, 10); + date = strtoul(rec + 1, &tz_c, 10); tz = strtoul(tz_c, NULL, 10); if (get_sha1_hex(logdata, sha1)) die("Log %s is corrupt.", logfile);