<td class="icon">\r
<div class="title">Note</div>\r
</td>\r
-<td class="content">This is a bit of lie. In certain special cases, your index are\r
-allowed to be different from the tree of <tt>HEAD</tt> commit. The most\r
+<td class="content">This is a bit of a lie. In certain special cases, your index is\r
+allowed to be different from the tree of the <tt>HEAD</tt> commit. The most\r
notable case is when your <tt>HEAD</tt> commit is already ahead of what\r
is being merged, in which case your index can have arbitrary\r
-difference from your <tt>HEAD</tt> commit. Otherwise, your index entries\r
-are allowed have differences from your <tt>HEAD</tt> commit that match\r
-the result of trivial merge (e.g. you received the same patch\r
-from external source to produce the same result as what you are\r
+differences from your <tt>HEAD</tt> commit. Also, your index entries\r
+may have differences from your <tt>HEAD</tt> commit that match\r
+the result of a trivial merge (e.g. you received the same patch\r
+from an external source to produce the same result as what you are\r
merging). For example, if a path did not exist in the common\r
ancestor and your head commit but exists in the tree you are\r
merging into your repository, and if you already happen to have\r
</div>\r
<div id="footer">\r
<div id="footer-text">\r
-Last updated 07-Jan-2008 07:50:33 UTC\r
+Last updated 17-Jan-2008 02:42:45 UTC\r
</div>\r
</div>\r
</body>\r
report no changes.
[NOTE]
-This is a bit of lie. In certain special cases, your index are
-allowed to be different from the tree of `HEAD` commit. The most
+This is a bit of a lie. In certain special cases, your index is
+allowed to be different from the tree of the `HEAD` commit. The most
notable case is when your `HEAD` commit is already ahead of what
is being merged, in which case your index can have arbitrary
-difference from your `HEAD` commit. Otherwise, your index entries
-are allowed have differences from your `HEAD` commit that match
-the result of trivial merge (e.g. you received the same patch
-from external source to produce the same result as what you are
+differences from your `HEAD` commit. Also, your index entries
+may have differences from your `HEAD` commit that match
+the result of a trivial merge (e.g. you received the same patch
+from an external source to produce the same result as what you are
merging). For example, if a path did not exist in the common
ancestor and your head commit but exists in the tree you are
merging into your repository, and if you already happen to have
</div>\r
<div id="preamble">\r
<div class="sectionbody">\r
-<p>Talk about <lockfile.c>, things like:</p>\r
+<p>The lockfile API serves two purposes:</p>\r
<ul>\r
<li>\r
<p>\r
-lockfile lifetime — atexit(3) looks at them, do not put them on the\r
- stack;\r
+Mutual exclusion. When we write out a new index file, first\r
+ we create a new file <tt>$GIT_DIR/index.lock</tt>, write the new\r
+ contents into it, and rename it to the final destination\r
+ <tt>$GIT_DIR/index</tt>. We try to create the <tt>$GIT_DIR/index.lock</tt>\r
+ file with O_EXCL so that we can notice and fail when somebody\r
+ else is already trying to update the index file.\r
</p>\r
</li>\r
<li>\r
<p>\r
-hold_lock_file_for_update()\r
+Automatic cruft removal. After we create the "lock" file, we\r
+ may decide to <tt>die()</tt>, and we would want to make sure that we\r
+ remove the file that has not been committed to its final\r
+ destination. This is done by remembering the lockfiles we\r
+ created in a linked list and cleaning them up from an\r
+ <tt>atexit(3)</tt> handler. Outstanding lockfiles are also removed\r
+ when the program dies on a signal.\r
</p>\r
</li>\r
-<li>\r
+</ul>\r
+</div>\r
+</div>\r
+<h2>The functions</h2>\r
+<div class="sectionbody">\r
+<dl>\r
+<dt>\r
+hold_lock_file_for_update\r
+</dt>\r
+<dd>\r
<p>\r
-commit_lock_file()\r
+ Take a pointer to <tt>struct lock_file</tt>, the filename of\r
+ the final destination (e.g. <tt>$GIT_DIR/index</tt>) and a flag\r
+ <tt>die_on_error</tt>. Attempt to create a lockfile for the\r
+ destination and return the file descriptor for writing\r
+ to the file. If <tt>die_on_error</tt> flag is true, it dies if\r
+ a lock is already taken for the file; otherwise it\r
+ returns a negative integer to the caller on failure.\r
</p>\r
-</li>\r
-<li>\r
+</dd>\r
+<dt>\r
+commit_lock_file\r
+</dt>\r
+<dd>\r
<p>\r
-rollback_rock_file()\r
+ Take a pointer to the <tt>struct lock_file</tt> initialized\r
+ with an earlier call to <tt>hold_lock_file_for_update()</tt>,\r
+ close the file descriptor and rename the lockfile to its\r
+ final destination. Returns 0 upon success, a negative\r
+ value on failure to close(2) or rename(2).\r
</p>\r
-</li>\r
-</ul>\r
-<p>(JC, Dscho, Shawn)</p>\r
-</div>\r
+</dd>\r
+<dt>\r
+rollback_lock_file\r
+</dt>\r
+<dd>\r
+<p>\r
+ Take a pointer to the <tt>struct lock_file</tt> initialized\r
+ with an earlier call to <tt>hold_lock_file_for_update()</tt>,\r
+ close the file descriptor and remove the lockfile.\r
+</p>\r
+</dd>\r
+<dt>\r
+close_lock_file\r
+</dt>\r
+<dd>\r
+<p>\r
+ Take a pointer to the <tt>struct lock_file</tt> initialized\r
+ with an earlier call to <tt>hold_lock_file_for_update()</tt>,\r
+ and close the file descriptor. Returns 0 upon success,\r
+ a negative value on failure to close(2).\r
+</p>\r
+</dd>\r
+</dl>\r
+<p>Because the structure is used in an <tt>atexit(3)</tt> handler, its\r
+storage has to stay throughout the life of the program. It\r
+cannot be an auto variable allocated on the stack.</p>\r
+<p>Call <tt>commit_lock_file()</tt> or <tt>rollback_lock_file()</tt> when you are\r
+done writing to the file descriptor. If you do not call either\r
+and simply <tt>exit(3)</tt> from the program, an <tt>atexit(3)</tt> handler\r
+will close and remove the lockfile.</p>\r
+<p>If you need to close the file descriptor you obtained from\r
+<tt>hold_lock_file_for_update</tt> function yourself, do so by calling\r
+<tt>close_lock_file()</tt>. You should never call <tt>close(2)</tt> yourself!\r
+Otherwise the <tt>struct\r
+lock_file</tt> structure still remembers that the file descriptor\r
+needs to be closed, and a later call to <tt>commit_lock_file()</tt> or\r
+<tt>rollback_lock_file()</tt> will result in duplicate calls to\r
+<tt>close(2)</tt>. Worse yet, if you <tt>close(2)</tt>, open another file\r
+descriptor for completely different purpose, and then call\r
+<tt>commit_lock_file()</tt> or <tt>rollback_lock_file()</tt>, they may close\r
+that unrelated file descriptor.</p>\r
</div>\r
<div id="footer">\r
<div id="footer-text">\r
-Last updated 07-Jan-2008 07:51:27 UTC\r
+Last updated 17-Jan-2008 02:42:45 UTC\r
</div>\r
</div>\r
</body>\r
lockfile API
============
-Talk about <lockfile.c>, things like:
+The lockfile API serves two purposes:
-* lockfile lifetime -- atexit(3) looks at them, do not put them on the
- stack;
-* hold_lock_file_for_update()
-* commit_lock_file()
-* rollback_rock_file()
+* 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.
-(JC, Dscho, Shawn)
+* 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.