* Same as the previous state, except that the lockfile is closed
* and fd is -1.
*
- * - Unlocked (after commit_lock_file(), rollback_lock_file(), a
- * failed attempt to lock, or a failed close_lock_file()). In this
- * state:
+ * - 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
}
/*
- * 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);
}
if (is_absolute_path(link.buf))
/* absolute path simply replaces p */
strbuf_reset(path);
- else {
+ else
/*
* link is a relative path, so replace the
* last element of p with it.
*/
- char *r = last_path_elm(path->buf);
- strbuf_setlen(path, r - path->buf);
- }
+ trim_last_path_component(path);
strbuf_addbuf(path, &link);
}
return lk->fd;
}
-int commit_lock_file(struct lock_file *lk)
+int commit_lock_file_to(struct lock_file *lk, const char *path)
{
- static struct strbuf result_file = STRBUF_INIT;
- int err;
-
if (!lk->active)
- die("BUG: attempt to commit unlocked object");
+ die("BUG: attempt to commit unlocked object to \"%s\"", path);
if (close_lock_file(lk))
return -1;
- /* remove ".lock": */
- strbuf_add(&result_file, lk->filename.buf,
- lk->filename.len - LOCK_SUFFIX_LEN);
- err = rename(lk->filename.buf, result_file.buf);
- strbuf_reset(&result_file);
- if (err) {
+ if (rename(lk->filename.buf, path)) {
int save_errno = errno;
rollback_lock_file(lk);
errno = save_errno;
return 0;
}
+int commit_lock_file(struct lock_file *lk)
+{
+ static struct strbuf result_file = STRBUF_INIT;
+ int err;
+
+ 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;
+}
+
int hold_locked_index(struct lock_file *lk, int die_on_error)
{
return hold_lock_file_for_update(lk, get_index_file(),