int log_ref_setup(const char *ref_name, char *logfile, int bufsize) { int logfd, oflags = O_APPEND | O_WRONLY; git_snpath(logfile, bufsize, "logs/%s", ref_name); if (log_all_ref_updates && (!prefixcmp(ref_name, "refs/heads/") || !prefixcmp(ref_name, "refs/remotes/") || !prefixcmp(ref_name, "refs/notes/") || !strcmp(ref_name, "HEAD"))) { if (safe_create_leading_directories(logfile) < 0) return error("unable to create directory for %s", logfile); oflags |= O_CREAT; } logfd = open(logfile, oflags, 0666); if (logfd < 0) { if (!(oflags & O_CREAT) && errno == ENOENT) return 0; if ((oflags & O_CREAT) && errno == EISDIR) { if (remove_empty_directories(logfile)) { return error("There are still logs under '%s'", logfile); } logfd = open(logfile, oflags, 0666); } if (logfd < 0) return error("Unable to append to %s: %s", logfile, strerror(errno)); } adjust_shared_perm(logfile); close(logfd); return 0; }
/* * If the "reading" argument is set, this function finds out what _object_ * the ref points at by "reading" the ref. The ref, if it is not symbolic, * has to exist, and if it is symbolic, it has to point at an existing ref, * because the "read" goes through the symref to the ref it points at. * * The access that is not "reading" may often be "writing", but does not * have to; it can be merely checking _where it leads to_. If it is a * prelude to "writing" to the ref, a write to a symref that points at * yet-to-be-born ref will create the real ref pointed by the symref. * reading=0 allows the caller to check where such a symref leads to. */ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag) { int depth = MAXDEPTH; ssize_t len; char buffer[256]; static char ref_buffer[256]; if (flag) *flag = 0; for (;;) { char path[PATH_MAX]; struct stat st; char *buf; int fd; if (--depth < 0) return NULL; git_snpath(path, sizeof(path), "%s", ref); /* Special case: non-existing file. */ if (lstat(path, &st) < 0) { struct ref_list *list = get_packed_refs(NULL); while (list) { if (!strcmp(ref, list->name)) { hashcpy(sha1, list->sha1); if (flag) *flag |= REF_ISPACKED; return ref; } list = list->next; } if (reading || errno != ENOENT) return NULL; hashclr(sha1); return ref; } /* Follow "normalized" - ie "refs/.." symlinks by hand */ if (S_ISLNK(st.st_mode)) { len = readlink(path, buffer, sizeof(buffer)-1); if (len >= 5 && !memcmp("refs/", buffer, 5)) { buffer[len] = 0; strcpy(ref_buffer, buffer); ref = ref_buffer; if (flag) *flag |= REF_ISSYMREF; continue; } } /* Is it a directory? */ if (S_ISDIR(st.st_mode)) { errno = EISDIR; return NULL; } /* * Anything else, just open it and try to use it as * a ref */ fd = open(path, O_RDONLY); if (fd < 0) return NULL; len = read_in_full(fd, buffer, sizeof(buffer)-1); close(fd); /* * Is it a symbolic ref? */ if (len < 4 || memcmp("ref:", buffer, 4)) break; buf = buffer + 4; len -= 4; while (len && isspace(*buf)) buf++, len--; while (len && isspace(buf[len-1])) len--; buf[len] = 0; memcpy(ref_buffer, buf, len + 1); ref = ref_buffer; if (flag) *flag |= REF_ISSYMREF; } if (len < 40 || get_sha1_hex(buffer, sha1)) return NULL; return ref; }
static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, const unsigned char *new_sha1, const char *msg) { int logfd, written, oflags = O_APPEND | O_WRONLY; unsigned maxlen, len; int msglen; char log_file[PATH_MAX]; char *logrec; const char *committer; if (log_all_ref_updates < 0) log_all_ref_updates = !is_bare_repository(); git_snpath(log_file, sizeof(log_file), "logs/%s", ref_name); if (log_all_ref_updates && (!prefixcmp(ref_name, "refs/heads/") || !prefixcmp(ref_name, "refs/remotes/") || !strcmp(ref_name, "HEAD"))) { if (safe_create_leading_directories(log_file) < 0) return error("unable to create directory for %s", log_file); oflags |= O_CREAT; } logfd = open(log_file, oflags, 0666); if (logfd < 0) { if (!(oflags & O_CREAT) && errno == ENOENT) return 0; if ((oflags & O_CREAT) && errno == EISDIR) { if (remove_empty_directories(log_file)) { return error("There are still logs under '%s'", log_file); } logfd = open(log_file, oflags, 0666); } if (logfd < 0) return error("Unable to append to %s: %s", log_file, strerror(errno)); } adjust_shared_perm(log_file); msglen = msg ? strlen(msg) : 0; committer = git_committer_info(0); maxlen = strlen(committer) + msglen + 100; logrec = xmalloc(maxlen); len = sprintf(logrec, "%s %s %s\n", sha1_to_hex(old_sha1), sha1_to_hex(new_sha1), committer); if (msglen) 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) return error("Unable to append to %s", log_file); return 0; }