Merge branch 'mh/tempfile'
The "lockfile" API has been rebuilt on top of a new "tempfile" API. * mh/tempfile: credential-cache--daemon: use tempfile module credential-cache--daemon: delete socket from main() gc: use tempfile module to handle gc.pid file lock_repo_for_gc(): compute the path to "gc.pid" only once diff: use tempfile module setup_temporary_shallow(): use tempfile module write_shared_index(): use tempfile module register_tempfile(): new function to handle an existing temporary file tempfile: add several functions for creating temporary files prepare_tempfile_object(): new function, extracted from create_tempfile() tempfile: a new module for handling temporary files commit_lock_file(): use get_locked_file_path() lockfile: add accessor get_lock_file_path() lockfile: add accessors get_lock_file_fd() and get_lock_file_fp() create_bundle(): duplicate file descriptor to avoid closing it twice lockfile: move documentation to lockfile.h and lockfile.c
This commit is contained in:
211
lockfile.c
211
lockfile.c
@ -1,38 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Junio C Hamano
|
||||
*/
|
||||
|
||||
#include "cache.h"
|
||||
#include "lockfile.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
static struct lock_file *volatile lock_file_list;
|
||||
|
||||
static void remove_lock_files(int skip_fclose)
|
||||
{
|
||||
pid_t me = getpid();
|
||||
|
||||
while (lock_file_list) {
|
||||
if (lock_file_list->owner == me) {
|
||||
/* fclose() is not safe to call in a signal handler */
|
||||
if (skip_fclose)
|
||||
lock_file_list->fp = NULL;
|
||||
rollback_lock_file(lock_file_list);
|
||||
}
|
||||
lock_file_list = lock_file_list->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_lock_files_on_exit(void)
|
||||
{
|
||||
remove_lock_files(0);
|
||||
}
|
||||
|
||||
static void remove_lock_files_on_signal(int signo)
|
||||
{
|
||||
remove_lock_files(1);
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
/*
|
||||
* path = absolute or relative path name
|
||||
@ -101,60 +72,17 @@ static void resolve_symlink(struct strbuf *path)
|
||||
/* Make sure errno contains a meaningful value on error */
|
||||
static int lock_file(struct lock_file *lk, const char *path, int flags)
|
||||
{
|
||||
size_t pathlen = strlen(path);
|
||||
int fd;
|
||||
struct strbuf filename = STRBUF_INIT;
|
||||
|
||||
if (!lock_file_list) {
|
||||
/* One-time initialization */
|
||||
sigchain_push_common(remove_lock_files_on_signal);
|
||||
atexit(remove_lock_files_on_exit);
|
||||
}
|
||||
strbuf_addstr(&filename, path);
|
||||
if (!(flags & LOCK_NO_DEREF))
|
||||
resolve_symlink(&filename);
|
||||
|
||||
if (lk->active)
|
||||
die("BUG: cannot lock_file(\"%s\") using active struct lock_file",
|
||||
path);
|
||||
if (!lk->on_list) {
|
||||
/* Initialize *lk and add it to lock_file_list: */
|
||||
lk->fd = -1;
|
||||
lk->fp = NULL;
|
||||
lk->active = 0;
|
||||
lk->owner = 0;
|
||||
strbuf_init(&lk->filename, pathlen + LOCK_SUFFIX_LEN);
|
||||
lk->next = lock_file_list;
|
||||
lock_file_list = lk;
|
||||
lk->on_list = 1;
|
||||
} else if (lk->filename.len) {
|
||||
/* This shouldn't happen, but better safe than sorry. */
|
||||
die("BUG: lock_file(\"%s\") called with improperly-reset lock_file object",
|
||||
path);
|
||||
}
|
||||
|
||||
if (flags & LOCK_NO_DEREF) {
|
||||
strbuf_add_absolute_path(&lk->filename, path);
|
||||
} else {
|
||||
struct strbuf resolved_path = STRBUF_INIT;
|
||||
|
||||
strbuf_add(&resolved_path, path, pathlen);
|
||||
resolve_symlink(&resolved_path);
|
||||
strbuf_add_absolute_path(&lk->filename, resolved_path.buf);
|
||||
strbuf_release(&resolved_path);
|
||||
}
|
||||
|
||||
strbuf_addstr(&lk->filename, LOCK_SUFFIX);
|
||||
lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
|
||||
if (lk->fd < 0) {
|
||||
strbuf_reset(&lk->filename);
|
||||
return -1;
|
||||
}
|
||||
lk->owner = getpid();
|
||||
lk->active = 1;
|
||||
if (adjust_shared_perm(lk->filename.buf)) {
|
||||
int save_errno = errno;
|
||||
error("cannot fix permission bits on %s", lk->filename.buf);
|
||||
rollback_lock_file(lk);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
return lk->fd;
|
||||
strbuf_addstr(&filename, LOCK_SUFFIX);
|
||||
fd = create_tempfile(&lk->tempfile, filename.buf);
|
||||
strbuf_release(&filename);
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -287,116 +215,29 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
|
||||
return fd;
|
||||
}
|
||||
|
||||
FILE *fdopen_lock_file(struct lock_file *lk, const char *mode)
|
||||
{
|
||||
if (!lk->active)
|
||||
die("BUG: fdopen_lock_file() called for unlocked object");
|
||||
if (lk->fp)
|
||||
die("BUG: fdopen_lock_file() called twice for file '%s'", lk->filename.buf);
|
||||
|
||||
lk->fp = fdopen(lk->fd, mode);
|
||||
return lk->fp;
|
||||
}
|
||||
|
||||
char *get_locked_file_path(struct lock_file *lk)
|
||||
{
|
||||
if (!lk->active)
|
||||
die("BUG: get_locked_file_path() called for unlocked object");
|
||||
if (lk->filename.len <= LOCK_SUFFIX_LEN)
|
||||
struct strbuf ret = STRBUF_INIT;
|
||||
|
||||
strbuf_addstr(&ret, get_tempfile_path(&lk->tempfile));
|
||||
if (ret.len <= LOCK_SUFFIX_LEN ||
|
||||
strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
|
||||
die("BUG: get_locked_file_path() called for malformed lock object");
|
||||
return xmemdupz(lk->filename.buf, lk->filename.len - LOCK_SUFFIX_LEN);
|
||||
}
|
||||
|
||||
int close_lock_file(struct lock_file *lk)
|
||||
{
|
||||
int fd = lk->fd;
|
||||
FILE *fp = lk->fp;
|
||||
int err;
|
||||
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
lk->fd = -1;
|
||||
if (fp) {
|
||||
lk->fp = NULL;
|
||||
|
||||
/*
|
||||
* Note: no short-circuiting here; we want to fclose()
|
||||
* in any case!
|
||||
*/
|
||||
err = ferror(fp) | fclose(fp);
|
||||
} else {
|
||||
err = close(fd);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
int save_errno = errno;
|
||||
rollback_lock_file(lk);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reopen_lock_file(struct lock_file *lk)
|
||||
{
|
||||
if (0 <= lk->fd)
|
||||
die(_("BUG: reopen a lockfile that is still open"));
|
||||
if (!lk->active)
|
||||
die(_("BUG: reopen a lockfile that has been committed"));
|
||||
lk->fd = open(lk->filename.buf, O_WRONLY);
|
||||
return lk->fd;
|
||||
}
|
||||
|
||||
int commit_lock_file_to(struct lock_file *lk, const char *path)
|
||||
{
|
||||
if (!lk->active)
|
||||
die("BUG: attempt to commit unlocked object to \"%s\"", path);
|
||||
|
||||
if (close_lock_file(lk))
|
||||
return -1;
|
||||
|
||||
if (rename(lk->filename.buf, path)) {
|
||||
int save_errno = errno;
|
||||
rollback_lock_file(lk);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
lk->active = 0;
|
||||
strbuf_reset(&lk->filename);
|
||||
return 0;
|
||||
/* remove ".lock": */
|
||||
strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN);
|
||||
return strbuf_detach(&ret, NULL);
|
||||
}
|
||||
|
||||
int commit_lock_file(struct lock_file *lk)
|
||||
{
|
||||
static struct strbuf result_file = STRBUF_INIT;
|
||||
int err;
|
||||
char *result_path = get_locked_file_path(lk);
|
||||
|
||||
if (!lk->active)
|
||||
die("BUG: attempt to commit unlocked object");
|
||||
|
||||
if (lk->filename.len <= LOCK_SUFFIX_LEN ||
|
||||
strcmp(lk->filename.buf + lk->filename.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
|
||||
die("BUG: lockfile filename corrupt");
|
||||
|
||||
/* remove ".lock": */
|
||||
strbuf_add(&result_file, lk->filename.buf,
|
||||
lk->filename.len - LOCK_SUFFIX_LEN);
|
||||
err = commit_lock_file_to(lk, result_file.buf);
|
||||
strbuf_reset(&result_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
void rollback_lock_file(struct lock_file *lk)
|
||||
{
|
||||
if (!lk->active)
|
||||
return;
|
||||
|
||||
if (!close_lock_file(lk)) {
|
||||
unlink_or_warn(lk->filename.buf);
|
||||
lk->active = 0;
|
||||
strbuf_reset(&lk->filename);
|
||||
if (commit_lock_file_to(lk, result_path)) {
|
||||
int save_errno = errno;
|
||||
free(result_path);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
free(result_path);
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user