|
|
1.1 ! root 1: /* ! 2: * RCS file name handling ! 3: */ ! 4: #ifndef lint ! 5: static char ! 6: rcsid[]= "$Id: rcsfnms.c,v 3.10 88/02/18 11:57:27 bostic Exp $ Purdue CS"; ! 7: #endif ! 8: /**************************************************************************** ! 9: * creation and deletion of semaphorefile, ! 10: * creation of temporary filenames and cleanup() ! 11: * pairing of RCS file names and working file names. ! 12: * Testprogram: define PAIRTEST ! 13: **************************************************************************** ! 14: * ! 15: * Copyright (C) 1982 by Walter F. Tichy ! 16: * Purdue University ! 17: * Computer Science Department ! 18: * West Lafayette, IN 47907 ! 19: * ! 20: * All rights reserved. No part of this software may be sold or distributed ! 21: * in any form or by any means without the prior written permission of the ! 22: * author. ! 23: * Report problems and direct all inquiries to Tichy@purdue (ARPA net). ! 24: */ ! 25: ! 26: ! 27: /* $Log: rcsfnms.c,v $ ! 28: * Revision 3.10 88/02/18 11:57:27 bostic ! 29: * replaced with version 4 ! 30: * ! 31: * Revision 4.6 87/12/18 11:40:23 narten ! 32: * additional file types added from 4.3 BSD version, and SPARC assembler ! 33: * comment character added. Also, more lint cleanups. (Guy Harris) ! 34: * ! 35: * Revision 4.5 87/10/18 10:34:16 narten ! 36: * Updating version numbers. Changes relative to 1.1 actually relative ! 37: * to verion 4.3 ! 38: * ! 39: * Revision 1.3 87/03/27 14:22:21 jenkins ! 40: * Port to suns ! 41: * ! 42: * Revision 1.2 85/06/26 07:34:28 svb ! 43: * Comment leader '% ' for '*.tex' files added. ! 44: * ! 45: * Revision 1.1 84/01/23 14:50:24 kcs ! 46: * Initial revision ! 47: * ! 48: * Revision 4.3 83/12/15 12:26:48 wft ! 49: * Added check for KDELIM in file names to pairfilenames(). ! 50: * ! 51: * Revision 4.2 83/12/02 22:47:45 wft ! 52: * Added csh, red, and sl file name suffixes. ! 53: * ! 54: * Revision 4.1 83/05/11 16:23:39 wft ! 55: * Added initialization of Dbranch to InitAdmin(). Canged pairfilenames(): ! 56: * 1. added copying of path from workfile to RCS file, if RCS file is omitted; ! 57: * 2. added getting the file status of RCS and working files; ! 58: * 3. added ignoring of directories. ! 59: * ! 60: * Revision 3.7 83/05/11 15:01:58 wft ! 61: * Added comtable[] which pairs file name suffixes with comment leaders; ! 62: * updated InitAdmin() accordingly. ! 63: * ! 64: * Revision 3.6 83/04/05 14:47:36 wft ! 65: * fixed Suffix in InitAdmin(). ! 66: * ! 67: * Revision 3.5 83/01/17 18:01:04 wft ! 68: * Added getwd() and rename(); these can be removed by defining ! 69: * V4_2BSD, since they are not needed in 4.2 bsd. ! 70: * Changed sys/param.h to sys/types.h. ! 71: * ! 72: * Revision 3.4 82/12/08 21:55:20 wft ! 73: * removed unused variable. ! 74: * ! 75: * Revision 3.3 82/11/28 20:31:37 wft ! 76: * Changed mktempfile() to store the generated file names. ! 77: * Changed getfullRCSname() to store the file and pathname, and to ! 78: * delete leading "../" and "./". ! 79: * ! 80: * Revision 3.2 82/11/12 14:29:40 wft ! 81: * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(), ! 82: * checksuffix(), checkfullpath(). Semaphore name generation updated. ! 83: * mktempfile() now checks for nil path; lastfilename initialized properly. ! 84: * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST. ! 85: * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here. ! 86: * ! 87: * Revision 3.1 82/10/18 14:51:28 wft ! 88: * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h). ! 89: * renamed checkpath() to checkfullpath(). ! 90: */ ! 91: ! 92: ! 93: #include "rcsbase.h" ! 94: #include <sys/types.h> ! 95: #include <sys/stat.h> ! 96: #include <sys/dir.h> ! 97: ! 98: extern char * rindex(); ! 99: extern char * mktemp(); ! 100: extern char * malloc(); ! 101: extern FILE * fopen(); ! 102: extern char * getwd(); /* get working directory; forward decl */ ! 103: extern int stat(), fstat(); ! 104: ! 105: extern FILE * finptr; /* RCS input file descriptor */ ! 106: extern FILE * frewrite; /* New RCS file descriptor */ ! 107: extern char * RCSfilename, * workfilename; /* filenames */ ! 108: struct stat RCSstat, workstat; /* file status for RCS file and working file */ ! 109: int haveRCSstat, haveworkstat; /* indicators if status availalble */ ! 110: ! 111: ! 112: char tempfilename [NCPFN+10]; /* used for derived file names */ ! 113: char sub1filename [NCPPN]; /* used for files path/file.sfx,v */ ! 114: char sub2filename [NCPPN]; /* used for files path/RCS/file.sfx,v */ ! 115: char semafilename [NCPPN]; /* name of semaphore file */ ! 116: int madesema; /* indicates whether a semaphore file has been set */ ! 117: char * tfnames[10] = /* temp. file names to be unlinked when finished */ ! 118: {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}; ! 119: int lastfilename = -1;/* index of last file name in tfnames[] */ ! 120: ! 121: ! 122: struct compair { ! 123: char * suffix, * comlead; ! 124: }; ! 125: ! 126: struct compair comtable[] = { ! 127: /* comtable pairs each filename suffix with a comment leader. The comment */ ! 128: /* leader is placed before each line generated by the $Log keyword. This */ ! 129: /* table is used to guess the proper comment leader from the working file's */ ! 130: /* suffix during initial ci (see InitAdmin()). Comment leaders are needed */ ! 131: /* for languages without multiline comments; for others they are optional. */ ! 132: "c", " * ", /* C */ ! 133: "csh", "# ", /* shell */ ! 134: "e", "# ", /* efl */ ! 135: "f", "c ", /* fortran */ ! 136: "h", " * ", /* C-header */ ! 137: "l", " * ", /* lex NOTE: conflict between lex and franzlisp*/ ! 138: "mac", "; ", /* macro vms or dec-20 or pdp-11 macro */ ! 139: "me", "\\\" ", /* me-macros t/nroff*/ ! 140: "mm", "\\\" ", /* mm-macros t/nroff*/ ! 141: "ms", "\\\" ", /* ms-macros t/nroff*/ ! 142: "p", " * ", /* pascal */ ! 143: "r", "# ", /* ratfor */ ! 144: "red", "% ", /* psl/rlisp */ ! 145: ! 146: #ifdef sparc ! 147: "s", "! ", /* assembler */ ! 148: #endif ! 149: #ifdef mc68000 ! 150: "s", "| ", /* assembler */ ! 151: #endif ! 152: #ifdef pdp11 ! 153: "s", "/ ", /* assembler */ ! 154: #endif ! 155: #ifdef vax ! 156: "s", "# ", /* assembler */ ! 157: #endif ! 158: ! 159: "sh", "# ", /* shell */ ! 160: "sl", "% ", /* psl */ ! 161: "red", "% ", /* psl/rlisp */ ! 162: "cl", ";;; ", /* common lisp */ ! 163: "ml", "; ", /* mocklisp */ ! 164: "el", "; ", /* gnulisp */ ! 165: "tex", "% ", /* tex */ ! 166: "y", " * ", /* yacc */ ! 167: "ye", " * ", /* yacc-efl */ ! 168: "yr", " * ", /* yacc-ratfor */ ! 169: "", "# ", /* default for empty suffix */ ! 170: nil, "" /* default for unknown suffix; must always be last */ ! 171: }; ! 172: ! 173: ! 174: ffclose(fptr) ! 175: FILE * fptr; ! 176: /* Function: checks ferror(fptr) and aborts the program if there were ! 177: * errors; otherwise closes fptr. ! 178: */ ! 179: { if (ferror(fptr) || fclose(fptr)==EOF) ! 180: faterror("File read or write error; file system full?"); ! 181: } ! 182: ! 183: ! 184: ! 185: int trysema(RCSfilename,makesema) ! 186: char * RCSfilename; int makesema; ! 187: /* Function: Checks whether a semaphore file exists for RCSfilename. If yes, ! 188: * returns false. If not, creates one if makesema==true and returns true ! 189: * if successful. If a semaphore file was created, madesema is set to true. ! 190: * The name of the semaphore file is put into variable semafilename. ! 191: */ ! 192: { ! 193: register char * tp, *sp, *lp; ! 194: int fdesc; ! 195: ! 196: sp=RCSfilename; ! 197: lp = rindex(sp,'/'); ! 198: if (lp==0) { ! 199: semafilename[0]='.'; semafilename[1]='/'; ! 200: tp= &semafilename[2]; ! 201: } else { ! 202: /* copy path */ ! 203: tp=semafilename; ! 204: do *tp++ = *sp++; while (sp<=lp); ! 205: } ! 206: /*now insert `,' and append file name */ ! 207: *tp++ = ','; ! 208: lp = rindex(sp, RCSSEP); ! 209: while (sp<lp) *tp++ = *sp++; ! 210: *tp++ = ','; *tp++ = '\0'; /* will be the same length as RCSfilename*/ ! 211: ! 212: madesema = false; ! 213: if (access(semafilename, 0) == 0) { ! 214: error("RCS file %s is in use",RCSfilename); ! 215: return false; ! 216: } ! 217: if (makesema) { ! 218: if ((fdesc=creat(semafilename, 000)) == -1) { ! 219: error("Can't create semaphore file for RCS file %s",RCSfilename); ! 220: return false; ! 221: } else ! 222: VOID close(fdesc); ! 223: madesema=true; ! 224: } ! 225: return true; ! 226: } ! 227: ! 228: ! 229: int rmsema() ! 230: /* Function: delete the semaphore file if madeseam==true; ! 231: * sets madesema to false. ! 232: */ ! 233: { ! 234: if (madesema) { ! 235: madesema=false; ! 236: if (unlink(semafilename) == -1) { ! 237: error("Can't find semaphore file %s",semafilename); ! 238: return false; ! 239: } ! 240: } ! 241: return true; ! 242: } ! 243: ! 244: ! 245: ! 246: InitCleanup() ! 247: { lastfilename = -1; /* initialize pointer */ ! 248: } ! 249: ! 250: ! 251: cleanup() ! 252: /* Function: closes input file and rewrite file. ! 253: * Unlinks files in tfnames[], deletes semaphore file. ! 254: */ ! 255: { ! 256: register int i; ! 257: ! 258: if (finptr!=NULL) VOID fclose(finptr); ! 259: if (frewrite!=NULL) VOID fclose(frewrite); ! 260: for (i=0; i<=lastfilename; i++) { ! 261: if (tfnames[i][0]!='\0') VOID unlink(tfnames[i]); ! 262: } ! 263: InitCleanup(); ! 264: return (rmsema()); ! 265: } ! 266: ! 267: ! 268: char * mktempfile(fullpath,filename) ! 269: register char * fullpath, * filename; ! 270: /* Function: Creates a unique filename using the process id and stores it ! 271: * into a free slot in tfnames. The filename consists of the path contained ! 272: * in fullpath concatenated with filename. filename should end in "XXXXXX". ! 273: * Because of storage in tfnames, cleanup() can unlink the file later. ! 274: * lastfilename indicates the highest occupied slot in tfnames. ! 275: * Returns a pointer to the filename created. ! 276: * Example use: mktempfile("/tmp/", somefilename) ! 277: */ ! 278: { ! 279: register char * lastslash, *tp; ! 280: lastfilename++; ! 281: if ((tp=tfnames[lastfilename])==nil) ! 282: tp=tfnames[lastfilename] = malloc(NCPPN); ! 283: if (fullpath!=nil && (lastslash=rindex(fullpath,'/'))!=0) { ! 284: /* copy path */ ! 285: while (fullpath<=lastslash) *tp++ = *fullpath++; ! 286: } ! 287: while (*tp++ = *filename++); ! 288: return (mktemp(tfnames[lastfilename])); ! 289: } ! 290: ! 291: ! 292: ! 293: ! 294: char * bindex(sp,c) ! 295: register char * sp, c; ! 296: /* Function: Finds the last occurrence of character c in string sp ! 297: * and returns a pointer to the character just beyond it. If the ! 298: * character doesn't occur in the string, sp is returned. ! 299: */ ! 300: { register char * r; ! 301: r = sp; ! 302: while (*sp) { ! 303: if (*sp++ == c) r=sp; ! 304: } ! 305: return r; ! 306: } ! 307: ! 308: ! 309: ! 310: ! 311: ! 312: InitAdmin() ! 313: /* function: initializes an admin node */ ! 314: { register char * Suffix; ! 315: register int i; ! 316: ! 317: Head=Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil; ! 318: StrictLocks=STRICT_LOCKING; ! 319: ! 320: /* guess the comment leader from the suffix*/ ! 321: Suffix=bindex(workfilename, '.'); ! 322: if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/ ! 323: for (i=0;;i++) { ! 324: if (comtable[i].suffix==nil) { ! 325: Comment=comtable[i].comlead; /*default*/ ! 326: break; ! 327: } elsif (strcmp(Suffix,comtable[i].suffix)==0) { ! 328: Comment=comtable[i].comlead; /*default*/ ! 329: break; ! 330: } ! 331: } ! 332: Lexinit(); /* Note: if finptr==NULL, reads nothing; only initializes*/ ! 333: } ! 334: ! 335: ! 336: ! 337: char * findpairfile(argc, argv, fname) ! 338: int argc; char * argv[], *fname; ! 339: /* Function: Given a filename fname, findpairfile scans argv for a pathname ! 340: * ending in fname. If found, returns a pointer to the pathname, and sets ! 341: * the corresponding pointer in argv to nil. Otherwise returns fname. ! 342: * argc indicates the number of entries in argv. Some of them may be nil. ! 343: */ ! 344: { ! 345: register char * * next, * match; ! 346: register int count; ! 347: ! 348: for (next = argv, count = argc; count>0; next++,count--) { ! 349: if ((*next != nil) && strcmp(bindex(*next,'/'),fname)==0) { ! 350: /* bindex finds the beginning of the file name stem */ ! 351: match= *next; ! 352: *next=nil; ! 353: return match; ! 354: } ! 355: } ! 356: return fname; ! 357: } ! 358: ! 359: ! 360: int pairfilenames(argc, argv, mustread, tostdout) ! 361: int argc; char ** argv; int mustread, tostdout; ! 362: /* Function: Pairs the filenames pointed to by argv; argc indicates ! 363: * how many there are. ! 364: * Places a pointer to the RCS filename into RCSfilename, ! 365: * and a pointer to the name of the working file into workfilename. ! 366: * If both the workfilename and the RCS filename are given, and tostdout ! 367: * is true, a warning is printed. ! 368: * ! 369: * If the working file exists, places its status into workstat and ! 370: * sets haveworkstat to 0; otherwise, haveworkstat is set to -1; ! 371: * Similarly for the RCS file and the variables RCSstat and haveRCSstat. ! 372: * ! 373: * If the RCS file exists, it is opened for reading, the file pointer ! 374: * is placed into finptr, and the admin-node is read in; returns 1. ! 375: * If the RCS file does not exist and mustread==true, an error is printed ! 376: * and 0 returned. ! 377: * If the RCS file does not exist and mustread==false, the admin node ! 378: * is initialized to empty (Head, AccessList, Locks, Symbols, StrictLocks, Dbranch) ! 379: * and -1 returned. ! 380: * ! 381: * 0 is returned on all errors. Files that are directories are errors. ! 382: * Also calls InitCleanup(); ! 383: */ ! 384: { ! 385: register char * sp, * tp; ! 386: char * lastsep, * purefname, * pureRCSname; ! 387: int opened, returncode; ! 388: char * RCS1; ! 389: char prefdir[NCPPN]; ! 390: ! 391: if (*argv == nil) return 0; /* already paired filename */ ! 392: if (rindex(*argv,KDELIM)!=0) { ! 393: /* KDELIM causes havoc in keyword expansion */ ! 394: error("RCS file name may not contain %c",KDELIM); ! 395: return 0; ! 396: } ! 397: InitCleanup(); ! 398: ! 399: /* first check suffix to see whether it is an RCS file or not */ ! 400: purefname=bindex(*argv, '/'); /* skip path */ ! 401: lastsep=rindex(purefname, RCSSEP); ! 402: if (lastsep!= 0 && *(lastsep+1)==RCSSUF && *(lastsep+2)=='\0') { ! 403: /* RCS file name given*/ ! 404: RCS1=(*argv); pureRCSname=purefname; ! 405: /* derive workfilename*/ ! 406: sp = purefname; tp=tempfilename; ! 407: while (sp<lastsep) *tp++ = *sp++; *tp='\0'; ! 408: /* try to find workfile name among arguments */ ! 409: workfilename=findpairfile(argc-1,argv+1,tempfilename); ! 410: if (strlen(pureRCSname)>NCPFN) { ! 411: error("RCS file name %s too long",RCS1); ! 412: return 0; ! 413: } ! 414: } else { ! 415: /* working file given; now try to find RCS file */ ! 416: workfilename= *argv; ! 417: /* derive RCS file name*/ ! 418: sp=purefname; tp=tempfilename; ! 419: while (*tp++ = *sp++); ! 420: *(tp-1)=RCSSEP; *tp++=RCSSUF; *tp++='\0'; ! 421: /* Try to find RCS file name among arguments*/ ! 422: RCS1=findpairfile(argc-1,argv+1,tempfilename); ! 423: pureRCSname=bindex(RCS1, '/'); ! 424: if (strlen(pureRCSname)>NCPFN) { ! 425: error("working file name %s too long",workfilename); ! 426: return 0; ! 427: } ! 428: } ! 429: /* now we have a (tentative) RCS filename in RCS1 and workfilename */ ! 430: /* First, get status of workfilename */ ! 431: haveworkstat=stat(workfilename, &workstat); ! 432: if ((haveworkstat==0) && ((workstat.st_mode & S_IFDIR) == S_IFDIR)) { ! 433: diagnose("Directory %s ignored",workfilename); ! 434: return 0; ! 435: } ! 436: /* Second, try to find the right RCS file */ ! 437: if (pureRCSname!=RCS1) { ! 438: /* a path for RCSfile is given; single RCS file to look for */ ! 439: finptr=fopen(RCSfilename=RCS1, "r"); ! 440: if (finptr!=NULL) { ! 441: returncode=1; ! 442: } else { /* could not open */ ! 443: if (access(RCSfilename,0)==0) { ! 444: error("Can't open existing %s", RCSfilename); ! 445: return 0; ! 446: } ! 447: if (mustread) { ! 448: error("Can't find %s", RCSfilename); ! 449: return 0; ! 450: } else { ! 451: /* initialize if not mustread */ ! 452: returncode = -1; ! 453: } ! 454: } ! 455: } else { ! 456: /* no path for RCS file name. Prefix it with path of work */ ! 457: /* file if RCS file omitted. Make a second name including */ ! 458: /* RCSDIR and try to open that one first. */ ! 459: sub1filename[0]=sub2filename[0]= '\0'; ! 460: if (RCS1==tempfilename) { ! 461: /* RCS file name not given; prepend work path */ ! 462: sp= *argv; tp= sub1filename; ! 463: while (sp<purefname) *tp++ = *sp ++; ! 464: *tp='\0'; ! 465: VOID strcpy(sub2filename,sub1filename); /* second one */ ! 466: } ! 467: VOID strcat(sub1filename,RCSDIR); ! 468: VOID strcpy(prefdir,sub1filename); /* preferred directory for RCS file*/ ! 469: VOID strcat(sub1filename,RCS1); VOID strcat(sub2filename,RCS1); ! 470: ! 471: ! 472: opened=( ! 473: ((finptr=fopen(RCSfilename=sub1filename, "r"))!=NULL) || ! 474: ((finptr=fopen(RCSfilename=sub2filename,"r"))!=NULL) ); ! 475: ! 476: if (opened) { ! 477: /* open succeeded */ ! 478: returncode=1; ! 479: } else { ! 480: /* open failed; may be read protected */ ! 481: if ((access(RCSfilename=sub1filename,0)==0) || ! 482: (access(RCSfilename=sub2filename,0)==0)) { ! 483: error("Can't open existing %s",RCSfilename); ! 484: return 0; ! 485: } ! 486: if (mustread) { ! 487: error("Can't find %s nor %s",sub1filename,sub2filename); ! 488: return 0; ! 489: } else { ! 490: /* initialize new file. Put into ./RCS if possible, strip off suffix*/ ! 491: RCSfilename= (access(prefdir,0)==0)?sub1filename:sub2filename; ! 492: returncode= -1; ! 493: } ! 494: } ! 495: } ! 496: ! 497: if (returncode == 1) { /* RCS file open */ ! 498: haveRCSstat=fstat(fileno(finptr),&RCSstat); ! 499: if ((haveRCSstat== 0) && ((RCSstat.st_mode & S_IFDIR) == S_IFDIR)) { ! 500: diagnose("Directory %s ignored",RCSfilename); ! 501: return 0; ! 502: } ! 503: Lexinit(); getadmin(); ! 504: } else { /* returncode == -1; RCS file nonexisting */ ! 505: haveRCSstat = -1; ! 506: InitAdmin(); ! 507: }; ! 508: ! 509: if (tostdout&& ! 510: !(RCS1==tempfilename||workfilename==tempfilename)) ! 511: /*The last term determines whether a pair of */ ! 512: /* file names was given in the argument list */ ! 513: warn("Option -p is set; ignoring output file %s",workfilename); ! 514: ! 515: return returncode; ! 516: } ! 517: ! 518: ! 519: char * getfullRCSname() ! 520: /* Function: returns a pointer to the full path name of the RCS file. ! 521: * Calls getwd(), but only once. ! 522: * removes leading "../" and "./". ! 523: */ ! 524: { static char pathbuf[NCPPN]; ! 525: static char namebuf[NCPPN]; ! 526: static int pathlength =0; ! 527: ! 528: register char * realname, * lastpathchar; ! 529: register int dotdotcounter, realpathlength; ! 530: ! 531: if (*RCSfilename=='/') { ! 532: return(RCSfilename); ! 533: } else { ! 534: if (pathlength==0) { /*call curdir for the first time*/ ! 535: if (getwd(pathbuf)==NULL) ! 536: faterror("Can't build current directory path"); ! 537: pathlength=strlen(pathbuf); ! 538: if (!((pathlength==1) && (pathbuf[0]=='/'))) { ! 539: pathbuf[pathlength++]='/'; ! 540: /* Check needed because some getwd implementations */ ! 541: /* generate "/" for the root. */ ! 542: } ! 543: } ! 544: /*the following must be redone since RCSfilename may change*/ ! 545: /* find how many ../ to remvove from RCSfilename */ ! 546: dotdotcounter =0; ! 547: realname = RCSfilename; ! 548: while( realname[0]=='.' && ! 549: (realname[1]=='/'||(realname[1]=='.'&&realname[2]=='/'))){ ! 550: if (realname[1]=='/') { ! 551: /* drop leading ./ */ ! 552: realname += 2; ! 553: } else { ! 554: /* drop leading ../ and remember */ ! 555: dotdotcounter++; ! 556: realname += 3; ! 557: } ! 558: } ! 559: /* now remove dotdotcounter trailing directories from pathbuf*/ ! 560: lastpathchar=pathbuf + pathlength-1; ! 561: while (dotdotcounter>0 && lastpathchar>pathbuf) { ! 562: /* move pointer backwards over trailing directory */ ! 563: lastpathchar--; ! 564: if (*lastpathchar=='/') { ! 565: dotdotcounter--; ! 566: } ! 567: } ! 568: if (dotdotcounter>0) { ! 569: error("Can't generate full path name for RCS file"); ! 570: return RCSfilename; ! 571: } else { ! 572: /* build full path name */ ! 573: realpathlength=lastpathchar-pathbuf+1; ! 574: VOID strncpy(namebuf,pathbuf,realpathlength); ! 575: VOID strcpy(&namebuf[realpathlength],realname); ! 576: return(namebuf); ! 577: } ! 578: } ! 579: } ! 580: ! 581: ! 582: ! 583: int trydiraccess(filename) ! 584: char * filename; ! 585: /* checks write permission in directory of filename and returns ! 586: * true if writable, false otherwise ! 587: */ ! 588: { ! 589: char pathname[NCPPN]; ! 590: register char * tp, *sp, *lp; ! 591: lp = rindex(filename,'/'); ! 592: if (lp==0) { ! 593: /* check current directory */ ! 594: if (access(".",2)==0) ! 595: return true; ! 596: else { ! 597: error("Current directory not writable"); ! 598: return false; ! 599: } ! 600: } ! 601: /* copy path */ ! 602: sp=filename; ! 603: tp=pathname; ! 604: do *tp++ = *sp++; while (sp<=lp); ! 605: *tp='\0'; ! 606: if (access(pathname,2)==0) ! 607: return true; ! 608: else { ! 609: error("Directory %s not writable", pathname); ! 610: return false; ! 611: } ! 612: } ! 613: ! 614: ! 615: ! 616: #ifndef V4_2BSD ! 617: /* rename() and getwd() will be provided in bsd 4.2 */ ! 618: ! 619: ! 620: int rename(from, to) ! 621: char * from, *to; ! 622: /* Function: renames a file with the name given by from to the name given by to. ! 623: * unlinks the to-file if it already exists. returns -1 on error, 0 otherwise. ! 624: */ ! 625: { VOID unlink(to); /* no need to check return code; will be caught by link*/ ! 626: /* no harm done if file "to" does not exist */ ! 627: if (link(from,to)<0) return -1; ! 628: return(unlink(from)); ! 629: } ! 630: ! 631: ! 632: ! 633: #define dot "." ! 634: #define dotdot ".." ! 635: ! 636: ! 637: ! 638: char * getwd(name) ! 639: char * name; ! 640: /* Function: places full pathname of current working directory into name and ! 641: * returns name on success, NULL on failure. ! 642: * getwd is an adaptation of pwd. May not return to the current directory on ! 643: * failure. ! 644: */ ! 645: { ! 646: FILE *file; ! 647: struct stat d, dd; ! 648: char buf[2]; /* to NUL-terminate dir.d_name */ ! 649: struct direct dir; ! 650: ! 651: int rdev, rino; ! 652: int off; ! 653: register i,j; ! 654: ! 655: name[off= 0] = '/'; ! 656: name[1] = '\0'; ! 657: buf[0] = '\0'; ! 658: stat("/", &d); ! 659: rdev = d.st_dev; ! 660: rino = d.st_ino; ! 661: for (;;) { ! 662: if (stat(dot, &d)<0) return NULL; ! 663: if (d.st_ino==rino && d.st_dev==rdev) { ! 664: if (name[off] == '/') name[off] = '\0'; ! 665: chdir(name); /*change back to current directory*/ ! 666: return name; ! 667: } ! 668: if ((file = fopen(dotdot,"r")) == NULL) return NULL; ! 669: if (fstat(fileno(file), &dd)<0) goto fail; ! 670: chdir(dotdot); ! 671: if(d.st_dev == dd.st_dev) { ! 672: if(d.st_ino == dd.st_ino) { ! 673: if (name[off] == '/') name[off] = '\0'; ! 674: chdir(name); /*change back to current directory*/ ! 675: VOID fclose(file); ! 676: return name; ! 677: } ! 678: do { ! 679: if (fread((char *)&dir, sizeof(dir), 1, file) !=1) ! 680: goto fail; ! 681: } while (dir.d_ino != d.st_ino); ! 682: } ! 683: else do { ! 684: if(fread((char *)&dir, sizeof(dir), 1, file) != 1) { ! 685: goto fail; ! 686: } ! 687: stat(dir.d_name, &dd); ! 688: } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev); ! 689: VOID fclose(file); ! 690: ! 691: /* concatenate file name */ ! 692: i = -1; ! 693: while (dir.d_name[++i] != 0); ! 694: for(j=off+1; j>0; --j) ! 695: name[j+i+1] = name[j]; ! 696: off=i+off+1; ! 697: name[i+1] = '/'; ! 698: for(--i; i>=0; --i) ! 699: name[i+1] = dir.d_name[i]; ! 700: } /* end for */ ! 701: ! 702: fail: VOID fclose(file); ! 703: return NULL; ! 704: } ! 705: ! 706: ! 707: #endif ! 708: ! 709: ! 710: #ifdef PAIRTEST ! 711: /* test program for pairfilenames() and getfullRCSname() */ ! 712: char * workfilename, *RCSfilename; ! 713: extern int quietflag; ! 714: ! 715: main(argc, argv) ! 716: int argc; char *argv[]; ! 717: { ! 718: int result; ! 719: int initflag,tostdout; ! 720: quietflag=tostdout=initflag=false; ! 721: cmdid="pair"; ! 722: ! 723: while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { ! 724: switch ((*argv)[1]) { ! 725: ! 726: case 'p': tostdout=true; ! 727: break; ! 728: case 'i': initflag=true; ! 729: break; ! 730: case 'q': quietflag=true; ! 731: break; ! 732: default: error("unknown option: %s", *argv); ! 733: break; ! 734: } ! 735: } ! 736: ! 737: do { ! 738: RCSfilename=workfilename=nil; ! 739: result=pairfilenames(argc,argv,!initflag,tostdout); ! 740: if (result!=0) { ! 741: diagnose("RCSfile: %s; working file: %s",RCSfilename,workfilename); ! 742: diagnose("Full RCS file name: %s", getfullRCSname()); ! 743: } ! 744: switch (result) { ! 745: case 0: continue; /* already paired file */ ! 746: ! 747: case 1: if (initflag) { ! 748: error("RCS file %s exists already",RCSfilename); ! 749: } else { ! 750: diagnose("RCS file %s exists",RCSfilename); ! 751: } ! 752: VOID fclose(finptr); ! 753: break; ! 754: ! 755: case -1:diagnose("RCS file does not exist"); ! 756: break; ! 757: } ! 758: ! 759: } while (++argv, --argc>=1); ! 760: ! 761: } ! 762: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.