lockfile.con commit Merge branch 'jn/warn-on-inaccessible-loosen' (4f43e97)
   1/*
   2 * Copyright (c) 2005, Junio C Hamano
   3 */
   4#include "cache.h"
   5#include "sigchain.h"
   6
   7static struct lock_file *lock_file_list;
   8static const char *alternate_index_output;
   9
  10static void remove_lock_file(void)
  11{
  12        pid_t me = getpid();
  13
  14        while (lock_file_list) {
  15                if (lock_file_list->owner == me &&
  16                    lock_file_list->filename[0]) {
  17                        if (lock_file_list->fd >= 0)
  18                                close(lock_file_list->fd);
  19                        unlink_or_warn(lock_file_list->filename);
  20                }
  21                lock_file_list = lock_file_list->next;
  22        }
  23}
  24
  25static void remove_lock_file_on_signal(int signo)
  26{
  27        remove_lock_file();
  28        sigchain_pop(signo);
  29        raise(signo);
  30}
  31
  32/*
  33 * p = absolute or relative path name
  34 *
  35 * Return a pointer into p showing the beginning of the last path name
  36 * element.  If p is empty or the root directory ("/"), just return p.
  37 */
  38static char *last_path_elm(char *p)
  39{
  40        /* r starts pointing to null at the end of the string */
  41        char *r = strchr(p, '\0');
  42
  43        if (r == p)
  44                return p; /* just return empty string */
  45
  46        r--; /* back up to last non-null character */
  47
  48        /* back up past trailing slashes, if any */
  49        while (r > p && *r == '/')
  50                r--;
  51
  52        /*
  53         * then go backwards until I hit a slash, or the beginning of
  54         * the string
  55         */
  56        while (r > p && *(r-1) != '/')
  57                r--;
  58        return r;
  59}
  60
  61
  62/* We allow "recursive" symbolic links. Only within reason, though */
  63#define MAXDEPTH 5
  64
  65/*
  66 * p = path that may be a symlink
  67 * s = full size of p
  68 *
  69 * If p is a symlink, attempt to overwrite p with a path to the real
  70 * file or directory (which may or may not exist), following a chain of
  71 * symlinks if necessary.  Otherwise, leave p unmodified.
  72 *
  73 * This is a best-effort routine.  If an error occurs, p will either be
  74 * left unmodified or will name a different symlink in a symlink chain
  75 * that started with p's initial contents.
  76 *
  77 * Always returns p.
  78 */
  79
  80static char *resolve_symlink(char *p, size_t s)
  81{
  82        int depth = MAXDEPTH;
  83
  84        while (depth--) {
  85                char link[PATH_MAX];
  86                int link_len = readlink(p, link, sizeof(link));
  87                if (link_len < 0) {
  88                        /* not a symlink anymore */
  89                        return p;
  90                }
  91                else if (link_len < sizeof(link))
  92                        /* readlink() never null-terminates */
  93                        link[link_len] = '\0';
  94                else {
  95                        warning("%s: symlink too long", p);
  96                        return p;
  97                }
  98
  99                if (is_absolute_path(link)) {
 100                        /* absolute path simply replaces p */
 101                        if (link_len < s)
 102                                strcpy(p, link);
 103                        else {
 104                                warning("%s: symlink too long", p);
 105                                return p;
 106                        }
 107                } else {
 108                        /*
 109                         * link is a relative path, so I must replace the
 110                         * last element of p with it.
 111                         */
 112                        char *r = (char *)last_path_elm(p);
 113                        if (r - p + link_len < s)
 114                                strcpy(r, link);
 115                        else {
 116                                warning("%s: symlink too long", p);
 117                                return p;
 118                        }
 119                }
 120        }
 121        return p;
 122}
 123
 124
 125static int lock_file(struct lock_file *lk, const char *path, int flags)
 126{
 127        if (strlen(path) >= sizeof(lk->filename))
 128                return -1;
 129        strcpy(lk->filename, path);
 130        /*
 131         * subtract 5 from size to make sure there's room for adding
 132         * ".lock" for the lock file name
 133         */
 134        if (!(flags & LOCK_NODEREF))
 135                resolve_symlink(lk->filename, sizeof(lk->filename)-5);
 136        strcat(lk->filename, ".lock");
 137        lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
 138        if (0 <= lk->fd) {
 139                if (!lock_file_list) {
 140                        sigchain_push_common(remove_lock_file_on_signal);
 141                        atexit(remove_lock_file);
 142                }
 143                lk->owner = getpid();
 144                if (!lk->on_list) {
 145                        lk->next = lock_file_list;
 146                        lock_file_list = lk;
 147                        lk->on_list = 1;
 148                }
 149                if (adjust_shared_perm(lk->filename))
 150                        return error("cannot fix permission bits on %s",
 151                                     lk->filename);
 152        }
 153        else
 154                lk->filename[0] = 0;
 155        return lk->fd;
 156}
 157
 158static char *unable_to_lock_message(const char *path, int err)
 159{
 160        struct strbuf buf = STRBUF_INIT;
 161
 162        if (err == EEXIST) {
 163                strbuf_addf(&buf, "Unable to create '%s.lock': %s.\n\n"
 164                    "If no other git process is currently running, this probably means a\n"
 165                    "git process crashed in this repository earlier. Make sure no other git\n"
 166                    "process is running and remove the file manually to continue.",
 167                            absolute_path(path), strerror(err));
 168        } else
 169                strbuf_addf(&buf, "Unable to create '%s.lock': %s",
 170                            absolute_path(path), strerror(err));
 171        return strbuf_detach(&buf, NULL);
 172}
 173
 174int unable_to_lock_error(const char *path, int err)
 175{
 176        char *msg = unable_to_lock_message(path, err);
 177        error("%s", msg);
 178        free(msg);
 179        return -1;
 180}
 181
 182NORETURN void unable_to_lock_index_die(const char *path, int err)
 183{
 184        die("%s", unable_to_lock_message(path, err));
 185}
 186
 187int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
 188{
 189        int fd = lock_file(lk, path, flags);
 190        if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
 191                unable_to_lock_index_die(path, errno);
 192        return fd;
 193}
 194
 195int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
 196{
 197        int fd, orig_fd;
 198
 199        fd = lock_file(lk, path, flags);
 200        if (fd < 0) {
 201                if (flags & LOCK_DIE_ON_ERROR)
 202                        unable_to_lock_index_die(path, errno);
 203                return fd;
 204        }
 205
 206        orig_fd = open(path, O_RDONLY);
 207        if (orig_fd < 0) {
 208                if (errno != ENOENT) {
 209                        if (flags & LOCK_DIE_ON_ERROR)
 210                                die("cannot open '%s' for copying", path);
 211                        close(fd);
 212                        return error("cannot open '%s' for copying", path);
 213                }
 214        } else if (copy_fd(orig_fd, fd)) {
 215                if (flags & LOCK_DIE_ON_ERROR)
 216                        exit(128);
 217                close(fd);
 218                return -1;
 219        }
 220        return fd;
 221}
 222
 223int close_lock_file(struct lock_file *lk)
 224{
 225        int fd = lk->fd;
 226        lk->fd = -1;
 227        return close(fd);
 228}
 229
 230int commit_lock_file(struct lock_file *lk)
 231{
 232        char result_file[PATH_MAX];
 233        size_t i;
 234        if (lk->fd >= 0 && close_lock_file(lk))
 235                return -1;
 236        strcpy(result_file, lk->filename);
 237        i = strlen(result_file) - 5; /* .lock */
 238        result_file[i] = 0;
 239        if (rename(lk->filename, result_file))
 240                return -1;
 241        lk->filename[0] = 0;
 242        return 0;
 243}
 244
 245int hold_locked_index(struct lock_file *lk, int die_on_error)
 246{
 247        return hold_lock_file_for_update(lk, get_index_file(),
 248                                         die_on_error
 249                                         ? LOCK_DIE_ON_ERROR
 250                                         : 0);
 251}
 252
 253void set_alternate_index_output(const char *name)
 254{
 255        alternate_index_output = name;
 256}
 257
 258int commit_locked_index(struct lock_file *lk)
 259{
 260        if (alternate_index_output) {
 261                if (lk->fd >= 0 && close_lock_file(lk))
 262                        return -1;
 263                if (rename(lk->filename, alternate_index_output))
 264                        return -1;
 265                lk->filename[0] = 0;
 266                return 0;
 267        }
 268        else
 269                return commit_lock_file(lk);
 270}
 271
 272void rollback_lock_file(struct lock_file *lk)
 273{
 274        if (lk->filename[0]) {
 275                if (lk->fd >= 0)
 276                        close(lk->fd);
 277                unlink_or_warn(lk->filename);
 278        }
 279        lk->filename[0] = 0;
 280}