repository.c revision 1.14
1/* $OpenBSD: repository.c,v 1.14 2007/07/03 13:22:43 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 28struct cvs_wklhead repo_locks; 29 30void 31cvs_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 cvs_worklist_run(&repo_locks, cvs_worklist_unlink); 41} 42 43void 44cvs_repository_lock(const char *repo) 45{ 46 int i; 47 struct stat st; 48 char fpath[MAXPATHLEN]; 49 struct passwd *pw; 50 51 if (cvs_noexec == 1 || cvs_readonlyfs == 1) 52 return; 53 54 cvs_log(LP_TRACE, "cvs_repository_lock(%s)", repo); 55 56 (void)xsnprintf(fpath, sizeof(fpath), "%s/%s", repo, CVS_LOCK); 57 58 for (i = 0; i < CVS_LOCK_TRIES; i++) { 59 if (cvs_quit) 60 fatal("received signal %d", sig_received); 61 62 if (stat(fpath, &st) == -1) 63 break; 64 65 if ((pw = getpwuid(st.st_uid)) == NULL) 66 fatal("cvs_repository_lock: %s", strerror(errno)); 67 68 cvs_log(LP_NOTICE, "waiting for %s's lock in '%s'", 69 pw->pw_name, repo); 70 sleep(CVS_LOCK_SLEEP); 71 } 72 73 if (i == CVS_LOCK_TRIES) 74 fatal("maximum wait time for lock inside '%s' reached", repo); 75 76 if ((i = open(fpath, O_WRONLY|O_CREAT|O_TRUNC, 0755)) < 0) { 77 if (errno == EEXIST) 78 fatal("cvs_repository_lock: somebody beat us"); 79 else 80 fatal("cvs_repository_lock: %s: %s", 81 fpath, strerror(errno)); 82 } 83 84 (void)close(i); 85 cvs_worklist_add(fpath, &repo_locks); 86} 87 88void 89cvs_repository_getdir(const char *dir, const char *wdir, 90 struct cvs_flisthead *fl, struct cvs_flisthead *dl, int dodirs) 91{ 92 int type; 93 DIR *dirp; 94 struct stat st; 95 struct dirent *dp; 96 char *s, fpath[MAXPATHLEN], rpath[MAXPATHLEN]; 97 98 if ((dirp = opendir(dir)) == NULL) 99 fatal("cvs_repository_getdir: failed to open '%s'", dir); 100 101 while ((dp = readdir(dirp)) != NULL) { 102 if (!strcmp(dp->d_name, ".") || 103 !strcmp(dp->d_name, "..") || 104 !strcmp(dp->d_name, CVS_LOCK)) 105 continue; 106 107 if (cvs_file_chkign(dp->d_name)) 108 continue; 109 110 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", wdir, dp->d_name); 111 (void)xsnprintf(rpath, MAXPATHLEN, "%s/%s", dir, dp->d_name); 112 113 /* 114 * nfs and afs will show d_type as DT_UNKNOWN 115 * for files and/or directories so when we encounter 116 * this we call lstat() on the path to be sure. 117 */ 118 if (dp->d_type == DT_UNKNOWN) { 119 if (lstat(rpath, &st) == -1) 120 fatal("'%s': %s", rpath, strerror(errno)); 121 122 switch (st.st_mode & S_IFMT) { 123 case S_IFDIR: 124 type = CVS_DIR; 125 break; 126 case S_IFREG: 127 type = CVS_FILE; 128 break; 129 default: 130 fatal("Unknown file type in repository"); 131 } 132 } else { 133 switch (dp->d_type) { 134 case DT_DIR: 135 type = CVS_DIR; 136 break; 137 case DT_REG: 138 type = CVS_FILE; 139 break; 140 default: 141 fatal("Unknown file type in repository"); 142 } 143 } 144 145 if (dodirs == 0 && type == CVS_DIR) 146 continue; 147 148 switch (type) { 149 case CVS_DIR: 150 if (!strcmp(dp->d_name, CVS_PATH_ATTIC)) 151 cvs_repository_getdir(rpath, wdir, fl, dl, 0); 152 else 153 cvs_file_get(fpath, dl); 154 break; 155 case CVS_FILE: 156 if ((s = strrchr(fpath, ',')) != NULL) 157 *s = '\0'; 158 cvs_file_get(fpath, fl); 159 break; 160 default: 161 fatal("type %d unknown, shouldn't happen", type); 162 } 163 } 164 165 (void)closedir(dirp); 166} 167