зеркало из https://github.com/microsoft/git.git
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:
Родитель
0c0478cac8
Коммит
d6cf61bfd4
|
@ -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
|
||||||
|
|
2
cache.h
2
cache.h
|
@ -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);
|
||||||
|
|
||||||
|
|
26
lockfile.c
26
lockfile.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче