close_lock_file(): new function in the lockfile API

The lockfile API is a handy way to obtain a file that is cleaned
up if you die().  But sometimes you would need this sequence to
work:

 1. hold_lock_file_for_update() to get a file descriptor for
    writing;

 2. write the contents out, without being able to decide if the
    results should be committed or rolled back;

 3. do something else that makes the decision --- and this
    "something else" needs the lockfile not to have an open file
    descriptor for writing (e.g. Windows do not want a open file
    to be renamed);

 4. call commit_lock_file() or rollback_lock_file() as
    appropriately.

This adds close_lock_file() you can call between step 2 and 3 in
the above sequence.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Brandon Casey 2008-01-16 11:05:32 -08:00 коммит произвёл Junio C Hamano
Родитель 0c0478cac8
Коммит d6cf61bfd4
3 изменённых файлов: 35 добавлений и 12 удалений

Просмотреть файл

@ -37,7 +37,8 @@ commit_lock_file::
Take a pointer to the `struct lock_file` initialized Take a pointer to the `struct lock_file` initialized
with an earlier call to `hold_lock_file_for_update()`, with an earlier call to `hold_lock_file_for_update()`,
close the file descriptor and rename the lockfile to its close the file descriptor and rename the lockfile to its
final destination. final destination. Returns 0 upon success, a negative
value on failure to close(2) or rename(2).
rollback_lock_file:: rollback_lock_file::
@ -45,6 +46,12 @@ rollback_lock_file::
with an earlier call to `hold_lock_file_for_update()`, with an earlier call to `hold_lock_file_for_update()`,
close the file descriptor and remove the lockfile. close the file descriptor and remove the lockfile.
close_lock_file::
Take a pointer to the `struct lock_file` initialized
with an earlier call to `hold_lock_file_for_update()`,
and close the file descriptor. Returns 0 upon success,
a negative value on failure to close(2).
Because the structure is used in an `atexit(3)` handler, its Because the structure is used in an `atexit(3)` handler, its
storage has to stay throughout the life of the program. It storage has to stay throughout the life of the program. It
cannot be an auto variable allocated on the stack. cannot be an auto variable allocated on the stack.
@ -54,8 +61,10 @@ done writing to the file descriptor. If you do not call either
and simply `exit(3)` from the program, an `atexit(3)` handler and simply `exit(3)` from the program, an `atexit(3)` handler
will close and remove the lockfile. will close and remove the lockfile.
You should not close the file descriptor you obtained from If you need to close the file descriptor you obtained from
`hold_lock_file_for_update` function yourself. The `struct `hold_lock_file_for_update` function yourself, do so by calling
`close_lock_file()`. You should never call `close(2)` yourself!
Otherwise the `struct
lock_file` structure still remembers that the file descriptor lock_file` structure still remembers that the file descriptor
needs to be closed, and a later call to `commit_lock_file()` or needs to be closed, and a later call to `commit_lock_file()` or
`rollback_lock_file()` will result in duplicate calls to `rollback_lock_file()` will result in duplicate calls to

Просмотреть файл

@ -308,7 +308,7 @@ extern int commit_lock_file(struct lock_file *);
extern int hold_locked_index(struct lock_file *, int); extern int hold_locked_index(struct lock_file *, int);
extern int commit_locked_index(struct lock_file *); extern int commit_locked_index(struct lock_file *);
extern void set_alternate_index_output(const char *); extern void set_alternate_index_output(const char *);
extern int close_lock_file(struct lock_file *);
extern void rollback_lock_file(struct lock_file *); extern void rollback_lock_file(struct lock_file *);
extern int delete_ref(const char *, const unsigned char *sha1); extern int delete_ref(const char *, const unsigned char *sha1);

Просмотреть файл

@ -13,6 +13,7 @@ static void remove_lock_file(void)
while (lock_file_list) { while (lock_file_list) {
if (lock_file_list->owner == me && if (lock_file_list->owner == me &&
lock_file_list->filename[0]) { lock_file_list->filename[0]) {
if (lock_file_list->fd >= 0)
close(lock_file_list->fd); close(lock_file_list->fd);
unlink(lock_file_list->filename); unlink(lock_file_list->filename);
} }
@ -159,17 +160,26 @@ int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on
return fd; return fd;
} }
int close_lock_file(struct lock_file *lk)
{
int fd = lk->fd;
lk->fd = -1;
return close(fd);
}
int commit_lock_file(struct lock_file *lk) int commit_lock_file(struct lock_file *lk)
{ {
char result_file[PATH_MAX]; char result_file[PATH_MAX];
int i; size_t i;
close(lk->fd); if (lk->fd >= 0 && close_lock_file(lk))
return -1;
strcpy(result_file, lk->filename); strcpy(result_file, lk->filename);
i = strlen(result_file) - 5; /* .lock */ i = strlen(result_file) - 5; /* .lock */
result_file[i] = 0; result_file[i] = 0;
i = rename(lk->filename, result_file); if (rename(lk->filename, result_file))
return -1;
lk->filename[0] = 0; lk->filename[0] = 0;
return i; return 0;
} }
int hold_locked_index(struct lock_file *lk, int die_on_error) int hold_locked_index(struct lock_file *lk, int die_on_error)
@ -185,9 +195,12 @@ void set_alternate_index_output(const char *name)
int commit_locked_index(struct lock_file *lk) int commit_locked_index(struct lock_file *lk)
{ {
if (alternate_index_output) { if (alternate_index_output) {
int result = rename(lk->filename, alternate_index_output); if (lk->fd >= 0 && close_lock_file(lk))
return -1;
if (rename(lk->filename, alternate_index_output))
return -1;
lk->filename[0] = 0; lk->filename[0] = 0;
return result; return 0;
} }
else else
return commit_lock_file(lk); return commit_lock_file(lk);
@ -196,6 +209,7 @@ int commit_locked_index(struct lock_file *lk)
void rollback_lock_file(struct lock_file *lk) void rollback_lock_file(struct lock_file *lk)
{ {
if (lk->filename[0]) { if (lk->filename[0]) {
if (lk->fd >= 0)
close(lk->fd); close(lk->fd);
unlink(lk->filename); unlink(lk->filename);
} }