# lockfile API

The lockfile API serves two purposes:

- 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 either:

- writing to the file descriptor returned by the `hold_lock_file_*` functions (also available via `lock->fd`).

- calling `fdopen_lock_file` to get a `FILE` pointer for the open file and writing to the file using stdio.

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)` or `fclose(3)` 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 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

hold_lock_file_for_update

  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.

fdopen_lock_file

  Associate a stdio stream with the lockfile. Return NULL (without rolling back the lockfile) on error. The stream is closed automatically when `close_lock_file` is called or when the file is committed or rolled back.

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` 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` 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` or `hold_lock_file_for_append`. Close the file descriptor (and the file pointer if it has been opened using `fdopen_lock_file`). 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.