1 /* $OpenBSD: repository.c,v 1.23 2010/07/23 08:31:19 ray 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[MAXPATHLEN]; 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 /* XXX - this ok? */ 40 worklist_run(&repo_locks, worklist_unlink); 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[MAXPATHLEN]; 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[MAXPATHLEN], rpath[MAXPATHLEN]; 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, MAXPATHLEN, "%s/%s", wdir, dp->d_name); 117 (void)xsnprintf(rpath, MAXPATHLEN, "%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 } 190