lockfile.con commit dump_marks(): reimplement using fdopen_lock_file() (f70f056)
   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
 165int unable_to_lock_error(const char *path, int err)
 166{
 167        struct strbuf buf = STRBUF_INIT;
 168
 169        unable_to_lock_message(path, err, &buf);
 170        error("%s", buf.buf);
 171        strbuf_release(&buf);
 172        return -1;
 173}
 174
 175NORETURN void unable_to_lock_die(const char *path, int err)
 176{
 177        struct strbuf buf = STRBUF_INIT;
 178
 179        unable_to_lock_message(path, err, &buf);
 180        die("%s", buf.buf);
 181}
 182
 183/* This should return a meaningful errno on failure */
 184int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
 185{
 186        int fd = lock_file(lk, path, flags);
 187        if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
 188                unable_to_lock_die(path, errno);
 189        return fd;
 190}
 191
 192int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
 193{
 194        int fd, orig_fd;
 195
 196        fd = lock_file(lk, path, flags);
 197        if (fd < 0) {
 198                if (flags & LOCK_DIE_ON_ERROR)
 199                        unable_to_lock_die(path, errno);
 200                return fd;
 201        }
 202
 203        orig_fd = open(path, O_RDONLY);
 204        if (orig_fd < 0) {
 205                if (errno != ENOENT) {
 206                        int save_errno = errno;
 207
 208                        if (flags & LOCK_DIE_ON_ERROR)
 209                                die("cannot open '%s' for copying", path);
 210                        rollback_lock_file(lk);
 211                        error("cannot open '%s' for copying", path);
 212                        errno = save_errno;
 213                        return -1;
 214                }
 215        } else if (copy_fd(orig_fd, fd)) {
 216                int save_errno = errno;
 217
 218                if (flags & LOCK_DIE_ON_ERROR)
 219                        exit(128);
 220                rollback_lock_file(lk);
 221                errno = save_errno;
 222                return -1;
 223        }
 224        return fd;
 225}
 226
 227FILE *fdopen_lock_file(struct lock_file *lk, const char *mode)
 228{
 229        if (!lk->active)
 230                die("BUG: fdopen_lock_file() called for unlocked object");
 231        if (lk->fp)
 232                die("BUG: fdopen_lock_file() called twice for file '%s'", lk->filename.buf);
 233
 234        lk->fp = fdopen(lk->fd, mode);
 235        return lk->fp;
 236}
 237
 238char *get_locked_file_path(struct lock_file *lk)
 239{
 240        if (!lk->active)
 241                die("BUG: get_locked_file_path() called for unlocked object");
 242        if (lk->filename.len <= LOCK_SUFFIX_LEN)
 243                die("BUG: get_locked_file_path() called for malformed lock object");
 244        return xmemdupz(lk->filename.buf, lk->filename.len - LOCK_SUFFIX_LEN);
 245}
 246
 247int close_lock_file(struct lock_file *lk)
 248{
 249        int fd = lk->fd;
 250        FILE *fp = lk->fp;
 251        int err;
 252
 253        if (fd < 0)
 254                return 0;
 255
 256        lk->fd = -1;
 257        if (fp) {
 258                lk->fp = NULL;
 259
 260                /*
 261                 * Note: no short-circuiting here; we want to fclose()
 262                 * in any case!
 263                 */
 264                err = ferror(fp) | fclose(fp);
 265        } else {
 266                err = close(fd);
 267        }
 268
 269        if (err) {
 270                int save_errno = errno;
 271                rollback_lock_file(lk);
 272                errno = save_errno;
 273                return -1;
 274        }
 275
 276        return 0;
 277}
 278
 279int reopen_lock_file(struct lock_file *lk)
 280{
 281        if (0 <= lk->fd)
 282                die(_("BUG: reopen a lockfile that is still open"));
 283        if (!lk->active)
 284                die(_("BUG: reopen a lockfile that has been committed"));
 285        lk->fd = open(lk->filename.buf, O_WRONLY);
 286        return lk->fd;
 287}
 288
 289int commit_lock_file_to(struct lock_file *lk, const char *path)
 290{
 291        if (!lk->active)
 292                die("BUG: attempt to commit unlocked object to \"%s\"", path);
 293
 294        if (close_lock_file(lk))
 295                return -1;
 296
 297        if (rename(lk->filename.buf, path)) {
 298                int save_errno = errno;
 299                rollback_lock_file(lk);
 300                errno = save_errno;
 301                return -1;
 302        }
 303
 304        lk->active = 0;
 305        strbuf_reset(&lk->filename);
 306        return 0;
 307}
 308
 309int commit_lock_file(struct lock_file *lk)
 310{
 311        static struct strbuf result_file = STRBUF_INIT;
 312        int err;
 313
 314        if (!lk->active)
 315                die("BUG: attempt to commit unlocked object");
 316
 317        if (lk->filename.len <= LOCK_SUFFIX_LEN ||
 318            strcmp(lk->filename.buf + lk->filename.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
 319                die("BUG: lockfile filename corrupt");
 320
 321        /* remove ".lock": */
 322        strbuf_add(&result_file, lk->filename.buf,
 323                   lk->filename.len - LOCK_SUFFIX_LEN);
 324        err = commit_lock_file_to(lk, result_file.buf);
 325        strbuf_reset(&result_file);
 326        return err;
 327}
 328
 329void rollback_lock_file(struct lock_file *lk)
 330{
 331        if (!lk->active)
 332                return;
 333
 334        if (!close_lock_file(lk)) {
 335                unlink_or_warn(lk->filename.buf);
 336                lk->active = 0;
 337                strbuf_reset(&lk->filename);
 338        }
 339}