 d6cf61bfd4
			
		
	
	d6cf61bfd4
	
	
	
		
			
			The lockfile API is a handy way to obtain a file that is cleaned
up if you die().  But sometimes you would need this sequence to
work:
 1. hold_lock_file_for_update() to get a file descriptor for
    writing;
 2. write the contents out, without being able to decide if the
    results should be committed or rolled back;
 3. do something else that makes the decision --- and this
    "something else" needs the lockfile not to have an open file
    descriptor for writing (e.g. Windows do not want a open file
    to be renamed);
 4. call commit_lock_file() or rollback_lock_file() as
    appropriately.
This adds close_lock_file() you can call between step 2 and 3 in
the above sequence.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
		
	
		
			
				
	
	
		
			75 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 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.
 | |
| 
 | |
| 
 | |
| 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.
 | |
| 
 | |
| 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).
 | |
| 
 | |
| 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.
 | |
| 
 | |
| 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.
 |