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 ...maint
						commit
						bd107e1052
					
				| 
						 | 
				
			
			@ -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.
 | 
			
		||||
* 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.  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.
 | 
			
		||||
* 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.
 | 
			
		||||
	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.
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
reopen_lock_file::
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
	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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include "cache.h"
 | 
			
		||||
#include "builtin.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "dir.h"
 | 
			
		||||
#include "pathspec.h"
 | 
			
		||||
#include "exec_cmd.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "cache-tree.h"
 | 
			
		||||
#include "quote.h"
 | 
			
		||||
#include "blob.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include "builtin.h"
 | 
			
		||||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "quote.h"
 | 
			
		||||
#include "cache-tree.h"
 | 
			
		||||
#include "parse-options.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "builtin.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "parse-options.h"
 | 
			
		||||
#include "refs.h"
 | 
			
		||||
#include "commit.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#include "builtin.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "parse-options.h"
 | 
			
		||||
#include "fetch-pack.h"
 | 
			
		||||
#include "refs.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "commit.h"
 | 
			
		||||
#include "tag.h"
 | 
			
		||||
#include "refs.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#include "builtin.h"
 | 
			
		||||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "parse-options.h"
 | 
			
		||||
#include "run-command.h"
 | 
			
		||||
#include "sigchain.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "object.h"
 | 
			
		||||
#include "tree.h"
 | 
			
		||||
#include "tree-walk.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "builtin.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "pack.h"
 | 
			
		||||
#include "refs.h"
 | 
			
		||||
#include "pkt-line.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								bundle.c
								
								
								
								
							
							
						
						
									
										1
									
								
								bundle.c
								
								
								
								
							| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "bundle.h"
 | 
			
		||||
#include "object.h"
 | 
			
		||||
#include "commit.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "tree.h"
 | 
			
		||||
#include "tree-walk.h"
 | 
			
		||||
#include "cache-tree.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										20
									
								
								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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								config.c
								
								
								
								
							
							
						
						
									
										16
									
								
								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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "credential.h"
 | 
			
		||||
#include "string-list.h"
 | 
			
		||||
#include "parse-options.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "refs.h"
 | 
			
		||||
#include "pkt-line.h"
 | 
			
		||||
#include "commit.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										292
									
								
								lockfile.c
								
								
								
								
							
							
						
						
									
										292
									
								
								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
 | 
			
		||||
 * path contains a path that might be a symlink.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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_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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int commit_lock_file(struct lock_file *lk)
 | 
			
		||||
{
 | 
			
		||||
	char result_file[PATH_MAX];
 | 
			
		||||
	size_t i;
 | 
			
		||||
	if (lk->fd >= 0 && 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))
 | 
			
		||||
		return -1;
 | 
			
		||||
	lk->filename[0] = 0;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
	static struct strbuf result_file = STRBUF_INIT;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include "cache.h"
 | 
			
		||||
#include "advice.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "cache-tree.h"
 | 
			
		||||
#include "commit.h"
 | 
			
		||||
#include "blob.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								merge.c
								
								
								
								
							
							
						
						
									
										1
									
								
								merge.c
								
								
								
								
							| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "commit.h"
 | 
			
		||||
#include "run-command.h"
 | 
			
		||||
#include "resolve-undo.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										21
									
								
								read-cache.c
								
								
								
								
							
							
						
						
									
										21
									
								
								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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										23
									
								
								refs.c
								
								
								
								
							
							
						
						
									
										23
									
								
								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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								rerere.c
								
								
								
								
							
							
						
						
									
										1
									
								
								rerere.c
								
								
								
								
							| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "string-list.h"
 | 
			
		||||
#include "rerere.h"
 | 
			
		||||
#include "xdiff-interface.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "sequencer.h"
 | 
			
		||||
#include "dir.h"
 | 
			
		||||
#include "object.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include "cache.h"
 | 
			
		||||
#include "string-list.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "delta.h"
 | 
			
		||||
#include "pack.h"
 | 
			
		||||
#include "blob.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "cache.h"
 | 
			
		||||
#include "lockfile.h"
 | 
			
		||||
#include "tree.h"
 | 
			
		||||
#include "cache-tree.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue