lockfile.con commit Merge branch 'ew/svn-rev-db' (3e5f260)
   1/*
   2 * Copyright (c) 2005, Junio C Hamano
   3 */
   4#include "cache.h"
   5
   6static struct lock_file *lock_file_list;
   7static const char *alternate_index_output;
   8
   9static void remove_lock_file(void)
  10{
  11        pid_t me = getpid();
  12
  13        while (lock_file_list) {
  14                if (lock_file_list->owner == me &&
  15                    lock_file_list->filename[0]) {
  16                        close(lock_file_list->fd);
  17                        unlink(lock_file_list->filename);
  18                }
  19                lock_file_list = lock_file_list->next;
  20        }
  21}
  22
  23static void remove_lock_file_on_signal(int signo)
  24{
  25        remove_lock_file();
  26        signal(SIGINT, SIG_DFL);
  27        raise(signo);
  28}
  29
  30/*
  31 * p = absolute or relative path name
  32 *
  33 * Return a pointer into p showing the beginning of the last path name
  34 * element.  If p is empty or the root directory ("/"), just return p.
  35 */
  36static char *last_path_elm(char *p)
  37{
  38        /* r starts pointing to null at the end of the string */
  39        char *r = strchr(p, '\0');
  40
  41        if (r == p)
  42                return p; /* just return empty string */
  43
  44        r--; /* back up to last non-null character */
  45
  46        /* back up past trailing slashes, if any */
  47        while (r > p && *r == '/')
  48                r--;
  49
  50        /*
  51         * then go backwards until I hit a slash, or the beginning of
  52         * the string
  53         */
  54        while (r > p && *(r-1) != '/')
  55                r--;
  56        return r;
  57}
  58
  59
  60/* We allow "recursive" symbolic links. Only within reason, though */
  61#define MAXDEPTH 5
  62
  63/*
  64 * p = path that may be a symlink
  65 * s = full size of p
  66 *
  67 * If p is a symlink, attempt to overwrite p with a path to the real
  68 * file or directory (which may or may not exist), following a chain of
  69 * symlinks if necessary.  Otherwise, leave p unmodified.
  70 *
  71 * This is a best-effort routine.  If an error occurs, p will either be
  72 * left unmodified or will name a different symlink in a symlink chain
  73 * that started with p's initial contents.
  74 *
  75 * Always returns p.
  76 */
  77
  78static char *resolve_symlink(char *p, size_t s)
  79{
  80        int depth = MAXDEPTH;
  81
  82        while (depth--) {
  83                char link[PATH_MAX];
  84                int link_len = readlink(p, link, sizeof(link));
  85                if (link_len < 0) {
  86                        /* not a symlink anymore */
  87                        return p;
  88                }
  89                else if (link_len < sizeof(link))
  90                        /* readlink() never null-terminates */
  91                        link[link_len] = '\0';
  92                else {
  93                        warning("%s: symlink too long", p);
  94                        return p;
  95                }
  96
  97                if (is_absolute_path(link)) {
  98                        /* absolute path simply replaces p */
  99                        if (link_len < s)
 100                                strcpy(p, link);
 101                        else {
 102                                warning("%s: symlink too long", p);
 103                                return p;
 104                        }
 105                } else {
 106                        /*
 107                         * link is a relative path, so I must replace the
 108                         * last element of p with it.
 109                         */
 110                        char *r = (char*)last_path_elm(p);
 111                        if (r - p + link_len < s)
 112                                strcpy(r, link);
 113                        else {
 114                                warning("%s: symlink too long", p);
 115                                return p;
 116                        }
 117                }
 118        }
 119        return p;
 120}
 121
 122
 123static int lock_file(struct lock_file *lk, const char *path)
 124{
 125        if (strlen(path) >= sizeof(lk->filename)) return -1;
 126        strcpy(lk->filename, path);
 127        /*
 128         * subtract 5 from size to make sure there's room for adding
 129         * ".lock" for the lock file name
 130         */
 131        resolve_symlink(lk->filename, sizeof(lk->filename)-5);
 132        strcat(lk->filename, ".lock");
 133        lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
 134        if (0 <= lk->fd) {
 135                if (!lock_file_list) {
 136                        signal(SIGINT, remove_lock_file_on_signal);
 137                        atexit(remove_lock_file);
 138                }
 139                lk->owner = getpid();
 140                if (!lk->on_list) {
 141                        lk->next = lock_file_list;
 142                        lock_file_list = lk;
 143                        lk->on_list = 1;
 144                }
 145                if (adjust_shared_perm(lk->filename))
 146                        return error("cannot fix permission bits on %s",
 147                                     lk->filename);
 148        }
 149        else
 150                lk->filename[0] = 0;
 151        return lk->fd;
 152}
 153
 154int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error)
 155{
 156        int fd = lock_file(lk, path);
 157        if (fd < 0 && die_on_error)
 158                die("unable to create '%s.lock': %s", path, strerror(errno));
 159        return fd;
 160}
 161
 162int commit_lock_file(struct lock_file *lk)
 163{
 164        char result_file[PATH_MAX];
 165        int i;
 166        close(lk->fd);
 167        strcpy(result_file, lk->filename);
 168        i = strlen(result_file) - 5; /* .lock */
 169        result_file[i] = 0;
 170        i = rename(lk->filename, result_file);
 171        lk->filename[0] = 0;
 172        return i;
 173}
 174
 175int hold_locked_index(struct lock_file *lk, int die_on_error)
 176{
 177        return hold_lock_file_for_update(lk, get_index_file(), die_on_error);
 178}
 179
 180void set_alternate_index_output(const char *name)
 181{
 182        alternate_index_output = name;
 183}
 184
 185int commit_locked_index(struct lock_file *lk)
 186{
 187        if (alternate_index_output) {
 188                int result = rename(lk->filename, alternate_index_output);
 189                lk->filename[0] = 0;
 190                return result;
 191        }
 192        else
 193                return commit_lock_file(lk);
 194}
 195
 196void rollback_lock_file(struct lock_file *lk)
 197{
 198        if (lk->filename[0]) {
 199                close(lk->fd);
 200                unlink(lk->filename);
 201        }
 202        lk->filename[0] = 0;
 203}