lock_file(): always initialize and register lock_file object

The purpose of this change is to make the state diagram for lock_file objects simpler and deterministic. If locking fails, lock_file() sometimes leaves the lock_file object partly initialized, but sometimes not. It sometimes registers the object in lock_file_list, but sometimes not. This makes the state diagram for lock_file objects effectively indeterministic and hard to reason about. A future patch will also change the filename field into a strbuf, which needs more involved initialization, so it will become even more important that the state of a lock_file object is well-defined after a failed attempt to lock. The ambiguity doesn't currently have any ill effects, because lock_file objects cannot be removed from the lock_file_list anyway. But to make it easier to document and reason about the code, make this behavior consistent: *always* initialize the lock_file object and *always* register it in lock_file_list the first time it is used, regardless of whether an error occurs. While we're at it, make sure that all of the lock_file fields are initialized to values appropriate for an unlocked object; the caller is only responsible for making sure that on_list is set to zero before the first time it is used. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Oct 1, 2014 at 12:28 UTC 04e57d4d32541bc5dba553a31f09aa2ee456bdad
1 file changed +16 -9
lockfile.c
+16 -9
@@ -129,6 +129,22 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
129 */
130 static const size_t max_path_len = sizeof(lk->filename) - 5;
131
132 + if (!lock_file_list) {
133 + /* One-time initialization */
134 + sigchain_push_common(remove_lock_file_on_signal);
135 + atexit(remove_lock_file);
136 + }
137 +
138 + if (!lk->on_list) {
139 + /* Initialize *lk and add it to lock_file_list: */
140 + lk->fd = -1;
141 + lk->owner = 0;
142 + lk->filename[0] = 0;
143 + lk->next = lock_file_list;
144 + lock_file_list = lk;
145 + lk->on_list = 1;
146 + }
147 +
148 if (strlen(path) >= max_path_len) {
149 errno = ENAMETOOLONG;
150 return -1;
@@ -139,16 +155,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
155 strcat(lk->filename, ".lock");
156 lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
157 if (0 <= lk->fd) {
142 - if (!lock_file_list) {
143 - sigchain_push_common(remove_lock_file_on_signal);
144 - atexit(remove_lock_file);
145 - }
158 lk->owner = getpid();
147 - if (!lk->on_list) {
148 - lk->next = lock_file_list;
149 - lock_file_list = lk;
150 - lk->on_list = 1;
151 - }
159 if (adjust_shared_perm(lk->filename)) {
160 int save_errno = errno;
161 error("cannot fix permission bits on %s",