]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2005, Junio C Hamano | |
3 | */ | |
4 | #include "cache.h" | |
5 | ||
6 | static struct lock_file *lock_file_list; | |
7 | static const char *alternate_index_output; | |
8 | ||
9 | static 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 | unlink(lock_file_list->filename); | |
17 | lock_file_list = lock_file_list->next; | |
18 | } | |
19 | } | |
20 | ||
21 | static void remove_lock_file_on_signal(int signo) | |
22 | { | |
23 | remove_lock_file(); | |
24 | signal(SIGINT, SIG_DFL); | |
25 | raise(signo); | |
26 | } | |
27 | ||
28 | static int lock_file(struct lock_file *lk, const char *path) | |
29 | { | |
30 | int fd; | |
31 | struct stat st; | |
32 | ||
33 | if ((!lstat(path, &st)) && S_ISLNK(st.st_mode)) { | |
34 | ssize_t sz; | |
35 | static char target[PATH_MAX]; | |
36 | sz = readlink(path, target, sizeof(target)); | |
37 | if (sz < 0) | |
38 | warning("Cannot readlink %s", path); | |
39 | else if (target[0] != '/') | |
40 | warning("Cannot lock target of relative symlink %s", path); | |
41 | else | |
42 | path = target; | |
43 | } | |
44 | sprintf(lk->filename, "%s.lock", path); | |
45 | fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); | |
46 | if (0 <= fd) { | |
47 | if (!lock_file_list) { | |
48 | signal(SIGINT, remove_lock_file_on_signal); | |
49 | atexit(remove_lock_file); | |
50 | } | |
51 | lk->owner = getpid(); | |
52 | if (!lk->on_list) { | |
53 | lk->next = lock_file_list; | |
54 | lock_file_list = lk; | |
55 | lk->on_list = 1; | |
56 | } | |
57 | if (adjust_shared_perm(lk->filename)) | |
58 | return error("cannot fix permission bits on %s", | |
59 | lk->filename); | |
60 | } | |
61 | else | |
62 | lk->filename[0] = 0; | |
63 | return fd; | |
64 | } | |
65 | ||
66 | int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error) | |
67 | { | |
68 | int fd = lock_file(lk, path); | |
69 | if (fd < 0 && die_on_error) | |
70 | die("unable to create '%s.lock': %s", path, strerror(errno)); | |
71 | return fd; | |
72 | } | |
73 | ||
74 | int commit_lock_file(struct lock_file *lk) | |
75 | { | |
76 | char result_file[PATH_MAX]; | |
77 | int i; | |
78 | strcpy(result_file, lk->filename); | |
79 | i = strlen(result_file) - 5; /* .lock */ | |
80 | result_file[i] = 0; | |
81 | i = rename(lk->filename, result_file); | |
82 | lk->filename[0] = 0; | |
83 | return i; | |
84 | } | |
85 | ||
86 | int hold_locked_index(struct lock_file *lk, int die_on_error) | |
87 | { | |
88 | return hold_lock_file_for_update(lk, get_index_file(), die_on_error); | |
89 | } | |
90 | ||
91 | void set_alternate_index_output(const char *name) | |
92 | { | |
93 | alternate_index_output = name; | |
94 | } | |
95 | ||
96 | int commit_locked_index(struct lock_file *lk) | |
97 | { | |
98 | if (alternate_index_output) { | |
99 | int result = rename(lk->filename, alternate_index_output); | |
100 | lk->filename[0] = 0; | |
101 | return result; | |
102 | } | |
103 | else | |
104 | return commit_lock_file(lk); | |
105 | } | |
106 | ||
107 | void rollback_lock_file(struct lock_file *lk) | |
108 | { | |
109 | if (lk->filename[0]) | |
110 | unlink(lk->filename); | |
111 | lk->filename[0] = 0; | |
112 | } |