lockfile.con commit t1400: add some more tests of "update-ref --stdin"'s verify command (a46e41f)
   1/*
   2 * Copyright (c) 2005, Junio C Hamano
   3 */
   4#include "cache.h"
   5#include "lockfile.h"
   6#include "sigchain.h"
   7
   8static struct lock_file *volatile lock_file_list;
   9
  10static void remove_lock_files(int skip_fclose)
  11{
  12        pid_t me = getpid();
  13
  14        while (lock_file_list) {
  15                if (lock_file_list->owner == me) {
  16                        /* fclose() is not safe to call in a signal handler */
  17                        if (skip_fclose)
  18                                lock_file_list->fp = NULL;
  19                        rollback_lock_file(lock_file_list);
  20                }
  21                lock_file_list = lock_file_list->next;
  22        }
  23}
  24
  25static void remove_lock_files_on_exit(void)
  26{
  27        remove_lock_files(0);
  28}
  29
  30static void remove_lock_files_on_signal(int signo)
  31{
  32        remove_lock_files(1);
  33        sigchain_pop(signo);
  34        raise(signo);
  35}
  36
  37/*
  38 * path = absolute or relative path name
  39 *
  40 * Remove the last path name element from path (leaving the preceding
  41 * "/", if any).  If path is empty or the root directory ("/"), set
  42 * path to the empty string.
  43 */
  44static void trim_last_path_component(struct strbuf *path)
  45{
  46        int i = path->len;
  47
  48        /* back up past trailing slashes, if any */
  49        while (i && path->buf[i - 1] == '/')
  50                i--;
  51
  52        /*
  53         * then go backwards until a slash, or the beginning of the
  54         * string
  55         */
  56        while (i && path->buf[i - 1] != '/')
  57                i--;
  58
  59        strbuf_setlen(path, i);
  60}
  61
  62
  63/* We allow "recursive" symbolic links. Only within reason, though */
  64#define MAXDEPTH 5
  65
  66/*
  67 * path contains a path that might be a symlink.
  68 *
  69 * If path is a symlink, attempt to overwrite it with a path to the
  70 * real file or directory (which may or may not exist), following a
  71 * chain of symlinks if necessary.  Otherwise, leave path unmodified.
  72 *
  73 * This is a best-effort routine.  If an error occurs, path will
  74 * either be left unmodified or will name a different symlink in a
  75 * symlink chain that started with the original path.
  76 */
  77static void resolve_symlink(struct strbuf *path)
  78{
  79        int depth = MAXDEPTH;
  80        static struct strbuf link = STRBUF_INIT;
  81
  82        while (depth--) {
  83                if (strbuf_readlink(&link, path->buf, path->len) < 0)
  84                        break;
  85
  86                if (is_absolute_path(link.buf))
  87                        /* absolute path simply replaces p */
  88                        strbuf_reset(path);
  89                else
  90                        /*
  91                         * link is a relative path, so replace the
  92                         * last element of p with it.
  93                         */
  94                        trim_last_path_component(path);
  95
  96                strbuf_addbuf(path, &link);
  97        }
  98        strbuf_reset(&link);
  99}
 100
 101/* Make sure errno contains a meaningful value on error */
 102static int lock_file(struct lock_file *lk, const char *path, int flags)
 103{
 104        size_t pathlen = strlen(path);
 105
 106        if (!lock_file_list) {
 107                /* One-time initialization */
 108                sigchain_push_common(remove_lock_files_on_signal);
 109                atexit(remove_lock_files_on_exit);
 110        }
 111
 112        if (lk->active)
 113                die("BUG: cannot lock_file(\"%s\") using active struct lock_file",
 114                    path);
 115        if (!lk->on_list) {
 116                /* Initialize *lk and add it to lock_file_list: */
 117                lk->fd = -1;
 118                lk->fp = NULL;
 119                lk->active = 0;
 120                lk->owner = 0;
 121                strbuf_init(&lk->filename, pathlen + LOCK_SUFFIX_LEN);
 122                lk->next = lock_file_list;
 123                lock_file_list = lk;
 124                lk->on_list = 1;
 125        } else if (lk->filename.len) {
 126                /* This shouldn't happen, but better safe than sorry. */
 127                die("BUG: lock_file(\"%s\") called with improperly-reset lock_file object",
 128                    path);
 129        }
 130
 131        strbuf_add(&lk->filename, path, pathlen);
 132        if (!(flags & LOCK_NO_DEREF))
 133                resolve_symlink(&lk->filename);
 134        strbuf_addstr(&lk->filename, LOCK_SUFFIX);
 135        lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
 136        if (lk->fd < 0) {
 137                strbuf_reset(&lk->filename);
 138                return -1;
 139        }
 140        lk->owner = getpid();
 141        lk->active = 1;
 142        if (adjust_shared_perm(lk->filename.buf)) {
 143                int save_errno = errno;
 144                error("cannot fix permission bits on %s", lk->filename.buf);
 145                rollback_lock_file(lk);
 146                errno = save_errno;
 147                return -1;
 148        }
 149        return lk->fd;
 150}
 151
 152void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
 153{
 154        if (err == EEXIST) {
 155                strbuf_addf(buf, "Unable to create '%s.lock': %s.\n\n"
 156                    "If no other git process is currently running, this probably means a\n"
 157                    "git process crashed in this repository earlier. Make sure no other git\n"
 158                    "process is running and remove the file manually to continue.",
 159                            absolute_path(path), strerror(err));
 160        } else
 161                strbuf_addf(buf, "Unable to create '%s.lock': %s",
 162                            absolute_path(path), strerror(err));
 163}
 164
 165NORETURN void unable_to_lock_die(const char *path, int err)
 166{
 167        struct strbuf buf = STRBUF_INIT;
 168
 169        unable_to_lock_message(path, err, &buf);
 170        die("%s", buf.buf);
 171}
 172
 173/* This should return a meaningful errno on failure */
 174int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
 175{
 176        int fd = lock_file(lk, path, flags);
 177        if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
 178                unable_to_lock_die(path, errno);
 179        return fd;
 180}
 181
 182int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
 183{
 184        int fd, orig_fd;
 185
 186        fd = lock_file(lk, path, flags);
 187        if (fd < 0) {
 188                if (flags & LOCK_DIE_ON_ERROR)
 189                        unable_to_lock_die(path, errno);
 190                return fd;
 191        }
 192
 193        orig_fd = open(path, O_RDONLY);
 194        if (orig_fd < 0) {
 195                if (errno != ENOENT) {
 196                        int save_errno = errno;
 197
 198                        if (flags & LOCK_DIE_ON_ERROR)
 199                                die("cannot open '%s' for copying", path);
 200                        rollback_lock_file(lk);
 201                        error("cannot open '%s' for copying", path);
 202                        errno = save_errno;
 203                        return -1;
 204                }
 205        } else if (copy_fd(orig_fd, fd)) {
 206                int save_errno = errno;
 207
 208                if (flags & LOCK_DIE_ON_ERROR)
 209                        exit(128);
 210                close(orig_fd);
 211                rollback_lock_file(lk);
 212                errno = save_errno;
 213                return -1;
 214        } else {
 215                close(orig_fd);
 216        }
 217        return fd;
 218}
 219
 220FILE *fdopen_lock_file(struct lock_file *lk, const char *mode)
 221{
 222        if (!lk->active)
 223                die("BUG: fdopen_lock_file() called for unlocked object");
 224        if (lk->fp)
 225                die("BUG: fdopen_lock_file() called twice for file '%s'", lk->filename.buf);
 226
 227        lk->fp = fdopen(lk->fd, mode);
 228        return lk->fp;
 229}
 230
 231char *get_locked_file_path(struct lock_file *lk)
 232{
 233        if (!lk->active)
 234                die("BUG: get_locked_file_path() called for unlocked object");
 235        if (lk->filename.len <= LOCK_SUFFIX_LEN)
 236                die("BUG: get_locked_file_path() called for malformed lock object");
 237        return xmemdupz(lk->filename.buf, lk->filename.len - LOCK_SUFFIX_LEN);
 238}
 239
 240int close_lock_file(struct lock_file *lk)
 241{
 242        int fd = lk->fd;
 243        FILE *fp = lk->fp;
 244        int err;
 245
 246        if (fd < 0)
 247                return 0;
 248
 249        lk->fd = -1;
 250        if (fp) {
 251                lk->fp = NULL;
 252
 253                /*
 254                 * Note: no short-circuiting here; we want to fclose()
 255                 * in any case!
 256                 */
 257                err = ferror(fp) | fclose(fp);
 258        } else {
 259                err = close(fd);
 260        }
 261
 262        if (err) {
 263                int save_errno = errno;
 264                rollback_lock_file(lk);
 265                errno = save_errno;
 266                return -1;
 267        }
 268
 269        return 0;
 270}
 271
 272int reopen_lock_file(struct lock_file *lk)
 273{
 274        if (0 <= lk->fd)
 275                die(_("BUG: reopen a lockfile that is still open"));
 276        if (!lk->active)
 277                die(_("BUG: reopen a lockfile that has been committed"));
 278        lk->fd = open(lk->filename.buf, O_WRONLY);
 279        return lk->fd;
 280}
 281
 282int commit_lock_file_to(struct lock_file *lk, const char *path)
 283{
 284        if (!lk->active)
 285                die("BUG: attempt to commit unlocked object to \"%s\"", path);
 286
 287        if (close_lock_file(lk))
 288                return -1;
 289
 290        if (rename(lk->filename.buf, path)) {
 291                int save_errno = errno;
 292                rollback_lock_file(lk);
 293                errno = save_errno;
 294                return -1;
 295        }
 296
 297        lk->active = 0;
 298        strbuf_reset(&lk->filename);
 299        return 0;
 300}
 301
 302int commit_lock_file(struct lock_file *lk)
 303{
 304        static struct strbuf result_file = STRBUF_INIT;
 305        int err;
 306
 307        if (!lk->active)
 308                die("BUG: attempt to commit unlocked object");
 309
 310        if (lk->filename.len <= LOCK_SUFFIX_LEN ||
 311            strcmp(lk->filename.buf + lk->filename.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
 312                die("BUG: lockfile filename corrupt");
 313
 314        /* remove ".lock": */
 315        strbuf_add(&result_file, lk->filename.buf,
 316                   lk->filename.len - LOCK_SUFFIX_LEN);
 317        err = commit_lock_file_to(lk, result_file.buf);
 318        strbuf_reset(&result_file);
 319        return err;
 320}
 321
 322void rollback_lock_file(struct lock_file *lk)
 323{
 324        if (!lk->active)
 325                return;
 326
 327        if (!close_lock_file(lk)) {
 328                unlink_or_warn(lk->filename.buf);
 329                lk->active = 0;
 330                strbuf_reset(&lk->filename);
 331        }
 332}