lockfile.con commit tests: allow user to specify trash directory location (f423ef5)
   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
 158
 159NORETURN void unable_to_lock_index_die(const char *path, int err)
 160{
 161        if (err == EEXIST) {
 162                die("Unable to create '%s.lock': %s.\n\n"
 163                    "If no other git process is currently running, this probably means a\n"
 164                    "git process crashed in this repository earlier. Make sure no other git\n"
 165                    "process is running and remove the file manually to continue.",
 166                    path, strerror(err));
 167        } else {
 168                die("Unable to create '%s.lock': %s", path, strerror(err));
 169        }
 170}
 171
 172int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
 173{
 174        int fd = lock_file(lk, path, flags);
 175        if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
 176                unable_to_lock_index_die(path, errno);
 177        return fd;
 178}
 179
 180int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
 181{
 182        int fd, orig_fd;
 183
 184        fd = lock_file(lk, path, flags);
 185        if (fd < 0) {
 186                if (flags & LOCK_DIE_ON_ERROR)
 187                        unable_to_lock_index_die(path, errno);
 188                return fd;
 189        }
 190
 191        orig_fd = open(path, O_RDONLY);
 192        if (orig_fd < 0) {
 193                if (errno != ENOENT) {
 194                        if (flags & LOCK_DIE_ON_ERROR)
 195                                die("cannot open '%s' for copying", path);
 196                        close(fd);
 197                        return error("cannot open '%s' for copying", path);
 198                }
 199        } else if (copy_fd(orig_fd, fd)) {
 200                if (flags & LOCK_DIE_ON_ERROR)
 201                        exit(128);
 202                close(fd);
 203                return -1;
 204        }
 205        return fd;
 206}
 207
 208int close_lock_file(struct lock_file *lk)
 209{
 210        int fd = lk->fd;
 211        lk->fd = -1;
 212        return close(fd);
 213}
 214
 215int commit_lock_file(struct lock_file *lk)
 216{
 217        char result_file[PATH_MAX];
 218        size_t i;
 219        if (lk->fd >= 0 && close_lock_file(lk))
 220                return -1;
 221        strcpy(result_file, lk->filename);
 222        i = strlen(result_file) - 5; /* .lock */
 223        result_file[i] = 0;
 224        if (rename(lk->filename, result_file))
 225                return -1;
 226        lk->filename[0] = 0;
 227        return 0;
 228}
 229
 230int hold_locked_index(struct lock_file *lk, int die_on_error)
 231{
 232        return hold_lock_file_for_update(lk, get_index_file(),
 233                                         die_on_error
 234                                         ? LOCK_DIE_ON_ERROR
 235                                         : 0);
 236}
 237
 238void set_alternate_index_output(const char *name)
 239{
 240        alternate_index_output = name;
 241}
 242
 243int commit_locked_index(struct lock_file *lk)
 244{
 245        if (alternate_index_output) {
 246                if (lk->fd >= 0 && close_lock_file(lk))
 247                        return -1;
 248                if (rename(lk->filename, alternate_index_output))
 249                        return -1;
 250                lk->filename[0] = 0;
 251                return 0;
 252        }
 253        else
 254                return commit_lock_file(lk);
 255}
 256
 257void rollback_lock_file(struct lock_file *lk)
 258{
 259        if (lk->filename[0]) {
 260                if (lk->fd >= 0)
 261                        close(lk->fd);
 262                unlink_or_warn(lk->filename);
 263        }
 264        lk->filename[0] = 0;
 265}