summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-10-14 10:49:45 -0700
committerJunio C Hamano <gitster@pobox.com>2014-10-14 10:49:45 -0700
commitbd107e1052a11cf7dd6baf9077eab52fbb9d9c90 (patch)
tree8488a958144d162776be2fa557d291cb25ac0e6b
parent7543dea8b2a33e4a56b0fdd408bc47769238025e (diff)
parent697cc8efd944a32ca472337cd6640004c474b788 (diff)
downloadgit-bd107e1052a11cf7dd6baf9077eab52fbb9d9c90.tar.gz
Merge branch 'mh/lockfile'
The lockfile API and its users have been cleaned up. * mh/lockfile: (38 commits) lockfile.h: extract new header file for the functions in lockfile.c hold_locked_index(): move from lockfile.c to read-cache.c hold_lock_file_for_append(): restore errno before returning get_locked_file_path(): new function lockfile.c: rename static functions lockfile: rename LOCK_NODEREF to LOCK_NO_DEREF commit_lock_file_to(): refactor a helper out of commit_lock_file() trim_last_path_component(): replace last_path_elm() resolve_symlink(): take a strbuf parameter resolve_symlink(): use a strbuf for internal scratch space lockfile: change lock_file::filename into a strbuf commit_lock_file(): use a strbuf to manage temporary space try_merge_strategy(): use a statically-allocated lock_file object try_merge_strategy(): remove redundant lock_file allocation struct lock_file: declare some fields volatile lockfile: avoid transitory invalid states git_config_set_multivar_in_file(): avoid call to rollback_lock_file() dump_marks(): remove a redundant call to rollback_lock_file() api-lockfile: document edge cases commit_lock_file(): rollback lock file on failure to rename ...
-rw-r--r--Documentation/technical/api-lockfile.txt242
-rw-r--r--builtin/add.c1
-rw-r--r--builtin/apply.c1
-rw-r--r--builtin/checkout-index.c2
-rw-r--r--builtin/checkout.c2
-rw-r--r--builtin/clone.c1
-rw-r--r--builtin/commit.c17
-rw-r--r--builtin/describe.c1
-rw-r--r--builtin/diff.c1
-rw-r--r--builtin/gc.c2
-rw-r--r--builtin/merge.c16
-rw-r--r--builtin/mv.c2
-rw-r--r--builtin/read-tree.c1
-rw-r--r--builtin/receive-pack.c1
-rw-r--r--builtin/reflog.c4
-rw-r--r--builtin/reset.c1
-rw-r--r--builtin/rm.c2
-rw-r--r--builtin/update-index.c3
-rw-r--r--bundle.c1
-rw-r--r--cache-tree.c1
-rw-r--r--cache.h20
-rw-r--r--config.c16
-rw-r--r--credential-store.c1
-rw-r--r--fast-import.c5
-rw-r--r--fetch-pack.c1
-rw-r--r--lockfile.c284
-rw-r--r--lockfile.h84
-rw-r--r--merge-recursive.c1
-rw-r--r--merge.c1
-rw-r--r--read-cache.c21
-rw-r--r--refs.c23
-rw-r--r--rerere.c1
-rw-r--r--sequencer.c1
-rw-r--r--sha1_file.c1
-rw-r--r--shallow.c7
-rw-r--r--test-scrap-cache-tree.c1
36 files changed, 510 insertions, 260 deletions
diff --git a/Documentation/technical/api-lockfile.txt b/Documentation/technical/api-lockfile.txt
index dd894043ae..d4484d154d 100644
--- a/Documentation/technical/api-lockfile.txt
+++ b/Documentation/technical/api-lockfile.txt
@@ -3,20 +3,128 @@ lockfile API
The lockfile API serves two purposes:
-* Mutual exclusion. When we write out a new index file, first
- we create a new file `$GIT_DIR/index.lock`, write the new
- contents into it, and rename it to the final destination
- `$GIT_DIR/index`. We try to create the `$GIT_DIR/index.lock`
- file with O_EXCL so that we can notice and fail when somebody
- else is already trying to update the index file.
-
-* Automatic cruft removal. After we create the "lock" file, we
- may decide to `die()`, and we would want to make sure that we
- remove the file that has not been committed to its final
- destination. This is done by remembering the lockfiles we
- created in a linked list and cleaning them up from an
- `atexit(3)` handler. Outstanding lockfiles are also removed
- when the program dies on a signal.
+* Mutual exclusion and atomic file updates. When we want to change a
+ file, we create a lockfile `<filename>.lock`, write the new file
+ contents into it, and then rename the lockfile to its final
+ destination `<filename>`. We create the `<filename>.lock` file with
+ `O_CREAT|O_EXCL` so that we can notice and fail if somebody else has
+ already locked the file, then atomically rename the lockfile to its
+ final destination to commit the changes and unlock the file.
+
+* Automatic cruft removal. If the program exits after we lock a file
+ but before the changes have been committed, we want to make sure
+ that we remove the lockfile. This is done by remembering the
+ lockfiles we have created in a linked list and setting up an
+ `atexit(3)` handler and a signal handler that clean up the
+ lockfiles. This mechanism ensures that outstanding lockfiles are
+ cleaned up if the program exits (including when `die()` is called)
+ or if the program dies on a signal.
+
+Please note that lockfiles only block other writers. Readers do not
+block, but they are guaranteed to see either the old contents of the
+file or the new contents of the file (assuming that the filesystem
+implements `rename(2)` atomically).
+
+
+Calling sequence
+----------------
+
+The caller:
+
+* Allocates a `struct lock_file` either as a static variable or on the
+ heap, initialized to zeros. Once you use the structure to call the
+ `hold_lock_file_*` family of functions, it belongs to the lockfile
+ subsystem and its storage must remain valid throughout the life of
+ the program (i.e. you cannot use an on-stack variable to hold this
+ structure).
+
+* Attempts to create a lockfile by passing that variable and the path
+ of the final destination (e.g. `$GIT_DIR/index`) to
+ `hold_lock_file_for_update` or `hold_lock_file_for_append`.
+
+* Writes new content for the destination file by writing to the file
+ descriptor returned by those functions (also available via
+ `lock->fd`).
+
+When finished writing, the caller can:
+
+* Close the file descriptor and rename the lockfile to its final
+ destination by calling `commit_lock_file` or `commit_lock_file_to`.
+
+* Close the file descriptor and remove the lockfile by calling
+ `rollback_lock_file`.
+
+* Close the file descriptor without removing or renaming the lockfile
+ by calling `close_lock_file`, and later call `commit_lock_file`,
+ `commit_lock_file_to`, `rollback_lock_file`, or `reopen_lock_file`.
+
+Even after the lockfile is committed or rolled back, the `lock_file`
+object must not be freed or altered by the caller. However, it may be
+reused; just pass it to another call of `hold_lock_file_for_update` or
+`hold_lock_file_for_append`.
+
+If the program exits before you have called one of `commit_lock_file`,
+`commit_lock_file_to`, `rollback_lock_file`, or `close_lock_file`, an
+`atexit(3)` handler will close and remove the lockfile, rolling back
+any uncommitted changes.
+
+If you need to close the file descriptor you obtained from a
+`hold_lock_file_*` function yourself, do so by calling
+`close_lock_file`. You should never call `close(2)` yourself!
+Otherwise the `struct lock_file` structure would still think that the
+file descriptor needs to be closed, and a commit or rollback would
+result in duplicate calls to `close(2)`. Worse yet, if you `close(2)`
+and then later open another file descriptor for a completely different
+purpose, then a commit or rollback might close that unrelated file
+descriptor.
+
+
+Error handling
+--------------
+
+The `hold_lock_file_*` functions return a file descriptor on success
+or -1 on failure (unless `LOCK_DIE_ON_ERROR` is used; see below). On
+errors, `errno` describes the reason for failure. Errors can be
+reported by passing `errno` to one of the following helper functions:
+
+unable_to_lock_message::
+
+ Append an appropriate error message to a `strbuf`.
+
+unable_to_lock_error::
+
+ Emit an appropriate error message using `error()`.
+
+unable_to_lock_die::
+
+ Emit an appropriate error message and `die()`.
+
+Similarly, `commit_lock_file`, `commit_lock_file_to`, and
+`close_lock_file` return 0 on success. On failure they set `errno`
+appropriately, do their best to roll back the lockfile, and return -1.
+
+
+Flags
+-----
+
+The following flags can be passed to `hold_lock_file_for_update` or
+`hold_lock_file_for_append`:
+
+LOCK_NO_DEREF::
+
+ Usually symbolic links in the destination path are resolved
+ and the lockfile is created by adding ".lock" to the resolved
+ path. If `LOCK_NO_DEREF` is set, then the lockfile is created
+ by adding ".lock" to the path argument itself. This option is
+ used, for example, when locking a symbolic reference, which
+ for backwards-compatibility reasons can be a symbolic link
+ containing the name of the referred-to-reference.
+
+LOCK_DIE_ON_ERROR::
+
+ If a lock is already taken for the file, `die()` with an error
+ message. If this option is not specified, trying to lock a
+ file that is already locked returns -1 to the caller.
The functions
@@ -24,51 +132,77 @@ The functions
hold_lock_file_for_update::
- Take a pointer to `struct lock_file`, the filename of
- the final destination (e.g. `$GIT_DIR/index`) and a flag
- `die_on_error`. Attempt to create a lockfile for the
- destination and return the file descriptor for writing
- to the file. If `die_on_error` flag is true, it dies if
- a lock is already taken for the file; otherwise it
- returns a negative integer to the caller on failure.
+ Take a pointer to `struct lock_file`, the path of the file to
+ be locked (e.g. `$GIT_DIR/index`) and a flags argument (see
+ above). Attempt to create a lockfile for the destination and
+ return the file descriptor for writing to the file.
+
+hold_lock_file_for_append::
+
+ Like `hold_lock_file_for_update`, but before returning copy
+ the existing contents of the file (if any) to the lockfile and
+ position its write pointer at the end of the file.
+
+get_locked_file_path::
+
+ Return the path of the file that is locked by the specified
+ lock_file object. The caller must free the memory.
commit_lock_file::
- Take a pointer to the `struct lock_file` initialized
- with an earlier call to `hold_lock_file_for_update()`,
- close the file descriptor and rename the lockfile to its
- final destination. Returns 0 upon success, a negative
- value on failure to close(2) or rename(2).
+ Take a pointer to the `struct lock_file` initialized with an
+ earlier call to `hold_lock_file_for_update` or
+ `hold_lock_file_for_append`, close the file descriptor, and
+ rename the lockfile to its final destination. Return 0 upon
+ success. On failure, roll back the lock file and return -1,
+ with `errno` set to the value from the failing call to
+ `close(2)` or `rename(2)`. It is a bug to call
+ `commit_lock_file` for a `lock_file` object that is not
+ currently locked.
+
+commit_lock_file_to::
+
+ Like `commit_lock_file()`, except that it takes an explicit
+ `path` argument to which the lockfile should be renamed. The
+ `path` must be on the same filesystem as the lock file.
rollback_lock_file::
- Take a pointer to the `struct lock_file` initialized
- with an earlier call to `hold_lock_file_for_update()`,
- close the file descriptor and remove the lockfile.
+ Take a pointer to the `struct lock_file` initialized with an
+ earlier call to `hold_lock_file_for_update` or
+ `hold_lock_file_for_append`, close the file descriptor and
+ remove the lockfile. It is a NOOP to call
+ `rollback_lock_file()` for a `lock_file` object that has
+ already been committed or rolled back.
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
-storage has to stay throughout the life of the program. It
-cannot be an auto variable allocated on the stack.
-
-Call `commit_lock_file()` or `rollback_lock_file()` when you are
-done writing to the file descriptor. If you do not call either
-and simply `exit(3)` from the program, an `atexit(3)` handler
-will close and remove the lockfile.
-
-If you need to close the file descriptor you obtained from
-`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
-needs to be closed, and a later call to `commit_lock_file()` or
-`rollback_lock_file()` will result in duplicate calls to
-`close(2)`. Worse yet, if you `close(2)`, open another file
-descriptor for completely different purpose, and then call
-`commit_lock_file()` or `rollback_lock_file()`, they may close
-that unrelated file descriptor.
+
+ Take a pointer to the `struct lock_file` initialized with an
+ earlier call to `hold_lock_file_for_update` or
+ `hold_lock_file_for_append`, and close the file descriptor.
+ Return 0 upon success. On failure to `close(2)`, return a
+ negative value and roll back the lock file. Usually
+ `commit_lock_file`, `commit_lock_file_to`, or
+ `rollback_lock_file` should eventually be called if
+ `close_lock_file` succeeds.
+
+reopen_lock_file::
+
+ Re-open a lockfile that has been closed (using
+ `close_lock_file`) but not yet committed or rolled back. This
+ can be used to implement a sequence of operations like the
+ following:
+
+ * Lock file.
+
+ * Write new contents to lockfile, then `close_lock_file` to
+ cause the contents to be written to disk.
+
+ * Pass the name of the lockfile to another program to allow it
+ (and nobody else) to inspect the contents you wrote, while
+ still holding the lock yourself.
+
+ * `reopen_lock_file` to reopen the lockfile. Make further
+ updates to the contents.
+
+ * `commit_lock_file` to make the final version permanent.
diff --git a/builtin/add.c b/builtin/add.c
index 352b85e8db..ae6d3e262b 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -5,6 +5,7 @@
*/
#include "cache.h"
#include "builtin.h"
+#include "lockfile.h"
#include "dir.h"
#include "pathspec.h"
#include "exec_cmd.h"
diff --git a/builtin/apply.c b/builtin/apply.c
index 8714a88720..69efb0e4df 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -7,6 +7,7 @@
*
*/
#include "cache.h"
+#include "lockfile.h"
#include "cache-tree.h"
#include "quote.h"
#include "blob.h"
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 05edd9e1df..383dccf93e 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -5,7 +5,7 @@
*
*/
#include "builtin.h"
-#include "cache.h"
+#include "lockfile.h"
#include "quote.h"
#include "cache-tree.h"
#include "parse-options.h"
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 8afdf2b5c4..570bb09c4f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,5 +1,5 @@
-#include "cache.h"
#include "builtin.h"
+#include "lockfile.h"
#include "parse-options.h"
#include "refs.h"
#include "commit.h"
diff --git a/builtin/clone.c b/builtin/clone.c
index 3927edfb6e..d3bf9532d6 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -9,6 +9,7 @@
*/
#include "builtin.h"
+#include "lockfile.h"
#include "parse-options.h"
#include "fetch-pack.h"
#include "refs.h"
diff --git a/builtin/commit.c b/builtin/commit.c
index b0fe7847d3..c2300185ec 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -6,6 +6,7 @@
*/
#include "cache.h"
+#include "lockfile.h"
#include "cache-tree.h"
#include "color.h"
#include "dir.h"
@@ -315,8 +316,8 @@ static void refresh_cache_or_die(int refresh_flags)
die_resolve_conflict("commit");
}
-static char *prepare_index(int argc, const char **argv, const char *prefix,
- const struct commit *current_head, int is_status)
+static const char *prepare_index(int argc, const char **argv, const char *prefix,
+ const struct commit *current_head, int is_status)
{
struct string_list partial;
struct pathspec pathspec;
@@ -341,7 +342,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
die(_("unable to create temporary index"));
old_index_env = getenv(INDEX_ENVIRONMENT);
- setenv(INDEX_ENVIRONMENT, index_lock.filename, 1);
+ setenv(INDEX_ENVIRONMENT, index_lock.filename.buf, 1);
if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
die(_("interactive add failed"));
@@ -352,7 +353,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
unsetenv(INDEX_ENVIRONMENT);
discard_cache();
- read_cache_from(index_lock.filename);
+ read_cache_from(index_lock.filename.buf);
if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
if (reopen_lock_file(&index_lock) < 0)
die(_("unable to write index file"));
@@ -362,7 +363,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
warning(_("Failed to update main cache tree"));
commit_style = COMMIT_NORMAL;
- return index_lock.filename;
+ return index_lock.filename.buf;
}
/*
@@ -385,7 +386,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
die(_("unable to write new_index file"));
commit_style = COMMIT_NORMAL;
- return index_lock.filename;
+ return index_lock.filename.buf;
}
/*
@@ -472,9 +473,9 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
die(_("unable to write temporary index file"));
discard_cache();
- read_cache_from(false_lock.filename);
+ read_cache_from(false_lock.filename.buf);
- return false_lock.filename;
+ return false_lock.filename.buf;
}
static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
diff --git a/builtin/describe.c b/builtin/describe.c
index ee6a3b998f..9103193b4f 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "commit.h"
#include "tag.h"
#include "refs.h"
diff --git a/builtin/diff.c b/builtin/diff.c
index 0f247d2400..4326fa56bf 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -4,6 +4,7 @@
* Copyright (c) 2006 Junio C Hamano
*/
#include "cache.h"
+#include "lockfile.h"
#include "color.h"
#include "commit.h"
#include "blob.h"
diff --git a/builtin/gc.c b/builtin/gc.c
index ced1456e1e..005adbebea 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -11,7 +11,7 @@
*/
#include "builtin.h"
-#include "cache.h"
+#include "lockfile.h"
#include "parse-options.h"
#include "run-command.h"
#include "sigchain.h"
diff --git a/builtin/merge.c b/builtin/merge.c
index dff043dac3..4513fadc5f 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -9,6 +9,7 @@
#include "cache.h"
#include "parse-options.h"
#include "builtin.h"
+#include "lockfile.h"
#include "run-command.h"
#include "diff.h"
#include "refs.h"
@@ -656,19 +657,18 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
struct commit_list *remoteheads,
struct commit *head, const char *head_arg)
{
- struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+ static struct lock_file lock;
- hold_locked_index(lock, 1);
+ hold_locked_index(&lock, 1);
refresh_cache(REFRESH_QUIET);
if (active_cache_changed &&
- write_locked_index(&the_index, lock, COMMIT_LOCK))
+ write_locked_index(&the_index, &lock, COMMIT_LOCK))
return error(_("Unable to write index."));
- rollback_lock_file(lock);
+ rollback_lock_file(&lock);
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
int clean, x;
struct commit *result;
- struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
struct commit_list *reversed = NULL;
struct merge_options o;
struct commit_list *j;
@@ -696,13 +696,13 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
for (j = common; j; j = j->next)
commit_list_insert(j->item, &reversed);
- hold_locked_index(lock, 1);
+ hold_locked_index(&lock, 1);
clean = merge_recursive(&o, head,
remoteheads->item, reversed, &result);
if (active_cache_changed &&
- write_locked_index(&the_index, lock, COMMIT_LOCK))
+ write_locked_index(&the_index, &lock, COMMIT_LOCK))
die (_("unable to write %s"), get_index_file());
- rollback_lock_file(lock);
+ rollback_lock_file(&lock);
return clean ? 0 : 1;
} else {
return try_merge_command(strategy, xopts_nr, xopts,
diff --git a/builtin/mv.c b/builtin/mv.c
index 8883baa903..563d05ba1a 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -3,8 +3,8 @@
*
* Copyright (C) 2006 Johannes Schindelin
*/
-#include "cache.h"
#include "builtin.h"
+#include "lockfile.h"
#include "dir.h"
#include "cache-tree.h"
#include "string-list.h"
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index e7e1c33a7f..43b47f72f1 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -5,6 +5,7 @@
*/
#include "cache.h"
+#include "lockfile.h"
#include "object.h"
#include "tree.h"
#include "tree-walk.h"
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index a01ac2096a..f2f6c67359 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1,4 +1,5 @@
#include "builtin.h"
+#include "lockfile.h"
#include "pack.h"
#include "refs.h"
#include "pkt-line.h"
diff --git a/builtin/reflog.c b/builtin/reflog.c
index e8a8fb13b9..b6388f75b0 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -1,5 +1,5 @@
-#include "cache.h"
#include "builtin.h"
+#include "lockfile.h"
#include "commit.h"
#include "refs.h"
#include "dir.h"
@@ -431,7 +431,7 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
write_str_in_full(lock->lock_fd, "\n") != 1 ||
close_ref(lock) < 0)) {
status |= error("Couldn't write %s",
- lock->lk->filename);
+ lock->lk->filename.buf);
unlink(newlog_path);
} else if (rename(newlog_path, log_file)) {
status |= error("cannot rename %s to %s",
diff --git a/builtin/reset.c b/builtin/reset.c
index 855d478e3b..4c08ddc1ca 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -8,6 +8,7 @@
* Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
*/
#include "builtin.h"
+#include "lockfile.h"
#include "tag.h"
#include "object.h"
#include "commit.h"
diff --git a/builtin/rm.c b/builtin/rm.c
index 2b61d3bd41..d8a9c86dd1 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -3,8 +3,8 @@
*
* Copyright (C) Linus Torvalds 2006
*/
-#include "cache.h"
#include "builtin.h"
+#include "lockfile.h"
#include "dir.h"
#include "cache-tree.h"
#include "tree-walk.h"
diff --git a/builtin/update-index.c b/builtin/update-index.c
index e8c7fd4d49..b0e3dc9105 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -4,6 +4,7 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
+#include "lockfile.h"
#include "quote.h"
#include "cache-tree.h"
#include "tree-walk.h"
@@ -942,7 +943,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
if (newfd < 0) {
if (refresh_args.flags & REFRESH_QUIET)
exit(128);
- unable_to_lock_index_die(get_index_file(), lock_error);
+ unable_to_lock_die(get_index_file(), lock_error);
}
if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
die("Unable to write new index file");
diff --git a/bundle.c b/bundle.c
index b2b89fe862..891a3cacda 100644
--- a/bundle.c
+++ b/bundle.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "bundle.h"
#include "object.h"
#include "commit.h"
diff --git a/cache-tree.c b/cache-tree.c
index 75a54fdc72..215202c42d 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
diff --git a/cache.h b/cache.h
index 3e6a914dba..5b86065815 100644
--- a/cache.h
+++ b/cache.h
@@ -570,29 +570,11 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
#define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */
extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
-struct lock_file {
- struct lock_file *next;
- int fd;
- pid_t owner;
- char on_list;
- char filename[PATH_MAX];
-};
-#define LOCK_DIE_ON_ERROR 1
-#define LOCK_NODEREF 2
-extern int unable_to_lock_error(const char *path, int err);
-extern void unable_to_lock_message(const char *path, int err,
- struct strbuf *buf);
-extern NORETURN void unable_to_lock_index_die(const char *path, int err);
-extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
-extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
-extern int commit_lock_file(struct lock_file *);
-extern int reopen_lock_file(struct lock_file *);
extern void update_index_if_able(struct index_state *, struct lock_file *);
extern int hold_locked_index(struct lock_file *, int);
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 int delete_ref(const char *, const unsigned char *sha1, int delopt);
/* Environment bits from configuration mechanism */
diff --git a/config.c b/config.c
index 039647d247..15a2983577 100644
--- a/config.c
+++ b/config.c
@@ -6,6 +6,7 @@
*
*/
#include "cache.h"
+#include "lockfile.h"
#include "exec_cmd.h"
#include "strbuf.h"
#include "quote.h"
@@ -2040,9 +2041,9 @@ int git_config_set_multivar_in_file(const char *config_filename,
MAP_PRIVATE, in_fd, 0);
close(in_fd);
- if (chmod(lock->filename, st.st_mode & 07777) < 0) {
+ if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
error("chmod on %s failed: %s",
- lock->filename, strerror(errno));
+ lock->filename.buf, strerror(errno));
ret = CONFIG_NO_WRITE;
goto out_free;
}
@@ -2099,6 +2100,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
if (commit_lock_file(lock) < 0) {
error("could not commit config file %s", config_filename);
ret = CONFIG_NO_WRITE;
+ lock = NULL;
goto out_free;
}
@@ -2121,7 +2123,7 @@ out_free:
return ret;
write_err_out:
- ret = write_error(lock->filename);
+ ret = write_error(lock->filename.buf);
goto out_free;
}
@@ -2222,9 +2224,9 @@ int git_config_rename_section_in_file(const char *config_filename,
fstat(fileno(config_file), &st);
- if (chmod(lock->filename, st.st_mode & 07777) < 0) {
+ if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
ret = error("chmod on %s failed: %s",
- lock->filename, strerror(errno));
+ lock->filename.buf, strerror(errno));
goto out;
}
@@ -2245,7 +2247,7 @@ int git_config_rename_section_in_file(const char *config_filename,
}
store.baselen = strlen(new_name);
if (!store_write_section(out_fd, new_name)) {
- ret = write_error(lock->filename);
+ ret = write_error(lock->filename.buf);
goto out;
}
/*
@@ -2271,7 +2273,7 @@ int git_config_rename_section_in_file(const char *config_filename,
continue;
length = strlen(output);
if (write_in_full(out_fd, output, length) != length) {
- ret = write_error(lock->filename);
+ ret = write_error(lock->filename.buf);
goto out;
}
}
diff --git a/credential-store.c b/credential-store.c
index f9146e576f..d435514cbe 100644
--- a/credential-store.c
+++ b/credential-store.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "credential.h"
#include "string-list.h"
#include "parse-options.h"
diff --git a/fast-import.c b/fast-import.c
index 96b0f4236a..deadc33f94 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -153,6 +153,7 @@ Format of STDIN stream:
#include "builtin.h"
#include "cache.h"
+#include "lockfile.h"
#include "object.h"
#include "blob.h"
#include "tree.h"
@@ -1832,10 +1833,8 @@ static void dump_marks(void)
}
if (commit_lock_file(&mark_lock)) {
- int saved_errno = errno;
- rollback_lock_file(&mark_lock);
failure |= error("Unable to commit marks file %s: %s",
- export_marks_file, strerror(saved_errno));
+ export_marks_file, strerror(errno));
return;
}
}
diff --git a/fetch-pack.c b/fetch-pack.c
index 7487aa7306..655ee64256 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "refs.h"
#include "pkt-line.h"
#include "commit.h"
diff --git a/lockfile.c b/lockfile.c
index d34a96df4f..7bfec4b773 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -2,59 +2,52 @@
* Copyright (c) 2005, Junio C Hamano
*/
#include "cache.h"
+#include "lockfile.h"
#include "sigchain.h"
-static struct lock_file *lock_file_list;
+static struct lock_file *volatile lock_file_list;
-static void remove_lock_file(void)
+static void remove_lock_files(void)
{
pid_t me = getpid();
while (lock_file_list) {
- if (lock_file_list->owner == me &&
- lock_file_list->filename[0]) {
- if (lock_file_list->fd >= 0)
- close(lock_file_list->fd);
- unlink_or_warn(lock_file_list->filename);
- }
+ if (lock_file_list->owner == me)
+ rollback_lock_file(lock_file_list);
lock_file_list = lock_file_list->next;
}
}
-static void remove_lock_file_on_signal(int signo)
+static void remove_lock_files_on_signal(int signo)
{
- remove_lock_file();
+ remove_lock_files();
sigchain_pop(signo);
raise(signo);
}
/*
- * p = absolute or relative path name
+ * path = absolute or relative path name
*
- * Return a pointer into p showing the beginning of the last path name
- * element. If p is empty or the root directory ("/"), just return p.
+ * Remove the last path name element from path (leaving the preceding
+ * "/", if any). If path is empty or the root directory ("/"), set
+ * path to the empty string.
*/
-static char *last_path_elm(char *p)
+static void trim_last_path_component(struct strbuf *path)
{
- /* r starts pointing to null at the end of the string */
- char *r = strchr(p, '\0');
-
- if (r == p)
- return p; /* just return empty string */
-
- r--; /* back up to last non-null character */
+ int i = path->len;
/* back up past trailing slashes, if any */
- while (r > p && *r == '/')
- r--;
+ while (i && path->buf[i - 1] == '/')
+ i--;
/*
- * then go backwards until I hit a slash, or the beginning of
- * the string
+ * then go backwards until a slash, or the beginning of the
+ * string
*/
- while (r > p && *(r-1) != '/')
- r--;
- return r;
+ while (i && path->buf[i - 1] != '/')
+ i--;
+
+ strbuf_setlen(path, i);
}
@@ -62,103 +55,87 @@ static char *last_path_elm(char *p)
#define MAXDEPTH 5
/*
- * p = path that may be a symlink
- * s = full size of p
- *
- * If p is a symlink, attempt to overwrite p with a path to the real
- * file or directory (which may or may not exist), following a chain of
- * symlinks if necessary. Otherwise, leave p unmodified.
+ * path contains a path that might be a symlink.
*
- * This is a best-effort routine. If an error occurs, p will either be
- * left unmodified or will name a different symlink in a symlink chain
- * that started with p's initial contents.
+ * If path is a symlink, attempt to overwrite it with a path to the
+ * real file or directory (which may or may not exist), following a
+ * chain of symlinks if necessary. Otherwise, leave path unmodified.
*
- * Always returns p.
+ * This is a best-effort routine. If an error occurs, path will
+ * either be left unmodified or will name a different symlink in a
+ * symlink chain that started with the original path.
*/
-
-static char *resolve_symlink(char *p, size_t s)
+static void resolve_symlink(struct strbuf *path)
{
int depth = MAXDEPTH;
+ static struct strbuf link = STRBUF_INIT;
while (depth--) {
- char link[PATH_MAX];
- int link_len = readlink(p, link, sizeof(link));
- if (link_len < 0) {
- /* not a symlink anymore */
- return p;
- }
- else if (link_len < sizeof(link))
- /* readlink() never null-terminates */
- link[link_len] = '\0';
- else {
- warning("%s: symlink too long", p);
- return p;
- }
+ if (strbuf_readlink(&link, path->buf, path->len) < 0)
+ break;
- if (is_absolute_path(link)) {
+ if (is_absolute_path(link.buf))
/* absolute path simply replaces p */
- if (link_len < s)
- strcpy(p, link);
- else {
- warning("%s: symlink too long", p);
- return p;
- }
- } else {
+ strbuf_reset(path);
+ else
/*
- * link is a relative path, so I must replace the
+ * link is a relative path, so replace the
* last element of p with it.
*/
- char *r = (char *)last_path_elm(p);
- if (r - p + link_len < s)
- strcpy(r, link);
- else {
- warning("%s: symlink too long", p);
- return p;
- }
- }
+ trim_last_path_component(path);
+
+ strbuf_addbuf(path, &link);
}
- return p;
+ strbuf_reset(&link);
}
/* Make sure errno contains a meaningful value on error */
static int lock_file(struct lock_file *lk, const char *path, int flags)
{
- /*
- * subtract 5 from size to make sure there's room for adding
- * ".lock" for the lock file name
- */
- static const size_t max_path_len = sizeof(lk->filename) - 5;
+ size_t pathlen = strlen(path);
- if (strlen(path) >= max_path_len) {
- errno = ENAMETOOLONG;
+ if (!lock_file_list) {
+ /* One-time initialization */
+ sigchain_push_common(remove_lock_files_on_signal);
+ atexit(remove_lock_files);
+ }
+
+ 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->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);
+ }
+
+ strbuf_add(&lk->filename, path, pathlen);
+ if (!(flags & LOCK_NO_DEREF))
+ resolve_symlink(&lk->filename);
+ 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;
}
- strcpy(lk->filename, path);
- if (!(flags & LOCK_NODEREF))
- resolve_symlink(lk->filename, max_path_len);
- strcat(lk->filename, ".lock");
- lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
- if (0 <= lk->fd) {
- if (!lock_file_list) {
- sigchain_push_common(remove_lock_file_on_signal);
- atexit(remove_lock_file);
- }
- lk->owner = getpid();
- if (!lk->on_list) {
- lk->next = lock_file_list;
- lock_file_list = lk;
- lk->on_list = 1;
- }
- if (adjust_shared_perm(lk->filename)) {
- int save_errno = errno;
- error("cannot fix permission bits on %s",
- lk->filename);
- errno = save_errno;
- 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;
}
- else
- lk->filename[0] = 0;
return lk->fd;
}
@@ -185,7 +162,7 @@ int unable_to_lock_error(const char *path, int err)
return -1;
}
-NORETURN void unable_to_lock_index_die(const char *path, int err)
+NORETURN void unable_to_lock_die(const char *path, int err)
{
struct strbuf buf = STRBUF_INIT;
@@ -198,7 +175,7 @@ int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
{
int fd = lock_file(lk, path, flags);
if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
- unable_to_lock_index_die(path, errno);
+ unable_to_lock_die(path, errno);
return fd;
}
@@ -209,23 +186,30 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
fd = lock_file(lk, path, flags);
if (fd < 0) {
if (flags & LOCK_DIE_ON_ERROR)
- unable_to_lock_index_die(path, errno);
+ unable_to_lock_die(path, errno);
return fd;
}
orig_fd = open(path, O_RDONLY);
if (orig_fd < 0) {
if (errno != ENOENT) {
+ int save_errno = errno;
+
if (flags & LOCK_DIE_ON_ERROR)
die("cannot open '%s' for copying", path);
- close(fd);
- return error("cannot open '%s' for copying", path);
+ rollback_lock_file(lk);
+ error("cannot open '%s' for copying", path);
+ errno = save_errno;
+ return -1;
}
} else if (copy_fd(orig_fd, fd)) {
+ int save_errno = errno;
+
if (flags & LOCK_DIE_ON_ERROR)
exit(128);
close(orig_fd);
- close(fd);
+ rollback_lock_file(lk);
+ errno = save_errno;
return -1;
} else {
close(orig_fd);
@@ -233,52 +217,90 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
return fd;
}
+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)
+ 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;
+
+ if (fd < 0)
+ return 0;
+
lk->fd = -1;
- return close(fd);
+ if (close(fd)) {
+ 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->filename[0])
+ if (!lk->active)
die(_("BUG: reopen a lockfile that has been committed"));
- lk->fd = open(lk->filename, O_WRONLY);
+ lk->fd = open(lk->filename.buf, O_WRONLY);
return lk->fd;
}
-int commit_lock_file(struct lock_file *lk)
+int commit_lock_file_to(struct lock_file *lk, const char *path)
{
- char result_file[PATH_MAX];
- size_t i;
- if (lk->fd >= 0 && close_lock_file(lk))
+ if (!lk->active)
+ die("BUG: attempt to commit unlocked object to \"%s\"", path);
+
+ if (close_lock_file(lk))
return -1;
- strcpy(result_file, lk->filename);
- i = strlen(result_file) - 5; /* .lock */
- result_file[i] = 0;
- if (rename(lk->filename, result_file))
+
+ if (rename(lk->filename.buf, path)) {
+ int save_errno = errno;
+ rollback_lock_file(lk);
+ errno = save_errno;
return -1;
- lk->filename[0] = 0;
+ }
+
+ lk->active = 0;
+ strbuf_reset(&lk->filename);
return 0;
}
-int hold_locked_index(struct lock_file *lk, int die_on_error)
+int commit_lock_file(struct lock_file *lk)
{
- return hold_lock_file_for_update(lk, get_index_file(),
- die_on_error
- ? LOCK_DIE_ON_ERROR
- : 0);
+ static struct strbuf result_file = STRBUF_INIT;
+ int err;
+
+ 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->filename[0]) {
- if (lk->fd >= 0)
- close(lk->fd);
- unlink_or_warn(lk->filename);
+ if (!lk->active)
+ return;
+
+ if (!close_lock_file(lk)) {
+ unlink_or_warn(lk->filename.buf);
+ lk->active = 0;
+ strbuf_reset(&lk->filename);
}
- lk->filename[0] = 0;
}
diff --git a/lockfile.h b/lockfile.h
new file mode 100644
index 0000000000..9059e8958f
--- /dev/null
+++ b/lockfile.h
@@ -0,0 +1,84 @@
+#ifndef LOCKFILE_H
+#define LOCKFILE_H
+
+/*
+ * File write-locks as used by Git.
+ *
+ * For an overview of how to use the lockfile API, please see
+ *
+ * Documentation/technical/api-lockfile.txt
+ *
+ * This module keeps track of all locked files in lock_file_list for
+ * use at cleanup. This list and the lock_file objects that comprise
+ * it must be kept in self-consistent states at all time, because the
+ * program can be interrupted any time by a signal, in which case the
+ * signal handler will walk through the list attempting to clean up
+ * any open lock files.
+ *
+ * A lockfile is owned by the process that created it. The lock_file
+ * object has an "owner" field that records its owner. This field is
+ * used to prevent a forked process from closing a lockfile created by
+ * its parent.
+ *
+ * The possible states of a lock_file object are as follows:
+ *
+ * - Uninitialized. In this state the object's on_list field must be
+ * zero but the rest of its contents need not be initialized. As
+ * soon as the object is used in any way, it is irrevocably
+ * registered in the lock_file_list, and on_list is set.
+ *
+ * - Locked, lockfile open (after hold_lock_file_for_update(),
+ * hold_lock_file_for_append(), or reopen_lock_file()). In this
+ * state:
+ * - the lockfile exists
+ * - active is set
+ * - filename holds the filename of the lockfile
+ * - fd holds a file descriptor open for writing to the lockfile
+ * - owner holds the PID of the process that locked the file
+ *
+ * - Locked, lockfile closed (after successful close_lock_file()).
+ * Same as the previous state, except that the lockfile is closed
+ * and fd is -1.
+ *
+ * - Unlocked (after commit_lock_file(), commit_lock_file_to(),
+ * rollback_lock_file(), a failed attempt to lock, or a failed
+ * close_lock_file()). In this state:
+ * - active is unset
+ * - filename is empty (usually, though there are transitory
+ * states in which this condition doesn't hold). Client code should
+ * *not* rely on the filename being empty in this state.
+ * - fd is -1
+ * - the object is left registered in the lock_file_list, and
+ * on_list is set.
+ */
+
+struct lock_file {
+ struct lock_file *volatile next;
+ volatile sig_atomic_t active;
+ volatile int fd;
+ volatile pid_t owner;
+ char on_list;
+ struct strbuf filename;
+};
+
+/* String appended to a filename to derive the lockfile name: */
+#define LOCK_SUFFIX ".lock"
+#define LOCK_SUFFIX_LEN 5
+
+#define LOCK_DIE_ON_ERROR 1
+#define LOCK_NO_DEREF 2
+
+extern int unable_to_lock_error(const char *path, int err);
+extern void unable_to_lock_message(const char *path, int err,
+ struct strbuf *buf);
+extern NORETURN void unable_to_lock_die(const char *path, int err);
+extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
+extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
+extern char *get_locked_file_path(struct lock_file *);
+extern int commit_lock_file_to(struct lock_file *, const char *path);
+extern int commit_lock_file(struct lock_file *);
+extern int reopen_lock_file(struct lock_file *);
+extern int close_lock_file(struct lock_file *);
+extern void rollback_lock_file(struct lock_file *);
+
+#endif /* LOCKFILE_H */
diff --git a/merge-recursive.c b/merge-recursive.c
index 9fc71a2391..fdb7d0f10b 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -5,6 +5,7 @@
*/
#include "cache.h"
#include "advice.h"
+#include "lockfile.h"
#include "cache-tree.h"
#include "commit.h"
#include "blob.h"
diff --git a/merge.c b/merge.c
index 74ced7f70b..fcff632bd6 100644
--- a/merge.c
+++ b/merge.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "commit.h"
#include "run-command.h"
#include "resolve-undo.h"
diff --git a/read-cache.c b/read-cache.c
index 2fc1182f22..8f3e9eb314 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -5,6 +5,7 @@
*/
#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
+#include "lockfile.h"
#include "cache-tree.h"
#include "refs.h"
#include "dir.h"
@@ -1367,6 +1368,14 @@ static int read_index_extension(struct index_state *istate,
return 0;
}
+int hold_locked_index(struct lock_file *lk, int die_on_error)
+{
+ return hold_lock_file_for_update(lk, get_index_file(),
+ die_on_error
+ ? LOCK_DIE_ON_ERROR
+ : 0);
+}
+
int read_index(struct index_state *istate)
{
return read_index_from(istate, get_index_file());
@@ -2041,16 +2050,10 @@ void set_alternate_index_output(const char *name)
static int commit_locked_index(struct lock_file *lk)
{
- if (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;
- return 0;
- } else {
+ if (alternate_index_output)
+ return commit_lock_file_to(lk, alternate_index_output);
+ else
return commit_lock_file(lk);
- }
}
static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
diff --git a/refs.c b/refs.c
index ffd45e9292..1d73f1daf5 100644
--- a/refs.c
+++ b/refs.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "refs.h"
#include "object.h"
#include "tag.h"
@@ -79,7 +80,8 @@ out:
if (refname[1] == '\0')
return -1; /* Component equals ".". */
}
- if (cp - refname >= 5 && !memcmp(cp - 5, ".lock", 5))
+ if (cp - refname >= LOCK_SUFFIX_LEN &&
+ !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN))
return -1; /* Refname ends with ".lock". */
return cp - refname;
}
@@ -2191,7 +2193,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
lflags = 0;
if (flags & REF_NODEREF) {
refname = orig_refname;
- lflags |= LOCK_NODEREF;
+ lflags |= LOCK_NO_DEREF;
}
lock->ref_name = xstrdup(refname);
lock->orig_ref_name = xstrdup(orig_refname);
@@ -2225,7 +2227,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
*/
goto retry;
else
- unable_to_lock_index_die(ref_file, errno);
+ unable_to_lock_die(ref_file, errno);
}
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
@@ -2601,12 +2603,13 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
static int delete_ref_loose(struct ref_lock *lock, int flag)
{
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
- /* loose */
- int err, i = strlen(lock->lk->filename) - 5; /* .lock */
-
- lock->lk->filename[i] = 0;
- err = unlink_or_warn(lock->lk->filename);
- lock->lk->filename[i] = '.';
+ /*
+ * loose. The loose file name is the same as the
+ * lockfile name, minus ".lock":
+ */
+ char *loose_filename = get_locked_file_path(lock->lk);
+ int err = unlink_or_warn(loose_filename);
+ free(loose_filename);
if (err && errno != ENOENT)
return 1;
}
@@ -2968,7 +2971,7 @@ int write_ref_sha1(struct ref_lock *lock,
write_in_full(lock->lock_fd, &term, 1) != 1 ||
close_ref(lock) < 0) {
int save_errno = errno;
- error("Couldn't write %s", lock->lk->filename);
+ error("Couldn't write %s", lock->lk->filename.buf);
unlock_ref(lock);
errno = save_errno;
return -1;
diff --git a/rerere.c b/rerere.c
index 20b18add42..1b0555f1a5 100644
--- a/rerere.c
+++ b/rerere.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "string-list.h"
#include "rerere.h"
#include "xdiff-interface.h"
diff --git a/sequencer.c b/sequencer.c
index 5e8a207474..1b9a35e587 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "sequencer.h"
#include "dir.h"
#include "object.h"
diff --git a/sha1_file.c b/sha1_file.c
index 6f18c22ab1..83f77f01b6 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -8,6 +8,7 @@
*/
#include "cache.h"
#include "string-list.h"
+#include "lockfile.h"
#include "delta.h"
#include "pack.h"
#include "blob.h"
diff --git a/shallow.c b/shallow.c
index 57f4afa6b4..bd7569e815 100644
--- a/shallow.c
+++ b/shallow.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "commit.h"
#include "tag.h"
#include "pkt-line.h"
@@ -269,8 +270,8 @@ void setup_alternate_shallow(struct lock_file *shallow_lock,
if (write_shallow_commits(&sb, 0, extra)) {
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
die_errno("failed to write to %s",
- shallow_lock->filename);
- *alternate_shallow_file = shallow_lock->filename;
+ shallow_lock->filename.buf);
+ *alternate_shallow_file = shallow_lock->filename.buf;
} else
/*
* is_repository_shallow() sees empty string as "no
@@ -316,7 +317,7 @@ void prune_shallow(int show_only)
if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
die_errno("failed to write to %s",
- shallow_lock.filename);
+ shallow_lock.filename.buf);
commit_lock_file(&shallow_lock);
} else {
unlink(git_path("shallow"));
diff --git a/test-scrap-cache-tree.c b/test-scrap-cache-tree.c
index 9ebcbca9d2..6efee31a48 100644
--- a/test-scrap-cache-tree.c
+++ b/test-scrap-cache-tree.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "tree.h"
#include "cache-tree.h"