home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / fileutil / mmv / mmv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-05  |  61.7 KB  |  2,937 lines

  1. /*
  2.     mmv 1.01b
  3.     Copyright (c) 1990 Vladimir Lanin.
  4.     This program may be freely used and copied on a non-commercial basis.
  5.     The author assumes no responsibility for any damage or data loss that may
  6.     result from the use of this program.
  7.  
  8.     Author may be reached at:
  9.  
  10.     lanin@csd4.cs.nyu.edu
  11.  
  12.     Vladimir Lanin
  13.     330 Wadsworth Ave, Apt 6F,
  14.     New York, NY 10040
  15.  
  16.     Many thanks to those who have to contributed to the design
  17.     and/or coding of this program:
  18.  
  19.     Tom Albrecht:    initial Sys V adaptation, consultation, and testing
  20.     Carl Mascott:    V7 adaptation
  21.     Mark Lewis:    -n flag idea, consultation.
  22.     Dave Bernhold:    upper/lowercase conversion idea.
  23.     Paul Stodghill:    copy option, argv[0] checking.
  24.     Frank Fiamingo:    consultation and testing.
  25.     Tom Jordahl:    bug reports and testing.
  26.     John Lukas, Hugh Redelmeyer, Barry Nelson, John Sauter,
  27.     Phil Dench, John Nelson:
  28.             bug reports.
  29. */
  30.  
  31. /*
  32.     Define SYSV to compile under System V.
  33.     Define both SYSV and V7 to compile under V7.
  34.     If your System V has a rename() call, define RENAME.
  35.     Otherwise, mmv will only be able to rename directories (via option -r)
  36.     when running as the super-user.
  37.     There is no reason to set the suid bit on mmv if rename() is available.
  38.     It is important that mmv not be run with effective uid set
  39.     to any value other than either the real uid or the super-user.
  40.     Even when running with effective uid set to super-user,
  41.     mmv will only perform actions permitted to the real uid.
  42.  
  43.     Define MSDOS to compile under MS-D*S Turbo C 1.5.
  44.     If you prefer mmv's output to use /'s instead of \'s under MS-D*S,
  45.     define SLASH.
  46.  
  47.     When neither MSDOS nor SYSV are defined, compiles under BSD.
  48.  
  49.     RENAME is automatically defined under MSDOS and BSD.
  50.  
  51.     If you are running a (UN*X) system that provides the
  52.     "struct dirent" readdir() directory reading standard,
  53.     define DIRENT. Otherwise, mmv uses the BSD-like
  54.     "struct direct" readdir().
  55.     If your (UN*X) system has neither of these, get the "dirent"
  56.     by Doug Gwyn, available as gwyn-dir-lib in volume 9
  57.     of the comp.sources.unix archives.
  58. */
  59.  
  60. static char USAGE[] =
  61. #ifdef MSDOS
  62.  
  63. "\nUsage: %s [-m|-x%s|-c|-o|-a|-z] [-h] [-d|-p] [-g|-t] [-v|-n] [-s] [from to]\n"
  64. "\nUse =N in the 'to' pattern to get the string matched"
  65. "\nby the N'th 'from' pattern wildcard.\n";
  66.  
  67. #define OTHEROPT (_osmajor < 3 ? "" : "|-r")
  68.  
  69. #else
  70.  
  71. "Usage: \
  72. %s [-m|x|r|c|o|a|l%s] [-h] [-d|p] [-g|t] [-v|n] [from to]\n\
  73. \n\
  74. Use =[l|u]N in the ``to'' pattern to get the [lowercase|uppercase of the]\n\
  75. string matched by the N'th ``from'' pattern wildcard.\n\
  76. \n\
  77. A ``from'' pattern containing wildcards should be quoted when given\n\
  78. on the command line.\n";
  79.  
  80. #ifdef SYSV
  81. #define OTHEROPT ""
  82. #else
  83. #define OTHEROPT "|s"
  84. #endif
  85.  
  86. #endif
  87.  
  88. #include <stdio.h>
  89. #include <ctype.h>
  90.  
  91. #ifdef MSDOS
  92. /* for MS-DOS (under Turbo C 1.5)*/
  93.  
  94. #include <string.h>
  95. #include <stdlib.h>
  96. #include <sys/types.h>
  97. #include <sys/stat.h>
  98. #include <direct.h>
  99. #include <io.h>
  100. #include <fcntl.h>
  101. #include <signal.h>
  102. #define INCL_NOPM
  103. #include <os2.h>
  104.  
  105. #define ESC '\''
  106. #ifdef SLASH
  107. #define SLASH '/'
  108. #define OTHERSLASH '\\'
  109. #else
  110. #define SLASH '\\'
  111. #define OTHERSLASH '/'
  112. #endif
  113.  
  114. typedef int DIRID;
  115. typedef int DEVID;
  116.  
  117. #define MAXPATH _MAX_PATH
  118. static char TTY[] = "con";
  119.  
  120. #define RENAME
  121.  
  122. #else
  123. /* for various flavors of UN*X */
  124.  
  125. #include <sys/types.h>
  126. #include <sys/stat.h>
  127. #include <sys/file.h>
  128.  
  129. extern char *getenv();
  130. extern long lseek();
  131. extern char *malloc();
  132.  
  133. #ifdef DIRENT
  134. #include <dirent.h>
  135. typedef struct dirent DIRENTRY;
  136. #else
  137. #ifdef SYSV
  138. #include <sys/dir.h>
  139. /* might need to be changed to <dir.h> */
  140. #else
  141. #include <sys/dir.h>
  142. #endif
  143. typedef struct direct DIRENTRY;
  144. #endif
  145.  
  146. #define void char    /* might want to remove this line */
  147.  
  148. #ifndef O_BINARY
  149. #define O_BINARY 0
  150. #endif
  151. #ifndef R_OK
  152. #define R_OK 4
  153. #define W_OK 2
  154. #define X_OK 1
  155. #endif
  156.  
  157. #define ESC '\\'
  158. #define SLASH '/'
  159.  
  160. typedef ino_t DIRID;
  161. typedef dev_t DEVID;
  162.  
  163. #define MAXPATH 1024
  164.  
  165. static char TTY[] = "/dev/tty";
  166.  
  167. #ifdef V7
  168. /* for Version 7 */
  169. #include <errno.h>
  170. extern int errno;
  171. #define strchr index
  172. extern char *strcpy(), *strchr();
  173. #include <signal.h>
  174. #define O_RDONLY 0
  175. #define O_WRONLY 1
  176. #define O_RDWR   2
  177.  
  178. #else
  179. /* for System V and BSD */
  180. #include <string.h>
  181. #include <sys/signal.h>
  182. #include <fcntl.h>
  183. #endif
  184.  
  185. #ifdef SYSV
  186. /* for System V and Version 7*/
  187. struct utimbuf {
  188.     time_t actime;
  189.     time_t modtime;
  190. };
  191. #define utimes(f, t) utime((f), &(t))
  192.  
  193. #else
  194. /* for BSD */
  195. #define RENAME
  196. #include <sys/time.h>
  197.  
  198. #endif
  199. #endif
  200.  
  201. #define mylower(c) (isupper(c) ? (c)-'A'+'a' : (c))
  202. #define myupper(c) (islower(c) ? (c)-'a'+'A' : (c))
  203. #define STRLEN(s) (sizeof(s) - 1)
  204. #define mydup(s) (strcpy((char *)challoc(strlen(s) + 1, 0), (s)))
  205.  
  206.  
  207. #define DFLT 0x001
  208. #define NORMCOPY 0x002
  209. #define OVERWRITE 0x004
  210. #define NORMMOVE 0x008
  211. #define XMOVE 0x010
  212. #define DIRMOVE 0x020
  213. #define NORMAPPEND 0x040
  214. #define ZAPPEND 0x080
  215. #define HARDLINK 0x100
  216. #define SYMLINK 0x200
  217.  
  218. #define COPY (NORMCOPY | OVERWRITE)
  219. #define MOVE (NORMMOVE | XMOVE | DIRMOVE)
  220. #define APPEND (NORMAPPEND | ZAPPEND)
  221. #define LINK (HARDLINK | SYMLINK)
  222.  
  223. static char MOVENAME[] = "mmv";
  224. static char COPYNAME[] = "mcp";
  225. static char APPENDNAME[] = "mad";
  226. static char LINKNAME[] = "mln";
  227.  
  228. #define ASKDEL 0
  229. #define ALLDEL 1
  230. #define NODEL 2
  231.  
  232. #define ASKBAD 0
  233. #define SKIPBAD 1
  234. #define ABORTBAD 2
  235.  
  236. #define STAY 0
  237. #define LOWER 1
  238. #define UPPER 2
  239.  
  240. #define MAXWILD 20
  241. #define MAXPATLEN MAXPATH
  242. #define INITROOM 10
  243. #define CHUNKSIZE 2048
  244. #define BUFSIZE 4096
  245.  
  246. #define FI_STTAKEN 0x01
  247. #define FI_LINKERR 0x02
  248. #define FI_INSTICKY 0x04
  249. #define FI_NODEL 0x08
  250. #define FI_KNOWWRITE 0x010
  251. #define FI_CANWRITE 0x20
  252. #define FI_ISDIR 0x40
  253. #define FI_ISLNK 0x80
  254.  
  255. typedef struct {
  256.     char *fi_name;
  257.     struct rep *fi_rep;
  258. #ifdef MSDOS
  259.     char fi_attrib;
  260. #else
  261.     short fi_mode;
  262.     char fi_stflags;
  263. #endif
  264. } FILEINFO;
  265.  
  266. #define DI_KNOWWRITE 0x01
  267. #define DI_CANWRITE 0x02
  268. #define DI_CLEANED 0x04
  269.  
  270. typedef struct {
  271.     DEVID di_vid;
  272.     DIRID di_did;
  273.     unsigned di_nfils;
  274.     FILEINFO **di_fils;
  275.     char di_flags;
  276. } DIRINFO;
  277.  
  278. #define H_NODIR 1
  279. #define H_NOREADDIR 2
  280.  
  281. typedef struct {
  282.     char *h_name;
  283.     DIRINFO *h_di;
  284.     char h_err;
  285. } HANDLE;
  286.  
  287. #define R_ISX 0x01
  288. #define R_SKIP 0x02
  289. #define R_DELOK 0x04
  290. #define R_ISALIASED 0x08
  291. #define R_ISCYCLE 0x10
  292. #define R_ONEDIRLINK 0x20
  293.  
  294. typedef struct rep {
  295.     HANDLE *r_hfrom;
  296.     FILEINFO *r_ffrom;
  297.     HANDLE *r_hto;
  298.     char *r_nto;            /* non-path part of new name */
  299.     FILEINFO *r_fdel;
  300.     struct rep *r_first;
  301.     struct rep *r_thendo;
  302.     struct rep *r_next;
  303.     char r_flags;
  304. } REP;
  305.  
  306. typedef struct {
  307.     REP *rd_p;
  308.     DIRINFO *rd_dto;
  309.     char *rd_nto;
  310.     unsigned rd_i;
  311. } REPDICT;
  312.  
  313. typedef struct chunk {
  314.     struct chunk *ch_next;
  315.     unsigned ch_len;
  316. } CHUNK;
  317.  
  318. typedef struct {
  319.     CHUNK *sl_first;
  320.     char *sl_unused;
  321.     int sl_len;
  322. } SLICER;
  323.  
  324.  
  325. static void init(/* */);
  326. static void procargs(/* int argc, char **argv,
  327.     char **pfrompat, char **ptopat */);
  328. static void domatch(/* char *cfrom, char *cto */);
  329. static int getpat(/* */);
  330. static int getword(/* char *buf */);
  331. static void matchpat(/*  */);
  332. static int parsepat(/*  */);
  333. static int dostage(/* char *lastend, char *pathend,
  334.     char **start1, int *len1, int stage, int anylev */);
  335. static int trymatch(/* FILEINFO *ffrom, char *pat */);
  336. static int keepmatch(/* FILEINFO *ffrom, char *pathend,
  337.     int *pk, int needslash, int dirs, int fils */);
  338. static int badrep(/* HANDLE *hfrom, FILEINFO *ffrom,
  339.     HANDLE **phto, char **pnto, FILEINFO **pfdel, int *pflags */);
  340. static int checkto(/* HANDLE *hfrom, char *f,
  341.     HANDLE **phto, char **pnto, FILEINFO **pfdel */);
  342. static char *getpath(/* char *tpath */);
  343. static int badname(/* char *s */);
  344. static FILEINFO *fsearch(/* char *s, DIRINFO *d */);
  345. static int ffirst(/* char *s, int n, DIRINFO *d */);
  346. static HANDLE *checkdir(/* char *p, char *pathend, int which */);
  347. static void takedir(/*
  348.     char *p, DIRINFO *di, int sticky
  349. or
  350.     struct ffblk *pff, DIRINFO *di
  351. */);
  352. static int fcmp(/* FILEINFO **pf1, FILEINFO **pf2 */);
  353. static HANDLE *hadd(/* char *n */);
  354. static int hsearch(/* char *n, int which, HANDLE **ph */);
  355. static DIRINFO *dadd(/* DEVID v, DIRID d */);
  356. static DIRINFO *dsearch(/* DEVID v, DIRID d */);
  357. static int match(/* char *pat, char *s, char **start1, int *len1 */);
  358. static void makerep(/*  */);
  359. static void checkcollisions(/*  */);
  360. static int rdcmp(/* REPDICT *rd1, REPDICT *rd2 */);
  361. static void findorder(/*  */);
  362. static void scandeletes(/* int (*pkilldel)(REP *p) */);
  363. static int baddel(/* REP *p */);
  364. static int skipdel(/* REP *p */);
  365. static void nochains(/*  */);
  366. static void printchain(/* REP *p */);
  367. static void goonordie(/*  */);
  368. static void doreps(/*  */);
  369. static long appendalias(/* REP *first, REP *p, int *pprintaliased */);
  370. static int movealias(/* REP *first, REP *p, int *pprintaliased */);
  371. static int snap(/* REP *first, REP *p */);
  372. static void showdone(/* REP *fin */);
  373. static void breakout(/*  */);
  374. static int breakrep(/* */);
  375. static void breakstat(/* */);
  376. static void quit(/*  */);
  377. static int copymove(/* REP *p */);
  378. static int copy(/* FILENFO *f, long len */);
  379. static int myunlink(/* char *n, FILEINFO *f */);
  380. static int getreply(/* char *m, int failact */);
  381. static void *myalloc(/* unsigned k */);
  382. static void *challoc(/* int k, int which */);
  383. static void chgive(/* void *p, unsigned k */);
  384. static int mygetc(/* */);
  385. static char *mygets(/* char *s, int l */);
  386. #ifdef MSDOS
  387. static int leave(/*  */);
  388. static void cleanup(/*  */);
  389. #else
  390. static int getstat(/* char *full, FILEINFO *f */);
  391. static int dwritable(/* HANDLE *h */);
  392. static int fwritable(/* char *hname, FILEINFO *f */);
  393. static void memmove(/* void *to, void *from, int k */);
  394. #endif
  395. #ifndef RENAME
  396. static int rename(/* char *from, char *to */);
  397. #endif
  398.  
  399. static int op, badstyle, delstyle, verbose, noex, matchall;
  400. static int patflags;
  401.  
  402. static unsigned ndirs = 0, dirroom;
  403. static DIRINFO **dirs;
  404. static unsigned nhandles = 0, handleroom;
  405. static HANDLE **handles;
  406. static HANDLE badhandle = {"\200", NULL, 0};
  407. static HANDLE *(lasthandle[2]) = {&badhandle, &badhandle};
  408. static unsigned nreps = 0;
  409. static REP hrep, *lastrep = &hrep;
  410. static CHUNK *freechunks = NULL;
  411. static SLICER slicer[2] = {{NULL, NULL, 0}, {NULL, NULL, 0}};
  412.  
  413. static int badreps = 0, paterr = 0, direrr, failed = 0, gotsig = 0, repbad;
  414. static FILE *outfile = stdout;
  415.  
  416. static char IDF[] = "$$mmvdid.";
  417. static char TEMP[] = "$$mmvtmp.";
  418. static char TOOLONG[] = "(too long)";
  419. static char EMPTY[] = "(empty)";
  420.  
  421. static char SLASHSTR[] = {SLASH, '\0'};
  422.  
  423. static char PATLONG[] = "%.40s... : pattern too long.\n";
  424.  
  425. char from[MAXPATLEN], to[MAXPATLEN];
  426. static int fromlen, tolen;
  427. static char *(stagel[MAXWILD]), *(firstwild[MAXWILD]), *(stager[MAXWILD]);
  428. static int nwilds[MAXWILD];
  429. static int nstages;
  430. char pathbuf[MAXPATH];
  431. char fullrep[MAXPATH + 1];
  432. static char *(start[MAXWILD]);
  433. static int len[MAXWILD];
  434. static char hasdot[MAXWILD];
  435. static REP mistake;
  436. #define MISTAKE (&mistake)
  437.  
  438. #ifdef MSDOS
  439.  
  440. static int olddevflag, curdisk, maxdisk;
  441. static struct {
  442.     char ph_banner[30];
  443.     char ph_name[9];
  444.     int ph_dfltop;
  445.     int ph_safeid;
  446.     int ph_clustoff;
  447.     int ph_driveoff;
  448.     int ph_drivea;
  449. } patch = {"mmv 1.0 patchable flags", "MMV", XMOVE, 1, 0};
  450.  
  451. #define DFLTOP (patch.ph_dfltop)
  452. #define CLUSTNO(pff) (*(int *)(((char *)(pff)) + patch.ph_clustoff))
  453. #define DRIVENO(pff) (*(((char *)(pff)) + patch.ph_driveoff) - patch.ph_drivea)
  454.  
  455.  
  456. #else
  457.  
  458. #define DFLTOP XMOVE
  459.  
  460. static char *home;
  461. static int homelen;
  462. static int uid, euid, oldumask;
  463. static DIRID cwdd = -1;
  464. static DEVID cwdv = -1;
  465.  
  466. #endif
  467.  
  468.  
  469. static char *cmdname;
  470. #define CMDNAME cmdname
  471. static int dostdin = 0;
  472.  
  473.  
  474. int main(argc, argv)
  475.     int argc;
  476.     char *(argv[]);
  477. {
  478.     char *frompat, *topat;
  479.  
  480.     init();
  481.     procargs(argc, argv, &frompat, &topat);
  482.     domatch(frompat, topat);
  483.     if (!(op & APPEND))
  484.         checkcollisions();
  485.     findorder();
  486.     if (op & (COPY | LINK))
  487.         nochains();
  488.     scandeletes(baddel);
  489.     goonordie();
  490.     if (!(op & APPEND) && delstyle == ASKDEL)
  491.         scandeletes(skipdel);
  492.     doreps();
  493.     return(failed ? 2 : nreps == 0 && (paterr || badreps));
  494. }
  495.  
  496.  
  497. static void init()
  498. {
  499. #ifdef MSDOS
  500.         ULONG drivemap;
  501.  
  502.         DosQCurDisk((PUSHORT) &curdisk, &drivemap);
  503.         for ( maxdisk = 0; drivemap; maxdisk++, drivemap >>= 1);
  504.  
  505.         atexit(cleanup);
  506.         signal(SIGINT, breakout);
  507. #else
  508.     struct stat dstat;
  509.  
  510.     if ((home = getenv("HOME")) == NULL || strcmp(home, SLASHSTR) == 0)
  511.         home = "";
  512.     if (!stat(".", &dstat)) {
  513.         cwdd = dstat.st_ino;
  514.         cwdv = dstat.st_dev;
  515.     }
  516.     oldumask = umask(0);
  517.     euid = geteuid();
  518.     uid = getuid();
  519.     signal(SIGINT, breakout);
  520. #endif
  521.  
  522.     dirroom = handleroom = INITROOM;
  523.     dirs = (DIRINFO **)myalloc(dirroom * sizeof(DIRINFO *));
  524.     handles = (HANDLE **)myalloc(handleroom * sizeof(HANDLE *));
  525.     ndirs = nhandles = 0;
  526. }
  527.  
  528.  
  529. static void usage()
  530. {
  531.         printf(USAGE, CMDNAME, OTHEROPT);
  532.  
  533.         printf(
  534. "\n  -m -x -r -c -o -a         (default -x)"
  535. "\n         move / move-crossdev / rename / copy / overwrite / append mode"
  536. "\n  -z     append mode with special care to ^Z (end-of-file character)\n"
  537.  
  538. "\n  -h     match . and .. and hidden or system files\n"
  539.  
  540. "\n  -d     overwrite silently existing target files"
  541. "\n  -p     do not overwrite any existing files\n"
  542.         );
  543.  
  544.         printf(
  545. "\n  -g     continue on errors with other actions"
  546. "\n  -t     abort when the first error is encountered\n"
  547.  
  548. "\n  -v     be verbose while working"
  549. "\n  -n     do not execute actions, only show them on stdout\n"
  550.  
  551. "\n  -s     read pattern pairs from stdin (not needed when redirected)\n"
  552.         );
  553.  
  554.         exit(1);
  555. }
  556.  
  557.  
  558. static void procargs(argc, argv, pfrompat, ptopat)
  559.     int argc;
  560.     char **argv;
  561.     char **pfrompat, **ptopat;
  562. {
  563.         char *p, c;
  564.  
  565.         cmdname = argv[0];
  566.  
  567. #ifdef MSDOS
  568.         if ( (p = strrchr(cmdname, '\\')) != NULL )
  569.           cmdname = p + 1;
  570.         if ( (p = strchr(cmdname, '.')) != NULL )
  571.           *p = 0;
  572.         strlwr(cmdname);
  573. #endif
  574.  
  575.     op = DFLT;
  576.     verbose = noex = matchall = 0;
  577.     delstyle = ASKDEL;
  578.     badstyle = ASKBAD;
  579.     for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++)
  580.         for (p = *argv + 1; *p != '\0'; p++) {
  581.             c = mylower(*p);
  582.             if (c == 'v' && !noex)
  583.                 verbose = 1;
  584.             else if (c == 'n' && !verbose)
  585.                 noex = 1;
  586.                         else if (c == 's')
  587.                                 dostdin = 1;
  588.             else if (c == 'h')
  589.                 matchall = 1;
  590.             else if (c == 'd' && delstyle == ASKDEL)
  591.                 delstyle = ALLDEL;
  592.             else if (c == 'p' && delstyle == ASKDEL)
  593.                 delstyle = NODEL;
  594.             else if (c == 'g' && badstyle == ASKBAD)
  595.                 badstyle = SKIPBAD;
  596.             else if (c == 't' && badstyle == ASKBAD)
  597.                 badstyle = ABORTBAD;
  598.             else if (c == 'm' && op == DFLT)
  599.                 op = NORMMOVE;
  600.             else if (c == 'x' && op == DFLT)
  601.                 op = XMOVE;
  602.             else if (c == 'r' && op == DFLT)
  603.                 op = DIRMOVE;
  604.             else if (c == 'c' && op == DFLT)
  605.                 op = NORMCOPY;
  606.             else if (c == 'o' && op == DFLT)
  607.                 op = OVERWRITE;
  608.             else if (c == 'a' && op == DFLT)
  609.                 op = NORMAPPEND;
  610. #ifdef MSDOS
  611.             else if (c == 'z' && op == DFLT)
  612.                 op = ZAPPEND;
  613. #else
  614.             else if (c == 'l' && op == DFLT)
  615.                 op = HARDLINK;
  616. #ifndef SYSV
  617.             else if (c == 's' && op == DFLT)
  618.                 op = SYMLINK;
  619. #endif
  620. #endif
  621.                         else
  622.                                 usage();
  623.         }
  624.  
  625.     if (op == DFLT)
  626.                 if (strcmp(cmdname, MOVENAME) == 0)
  627.             op = XMOVE;
  628.                 else if (strcmp(cmdname, COPYNAME) == 0)
  629.             op = NORMCOPY;
  630.                 else if (strcmp(cmdname, APPENDNAME) == 0)
  631.             op = NORMAPPEND;
  632.                 else if (strcmp(cmdname, LINKNAME) == 0)
  633.             op = HARDLINK;
  634.         else
  635.             op = DFLTOP;
  636.     if (
  637.         op & DIRMOVE &&
  638. #ifdef MSDOS
  639.         _osmajor < 3
  640. #else
  641. #ifndef RENAME
  642.         euid != 0
  643. #else
  644.         0
  645. #endif
  646. #endif
  647.     ) {
  648.         fprintf(stderr,
  649.             "Unable to do directory renames. Option -r refused.\n");
  650.         quit();
  651.     }
  652.  
  653. #ifndef MSDOS
  654.     if (euid != uid && !(op & DIRMOVE)) {
  655.         setuid(uid);
  656.         setgid(getgid());
  657.     }
  658. #endif
  659.  
  660.     if (badstyle != ASKBAD && delstyle == ASKDEL)
  661.         delstyle = NODEL;
  662.  
  663.     if (argc == 0)
  664.         *pfrompat = NULL;
  665.     else if (argc == 2) {
  666.         *pfrompat = *(argv++);
  667.         *ptopat = *(argv++);
  668.     }
  669.         else
  670.                 usage();
  671. }
  672.  
  673.  
  674. static void domatch(cfrom, cto)
  675.     char *cfrom, *cto;
  676. {
  677.         if (cfrom == NULL)
  678.         {
  679.                 if ( dostdin || !isatty(fileno(stdin)) )
  680.                         while (getpat())
  681.                             matchpat();
  682.                 else
  683.                         usage();
  684.         }
  685.     else if ((fromlen = strlen(cfrom)) >= MAXPATLEN) {
  686.         printf(PATLONG, cfrom);
  687.         paterr = 1;
  688.     }
  689.     else if ((tolen = strlen(cto)) >= MAXPATLEN) {
  690.         printf(PATLONG, cto);
  691.         paterr = 1;
  692.     }
  693.     else {
  694.         strcpy(from, cfrom);
  695.         strcpy(to, cto);
  696.         matchpat();
  697.     }
  698. }
  699.  
  700.  
  701. static int getpat()
  702. {
  703.     int c, gotit = 0;
  704.     char extra[MAXPATLEN];
  705.  
  706.     patflags = 0;
  707.     do {
  708.         if ((fromlen = getword(from)) == 0 || fromlen == -1)
  709.             goto nextline;
  710.  
  711.         do {
  712.             if ((tolen = getword(to)) == 0) {
  713.                 printf("%s -> ? : missing replacement pattern.\n", from);
  714.                 goto nextline;
  715.             }
  716.             if (tolen == -1)
  717.                 goto nextline;
  718.         } while (
  719.             tolen == 2 &&
  720.             (to[0] == '-' || to[0] == '=') &&
  721.             (to[1] == '>' || to[1] == '^')
  722.         );
  723.         if (getword(extra) == 0)
  724.             gotit = 1;
  725.         else if (strcmp(extra, "(*)") == 0) {
  726.             patflags |= R_DELOK;
  727.             gotit = (getword(extra) == 0);
  728.         }
  729.  
  730. nextline:
  731.         while ((c = mygetc()) != '\n' && c != EOF)
  732.             ;
  733.         if (c == EOF)
  734.             return(0);
  735.     } while (!gotit);
  736.  
  737.     return(1);
  738. }
  739.  
  740.  
  741. static int getword(buf)
  742.     char *buf;
  743. {
  744.     int c, prevc, n;
  745.     char *p;
  746.  
  747.     p = buf;
  748.     prevc = ' ';
  749.     n = 0;
  750.     while ((c = mygetc()) != EOF && (prevc == ESC || !isspace(c))) {
  751.         if (n == -1)
  752.             continue;
  753.         if (n == MAXPATLEN - 1) {
  754.             *p = '\0';
  755.             printf(PATLONG, buf);
  756.             n = -1;
  757.         }
  758.                 *(p++) = (char) c;
  759.         n++;
  760.         prevc = c;
  761.     }
  762.     *p = '\0';
  763.     while (c != EOF && isspace(c) && c != '\n')
  764.         c = mygetc();
  765.     if (c != EOF)
  766.         ungetc(c, stdin);
  767.     return(n);
  768. }
  769.  
  770.  
  771. static void matchpat()
  772. {
  773.     if (parsepat())
  774.         paterr = 1;
  775.     else if (dostage(from, pathbuf, start, len, 0, 0)) {
  776.         printf("%s -> %s : no match.\n", from, to);
  777.         paterr = 1;
  778.     }
  779. }
  780.  
  781.  
  782. static int parsepat()
  783. {
  784.     char *p, *lastname, c;
  785.     int totwilds, instage, x, havedot;
  786.     static char TRAILESC[] = "%s -> %s : trailing %c is superfluous.\n";
  787.  
  788.     lastname = from;
  789. #ifdef MSDOS
  790.     havedot = 0;
  791.     if (from[0] != '\0' && from[1] == ':')
  792.         lastname += 2;
  793. #else
  794.     if (from[0] == '~' && from[1] == SLASH) {
  795.         if ((homelen = strlen(home)) + fromlen > MAXPATLEN) {
  796.             printf(PATLONG, from);
  797.             return(-1);
  798.         }
  799.         memmove(from + homelen, from + 1, fromlen);
  800.         memmove(from, home, homelen);
  801.         lastname += homelen + 1;
  802.     }
  803. #endif
  804.     totwilds = nstages = instage = 0;
  805.     for (p = lastname; (c = *p) != '\0'; p++)
  806.         switch (c) {
  807. #ifdef MSDOS
  808.         case '.':
  809.             havedot = 1;
  810.             break;
  811.         case OTHERSLASH:
  812.             *p = SLASH;
  813. #endif
  814.          case SLASH:
  815. #ifdef MSDOS
  816.             if (!havedot && lastname != p) {
  817.                 if (fromlen++ == MAXPATLEN) {
  818.                     printf(PATLONG, from);
  819.                     return(-1);
  820.                 }
  821.                 memmove(p + 1, p, strlen(p) + 1);
  822.                 *(p++) = '.';
  823.             }
  824.             else
  825.                 havedot = 0;
  826. #endif
  827.             lastname = p + 1;
  828.             if (instage) {
  829.                 if (firstwild[nstages] == NULL)
  830.                     firstwild[nstages] = p;
  831.                 stager[nstages++] = p;
  832.                 instage = 0;
  833.             }
  834.             break;
  835.         case ';':
  836.             if (lastname != p) {
  837.                 printf("%s -> %s : badly placed ;.\n", from, to);
  838.                 return(-1);
  839.             }
  840.         case '!':
  841.         case '*':
  842.         case '?':
  843.         case '[':
  844. #ifdef MSDOS
  845.                         if ((hasdot[totwilds] = (char) (c == '!')) != 0)
  846.                 havedot = 1;
  847. #endif
  848.             if (totwilds++ == MAXWILD) {
  849.                 printf("%s -> %s : too many wildcards.\n", from, to);
  850.                 return(-1);
  851.             }
  852.             if (instage) {
  853.                 nwilds[nstages]++;
  854.                 if (firstwild[nstages] == NULL)
  855.                     firstwild[nstages] = p;
  856.             }
  857.             else {
  858.                 stagel[nstages] = lastname;
  859.                 firstwild[nstages] = (c == ';' ? NULL : p);
  860.                 nwilds[nstages] = 1;
  861.                 instage = 1;
  862.             }
  863.             if (c != '[')
  864.                 break;
  865.             while ((c = *(++p)) != ']') {
  866.                 switch (c) {
  867.                 case '\0':
  868.                     printf("%s -> %s : missing ].\n", from, to);
  869.                     return(-1);
  870. #ifdef MSDOS
  871.                 case '.':
  872.                 case ':':
  873.                 case OTHERSLASH:
  874. #endif
  875.                 case SLASH:
  876.                     printf("%s -> %s : '%c' can not be part of [].\n",
  877.                         from, to, c);
  878.                     return(-1);
  879.                 case ESC:
  880.                     if ((c = *(++p)) == '\0') {
  881.                         printf(TRAILESC, from, to, ESC);
  882.                         return(-1);
  883.                     }
  884. #ifdef MSDOS
  885.                 default:
  886.                     if (isupper(c))
  887.                         *p = c + ('a' - 'A');
  888. #endif
  889.                 }
  890.             }
  891.             break;
  892.         case ESC:
  893.             if ((c = *(++p)) == '\0') {
  894.                 printf(TRAILESC, from, to, ESC);
  895.                 return(-1);
  896.             }
  897. #ifdef MSDOS
  898.         default:
  899.             if (isupper(c))
  900.                 *p = c + ('a' - 'A');
  901. #endif
  902.         }
  903.  
  904. #ifdef MSDOS
  905.     if (!havedot && lastname != p) {
  906.         if (fromlen++ == MAXPATLEN) {
  907.             printf(PATLONG, from);
  908.             return(-1);
  909.         }
  910.         strcpy(p++, ".");
  911.     }
  912. #endif
  913.  
  914.     if (instage) {
  915.         if (firstwild[nstages] == NULL)
  916.             firstwild[nstages] = p;
  917.         stager[nstages++] = p;
  918.     }
  919.     else {
  920.         stagel[nstages] = lastname;
  921.         nwilds[nstages] = 0;
  922.         firstwild[nstages] = p;
  923.         stager[nstages++] = p;
  924.     }
  925.  
  926.     lastname = to;
  927. #ifdef MSDOS
  928.     havedot = 0;
  929.     if (to[0] != '\0' && to[1] == ':')
  930.         lastname += 2;
  931. #else
  932.     if (to[0] == '~' && to[1] == SLASH) {
  933.         if ((homelen = strlen(home)) + tolen > MAXPATLEN) {
  934.             printf(PATLONG, to);
  935.                 return(-1);
  936.         }
  937.         memmove(to + homelen, to + 1, tolen);
  938.         memmove(to, home, homelen);
  939.         lastname += homelen + 1;
  940.     }
  941. #endif
  942.  
  943.     for (p = lastname; (c = *p) != '\0'; p++)
  944.         switch (c) {
  945. #ifdef MSDOS
  946.         case '.':
  947.             havedot = 1;
  948.             break;
  949.         case OTHERSLASH:
  950.             *p = SLASH;
  951. #endif
  952.         case SLASH:
  953.             if (op & DIRMOVE) {
  954.                 printf("%s -> %s : no path allowed in target under -r.\n",
  955.                     from, to);
  956.                 return(-1);
  957.             }
  958. #ifdef MSDOS
  959.             if (!havedot && lastname != p) {
  960.                 if (tolen++ == MAXPATLEN) {
  961.                     printf(PATLONG, to);
  962.                     return(-1);
  963.                 }
  964.                 memmove(p + 1, p, strlen(p) + 1);
  965.                 *(p++) = '.';
  966.             }
  967.             else
  968.                 havedot = 0;
  969. #endif
  970.             lastname = p + 1;
  971.             break;
  972.         case '=':
  973.             c = *(++p);
  974.             if (c == 'l' || c == 'u') {
  975. #ifdef MSDOS
  976.                 strcpy(p, p + 1);
  977.                 c = *p;
  978. #else
  979.                 c = *(++p);
  980. #endif
  981.             }
  982.             if (!isdigit(c)) {
  983.                 printf("%s -> %s : expected digit (not '%c') after =.\n",
  984.                     from, to, c);
  985.                 return(-1);
  986.             }
  987.             for(x = 0; ;x *= 10) {
  988.                 x += c - '0';
  989.                 c = *(p+1);
  990.                 if (!isdigit(c))
  991.                     break;
  992.                 p++;
  993.             }
  994.             if (x < 1 || x > totwilds) {
  995.                 printf("%s -> %s : wildcard %d does not exist.\n",
  996.                     from, to, x);
  997.                 return(-1);
  998.             }
  999. #ifdef MSDOS
  1000.             if (hasdot[x - 1])
  1001.                 havedot = 1;
  1002. #endif
  1003.             break;
  1004.         case ESC:
  1005.             if ((c = *(++p)) == '\0') {
  1006.                 printf(TRAILESC, from, to, ESC);
  1007.                 return(-1);
  1008.             }
  1009.         default:
  1010.             if (
  1011. #ifdef MSDOS
  1012.                 c <= ' ' || c >= 127 ||
  1013.                 strchr(":/\\*?[]=+;,\"|<>", c) != NULL
  1014. #else
  1015.                 c & 0x80
  1016. #endif
  1017.             ) {
  1018.                 printf("%s -> %s : illegal character '%c' (0x%02X).\n",
  1019.                     from, to, c, c);
  1020.                 return(-1);
  1021.             }
  1022. #ifdef MSDOS
  1023.             if (isupper(c))
  1024.                 *p = c + ('a' - 'A');
  1025. #endif
  1026.         }
  1027.  
  1028. #ifdef MSDOS
  1029.     if (!havedot && lastname != p) {
  1030.         if (tolen++ == MAXPATLEN) {
  1031.             printf(PATLONG, to);
  1032.             return(-1);
  1033.         }
  1034.         strcpy(p++, ".");
  1035.     }
  1036. #endif
  1037.  
  1038.     return(0);
  1039. }
  1040.  
  1041.  
  1042. static int dostage(lastend, pathend, start1, len1, stage, anylev)
  1043.     char *lastend, *pathend;
  1044.     char **start1;
  1045.     int *len1;
  1046.     int stage;
  1047.     int anylev;
  1048. {
  1049.     DIRINFO *di;
  1050.     HANDLE *h, *hto;
  1051.     int prelen, litlen, nfils, i, k, flags, try;
  1052.     FILEINFO **pf, *fdel;
  1053.     char *nto, *firstesc;
  1054.     REP *p;
  1055.     int wantdirs, ret = 1, laststage = (stage + 1 == nstages);
  1056.  
  1057.     wantdirs = !laststage ||
  1058.         (op & (DIRMOVE | SYMLINK)) ||
  1059.         (nwilds[nstages - 1] == 0);
  1060.  
  1061.     if (!anylev) {
  1062.         prelen = stagel[stage] - lastend;
  1063.         if (pathend - pathbuf + prelen >= MAXPATH) {
  1064.             printf("%s -> %s : search path after %s too long.\n",
  1065.                 from, to, pathbuf);
  1066.             paterr = 1;
  1067.             return(1);
  1068.         }
  1069.         memmove(pathend, lastend, prelen);
  1070.         pathend += prelen;
  1071.         *pathend = '\0';
  1072.         lastend = stagel[stage];
  1073.     }
  1074.  
  1075.     if ((h = checkdir(pathbuf, pathend, 0)) == NULL) {
  1076.         if (stage == 0 || direrr == H_NOREADDIR) {
  1077.             printf("%s -> %s : directory %s does not %s.\n",
  1078.                 from, to, pathbuf, direrr == H_NOREADDIR ?
  1079.                 "allow reads/searches" : "exist");
  1080.             paterr = 1;
  1081.         }
  1082.         return(stage);
  1083.     }
  1084.     di = h->h_di;
  1085.  
  1086.     if (*lastend == ';') {
  1087.         anylev = 1;
  1088.         *start1 = pathend;
  1089.         *len1 = 0;
  1090.         lastend++;
  1091.     }
  1092.  
  1093.     nfils = di->di_nfils;
  1094.  
  1095. #ifndef MSDOS
  1096.     if ((op & MOVE) && !dwritable(h)) {
  1097.         printf("%s -> %s : directory %s does not allow writes.\n",
  1098.             from, to, pathbuf);
  1099.         paterr = 1;
  1100.         goto skiplev;
  1101.     }
  1102. #endif
  1103.  
  1104.     firstesc = strchr(lastend, ESC);
  1105.     if (firstesc == NULL || firstesc > firstwild[stage])
  1106.         firstesc = firstwild[stage];
  1107.     litlen = firstesc - lastend;
  1108.     pf = di->di_fils + (i = ffirst(lastend, litlen, di));
  1109.     if (i < nfils)
  1110.     do {
  1111.         if (
  1112.             (try = trymatch(*pf, lastend)) != 0 &&
  1113.             (
  1114.                 try == 1 ||
  1115.                 match(lastend + litlen, (*pf)->fi_name + litlen,
  1116.                     start1 + anylev, len1 + anylev)
  1117.             ) &&
  1118.             keepmatch(*pf, pathend, &k, 0, wantdirs, laststage)
  1119.         ) {
  1120.             if (!laststage)
  1121.                 ret &= dostage(stager[stage], pathend + k,
  1122.                     start1 + nwilds[stage], len1 + nwilds[stage],
  1123.                     stage + 1, 0);
  1124.             else {
  1125.                 ret = 0;
  1126.                 makerep();
  1127.                 if (badrep(h, *pf, &hto, &nto, &fdel, &flags))
  1128.                     (*pf)->fi_rep = MISTAKE;
  1129.                 else {
  1130.                     (*pf)->fi_rep = p = (REP *)challoc(sizeof(REP), 1);
  1131.                                         p->r_flags = (char) flags | patflags;
  1132.                     p->r_hfrom = h;
  1133.                     p->r_ffrom = *pf;
  1134.                     p->r_hto = hto;
  1135.                     p->r_nto = nto;
  1136.                     p->r_fdel = fdel;
  1137.                     p->r_first = p;
  1138.                     p->r_thendo = NULL;
  1139.                     p->r_next = NULL;
  1140.                     lastrep->r_next = p;
  1141.                     lastrep = p;
  1142.                     nreps++;
  1143.                 }
  1144.             }
  1145.         }
  1146.         i++, pf++;
  1147.     } while (i < nfils && strncmp(lastend, (*pf)->fi_name, litlen) == 0);
  1148.  
  1149. skiplev:
  1150.     if (anylev)
  1151.         for (pf = di->di_fils, i = 0; i < nfils; i++, pf++)
  1152.             if (
  1153.                 *((*pf)->fi_name) != '.' &&
  1154. #ifdef MSDOS
  1155.                                 ((*pf)->fi_attrib & FILE_DIRECTORY) &&
  1156. #endif
  1157.                 keepmatch(*pf, pathend, &k, 1, 1, 0)
  1158.             ) {
  1159.                 *len1 = pathend - *start1 + k;
  1160.                 ret &= dostage(lastend, pathend + k, start1, len1, stage, 1);
  1161.             }
  1162.  
  1163.     return(ret);
  1164. }
  1165.  
  1166.  
  1167. static int trymatch(ffrom, pat)
  1168.     FILEINFO *ffrom;
  1169.     char *pat;
  1170. {
  1171.     char *p;
  1172.  
  1173.     if (ffrom->fi_rep != NULL)
  1174.         return(0);
  1175.  
  1176.     p = ffrom->fi_name;
  1177.  
  1178. #ifdef MSDOS
  1179.         if (*p == '.' || (!matchall && ffrom->fi_attrib & (FILE_HIDDEN | FILE_SYSTEM)))
  1180.         return(strcmp(pat, p) == 0);
  1181. #else
  1182.     if (*p == '.')
  1183.         if (p[1] == '\0' || (p[1] == '.' && p[2] == '\0'))
  1184.             return(strcmp(pat, p) == 0);
  1185.         else if (!matchall && *pat != '.')
  1186.             return(0);
  1187. #endif
  1188.     return(-1);
  1189. }
  1190.  
  1191.  
  1192. static int keepmatch(ffrom, pathend, pk, needslash, dirs, fils)
  1193.     FILEINFO *ffrom;
  1194.     char *pathend;
  1195.     int *pk;
  1196.     int needslash;
  1197.     int dirs, fils;
  1198. {
  1199.     *pk = strlen(ffrom->fi_name);
  1200.     if (pathend - pathbuf + *pk + needslash >= MAXPATH) {
  1201.         *pathend = '\0';
  1202.         printf("%s -> %s : search path %s%s too long.\n",
  1203.             from, to, pathbuf, ffrom->fi_name);
  1204.         paterr = 1;
  1205.         return(0);
  1206.     }
  1207.     strcpy(pathend, ffrom->fi_name);
  1208. #ifdef MSDOS
  1209.         if ((ffrom->fi_attrib & FILE_DIRECTORY) ? !dirs : !fils)
  1210. #else
  1211.     getstat(pathbuf, ffrom);
  1212.     if ((ffrom->fi_stflags & FI_ISDIR) ? !dirs : !fils)
  1213. #endif
  1214.         return(0);
  1215.  
  1216.     if (needslash) {
  1217.         strcpy(pathend + *pk, SLASHSTR);
  1218.         (*pk)++;
  1219.     }
  1220.     return(1);
  1221. }
  1222.  
  1223.  
  1224. static int badrep(hfrom, ffrom, phto, pnto, pfdel, pflags)
  1225.     HANDLE *hfrom;
  1226.     FILEINFO *ffrom;
  1227.     HANDLE **phto;
  1228.     char **pnto;
  1229.     FILEINFO **pfdel;
  1230.     int *pflags;
  1231. {
  1232.     char *f = ffrom->fi_name;
  1233.  
  1234.     *pflags = 0;
  1235.     if (
  1236. #ifdef MSDOS
  1237.                 (ffrom->fi_attrib & FILE_DIRECTORY) &&
  1238. #else
  1239.         (ffrom->fi_stflags & FI_ISDIR) &&
  1240. #endif
  1241.         !(op & (DIRMOVE | SYMLINK))
  1242.     )
  1243.         printf("%s -> %s : source file is a directory.\n", pathbuf, fullrep);
  1244. #ifndef MSDOS
  1245. #ifndef SYSV
  1246.     else if ((ffrom->fi_stflags & FI_LINKERR) && !(op & (MOVE | SYMLINK)))
  1247.         printf("%s -> %s : source file is a badly aimed symbolic link.\n",
  1248.             pathbuf, fullrep);
  1249.     else if ((ffrom->fi_stflags & FI_NODEL) && (op & MOVE))
  1250.         printf("%s -> %s : no delete permission for source file.\n",
  1251.             pathbuf, fullrep);
  1252. #endif
  1253.     else if ((op & (COPY | APPEND)) && access(pathbuf, R_OK))
  1254.         printf("%s -> %s : no read permission for source file.\n",
  1255.             pathbuf, fullrep);
  1256. #endif
  1257.     else if (
  1258.         *f == '.' &&
  1259.         (f[1] == '\0' || strcmp(f, "..") == 0) &&
  1260.         !(op & SYMLINK)
  1261.     )
  1262.         printf("%s -> %s : . and .. can't be renamed.\n", pathbuf, fullrep);
  1263.     else if (repbad || checkto(hfrom, f, phto, pnto, pfdel) || badname(*pnto))
  1264.         printf("%s -> %s : bad new name.\n", pathbuf, fullrep);
  1265.     else if (*phto == NULL)
  1266.         printf("%s -> %s : %s.\n", pathbuf, fullrep,
  1267. #ifndef MSDOS
  1268.             direrr == H_NOREADDIR ?
  1269.             "no read or search permission for target directory" :
  1270. #endif
  1271.             "target directory does not exist");
  1272. #ifndef MSDOS
  1273.     else if (!dwritable(*phto))
  1274.         printf("%s -> %s : no write permission for target directory.\n",
  1275.             pathbuf, fullrep);
  1276. #endif
  1277.     else if (
  1278.         (*phto)->h_di->di_vid != hfrom->h_di->di_vid &&
  1279.         (*pflags = R_ISX, (op & (NORMMOVE | HARDLINK)))
  1280.     )
  1281.         printf("%s -> %s : cross-device move.\n",
  1282.             pathbuf, fullrep);
  1283. #ifndef MSDOS
  1284.     else if (
  1285.         *pflags && (op & MOVE) &&
  1286.         !(ffrom->fi_stflags & FI_ISLNK) &&
  1287.         access(pathbuf, R_OK)
  1288.     )
  1289.         printf("%s -> %s : no read permission for source file.\n",
  1290.             pathbuf, fullrep);
  1291. #ifndef SYSV
  1292.     else if (
  1293.         (op & SYMLINK) &&
  1294.         !(
  1295.             ((*phto)->h_di->di_vid == cwdv && (*phto)->h_di->di_did == cwdd) ||
  1296.             *(hfrom->h_name) == SLASH ||
  1297.             (*pflags |= R_ONEDIRLINK, hfrom->h_di == (*phto)->h_di)
  1298.         )
  1299.     )
  1300.         printf("%s -> %s : symbolic link would be badly aimed.\n",
  1301.             pathbuf, fullrep);
  1302. #endif
  1303. #endif
  1304.     else
  1305.         return(0);
  1306.     badreps++;
  1307.     return(-1);
  1308. }
  1309.  
  1310.  
  1311. static int checkto(hfrom, f, phto, pnto, pfdel)
  1312.     HANDLE *hfrom;
  1313.     char *f;
  1314.     HANDLE **phto;
  1315.     char **pnto;
  1316.     FILEINFO **pfdel;
  1317. {
  1318.     char tpath[MAXPATH + 1];
  1319.     char *pathend;
  1320.     FILEINFO *fdel;
  1321.     int hlen, tlen;
  1322.  
  1323.     if (op & DIRMOVE) {
  1324.         *phto = hfrom;
  1325.         hlen = strlen(hfrom->h_name);
  1326.         pathend = fullrep + hlen;
  1327.         memmove(pathend, fullrep, strlen(fullrep) + 1);
  1328.         memmove(fullrep, hfrom->h_name, hlen);
  1329.         if ((fdel = *pfdel = fsearch(pathend, hfrom->h_di)) != NULL) {
  1330.             *pnto = fdel->fi_name;
  1331. #ifndef MSDOS
  1332.             getstat(fullrep, fdel);
  1333. #endif
  1334.         }
  1335.         else
  1336.             *pnto = mydup(pathend);
  1337.     }
  1338.     else {
  1339.         pathend = getpath(tpath);
  1340.         hlen = pathend - fullrep;
  1341.         *phto = checkdir(tpath, tpath + hlen, 1);
  1342.         if (
  1343.             *phto != NULL &&
  1344.             *pathend != '\0' &&
  1345.             (fdel = *pfdel = fsearch(pathend, (*phto)->h_di)) != NULL &&
  1346. #ifdef MSDOS
  1347.                         (fdel->fi_attrib & FILE_DIRECTORY)
  1348. #else
  1349.             (getstat(fullrep, fdel), fdel->fi_stflags & FI_ISDIR)
  1350. #endif
  1351.         ) {
  1352.             tlen = strlen(pathend);
  1353.             strcpy(pathend + tlen, SLASHSTR);
  1354.             tlen++;
  1355.             strcpy(tpath + hlen, pathend);
  1356.             pathend += tlen;
  1357.             hlen += tlen;
  1358.             *phto = checkdir(tpath, tpath + hlen, 1);
  1359.         }
  1360.  
  1361.         if (*pathend == '\0') {
  1362.             *pnto = f;
  1363.             if (pathend - fullrep + strlen(f) >= MAXPATH) {
  1364.                 strcpy(fullrep, TOOLONG);
  1365.                 return(-1);
  1366.             }
  1367.             strcat(pathend, f);
  1368.             if (*phto != NULL) {
  1369.                 fdel = *pfdel = fsearch(f, (*phto)->h_di);
  1370. #ifndef MSDOS
  1371.                 if (fdel != NULL)
  1372.                     getstat(fullrep, fdel);
  1373. #endif
  1374.             }
  1375.         }
  1376.         else if (fdel != NULL)
  1377.             *pnto = fdel->fi_name;
  1378.         else
  1379.             *pnto = mydup(pathend);
  1380.     }
  1381.     return(0);
  1382. }
  1383.  
  1384.  
  1385. static char *getpath(tpath)
  1386.     char *tpath;
  1387. {
  1388.     char *pathstart, *pathend, c;
  1389.  
  1390. #ifdef MSDOS
  1391.     if (*fullrep != '\0' && fullrep[1] == ':')
  1392.         pathstart = fullrep + 2;
  1393.     else
  1394. #endif
  1395.         pathstart = fullrep;
  1396.  
  1397.     pathend = pathstart + strlen(pathstart) - 1;
  1398.     while (pathend >= pathstart && *pathend != SLASH)
  1399.         --pathend;
  1400.     pathend++;
  1401.  
  1402.     c = *pathend;
  1403.     *pathend = '\0';
  1404.     strcpy(tpath, fullrep);
  1405.     *pathend = c;
  1406.     return(pathend);
  1407. }
  1408.  
  1409.  
  1410. static int badname(s)
  1411.     char *s;
  1412. {
  1413.     char *ext;
  1414.  
  1415.     return (
  1416. #ifdef MSDOS
  1417.         *s == ' ' ||
  1418.         *s == '.' ||
  1419.                 (ext = strchr(s, '.')) - s >= _MAX_FNAME ||
  1420.         (*ext == '.' && strchr(ext + 1, '.') != NULL) ||
  1421.                 strlen(ext) >= _MAX_EXT ||
  1422.         strncmp(s, IDF, STRLEN(IDF)) == 0
  1423. #else
  1424.         (*s == '.' && (s[1] == '\0' || strcmp(s, "..") == 0)) ||
  1425.         strlen(s) > MAXNAMLEN
  1426. #endif
  1427.     );
  1428. }
  1429.  
  1430.  
  1431. #ifndef MSDOS
  1432. static int getstat(ffull, f)
  1433.     char *ffull;
  1434.     FILEINFO *f;
  1435. {
  1436.     struct stat fstat;
  1437.     int flags;
  1438.  
  1439.     if ((flags = f->fi_stflags) & FI_STTAKEN)
  1440.         return(flags & FI_LINKERR);
  1441.     flags |= FI_STTAKEN;
  1442. #ifdef SYSV
  1443.     if (stat(ffull, &fstat)) {
  1444.         fprintf(stderr, "Strange, couldn't stat %s.\n", ffull);
  1445.         quit();
  1446.     }
  1447. #else
  1448.     if (lstat(ffull, &fstat)) {
  1449.         fprintf(stderr, "Strange, couldn't lstat %s.\n", ffull);
  1450.         quit();
  1451.     }
  1452.     if ((flags & FI_INSTICKY) && fstat.st_uid != uid && uid != 0)
  1453.         flags |= FI_NODEL;
  1454.     if ((fstat.st_mode & S_IFMT) == S_IFLNK) {
  1455.         flags |= FI_ISLNK;
  1456.         if (stat(ffull, &fstat)) {
  1457.             f->fi_stflags = flags | FI_LINKERR;
  1458.             return(1);
  1459.         }
  1460.     }
  1461. #endif
  1462.     if ((fstat.st_mode & S_IFMT) == S_IFDIR)
  1463.         flags |= FI_ISDIR;
  1464.     f->fi_stflags = flags;
  1465.     f->fi_mode = fstat.st_mode;
  1466.     return(0);
  1467. }
  1468.  
  1469.  
  1470. static int dwritable(h)
  1471.     HANDLE *h;
  1472. {
  1473.     char *p = h->h_name, *myp, *lastslash = NULL, *pathend;
  1474.     char *pw = &(h->h_di->di_flags), r;
  1475.  
  1476.     if (uid == 0)
  1477.         return(1);
  1478.  
  1479.     if (*pw & DI_KNOWWRITE)
  1480.         return(*pw & DI_CANWRITE);
  1481.  
  1482.     pathend = p + strlen(p);
  1483.     if (*p == '\0')
  1484.         myp = ".";
  1485.     else if (pathend == p + 1)
  1486.         myp = SLASHSTR;
  1487.     else {
  1488.         lastslash = pathend - 1;
  1489.         *lastslash = '\0';
  1490.         myp = p;
  1491.     }
  1492.     r = !access(myp, W_OK) ? DI_CANWRITE : 0;
  1493.     *pw |= DI_KNOWWRITE | r;
  1494.  
  1495.     if (lastslash != NULL)
  1496.         *lastslash = SLASH;
  1497.     return(r);
  1498. }
  1499.  
  1500.  
  1501. static int fwritable(hname, f)
  1502.     char *hname;
  1503.     FILEINFO *f;
  1504. {
  1505.     int r;
  1506.  
  1507.     if (f->fi_stflags & FI_KNOWWRITE)
  1508.         return(f->fi_stflags & FI_CANWRITE);
  1509.  
  1510.     strcpy(fullrep, hname);
  1511.     strcat(fullrep, f->fi_name);
  1512.     r = !access(fullrep, W_OK) ? FI_CANWRITE : 0;
  1513.     f->fi_stflags |= FI_KNOWWRITE | r;
  1514.     return(r);
  1515. }
  1516. #endif
  1517.  
  1518.  
  1519. static FILEINFO *fsearch(s, d)
  1520.     char *s;
  1521.     DIRINFO *d;
  1522. {
  1523.     FILEINFO **fils = d->di_fils;
  1524.     int nfils = d->di_nfils;
  1525.     int first, k, last, res;
  1526.  
  1527.     for(first = 0, last = nfils - 1;;) {
  1528.         if (last < first)
  1529.             return(NULL);
  1530.         k = (first + last) >> 1;
  1531.         if ((res = strcmp(s, fils[k]->fi_name)) == 0)
  1532.             return(fils[k]);
  1533.         if (res < 0)
  1534.             last = k - 1;
  1535.         else
  1536.             first = k + 1;
  1537.     }
  1538. }
  1539.  
  1540.  
  1541. static int ffirst(s, n, d)
  1542.     char *s;
  1543.     int n;
  1544.     DIRINFO *d;
  1545. {
  1546.     int first, k, last, res;
  1547.     FILEINFO **fils = d->di_fils;
  1548.     int nfils = d->di_nfils;
  1549.  
  1550.     if (nfils == 0 || n == 0)
  1551.         return(0);
  1552.     first = 0;
  1553.     last = nfils - 1;
  1554.     for(;;) {
  1555.         k = (first + last) >> 1;
  1556.         res = strncmp(s, fils[k]->fi_name, n);
  1557.         if (first == last)
  1558.             return(res == 0 ? k : nfils);
  1559.         else if (res > 0)
  1560.             first = k + 1;
  1561.         else
  1562.             last = k;
  1563.     }
  1564. }
  1565.  
  1566.  
  1567. #ifdef MSDOS
  1568. /* checkdir and takedir for MS-D*S */
  1569.  
  1570. HDIR hdir;
  1571. USHORT count;
  1572.  
  1573. static HANDLE *checkdir(p, pathend, which)
  1574.     char *p, *pathend;
  1575.     int which;
  1576. {
  1577.         FILEFINDBUF de;
  1578.     DIRID d;
  1579.     DEVID v;
  1580.     HANDLE *h;
  1581.     char *dirstart = p;
  1582.     int fd;
  1583.     int firstfound;
  1584.     DIRINFO *di;
  1585.  
  1586.     if (hsearch(p, which, &h))
  1587.         if (h->h_di == NULL) {
  1588.             direrr = h->h_err;
  1589.             return(NULL);
  1590.         }
  1591.         else
  1592.             return(h);
  1593.  
  1594.     if (*p == '\0' || p[1] != ':')
  1595.         v = curdisk;
  1596.     else {
  1597.         dirstart += 2;
  1598.         v = mylower(p[0]) - 'a';
  1599.         if (v < 0 || v >= maxdisk)
  1600.             return(NULL);
  1601.     }
  1602.  
  1603.     if (patch.ph_safeid) {
  1604.         strcpy(pathend, IDF);
  1605.         strcpy(pathend + STRLEN(IDF), "*");
  1606.                 hdir = count = 1;
  1607.                 if (DosFindFirst(p, &hdir, 0, &de, sizeof(de), &count, 0L)) {
  1608.             if ((d = ndirs) == 1000) {
  1609.                 fprintf(stderr, "Too many different directories.\n");
  1610.                 quit();
  1611.             }
  1612.             sprintf(pathend + STRLEN(IDF), "%03d", d);
  1613.                         if ((fd = creat(p, S_IREAD | S_IWRITE)) < 0) {
  1614.                 direrr = h->h_err = H_NODIR;
  1615.                 return(NULL);
  1616.             }
  1617.                         close(fd);
  1618.             strcpy(pathend, "*.*");
  1619.                         hdir = count = 1;
  1620.                         if (DosFindFirst(p, &hdir, FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN, &de, sizeof(de), &count, 0L))
  1621.                 h->h_di = dadd(v, d);
  1622.             else
  1623.                 takedir(&de, h->h_di = dadd(v, d));
  1624.         }
  1625.                 else if ((d = atoi(de.achName + STRLEN(IDF))) < ndirs)
  1626.             h->h_di = dirs[d];
  1627.         else {
  1628.                         strcpy(pathend, de.achName);
  1629.             fprintf(stderr, "Strange dir-id file encountered: %s.\n", p);
  1630.             quit();
  1631.         }
  1632.         *pathend = '\0';
  1633.     }
  1634.     else {
  1635.         strcpy(pathend, "*.*");
  1636.                 hdir = count = 1;
  1637.                 firstfound = !DosFindFirst(p, &hdir, FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN, &de, sizeof(de), &count, 0L);
  1638.         *pathend = '\0';
  1639.         if (firstfound) {
  1640.             v = DRIVENO(&de);
  1641.             d = CLUSTNO(&de);
  1642.         }
  1643.         else {
  1644.             strcpy(pathend, "T.D");
  1645.             if (mkdir(p)) {
  1646.                 *pathend = '\0';
  1647.                 direrr = h->h_err = H_NODIR;
  1648.                 return(NULL);
  1649.             }
  1650.             strcpy(pathend, "*.*");
  1651.                         hdir = count = 1;
  1652.                         firstfound = !DosFindFirst(p, &hdir, FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN, &de, sizeof(de), &count, 0L);
  1653.             *pathend = '\0';
  1654.             v = DRIVENO(&de);
  1655.             d = CLUSTNO(&de);
  1656.             rmdir(p);
  1657.             if (!firstfound || d != 0) {
  1658.                 fprintf(stderr,
  1659.                     "Strange, %s does not seem to be a root dir.\n",
  1660.                     p);
  1661.                 quit();
  1662.             }
  1663.         }
  1664.  
  1665.         if ((di = dsearch(v, d)) == NULL)
  1666.             if (firstfound)
  1667.                 takedir(&de, h->h_di = dadd(v, d));
  1668.             else
  1669.                 h->h_di = dadd(v, d);
  1670.         else
  1671.             h->h_di = di;
  1672.     }
  1673.  
  1674.     return(h);
  1675. }
  1676.  
  1677.  
  1678. static void takedir(pff, di)
  1679.         FILEFINDBUF *pff;
  1680.     DIRINFO *di;
  1681. {
  1682.     int cnt, room, namlen, needdot;
  1683.     FILEINFO **fils, *f;
  1684.     char c, *p, *p1;
  1685.  
  1686.     room = INITROOM;
  1687.     di->di_fils = fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1688.     cnt = 0;
  1689.     do {
  1690.                 if (strnicmp(pff->achName, IDF, STRLEN(IDF)) == 0)
  1691.             continue;
  1692.         if (cnt == room) {
  1693.             room *= 2;
  1694.             fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1695.             memcpy(fils, di->di_fils, cnt * sizeof(FILEINFO *));
  1696.             chgive(di->di_fils, cnt * sizeof(FILEINFO *));
  1697.             di->di_fils = fils;
  1698.             fils = di->di_fils + cnt;
  1699.         }
  1700.         needdot = 1;
  1701.                 for (p = pff->achName, namlen = 0; (c = *p) != '\0'; p++, namlen++)
  1702.             if (c == '.')
  1703.                 needdot = 0;
  1704.         *fils = f = (FILEINFO *)challoc(sizeof(FILEINFO), 1);
  1705.         f->fi_name = p = (char *)challoc(namlen + needdot + 1, 0);
  1706.                 for (p1 = pff->achName; (c = *p1) != '\0'; p1++)
  1707.             *(p++) = mylower(c);
  1708.         if (needdot)
  1709.             *(p++) = '.';
  1710.         *p = '\0';
  1711.                 f->fi_attrib = (char) pff->attrFile;
  1712.         f->fi_rep = NULL;
  1713.         cnt++;
  1714.         fils++;
  1715.         } while (DosFindNext(hdir, pff, sizeof(*pff), &count) == 0);
  1716.     qsort(di->di_fils, cnt, sizeof(FILEINFO *), fcmp);
  1717.     di->di_nfils = cnt;
  1718. }
  1719.  
  1720. #else
  1721. /* checkdir, takedir for Un*x */
  1722.  
  1723. static HANDLE *checkdir(p, pathend, which)
  1724.     char *p, *pathend;
  1725.     int which;
  1726. {
  1727.     struct stat dstat;
  1728.     DIRID d;
  1729.     DEVID v;
  1730.     DIRINFO **newdirs, *di;
  1731.     int nfils;
  1732.     FILEINFO **fils;
  1733.     char *myp, *lastslash = NULL;
  1734.     int sticky;
  1735.     HANDLE *h;
  1736.  
  1737.     if (hsearch(p, which, &h))
  1738.         if (h->h_di == NULL) {
  1739.             direrr = h->h_err;
  1740.             return(NULL);
  1741.         }
  1742.         else
  1743.             return(h);
  1744.  
  1745.     if (*p == '\0')
  1746.         myp = ".";
  1747.     else if (pathend == p + 1)
  1748.         myp = SLASHSTR;
  1749.     else {
  1750.         lastslash = pathend - 1;
  1751.         *lastslash = '\0';
  1752.         myp = p;
  1753.     }
  1754.  
  1755.     if (stat(myp, &dstat) || (dstat.st_mode & S_IFMT) != S_IFDIR)
  1756.         direrr = h->h_err = H_NODIR;
  1757.     else if (access(myp, R_OK | X_OK))
  1758.         direrr = h->h_err = H_NOREADDIR;
  1759.     else {
  1760.         direrr = 0;
  1761.         sticky = (dstat.st_mode & S_ISVTX) && uid != 0 && uid != dstat.st_uid ?
  1762.             FI_INSTICKY : 0;
  1763.         v = dstat.st_dev;
  1764.         d = dstat.st_ino;
  1765.  
  1766.         if ((di = dsearch(v, d)) == NULL)
  1767.             takedir(myp, di = dadd(v, d), sticky);
  1768.     }
  1769.  
  1770.     if (lastslash != NULL)
  1771.         *lastslash = SLASH;
  1772.     if (direrr != 0)
  1773.         return(NULL);
  1774.     h->h_di = di;
  1775.     return(h);
  1776. }
  1777.  
  1778.  
  1779. static void takedir(p, di, sticky)
  1780.     char *p;
  1781.     DIRINFO *di;
  1782.     int sticky;
  1783. {
  1784.     int cnt, room;
  1785.     DIRENTRY *dp;
  1786.     FILEINFO *f, **fils;
  1787.     DIR *dirp;
  1788.  
  1789.     if ((dirp = opendir(p)) == NULL) {
  1790.         fprintf(stderr, "Strange, can't scan %s.\n", p);
  1791.         quit();
  1792.     }
  1793.     room = INITROOM;
  1794.     di->di_fils = fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1795.     cnt = 0;
  1796.     while ((dp = readdir(dirp)) != NULL) {
  1797.         if (cnt == room) {
  1798.             room *= 2;
  1799.             fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1800.             memcpy(fils, di->di_fils, cnt * sizeof(FILEINFO *));
  1801.             chgive(di->di_fils, cnt * sizeof(FILEINFO *));
  1802.             di->di_fils = fils;
  1803.             fils = di->di_fils + cnt;
  1804.         }
  1805.         *fils = f = (FILEINFO *)challoc(sizeof(FILEINFO), 1);
  1806.         f->fi_name = mydup(dp->d_name);
  1807.         f->fi_stflags = sticky;
  1808.         f->fi_rep = NULL;
  1809.         cnt++;
  1810.         fils++;
  1811.     }
  1812.     closedir(dirp);
  1813.     qsort(di->di_fils, cnt, sizeof(FILEINFO *), fcmp);
  1814.     di->di_nfils = cnt;
  1815. }
  1816.  
  1817. /* end of Un*x checkdir, takedir; back to general program */
  1818. #endif
  1819.  
  1820.  
  1821. static int fcmp(pf1, pf2)
  1822.     FILEINFO **pf1, **pf2;
  1823. {
  1824.         return(strcmp((*pf1)->fi_name, (*pf2)->fi_name));
  1825. }
  1826.  
  1827.  
  1828. static HANDLE *hadd(n)
  1829.     char *n;
  1830. {
  1831.     HANDLE **newhandles, *h;
  1832.  
  1833.     if (nhandles == handleroom) {
  1834.         handleroom *= 2;
  1835.         newhandles = (HANDLE **)myalloc(handleroom * sizeof(HANDLE *));
  1836.         memcpy(newhandles, handles, nhandles * sizeof(HANDLE *));
  1837.         chgive(handles, nhandles * sizeof(HANDLE *));
  1838.         handles = newhandles;
  1839.     }
  1840.     handles[nhandles++] = h = (HANDLE *)challoc(sizeof(HANDLE), 1);
  1841.     h->h_name = (char *)challoc(strlen(n) + 1, 0);
  1842.     strcpy(h->h_name, n);
  1843.     h->h_di = NULL;
  1844.     return(h);
  1845. }
  1846.  
  1847.  
  1848. static int hsearch(n, which, pret)
  1849.     char *n;
  1850.     int which;
  1851.     HANDLE **pret;
  1852. {
  1853.     int i;
  1854.     HANDLE **ph;
  1855.  
  1856.     if (strcmp(n, lasthandle[which]->h_name) == 0) {
  1857.         *pret = lasthandle[which];
  1858.         return(1);
  1859.     }
  1860.  
  1861.     for(i = 0, ph = handles; i < nhandles; i++, ph++)
  1862.         if (strcmp(n, (*ph)->h_name) == 0) {
  1863.             lasthandle[which] = *pret = *ph;
  1864.             return(1);
  1865.         }
  1866.  
  1867.     lasthandle[which] = *pret = hadd(n);
  1868.     return(0);
  1869. }
  1870.  
  1871.  
  1872. static DIRINFO *dadd(v, d)
  1873.     DEVID v;
  1874.     DIRID d;
  1875. {
  1876.     DIRINFO *di;
  1877.     DIRINFO **newdirs;
  1878.  
  1879.     if (ndirs == dirroom) {
  1880.         dirroom *= 2;
  1881.         newdirs = (DIRINFO **)myalloc(dirroom * sizeof(DIRINFO *));
  1882.         memcpy(newdirs, dirs, ndirs * sizeof(DIRINFO *));
  1883.         chgive(dirs, ndirs * sizeof(DIRINFO *));
  1884.         dirs = newdirs;
  1885.     }
  1886.     dirs[ndirs++] = di = (DIRINFO *)challoc(sizeof(DIRINFO), 1);
  1887.     di->di_vid = v;
  1888.     di->di_did = d;
  1889.     di->di_nfils = 0;
  1890.     di->di_fils = NULL;
  1891.     di->di_flags = 0;
  1892.     return(di);
  1893. }
  1894.  
  1895.  
  1896. static DIRINFO *dsearch(v, d)
  1897.     DEVID v;
  1898.     DIRID d;
  1899. {
  1900.     int i;
  1901.     DIRINFO *di;
  1902.  
  1903.     for(i = 0, di = *dirs; i < ndirs; i++, di++)
  1904.         if (v == di->di_vid && d == di->di_did)
  1905.             return(di);
  1906.     return(NULL);
  1907. }
  1908.  
  1909.  
  1910. static int match(pat, s, start1, len1)
  1911.     char *pat, *s, **start1;
  1912.     int *len1;
  1913. {
  1914.     char c, *olds;
  1915.  
  1916.     *start1 = 0;
  1917.     for(;;)
  1918.         switch (c = *pat) {
  1919.         case '\0':
  1920.         case SLASH:
  1921.             return(*s == '\0');
  1922. #ifdef MSDOS
  1923.         case '!':
  1924.             *start1 = olds = s;
  1925.             if ((s = strchr(s, '.')) == NULL)
  1926.                 return(0);
  1927.             s++;
  1928.             *len1 = s - olds;
  1929.             if ((c = *(++pat)) == '\0') {
  1930.                 *len1 += strlen(s);
  1931.                 return(1);
  1932.             }
  1933.             for ( ; !match(pat, s, start1 + 1, len1 + 1); (*len1)++, s++)
  1934.                 if (*s == '\0')
  1935.                     return(0);
  1936.             return(1);
  1937. #endif
  1938.         case '*':
  1939.             *start1 = s;
  1940.             if ((c = *(++pat)) == '\0') {
  1941.                 *len1 = strlen(s);
  1942.                 return(1);
  1943.             }
  1944.             else {
  1945.                 for (*len1=0; !match(pat, s, start1+1, len1+1); (*len1)++, s++)
  1946.                     if (
  1947. #ifdef MSDOS
  1948.                         *s == '.' ||
  1949. #endif
  1950.                         *s == '\0'
  1951.                     )
  1952.                         return(0);
  1953.                 return(1);
  1954.             }
  1955.         case '?':
  1956.             if (
  1957. #ifdef MSDOS
  1958.                 *s == '.' ||
  1959. #endif
  1960.                 *s == '\0'
  1961.             )
  1962.                 return(0);
  1963.             *(start1++) = s;
  1964.             *(len1++) = 1;
  1965.             pat++;
  1966.             s++;
  1967.             break;
  1968.         case '[':
  1969.             {
  1970.                 int matched = 0, notin = 0, inrange = 0;
  1971.                 char prevc = '\0';
  1972.  
  1973.                 if ((c = *(++pat)) == '^') {
  1974.                     notin = 1;
  1975.                     c = *(++pat);
  1976.                 }
  1977.                 while (c != ']') {
  1978.                     if (c == '-' && !inrange)
  1979.                         inrange = 1;
  1980.                     else {
  1981.                         if (c == ESC) {
  1982.                             c = *(++pat);
  1983.                         }
  1984.                         if (inrange) {
  1985.                             if (*s >= prevc && *s <= c)
  1986.                                 matched = 1;
  1987.                             inrange = 0;
  1988.                         }
  1989.                         else if (c == *s)
  1990.                             matched = 1;
  1991.                         prevc = c;
  1992.                     }
  1993.                     c = *(++pat);
  1994.                 }
  1995.                 if (inrange && *s >= prevc)
  1996.                     matched = 1;
  1997.                 if (!(matched ^ notin))
  1998.                     return(0);
  1999.                 *(start1++) = s;
  2000.                 *(len1++) = 1;
  2001.                 pat++;
  2002.                 s++;
  2003.             }
  2004.             break;
  2005.         case ESC:
  2006.             c = *(++pat);
  2007.         default:
  2008.             if (c == *s) {
  2009.                  pat++;
  2010.                 s++;
  2011.             }
  2012.             else
  2013.                 return(0);
  2014.         }
  2015. }
  2016.  
  2017.  
  2018. static void makerep()
  2019. {
  2020.     int l, x;
  2021. #ifndef MSDOS
  2022.     int i, cnv;
  2023.     char *q;
  2024. #endif
  2025.     char *p, *pat, c, pc;
  2026.  
  2027.     repbad = 0;
  2028.     p = fullrep;
  2029.     for (pat = to, l = 0; (c = *pat) != '\0'; pat++, l++) {
  2030.         if (c == '=') {
  2031.             c = *(++pat);
  2032. #ifndef MSDOS
  2033.             if (c == 'l') {
  2034.                 cnv = LOWER;
  2035.                 c = *(++pat);
  2036.             }
  2037.             else if (c == 'u') {
  2038.                 cnv = UPPER;
  2039.                 c = *(++pat);
  2040.             }
  2041.             else
  2042.                 cnv = STAY;
  2043. #endif
  2044.             for(x = 0; ;x *= 10) {
  2045.                 x += c - '0';
  2046.                 c = *(pat+1);
  2047.                 if (!isdigit(c))
  2048.                     break;
  2049.                 pat++;
  2050.             }
  2051.             --x;
  2052.             if (l + len[x] >= MAXPATH)
  2053.                 goto toolong;
  2054. #ifdef MSDOS
  2055.             if (
  2056.                 *(start[x]) == '.' &&
  2057.                 (
  2058.                     p == fullrep ||
  2059.                     *(p - 1) == SLASH
  2060.                 )
  2061.             ) {
  2062.                 repbad = 1;
  2063.                 if (l + STRLEN(EMPTY) >= MAXPATH)
  2064.                     goto toolong;
  2065.                 strcpy(p, EMPTY);
  2066.                 p += STRLEN(EMPTY);
  2067.                 l += STRLEN(EMPTY);
  2068.             }
  2069. #else
  2070.             switch (cnv) {
  2071.             case STAY:
  2072. #endif
  2073.                 memmove(p, start[x], len[x]);
  2074.                 p += len[x];
  2075. #ifndef MSDOS
  2076.                 break;
  2077.             case LOWER:
  2078.                 for (i = len[x], q = start[x]; i > 0; i--, p++, q++)
  2079.                     *p = mylower(*q);
  2080.                 break;
  2081.             case UPPER:
  2082.                 for (i = len[x], q = start[x]; i > 0; i--, p++, q++)
  2083.                     *p = myupper(*q);
  2084.             }
  2085. #endif
  2086.         }
  2087.         else {
  2088.             if (c == ESC)
  2089.                 c = *(++pat);
  2090.             if (l == MAXPATH)
  2091.                 goto toolong;
  2092.             if (
  2093.                 (
  2094. #ifdef MSDOS
  2095.                     c == '.' ||
  2096. #endif
  2097.                     c == SLASH
  2098.                 ) &&
  2099.                 (
  2100.                     p == fullrep ? pat != to :
  2101.                     (
  2102.                         (
  2103.                             (pc = *(p - 1)) == SLASH
  2104. #ifdef MSDOS
  2105.                             || pc == ':'
  2106. #endif
  2107.                         ) &&
  2108.                          *(pat - 1) != pc
  2109.                     )
  2110.                 )
  2111.             ) {
  2112.                 repbad = 1;
  2113.                 if (l + STRLEN(EMPTY) >= MAXPATH)
  2114.                     goto toolong;
  2115.                 strcpy(p, EMPTY);
  2116.                 p += STRLEN(EMPTY);
  2117.                 l += STRLEN(EMPTY);
  2118.             }
  2119.             *(p++)= c;
  2120.         }
  2121.     }
  2122.     if (p == fullrep) {
  2123.         strcpy(fullrep, EMPTY);
  2124.         repbad = 1;
  2125.     }
  2126.     *(p++) = '\0';
  2127.     return;
  2128.  
  2129. toolong:
  2130.     repbad = 1;
  2131.     strcpy(fullrep, TOOLONG);
  2132. }
  2133.  
  2134.  
  2135. static void checkcollisions()
  2136. {
  2137.     REPDICT *rd, *prd;
  2138.     REP *p, *q;
  2139.     int i, mult, oldnreps;
  2140.  
  2141.     if (nreps == 0)
  2142.         return;
  2143.     rd = (REPDICT *)myalloc(nreps * sizeof(REPDICT));
  2144.     for (
  2145.         q = &hrep, p = q->r_next, prd = rd, i = 0;
  2146.         p != NULL;
  2147.         q = p, p = p->r_next, prd++, i++
  2148.     ) {
  2149.         prd->rd_p = p;
  2150.         prd->rd_dto = p->r_hto->h_di;
  2151.         prd->rd_nto = p->r_nto;
  2152.         prd->rd_i = i;
  2153.     }
  2154.     qsort(rd, nreps, sizeof(REPDICT), rdcmp);
  2155.     mult = 0;
  2156.     for (i = 0, prd = rd, oldnreps = nreps; i < oldnreps; i++, prd++)
  2157.         if (
  2158.             i < oldnreps - 1 &&
  2159.             prd->rd_dto == (prd + 1)->rd_dto &&
  2160.             strcmp(prd->rd_nto, (prd + 1)->rd_nto) == 0
  2161.         ) {
  2162.             if (!mult)
  2163.                 mult = 1;
  2164.             else
  2165.                 printf(" , ");
  2166.             printf("%s%s", prd->rd_p->r_hfrom->h_name,
  2167.                 prd->rd_p->r_ffrom->fi_name);
  2168.             prd->rd_p->r_flags |= R_SKIP;
  2169.             prd->rd_p->r_ffrom->fi_rep = MISTAKE;
  2170.             nreps--;
  2171.             badreps++;
  2172.         }
  2173.         else if (mult) {
  2174.             prd->rd_p->r_flags |= R_SKIP;
  2175.             prd->rd_p->r_ffrom->fi_rep = MISTAKE;
  2176.             nreps--;
  2177.             badreps++;
  2178.             printf(" , %s%s -> %s%s : collision.\n",
  2179.                 prd->rd_p->r_hfrom->h_name, prd->rd_p->r_ffrom->fi_name,
  2180.                 prd->rd_p->r_hto->h_name, prd->rd_nto);
  2181.             mult = 0;
  2182.         }
  2183.     chgive(rd, oldnreps * sizeof(REPDICT));
  2184. }
  2185.  
  2186.  
  2187. static int rdcmp(rd1, rd2)
  2188.     REPDICT *rd1, *rd2;
  2189. {
  2190.     int ret;
  2191.  
  2192.     if (
  2193.         (ret = rd1->rd_dto - rd2->rd_dto) == 0 &&
  2194.         (ret = strcmp(rd1->rd_nto, rd2->rd_nto)) == 0
  2195.     )
  2196.         ret = rd1->rd_i - rd2->rd_i;
  2197.     return(ret);
  2198. }
  2199.  
  2200.  
  2201. static void findorder()
  2202. {
  2203.     REP *p, *q, *t, *first, *pred;
  2204.     FILEINFO *fi;
  2205.  
  2206.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next)
  2207.         if (p->r_flags & R_SKIP) {
  2208.             q->r_next = p->r_next;
  2209.             p = q;
  2210.         }
  2211.         else if (
  2212.             (fi = p->r_fdel) == NULL ||
  2213.             (pred = fi->fi_rep) == NULL ||
  2214.             pred == MISTAKE
  2215.         )
  2216.             continue;
  2217.         else if ((first = pred->r_first) == p) {
  2218.             p->r_flags |= R_ISCYCLE;
  2219.             pred->r_flags |= R_ISALIASED;
  2220.             if (op & MOVE)
  2221.                 p->r_fdel = NULL;
  2222.         }
  2223.         else {
  2224.             if (op & MOVE)
  2225.                 p->r_fdel = NULL;
  2226.             while (pred->r_thendo != NULL)
  2227.                 pred = pred->r_thendo;
  2228.             pred->r_thendo = p;
  2229.             for (t = p; t != NULL; t = t->r_thendo)
  2230.                 t->r_first = first;
  2231.             q->r_next = p->r_next;
  2232.             p = q;
  2233.         }
  2234. }
  2235.  
  2236.  
  2237. static void nochains()
  2238. {
  2239.     REP *p, *q;
  2240.  
  2241.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next)
  2242.         if (p->r_flags & R_ISCYCLE || p->r_thendo != NULL) {
  2243.             printchain(p);
  2244.             printf("%s%s : no chain copies allowed.\n",
  2245.                 p->r_hto->h_name, p->r_nto);
  2246.             q->r_next = p->r_next;
  2247.             p = q;
  2248.         }
  2249. }
  2250.  
  2251.  
  2252. static void printchain(p)
  2253.     REP *p;
  2254. {
  2255.     if (p->r_thendo != NULL)
  2256.         printchain(p->r_thendo);
  2257.     printf("%s%s -> ", p->r_hfrom->h_name, p->r_ffrom->fi_name);
  2258.     badreps++;
  2259.     nreps--;
  2260.     p->r_ffrom->fi_rep = MISTAKE;
  2261. }
  2262.  
  2263.  
  2264. static void scandeletes(pkilldel)
  2265.     int (*pkilldel)();
  2266. {
  2267.     REP *p, *q, *n;
  2268.  
  2269.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next) {
  2270.         if (p->r_fdel != NULL)
  2271.             while ((*pkilldel)(p)) {
  2272.                 nreps--;
  2273.                 p->r_ffrom->fi_rep = MISTAKE;
  2274.                 if ((n = p->r_thendo) != NULL) {
  2275.                     if (op & MOVE)
  2276.                         n->r_fdel = p->r_ffrom;
  2277.                     n->r_next = p->r_next;
  2278.                     q->r_next = p = n;
  2279.                 }
  2280.                 else {
  2281.                     q->r_next = p->r_next;
  2282.                     p = q;
  2283.                     break;
  2284.                 }
  2285.             }
  2286.     }
  2287. }
  2288.  
  2289.  
  2290. static int baddel(p)
  2291.     REP *p;
  2292. {
  2293.     HANDLE *hfrom = p->r_hfrom, *hto = p->r_hto;
  2294.     FILEINFO *fto = p->r_fdel;
  2295.     char *t = fto->fi_name, *f = p->r_ffrom->fi_name;
  2296.     char *hnf = hfrom->h_name, *hnt = hto->h_name;
  2297.  
  2298.     if (delstyle == NODEL && !(p->r_flags & R_DELOK) && !(op & APPEND))
  2299.         printf("%s%s -> %s%s : old %s%s would have to be %s.\n",
  2300.             hnf, f, hnt, t, hnt, t,
  2301.             (op & OVERWRITE) ? "overwritten" : "deleted");
  2302.     else if (fto->fi_rep == MISTAKE)
  2303.         printf("%s%s -> %s%s : old %s%s was to be done first.\n",
  2304.             hnf, f, hnt, t, hnt, t);
  2305.     else if (
  2306. #ifdef MSDOS
  2307.                 fto->fi_attrib & FILE_DIRECTORY
  2308. #else
  2309.         fto->fi_stflags & FI_ISDIR
  2310. #endif
  2311.     )
  2312.         printf("%s%s -> %s%s : %s%s%s is a directory.\n",
  2313.             hnf, f, hnt, t, (op & APPEND) ? "" : "old ", hnt, t);
  2314. #ifndef MSDOS
  2315.     else if ((fto->fi_stflags & FI_NODEL) && !(op & (APPEND | OVERWRITE)))
  2316.         printf("%s%s -> %s%s : old %s%s lacks delete permission.\n",
  2317.             hnf, f, hnt, t, hnt, t);
  2318. #endif
  2319.     else if (
  2320.         (op & (APPEND | OVERWRITE)) &&
  2321. #ifdef MSDOS
  2322.                 fto->fi_attrib & FILE_READONLY
  2323. #else
  2324.         !fwritable(hnt, fto)
  2325. #endif
  2326.     ) {
  2327.         printf("%s%s -> %s%s : %s%s %s.\n",
  2328.             hnf, f, hnt, t, hnt, t,
  2329. #ifndef MSDOS
  2330. #ifndef SYSV
  2331.             fto->fi_stflags & FI_LINKERR ?
  2332.             "is a badly aimed symbolic link" :
  2333. #endif
  2334. #endif
  2335.             "lacks write permission");
  2336.     }
  2337.     else
  2338.         return(0);
  2339.     badreps++;
  2340.     return(1);
  2341. }
  2342.  
  2343.  
  2344. static int skipdel(p)
  2345.     REP *p;
  2346. {
  2347.     if (p->r_flags & R_DELOK)
  2348.         return(0);
  2349.     fprintf(stderr, "%s%s -> %s%s : ",
  2350.         p->r_hfrom->h_name, p->r_ffrom->fi_name,
  2351.         p->r_hto->h_name, p->r_nto);
  2352.     if (
  2353. #ifdef MSDOS
  2354.                 p->r_fdel->fi_attrib & FILE_READONLY
  2355. #else
  2356. #ifndef SYSV
  2357.         !(p->r_ffrom->fi_stflags & FI_ISLNK) &&
  2358. #endif
  2359.         !fwritable(p->r_hto->h_name, p->r_fdel)
  2360. #endif
  2361.     )
  2362.         fprintf(stderr, "old %s%s lacks write permission. delete it",
  2363.             p->r_hto->h_name, p->r_nto);
  2364.     else
  2365.         fprintf(stderr, "%s old %s%s",
  2366.             (op & OVERWRITE) ? "overwrite" : "delete",
  2367.             p->r_hto->h_name, p->r_nto);
  2368.     return(!getreply("? ", -1));
  2369. }
  2370.  
  2371.  
  2372. static void goonordie()
  2373. {
  2374.     if ((paterr || badreps) && nreps > 0) {
  2375.         fprintf(stderr, "Not everything specified can be done.");
  2376.         if (badstyle == ABORTBAD) {
  2377.             fprintf(stderr, " Aborting.\n");
  2378.             exit(1);
  2379.         }
  2380.         else if (badstyle == SKIPBAD)
  2381.             fprintf(stderr, " Proceeding with the rest.\n");
  2382.         else if (!getreply(" Proceed with the rest? ", -1))
  2383.             exit(1);
  2384.     }
  2385. }
  2386.  
  2387.  
  2388. static void doreps()
  2389. {
  2390.     char *fstart;
  2391.     int k, printaliased = 0, alias;
  2392.     REP *first, *p;
  2393.     long aliaslen;
  2394.  
  2395.     signal(SIGINT, breakrep);
  2396.  
  2397.     for (first = hrep.r_next, k = 0; first != NULL; first = first->r_next) {
  2398.         for (p = first; p != NULL; p = p->r_thendo, k++) {
  2399.             if (gotsig) {
  2400.                 fflush(stdout);
  2401.                 fprintf(stderr, "User break.\n");
  2402.                 printaliased = snap(first, p);
  2403.                 gotsig = 0;
  2404.             }
  2405.             strcpy(fullrep, p->r_hto->h_name);
  2406.             strcat(fullrep, p->r_nto);
  2407.             if (!noex && (p->r_flags & R_ISCYCLE))
  2408.                 if (op & APPEND)
  2409.                     aliaslen = appendalias(first, p, &printaliased);
  2410.                 else
  2411.                     alias = movealias(first, p, &printaliased);
  2412.             strcpy(pathbuf, p->r_hfrom->h_name);
  2413.             fstart = pathbuf + strlen(pathbuf);
  2414.             if ((p->r_flags & R_ISALIASED) && !(op & APPEND))
  2415.                 sprintf(fstart, "%s%03d", TEMP, alias);
  2416.             else
  2417.                 strcpy(fstart, p->r_ffrom->fi_name);
  2418.             if (!noex) {
  2419.                 if (p->r_fdel != NULL && !(op & (APPEND | OVERWRITE)))
  2420.                     myunlink(fullrep, p->r_fdel);
  2421.                 if (
  2422.                     (op & (COPY | APPEND)) ?
  2423.                         copy(p->r_ffrom,
  2424.                             p->r_flags & R_ISALIASED ? aliaslen : -1L) :
  2425. #ifndef MSDOS
  2426.                     (op & HARDLINK) ?
  2427.                         link(pathbuf, fullrep) :
  2428. #ifndef SYSV
  2429.                     (op & SYMLINK) ?
  2430.                         symlink((p->r_flags & R_ONEDIRLINK) ? fstart : pathbuf,
  2431.                             fullrep) :
  2432. #endif
  2433. #endif
  2434.                     p->r_flags & R_ISX ?
  2435.                         copymove(p) :
  2436.                     /* move */
  2437.                         rename(pathbuf, fullrep)
  2438.                 ) {
  2439.                     fprintf(stderr,
  2440.                         "%s -> %s has failed.\n", pathbuf, fullrep);
  2441.                     printaliased = snap(first, p);
  2442.                 }
  2443.             }
  2444.             if (verbose || noex) {
  2445.                 if (p->r_flags & R_ISALIASED && !printaliased)
  2446.                     strcpy(fstart, p->r_ffrom->fi_name);
  2447.                 fprintf(outfile, "%s %c%c %s%s%s\n",
  2448.                     pathbuf,
  2449.                     p->r_flags & R_ISALIASED ? '=' : '-',
  2450.                     p->r_flags & R_ISCYCLE ? '^' : '>',
  2451.                     fullrep,
  2452.                     (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" : "",
  2453.                     noex ? "" : " : done");
  2454.             }
  2455.         }
  2456.         printaliased = 0;
  2457.     }
  2458.     if (k != nreps)
  2459.         fprintf(stderr, "Strange, did %d reps; %d were expected.\n",
  2460.             k, nreps);
  2461.     if (k == 0)
  2462.         fprintf(stderr, "Nothing done.\n");
  2463. }
  2464.  
  2465.  
  2466. static long appendalias(first, p, pprintaliased)
  2467.     REP *first, *p;
  2468.     int *pprintaliased;
  2469. {
  2470.     long ret;
  2471.  
  2472. #ifdef MSDOS
  2473.     int fd;
  2474.  
  2475.     if ((fd = open(fullrep, O_RDONLY | O_BINARY, 0)) < 0) {
  2476.         fprintf(stderr, "stat on %s has failed.\n", fullrep);
  2477.         *pprintaliased = snap(first, p);
  2478.     }
  2479.     else {
  2480.         ret = filelength(fd);
  2481.         close(fd);
  2482.     }
  2483. #else
  2484.     struct stat fstat;
  2485.  
  2486.     if (stat(fullrep, &fstat)) {
  2487.         fprintf(stderr, "append cycle stat on %s has failed.\n", fullrep);
  2488.         *pprintaliased = snap(first, p);
  2489.     }
  2490.     else
  2491.         ret = fstat.st_size;
  2492. #endif
  2493.  
  2494.     return(ret);
  2495. }
  2496.  
  2497.  
  2498. static int movealias(first, p, pprintaliased)
  2499.     REP *first, *p;
  2500.     int *pprintaliased;
  2501. {
  2502.     char *fstart;
  2503.     int ret;
  2504.  
  2505.     strcpy(pathbuf, p->r_hto->h_name);
  2506.     fstart = pathbuf + strlen(pathbuf);
  2507.     strcpy(fstart, TEMP);
  2508.     for (
  2509.         ret = 0;
  2510.         sprintf(fstart + STRLEN(TEMP), "%03d", ret),
  2511.         fsearch(fstart, p->r_hto->h_di) != NULL;
  2512.         ret++
  2513.     )
  2514.         ;
  2515.     if (rename(fullrep, pathbuf)) {
  2516.         fprintf(stderr,
  2517.             "%s -> %s has failed.\n", fullrep, pathbuf);
  2518.         *pprintaliased = snap(first, p);
  2519.     }
  2520.     return(ret);
  2521. }
  2522.  
  2523.  
  2524. static int snap(first, p)
  2525.     REP *first, *p;
  2526. {
  2527.     char fname[80];
  2528.     int redirected = 0;
  2529.  
  2530.     if (noex)
  2531.         exit(1);
  2532.  
  2533.     failed = 1;
  2534.     signal(SIGINT, breakstat);
  2535.     if (
  2536.         badstyle == ASKBAD &&
  2537.         isatty(fileno(stdout)) &&
  2538.         getreply("Redirect standard output to file? ", 0)
  2539.     ) {
  2540.         redirected = 1;
  2541. #ifndef MSDOS
  2542.         umask(oldumask);
  2543. #endif
  2544.         while (
  2545.             fprintf(stderr, "File name> "),
  2546.             (outfile = fopen(mygets(fname, 80), "w")) == NULL
  2547.         )
  2548.             fprintf(stderr, "Can't open %s.\n", fname);
  2549.     }
  2550.     if (redirected || !verbose)
  2551.         showdone(p);
  2552.     fprintf(outfile, "The following left undone:\n");
  2553.     noex = 1;
  2554.     return(first != p);
  2555. }
  2556.  
  2557.  
  2558. static void showdone(fin)
  2559.     REP *fin;
  2560. {
  2561.     REP *first, *p;
  2562.  
  2563.     for (first = hrep.r_next; ; first = first->r_next)
  2564.         for (p = first; p != NULL; p = p->r_thendo) {
  2565.             if (p == fin)
  2566.                 return;
  2567.             fprintf(outfile, "%s%s %c%c %s%s : done%s\n",
  2568.                 p->r_hfrom->h_name, p->r_ffrom->fi_name,
  2569.                 p->r_flags & R_ISALIASED ? '=' : '-',
  2570.                 p->r_flags & R_ISCYCLE ? '^' : '>',
  2571.                 p->r_hto->h_name, p->r_nto,
  2572.                 (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" : "");
  2573.         }
  2574. }
  2575.  
  2576.  
  2577. static void breakout()
  2578. {
  2579.     fflush(stdout);
  2580.     fprintf(stderr, "Aborting, nothing done.\n");
  2581.     exit(1);
  2582. }
  2583.  
  2584.  
  2585. static int breakrep()
  2586. {
  2587.     gotsig = 1;
  2588.     return(1);
  2589. }
  2590.  
  2591.  
  2592. static void breakstat()
  2593. {
  2594.     exit(1);
  2595. }
  2596.  
  2597.  
  2598. static void quit()
  2599. {
  2600.     fprintf(stderr, "Aborting, nothing done.\n");
  2601.     exit(1);
  2602. }
  2603.  
  2604.  
  2605. static int copymove(p)
  2606.     REP *p;
  2607. {
  2608. #ifndef MSDOS
  2609. #ifndef SYSV
  2610.     {
  2611.         int llen;
  2612.         char linkbuf[MAXPATH];
  2613.  
  2614.         if ((llen = readlink(pathbuf, linkbuf, MAXPATH - 1)) >= 0) {
  2615.             linkbuf[llen] = '\0';
  2616.             return(symlink(linkbuf, fullrep) || myunlink(pathbuf, p->r_ffrom));
  2617.         }
  2618.     }
  2619. #endif
  2620. #endif
  2621.     return(copy(p->r_ffrom, -1L) || myunlink(pathbuf, p->r_ffrom));
  2622. }
  2623.  
  2624.  
  2625.  
  2626. #define IRWMASK (S_IREAD | S_IWRITE)
  2627. #define RWMASK (IRWMASK | (IRWMASK >> 3) | (IRWMASK >> 6))
  2628.  
  2629. static int copy(ff, len)
  2630.     FILEINFO *ff;
  2631.     long len;
  2632. {
  2633.     char buf[BUFSIZE], c;
  2634.     int f, t, k, mode, perm;
  2635. #ifdef MSDOS
  2636.         FILESTATUS fs;
  2637. #else
  2638. #ifdef SYSV
  2639.     struct utimbuf tim;
  2640. #else
  2641.     struct timeval tim[2];
  2642. #endif
  2643.     struct stat fstat;
  2644. #endif
  2645.  
  2646.     if ((f = open(pathbuf, O_RDONLY | O_BINARY, 0)) < 0)
  2647.         return(-1);
  2648.     perm =
  2649. #ifdef MSDOS
  2650.         IRWMASK        /* will _chmod it later (to get all the attributes) */
  2651. #else
  2652.         (op & (APPEND | OVERWRITE)) ?
  2653.             (~oldumask & RWMASK) | (ff->fi_mode & ~RWMASK) :
  2654.             ff->fi_mode
  2655. #endif
  2656.         ;
  2657.  
  2658. #ifdef V7
  2659.     if (
  2660.         !(op & APPEND) ||
  2661.         (((t = open(fullrep, O_RDWR)) < 0 && errno == ENOENT)
  2662.     )
  2663.         t = creat(fullrep, perm);
  2664. #else
  2665.     mode = O_CREAT | (op & APPEND ? 0 : O_TRUNC) |
  2666. #ifdef MSDOS
  2667.         O_BINARY | (op & ZAPPEND ? O_RDWR : O_WRONLY)
  2668. #else
  2669.         O_WRONLY
  2670. #endif
  2671.         ;
  2672.     t = open(fullrep, mode, perm);
  2673. #endif
  2674.     if (t < 0) {
  2675.         close(f);
  2676.         return(-1);
  2677.     }
  2678.     if (op & APPEND)
  2679.         lseek(t, 0L, 2);
  2680. #ifdef MSDOS
  2681.     if (op & ZAPPEND && filelength(t) != 0) {
  2682.         if (lseek(t, -1L, 1) == -1L || read(t, &c, 1) != 1) {
  2683.             close(f);
  2684.             close(t);
  2685.             return(-1);
  2686.         }
  2687.         if (c == 26)
  2688.             lseek(t, -1L, 1);
  2689.     }
  2690. #endif
  2691.     if ((op & APPEND) && len != -1L) {
  2692.         while (
  2693.             len != 0 &&
  2694.             (k = read(f, buf, len > BUFSIZE ? BUFSIZE : (unsigned)len)) > 0 &&
  2695.             write(t, buf, k) == k
  2696.         )
  2697.             len -= k;
  2698.         if (len == 0)
  2699.             k = 0;
  2700.     }
  2701.     else
  2702.         while ((k = read(f, buf, BUFSIZE)) > 0 && write(t, buf, k) == k)
  2703.             ;
  2704.     if (!(op & (APPEND | OVERWRITE)))
  2705.         if (
  2706. #ifdef MSDOS
  2707.                         DosQFileInfo(f, 1, &fs, sizeof(fs)) ||
  2708.                         DosSetFileInfo(t, 1, (PBYTE) &fs, sizeof(fs)) ||
  2709.                         DosSetFileMode(fullrep, ff->fi_attrib, 0L)
  2710. #else
  2711.             stat(pathbuf, &fstat) ||
  2712.             (
  2713. #ifdef SYSV
  2714.                 tim.actime = fstat.st_atime,
  2715.                 tim.modtime = fstat.st_mtime,
  2716. #else
  2717.                 tim[0].tv_sec = fstat.st_atime,
  2718.                 tim[1].tv_sec = fstat.st_mtime,
  2719. #endif
  2720.                 utimes(fullrep, tim)
  2721.             )
  2722. #endif
  2723.         )
  2724.             fprintf(stderr, "Strange, couldn't transfer time from %s to %s.\n",
  2725.                 pathbuf, fullrep);
  2726.  
  2727.     close(f);
  2728.     close(t);
  2729.     if (k != 0) {
  2730.         if (!(op & APPEND))
  2731.             unlink(fullrep);
  2732.         return(-1);
  2733.     }
  2734.     return(0);
  2735. }
  2736.  
  2737.  
  2738. #ifndef RENAME
  2739. static int rename(from, to)
  2740.     char *from, *to;
  2741. {
  2742.     if (link(from, to))
  2743.         return(-1);
  2744.     if (unlink(from)) {
  2745.         unlink(to);
  2746.         return(-1);
  2747.     }
  2748.     return(0);
  2749. }
  2750. #endif
  2751.  
  2752.  
  2753. static int myunlink(n, f)
  2754.     char *n;
  2755.     FILEINFO *f;
  2756. {
  2757. #ifdef MSDOS
  2758.     int a;
  2759.  
  2760.         if (((a = f->fi_attrib) & FILE_READONLY) && DosSetFileMode(n, a & ~FILE_READONLY, 0L)) {
  2761.         fprintf(stderr, "Strange, can not _chmod (or unlink) %s.\n", f);
  2762.         return(-1);
  2763.     }
  2764. #endif
  2765.     if (unlink(n)) {
  2766.         fprintf(stderr, "Strange, can not unlink %s.\n", n);
  2767.         return(-1);
  2768.     }
  2769.     return(0);
  2770. }
  2771.  
  2772.  
  2773. static int getreply(m, failact)
  2774.     char *m;
  2775.     int failact;
  2776. {
  2777.     static FILE *tty = NULL;
  2778.     int c, r;
  2779.  
  2780.     fprintf(stderr, m);
  2781.     if (tty == NULL && (tty = fopen(TTY, "r")) == NULL) {
  2782.         fprintf(stderr, "Can not open %s to get reply.\n", TTY);
  2783.         if (failact == -1)
  2784.             quit();
  2785.         else
  2786.             return(failact);
  2787.     }
  2788.     for (;;) {
  2789.         r = fgetc(tty);
  2790.         if (r == EOF) {
  2791.             fprintf(stderr, "Can not get reply.\n");
  2792.             if (failact == -1)
  2793.                 quit();
  2794.             else
  2795.                 return(failact);
  2796.         }
  2797.         if (r != '\n')
  2798.             while ((c = fgetc(tty)) != '\n' && c != EOF)
  2799.                 ;
  2800.         r = mylower(r);
  2801.         if (r == 'y' || r == 'n')
  2802.             return(r == 'y');
  2803.         fprintf(stderr, "Yes or No? ");
  2804.     }
  2805. }
  2806.  
  2807.  
  2808. static void *myalloc(k)
  2809.     unsigned k;
  2810. {
  2811.     void *ret;
  2812.  
  2813.     if (k == 0)
  2814.         return(NULL);
  2815.     if ((ret = (void *)malloc(k)) == NULL) {
  2816.         fprintf(stderr, "Insufficient memory.\n");
  2817.         quit();
  2818.     }
  2819.     return(ret);
  2820. }
  2821.  
  2822.  
  2823. static void *challoc(k, which)
  2824.     int which;
  2825.     int k;
  2826. {
  2827.     void *ret;
  2828.     CHUNK *p, *q;
  2829.     SLICER *sl = &(slicer[which]);
  2830.  
  2831.     if (k > sl->sl_len) {
  2832.         for (
  2833.             q = NULL, p = freechunks;
  2834.             p != NULL && (sl->sl_len = p->ch_len) < k;
  2835.             q = p, p = p->ch_next
  2836.         )
  2837.             ;
  2838.         if (p == NULL) {
  2839.             sl->sl_len = CHUNKSIZE - sizeof(CHUNK *);
  2840.             p = (CHUNK *)myalloc(CHUNKSIZE);
  2841.         }
  2842.         else if (q == NULL)
  2843.             freechunks = p->ch_next;
  2844.         else
  2845.             q->ch_next = p->ch_next;
  2846.         p->ch_next = sl->sl_first;
  2847.         sl->sl_first = p;
  2848.         sl->sl_unused = (char *)&(p->ch_len);
  2849.     }
  2850.     sl->sl_len -= k;
  2851.     ret = (void *)sl->sl_unused;
  2852.     sl->sl_unused += k;
  2853.     return(ret);
  2854. }
  2855.  
  2856.  
  2857. static void chgive(p, k)
  2858.     void *p;
  2859.     unsigned k;
  2860. {
  2861.     ((CHUNK *)p)->ch_len = k - sizeof(CHUNK *);
  2862.     ((CHUNK *)p)->ch_next = freechunks;
  2863.     freechunks = (CHUNK *)p;
  2864. }
  2865.  
  2866.  
  2867. #ifndef MSDOS
  2868. static void memmove(to, from, k)
  2869.     char *to, *from;
  2870.     unsigned k;
  2871. {
  2872.     if (from > to)
  2873.         while (k-- != 0)
  2874.             *(to++) = *(from++);
  2875.     else {
  2876.         from += k;
  2877.         to += k;
  2878.         while (k-- != 0)
  2879.             *(--to) = *(--from);
  2880.     }
  2881. }
  2882. #endif
  2883.  
  2884.  
  2885. static int mygetc()
  2886. {
  2887.     static int lastc = 0;
  2888.  
  2889.     if (lastc == EOF)
  2890.         return(EOF);
  2891.     return(lastc = getchar());
  2892. }
  2893.  
  2894.  
  2895. static char *mygets(s, l)
  2896.     char *s;
  2897.     int l;
  2898. {
  2899.     char *nl;
  2900.  
  2901.     for (;;) {
  2902.         if (fgets(s, l, stdin) == NULL)
  2903.             return(NULL);
  2904.         if ((nl = strchr(s, '\n')) != NULL)
  2905.             break;
  2906.         fprintf(stderr, "Input string too long. Try again> ");
  2907.     }
  2908.     *nl = '\0';
  2909.     return(s);
  2910. }
  2911.  
  2912.  
  2913. #ifdef MSDOS
  2914. static int leave()
  2915. {
  2916.     return(0);
  2917. }
  2918.  
  2919. static void cleanup()
  2920. {
  2921.     int i;
  2922.  
  2923.     if (patch.ph_safeid) {
  2924.         for (i = 0; i < nhandles; i++) {
  2925.             if (!(handles[i]->h_di->di_flags & DI_CLEANED)) {
  2926.                 sprintf(pathbuf, "%s%s%03d",
  2927.                     handles[i]->h_name, IDF, handles[i]->h_di->di_did);
  2928.                 if (unlink(pathbuf))
  2929.                     fprintf(stderr, "Strange, couldn't unlink %s.\n", pathbuf);
  2930.                 handles[i]->h_di->di_flags |= DI_CLEANED;
  2931.             }
  2932.         }
  2933.     }
  2934. }
  2935.  
  2936. #endif
  2937.