1/* rcsclean - clean up working files */
| 1/* Clean up working files. */
|
2
| 2
|
3/* Copyright 1991 by Paul Eggert
| 3/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert
|
4 Distributed under license by the Free Software Foundation, Inc. 5 6This file is part of RCS. 7 8RCS is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 2, or (at your option) 11any later version. 12 13RCS is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License
| 4 Distributed under license by the Free Software Foundation, Inc. 5 6This file is part of RCS. 7 8RCS is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 2, or (at your option) 11any later version. 12 13RCS is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License
|
19along with RCS; see the file COPYING. If not, write to 20the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
| 19along with RCS; see the file COPYING. 20If not, write to the Free Software Foundation, 2159 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
21 22Report problems and direct all questions to: 23 24 rcs-bugs@cs.purdue.edu 25 26*/ 27 28#include "rcsbase.h" 29 30#if has_dirent 31 static int get_directory P((char const*,char***)); 32#endif 33 34static int unlock P((struct hshentry *)); 35static void cleanup P((void)); 36 37static RILE *workptr; 38static int exitstatus; 39
| 22 23Report problems and direct all questions to: 24 25 rcs-bugs@cs.purdue.edu 26 27*/ 28 29#include "rcsbase.h" 30 31#if has_dirent 32 static int get_directory P((char const*,char***)); 33#endif 34 35static int unlock P((struct hshentry *)); 36static void cleanup P((void)); 37 38static RILE *workptr; 39static int exitstatus; 40
|
40mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.1 1991/11/03 01:11:44 eggert Exp $")
| 41mainProg(rcscleanId, "rcsclean", "$Id: rcsclean.c,v 5.9 1995/06/16 06:19:24 eggert Exp $")
|
41{ 42 static char const usage[] =
| 42{ 43 static char const usage[] =
|
43 "\nrcsclean: usage: rcsclean [-ksubst] [-{nqru}[rev]] [-Vn] [-xsuffixes] [file ...]";
| 44 "\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ...";
|
44 45 static struct buf revision; 46 47 char *a, **newargv; 48 char const *rev, *p;
| 45 46 static struct buf revision; 47 48 char *a, **newargv; 49 char const *rev, *p;
|
49 int changelock, expmode, perform, unlocked, unlockflag, waslocked;
| 50 int dounlock, expmode, perform, unlocked, unlockflag, waslocked; 51 int Ttimeflag;
|
50 struct hshentries *deltas; 51 struct hshentry *delta; 52 struct stat workstat; 53 54 setrid(); 55 56 expmode = -1;
| 52 struct hshentries *deltas; 53 struct hshentry *delta; 54 struct stat workstat; 55 56 setrid(); 57 58 expmode = -1;
|
57 rev = nil;
| 59 rev = 0;
|
58 suffixes = X_DEFAULT; 59 perform = true; 60 unlockflag = false;
| 60 suffixes = X_DEFAULT; 61 perform = true; 62 unlockflag = false;
|
| 63 Ttimeflag = false;
|
61 62 argc = getRCSINIT(argc, argv, &newargv); 63 argv = newargv; 64 for (;;) {
| 64 65 argc = getRCSINIT(argc, argv, &newargv); 66 argv = newargv; 67 for (;;) {
|
65 if (--argc <= 0) {
| 68 if (--argc < 1) {
|
66# if has_dirent 67 argc = get_directory(".", &newargv); 68 argv = newargv; 69 break; 70# else
| 69# if has_dirent 70 argc = get_directory(".", &newargv); 71 argv = newargv; 72 break; 73# else
|
71 faterror("no file names specified");
| 74 faterror("no pathnames specified");
|
72# endif 73 } 74 a = *++argv;
| 75# endif 76 } 77 a = *++argv;
|
75 if (*a++ != '-')
| 78 if (!*a || *a++ != '-')
|
76 break; 77 switch (*a++) { 78 case 'k': 79 if (0 <= expmode) 80 redefined('k'); 81 if ((expmode = str2expmode(a)) < 0) 82 goto unknown; 83 break; 84 85 case 'n': 86 perform = false; 87 goto handle_revision; 88 89 case 'q': 90 quietflag = true; 91 /* fall into */ 92 case 'r': 93 handle_revision: 94 if (*a) { 95 if (rev) 96 warn("redefinition of revision number"); 97 rev = a; 98 } 99 break; 100
| 79 break; 80 switch (*a++) { 81 case 'k': 82 if (0 <= expmode) 83 redefined('k'); 84 if ((expmode = str2expmode(a)) < 0) 85 goto unknown; 86 break; 87 88 case 'n': 89 perform = false; 90 goto handle_revision; 91 92 case 'q': 93 quietflag = true; 94 /* fall into */ 95 case 'r': 96 handle_revision: 97 if (*a) { 98 if (rev) 99 warn("redefinition of revision number"); 100 rev = a; 101 } 102 break; 103
|
| 104 case 'T': 105 if (*a) 106 goto unknown; 107 Ttimeflag = true; 108 break; 109
|
101 case 'u': 102 unlockflag = true; 103 goto handle_revision; 104 105 case 'V': 106 setRCSversion(*argv); 107 break; 108 109 case 'x': 110 suffixes = a; 111 break; 112
| 110 case 'u': 111 unlockflag = true; 112 goto handle_revision; 113 114 case 'V': 115 setRCSversion(*argv); 116 break; 117 118 case 'x': 119 suffixes = a; 120 break; 121
|
| 122 case 'z': 123 zone_set(a); 124 break; 125
|
113 default: 114 unknown:
| 126 default: 127 unknown:
|
115 faterror("unknown option: %s%s", *argv, usage);
| 128 error("unknown option: %s%s", *argv, usage);
|
116 } 117 } 118
| 129 } 130 } 131
|
119 do {
| 132 dounlock = perform & unlockflag; 133 134 if (nerror) 135 cleanup(); 136 else 137 for (; 0 < argc; cleanup(), ++argv, --argc) { 138
|
120 ffree(); 121 122 if (!(
| 139 ffree(); 140 141 if (!(
|
123 0 < pairfilenames(
| 142 0 < pairnames(
|
124 argc, argv,
| 143 argc, argv,
|
125 unlockflag&perform ? rcswriteopen : rcsreadopen,
| 144 dounlock ? rcswriteopen : rcsreadopen,
|
126 true, true 127 ) &&
| 145 true, true 146 ) &&
|
128 (workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat))
| 147 (workptr = Iopen(workname, FOPEN_R_WORK, &workstat))
|
129 )) 130 continue; 131
| 148 )) 149 continue; 150
|
| 151 if (same_file(RCSstat, workstat, 0)) { 152 rcserror("RCS file is the same as working file %s.", 153 workname 154 ); 155 continue; 156 } 157
|
132 gettree(); 133 134 p = 0; 135 if (rev) { 136 if (!fexpandsym(rev, &revision, workptr)) 137 continue; 138 p = revision.string; 139 } else if (Head) 140 switch (unlockflag ? findlock(false,&delta) : 0) { 141 default: 142 continue; 143 case 0: 144 p = Dbranch ? Dbranch : ""; 145 break; 146 case 1: 147 p = delta->num; 148 break; 149 } 150 delta = 0; 151 deltas = 0; /* Keep lint happy. */ 152 if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas))) 153 continue; 154 155 waslocked = delta && delta->lockedby; 156 locker_expansion = unlock(delta); 157 unlocked = locker_expansion & unlockflag;
| 158 gettree(); 159 160 p = 0; 161 if (rev) { 162 if (!fexpandsym(rev, &revision, workptr)) 163 continue; 164 p = revision.string; 165 } else if (Head) 166 switch (unlockflag ? findlock(false,&delta) : 0) { 167 default: 168 continue; 169 case 0: 170 p = Dbranch ? Dbranch : ""; 171 break; 172 case 1: 173 p = delta->num; 174 break; 175 } 176 delta = 0; 177 deltas = 0; /* Keep lint happy. */ 178 if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas))) 179 continue; 180 181 waslocked = delta && delta->lockedby; 182 locker_expansion = unlock(delta); 183 unlocked = locker_expansion & unlockflag;
|
158 changelock = unlocked & perform;
| |
159 if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH)) 160 continue; 161
| 184 if (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH)) 185 continue; 186
|
162 if (!dorewrite(unlockflag, changelock))
| 187 if (unlocked && !checkaccesslist())
|
163 continue; 164
| 188 continue; 189
|
| 190 if (dorewrite(dounlock, unlocked) != 0) 191 continue; 192
|
165 if (0 <= expmode) 166 Expand = expmode; 167 else if ( 168 waslocked && 169 Expand == KEYVAL_EXPAND && 170 WORKMODE(RCSstat.st_mode,true) == workstat.st_mode 171 ) 172 Expand = KEYVALLOCK_EXPAND; 173 174 getdesc(false); 175 176 if (
| 193 if (0 <= expmode) 194 Expand = expmode; 195 else if ( 196 waslocked && 197 Expand == KEYVAL_EXPAND && 198 WORKMODE(RCSstat.st_mode,true) == workstat.st_mode 199 ) 200 Expand = KEYVALLOCK_EXPAND; 201 202 getdesc(false); 203 204 if (
|
177 !delta ? workstat.st_size!=0 :
| 205 !delta ? workstat.st_size!=0 :
|
178 0 < rcsfcmp(
| 206 0 < rcsfcmp(
|
179 workptr, &workstat, 180 buildrevision(deltas, delta, (FILE*)0, false), 181 delta
| 207 workptr, &workstat, 208 buildrevision(deltas, delta, (FILE*)0, false), 209 delta
|
182 ) 183 ) 184 continue; 185 186 if (quietflag < unlocked)
| 210 ) 211 ) 212 continue; 213 214 if (quietflag < unlocked)
|
187 aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSfilename);
| 215 aprintf(stdout, "rcs -u%s %s\n", delta->num, RCSname);
|
188
| 216
|
189 if_advise_access(changelock && deltas->first != delta, 190 finptr, MADV_SEQUENTIAL 191 ); 192 if (!donerewrite(changelock)) 193 continue;
| 217 if (perform & unlocked) { 218 if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL); 219 if (donerewrite(true, 220 Ttimeflag ? RCSstat.st_mtime : (time_t)-1 221 ) != 0) 222 continue; 223 }
|
194 195 if (!quietflag)
| 224 225 if (!quietflag)
|
196 aprintf(stdout, "rm -f %s\n", workfilename);
| 226 aprintf(stdout, "rm -f %s\n", workname);
|
197 Izclose(&workptr);
| 227 Izclose(&workptr);
|
198 if (perform && un_link(workfilename) != 0) 199 eerror(workfilename);
| 228 if (perform && un_link(workname) != 0) 229 eerror(workname);
|
200
| 230
|
201 } while (cleanup(), ++argv, 0 < --argc);
| 231 }
|
202 203 tempunlink(); 204 if (!quietflag) 205 Ofclose(stdout); 206 exitmain(exitstatus); 207} 208 209 static void 210cleanup() 211{ 212 if (nerror) exitstatus = EXIT_FAILURE; 213 Izclose(&finptr); 214 Izclose(&workptr); 215 Ozclose(&fcopy);
| 232 233 tempunlink(); 234 if (!quietflag) 235 Ofclose(stdout); 236 exitmain(exitstatus); 237} 238 239 static void 240cleanup() 241{ 242 if (nerror) exitstatus = EXIT_FAILURE; 243 Izclose(&finptr); 244 Izclose(&workptr); 245 Ozclose(&fcopy);
|
216 Ozclose(&frewrite);
| 246 ORCSclose();
|
217 dirtempunlink(); 218} 219
| 247 dirtempunlink(); 248} 249
|
220#if lint 221# define exiterr rcscleanExit
| 250#if RCS_lint 251# define exiterr rcscleanExit
|
222#endif
| 252#endif
|
223 exiting void
| 253 void
|
224exiterr() 225{
| 254exiterr() 255{
|
| 256 ORCSerror();
|
226 dirtempunlink(); 227 tempunlink(); 228 _exit(EXIT_FAILURE); 229} 230 231 static int 232unlock(delta) 233 struct hshentry *delta; 234{
| 257 dirtempunlink(); 258 tempunlink(); 259 _exit(EXIT_FAILURE); 260} 261 262 static int 263unlock(delta) 264 struct hshentry *delta; 265{
|
235 register struct lock **al, *l;
| 266 register struct rcslock **al, *l;
|
236 237 if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0) 238 for (al = &Locks; (l = *al); al = &l->nextlock) 239 if (l->delta == delta) { 240 *al = l->nextlock; 241 delta->lockedby = 0; 242 return true; 243 } 244 return false; 245} 246 247#if has_dirent 248 static int 249get_directory(dirname, aargv) 250 char const *dirname; 251 char ***aargv; 252/* 253 * Put a vector of all DIRNAME's directory entries names into *AARGV. 254 * Ignore names of RCS files. 255 * Yield the number of entries found. Terminate the vector with 0. 256 * Allocate the storage for the vector and entry names. 257 * Do not sort the names. Do not include '.' and '..'. 258 */ 259{ 260 int i, entries = 0, entries_max = 64; 261 size_t chars = 0, chars_max = 1024; 262 size_t *offset = tnalloc(size_t, entries_max); 263 char *a = tnalloc(char, chars_max), **p; 264 DIR *d; 265 struct dirent *e; 266 267 if (!(d = opendir(dirname))) 268 efaterror(dirname); 269 while ((errno = 0, e = readdir(d))) { 270 char const *en = e->d_name; 271 size_t s = strlen(en) + 1;
| 267 268 if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0) 269 for (al = &Locks; (l = *al); al = &l->nextlock) 270 if (l->delta == delta) { 271 *al = l->nextlock; 272 delta->lockedby = 0; 273 return true; 274 } 275 return false; 276} 277 278#if has_dirent 279 static int 280get_directory(dirname, aargv) 281 char const *dirname; 282 char ***aargv; 283/* 284 * Put a vector of all DIRNAME's directory entries names into *AARGV. 285 * Ignore names of RCS files. 286 * Yield the number of entries found. Terminate the vector with 0. 287 * Allocate the storage for the vector and entry names. 288 * Do not sort the names. Do not include '.' and '..'. 289 */ 290{ 291 int i, entries = 0, entries_max = 64; 292 size_t chars = 0, chars_max = 1024; 293 size_t *offset = tnalloc(size_t, entries_max); 294 char *a = tnalloc(char, chars_max), **p; 295 DIR *d; 296 struct dirent *e; 297 298 if (!(d = opendir(dirname))) 299 efaterror(dirname); 300 while ((errno = 0, e = readdir(d))) { 301 char const *en = e->d_name; 302 size_t s = strlen(en) + 1;
|
272 if (en[0]=='.' && (!en[1] || en[1]=='.' && !en[2]))
| 303 if (en[0]=='.' && (!en[1] || (en[1]=='.' && !en[2])))
|
273 continue; 274 if (rcssuffix(en)) 275 continue; 276 while (chars_max < s + chars) 277 a = trealloc(char, a, chars_max<<=1); 278 if (entries == entries_max) 279 offset = trealloc(size_t, offset, entries_max<<=1); 280 offset[entries++] = chars; 281 VOID strcpy(a+chars, en); 282 chars += s; 283 }
| 304 continue; 305 if (rcssuffix(en)) 306 continue; 307 while (chars_max < s + chars) 308 a = trealloc(char, a, chars_max<<=1); 309 if (entries == entries_max) 310 offset = trealloc(size_t, offset, entries_max<<=1); 311 offset[entries++] = chars; 312 VOID strcpy(a+chars, en); 313 chars += s; 314 }
|
284 if (errno || closedir(d) != 0)
| 315# if void_closedir 316# define close_directory(d) (closedir(d), 0) 317# else 318# define close_directory(d) closedir(d) 319# endif 320 if (errno || close_directory(d) != 0)
|
285 efaterror(dirname); 286 if (chars) 287 a = trealloc(char, a, chars); 288 else 289 tfree(a); 290 *aargv = p = tnalloc(char*, entries+1); 291 for (i=0; i<entries; i++) 292 *p++ = a + offset[i]; 293 *p = 0; 294 tfree(offset); 295 return entries; 296} 297#endif
| 321 efaterror(dirname); 322 if (chars) 323 a = trealloc(char, a, chars); 324 else 325 tfree(a); 326 *aargv = p = tnalloc(char*, entries+1); 327 for (i=0; i<entries; i++) 328 *p++ = a + offset[i]; 329 *p = 0; 330 tfree(offset); 331 return entries; 332} 333#endif
|