Code

Merge branch 'maint'
[git.git] / lockfile.c
1 /*
2  * Copyright (c) 2005, Junio C Hamano
3  */
4 #include "cache.h"
6 static struct lock_file *lock_file_list;
7 static const char *alternate_index_output;
9 static void remove_lock_file(void)
10 {
11         pid_t me = getpid();
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 }
23 static void remove_lock_file_on_signal(int signo)
24 {
25         remove_lock_file();
26         signal(SIGINT, SIG_DFL);
27         raise(signo);
28 }
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  */
36 static 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');
41         if (r == p)
42                 return p; /* just return empty string */
44         r--; /* back up to last non-null character */
46         /* back up past trailing slashes, if any */
47         while (r > p && *r == '/')
48                 r--;
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 }
60 /* We allow "recursive" symbolic links. Only within reason, though */
61 #define MAXDEPTH 5
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  */
78 static char *resolve_symlink(char *p, size_t s)
79 {
80         int depth = MAXDEPTH;
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                 }
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;
123 static int lock_file(struct lock_file *lk, const char *path)
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;
154 int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error)
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;
162 int commit_lock_file(struct lock_file *lk)
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;
175 int hold_locked_index(struct lock_file *lk, int die_on_error)
177         return hold_lock_file_for_update(lk, get_index_file(), die_on_error);
180 void set_alternate_index_output(const char *name)
182         alternate_index_output = name;
185 int commit_locked_index(struct lock_file *lk)
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);
196 void rollback_lock_file(struct lock_file *lk)
198         if (lk->filename[0]) {
199                 close(lk->fd);
200                 unlink(lk->filename);
201         }
202         lk->filename[0] = 0;