1 |
|
|
/* $OpenBSD: repository.c,v 1.25 2017/05/31 16:18:20 joris Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2006 Joris Vink <joris@openbsd.org> |
4 |
|
|
* |
5 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
6 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
7 |
|
|
* copyright notice and this permission notice appear in all copies. |
8 |
|
|
* |
9 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 |
|
|
*/ |
17 |
|
|
|
18 |
|
|
#include <sys/stat.h> |
19 |
|
|
|
20 |
|
|
#include <errno.h> |
21 |
|
|
#include <fcntl.h> |
22 |
|
|
#include <pwd.h> |
23 |
|
|
#include <string.h> |
24 |
|
|
#include <unistd.h> |
25 |
|
|
|
26 |
|
|
#include "cvs.h" |
27 |
|
|
|
28 |
|
|
struct wklhead repo_locks; |
29 |
|
|
|
30 |
|
|
void |
31 |
|
|
cvs_repository_unlock(const char *repo) |
32 |
|
|
{ |
33 |
|
|
char fpath[PATH_MAX]; |
34 |
|
|
|
35 |
|
|
cvs_log(LP_TRACE, "cvs_repository_unlock(%s)", repo); |
36 |
|
|
|
37 |
|
|
(void)xsnprintf(fpath, sizeof(fpath), "%s/%s", repo, CVS_LOCK); |
38 |
|
|
|
39 |
|
|
if (unlink(fpath) == -1 && errno != ENOENT) |
40 |
|
|
cvs_log(LP_ERR, "warning: failed to unlink %s", fpath); |
41 |
|
|
} |
42 |
|
|
|
43 |
|
|
void |
44 |
|
|
cvs_repository_lock(const char *repo, int wantlock) |
45 |
|
|
{ |
46 |
|
|
int i; |
47 |
|
|
uid_t myuid; |
48 |
|
|
struct stat st; |
49 |
|
|
char fpath[PATH_MAX]; |
50 |
|
|
struct passwd *pw; |
51 |
|
|
|
52 |
|
|
if (cvs_noexec == 1 || cvs_readonlyfs == 1) |
53 |
|
|
return; |
54 |
|
|
|
55 |
|
|
cvs_log(LP_TRACE, "cvs_repository_lock(%s, %d)", repo, wantlock); |
56 |
|
|
|
57 |
|
|
(void)xsnprintf(fpath, sizeof(fpath), "%s/%s", repo, CVS_LOCK); |
58 |
|
|
|
59 |
|
|
myuid = getuid(); |
60 |
|
|
|
61 |
|
|
for (i = 0; i < CVS_LOCK_TRIES; i++) { |
62 |
|
|
if (cvs_quit) |
63 |
|
|
fatal("received signal %d", sig_received); |
64 |
|
|
|
65 |
|
|
if (stat(fpath, &st) == -1) |
66 |
|
|
break; |
67 |
|
|
|
68 |
|
|
if (st.st_uid == myuid) |
69 |
|
|
return; |
70 |
|
|
|
71 |
|
|
if ((pw = getpwuid(st.st_uid)) == NULL) |
72 |
|
|
fatal("cvs_repository_lock: %s", strerror(errno)); |
73 |
|
|
|
74 |
|
|
cvs_log(LP_NOTICE, "waiting for %s's lock in '%s'", |
75 |
|
|
pw->pw_name, repo); |
76 |
|
|
sleep(CVS_LOCK_SLEEP); |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
if (i == CVS_LOCK_TRIES) |
80 |
|
|
fatal("maximum wait time for lock inside '%s' reached", repo); |
81 |
|
|
|
82 |
|
|
if (wantlock == 0) |
83 |
|
|
return; |
84 |
|
|
|
85 |
|
|
if ((i = open(fpath, O_WRONLY|O_CREAT|O_TRUNC, 0755)) < 0) { |
86 |
|
|
if (errno == EEXIST) |
87 |
|
|
fatal("cvs_repository_lock: somebody beat us"); |
88 |
|
|
else |
89 |
|
|
fatal("cvs_repository_lock: %s: %s", |
90 |
|
|
fpath, strerror(errno)); |
91 |
|
|
} |
92 |
|
|
|
93 |
|
|
(void)close(i); |
94 |
|
|
worklist_add(fpath, &repo_locks); |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
void |
98 |
|
|
cvs_repository_getdir(const char *dir, const char *wdir, |
99 |
|
|
struct cvs_flisthead *fl, struct cvs_flisthead *dl, int flags) |
100 |
|
|
{ |
101 |
|
|
int type; |
102 |
|
|
DIR *dirp; |
103 |
|
|
struct stat st; |
104 |
|
|
struct dirent *dp; |
105 |
|
|
char *s, fpath[PATH_MAX], rpath[PATH_MAX]; |
106 |
|
|
|
107 |
|
|
if ((dirp = opendir(dir)) == NULL) |
108 |
|
|
fatal("cvs_repository_getdir: failed to open '%s'", dir); |
109 |
|
|
|
110 |
|
|
while ((dp = readdir(dirp)) != NULL) { |
111 |
|
|
if (!strcmp(dp->d_name, ".") || |
112 |
|
|
!strcmp(dp->d_name, "..") || |
113 |
|
|
!strcmp(dp->d_name, CVS_LOCK)) |
114 |
|
|
continue; |
115 |
|
|
|
116 |
|
|
(void)xsnprintf(fpath, PATH_MAX, "%s/%s", wdir, dp->d_name); |
117 |
|
|
(void)xsnprintf(rpath, PATH_MAX, "%s/%s", dir, dp->d_name); |
118 |
|
|
|
119 |
|
|
if (!TAILQ_EMPTY(&checkout_ign_pats)) { |
120 |
|
|
if ((s = strrchr(fpath, ',')) != NULL) |
121 |
|
|
*s = '\0'; |
122 |
|
|
if (cvs_file_chkign(fpath)) |
123 |
|
|
continue; |
124 |
|
|
if (s != NULL) |
125 |
|
|
*s = ','; |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
/* |
129 |
|
|
* nfs and afs will show d_type as DT_UNKNOWN |
130 |
|
|
* for files and/or directories so when we encounter |
131 |
|
|
* this we call lstat() on the path to be sure. |
132 |
|
|
*/ |
133 |
|
|
if (dp->d_type == DT_UNKNOWN) { |
134 |
|
|
if (lstat(rpath, &st) == -1) |
135 |
|
|
fatal("'%s': %s", rpath, strerror(errno)); |
136 |
|
|
|
137 |
|
|
switch (st.st_mode & S_IFMT) { |
138 |
|
|
case S_IFDIR: |
139 |
|
|
type = CVS_DIR; |
140 |
|
|
break; |
141 |
|
|
case S_IFREG: |
142 |
|
|
type = CVS_FILE; |
143 |
|
|
break; |
144 |
|
|
default: |
145 |
|
|
fatal("Unknown file type in repository"); |
146 |
|
|
} |
147 |
|
|
} else { |
148 |
|
|
switch (dp->d_type) { |
149 |
|
|
case DT_DIR: |
150 |
|
|
type = CVS_DIR; |
151 |
|
|
break; |
152 |
|
|
case DT_REG: |
153 |
|
|
type = CVS_FILE; |
154 |
|
|
break; |
155 |
|
|
default: |
156 |
|
|
fatal("Unknown file type in repository"); |
157 |
|
|
} |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
if (!(flags & REPOSITORY_DODIRS) && type == CVS_DIR) { |
161 |
|
|
if (strcmp(dp->d_name, CVS_PATH_ATTIC)) |
162 |
|
|
continue; |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
switch (type) { |
166 |
|
|
case CVS_DIR: |
167 |
|
|
if (!strcmp(dp->d_name, CVS_PATH_ATTIC)) { |
168 |
|
|
cvs_repository_getdir(rpath, wdir, fl, dl, |
169 |
|
|
REPOSITORY_IS_ATTIC); |
170 |
|
|
} else { |
171 |
|
|
cvs_file_get(fpath, 0, dl, CVS_DIR); |
172 |
|
|
} |
173 |
|
|
break; |
174 |
|
|
case CVS_FILE: |
175 |
|
|
if ((s = strrchr(fpath, ',')) != NULL && |
176 |
|
|
s != fpath && !strcmp(s, RCS_FILE_EXT)) { |
177 |
|
|
*s = '\0'; |
178 |
|
|
cvs_file_get(fpath, |
179 |
|
|
(flags & REPOSITORY_IS_ATTIC) ? |
180 |
|
|
FILE_INSIDE_ATTIC : 0, fl, CVS_FILE); |
181 |
|
|
} |
182 |
|
|
break; |
183 |
|
|
default: |
184 |
|
|
fatal("type %d unknown, shouldn't happen", type); |
185 |
|
|
} |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
(void)closedir(dirp); |
189 |
|
|
} |