|
|
1.1 root 1: /*
2: * Cpdir. Copy hierarchies in a file system, preserving structure.
3: * Define SLOW for 'block at a time copying' - not recommended tho.
4: */
5: #include <stdio.h>
6: #include <errno.h>
7: #include <signal.h>
8: #include <sys/types.h>
9: #include <sys/stat.h>
10: #include <sys/dir.h>
11: #include <ctype.h>
12: #include <access.h>
13: #include <canon.h>
14:
15: #define VERSION "1.1"
16: #define CPBUFSIZ (50*BUFSIZ) /* copy buffer */
17: #define SDSIZ (sizeof(struct direct))
18: #define MAXINT 32767
19: #define SOURCE 0
20: #define TARGET 1
21: #define DEV0 ((dev_t)0)
22: #define INODE0 ((ino_t)0)
23: #define ROOTUID 0
24: #define HASHSIZE 37
25:
26: #define hash(ino) ((ino)%HASHSIZE)
27:
28: #define TRUE (0==0)
29: #define FALSE (0==1)
30:
31: typedef char bool;
32: typedef unsigned char uchar;
33: typedef unsigned int uint;
34: typedef unsigned short ushort;
35: typedef unsigned long ulong;
36:
37: typedef union {
38: struct direct dbuf;
39: char cbuf[SDSIZ + 1];
40: } DIRBUF;
41: #define db_ino dbuf.d_ino
42: #define db_name dbuf.d_name
43:
44: typedef struct link {
45: ino_t l_ino;
46: dev_t l_dev;
47: dev_t l_tdev;
48: struct link *l_next;
49: uint l_nlink;
50: char l_name[];
51: } LINK;
52:
53: typedef struct str {
54: struct str *s_next;
55: char s_str[];
56: } STR;
57:
58:
59:
60: /*
61: * Global variables.
62: */
63: extern int errno;
64: dev_t dir2_dev;
65: ino_t dir2_ino;
66: dev_t src_dev;
67: dev_t tgt_dev;
68: struct stat srcstat;
69: struct stat tgtstat;
70: LINK *srctab[HASHSIZE];
71: LINK *tgttab[HASHSIZE];
72: STR *strtab[HASHSIZE];
73:
74: bool aflag;
75: bool dflag;
76: bool eflag;
77: bool sflag;
78: bool tflag;
79: bool uflag;
80: bool vflag;
81: bool wflag;
82: bool root;
83: bool splitmsg;
84: bool errprefix;
85: bool dir1slash;
86: bool dir2slash;
87:
88: int rlimit = MAXINT;
89: int rlevel = 1;
90: int exitval;
91: int numsuppress;
92: int broken;
93: int srclinks;
94: int tgtlinks;
95: int srcsize;
96: int tgtsize;
97: int dir1len;
98: int dir2len;
99: int interrupted; /* For handling SIGINT and SIGQUIT */
100:
101: short uid;
102: short gid;
103:
104: char *dir1;
105: char *dir2;
106: char *target;
107: char *source;
108:
109: /*
110: * Error message and other strings.
111: */
112: char *dot = ".";
113: char *dotdot = "..";
114: char *fmt1 = "%s\n";
115: char *fmt1a = "%-72s\r";
116: char *fmt2 = "%s: %s\n";
117: char *fmt3 = "%s: %s%s\n";
118: char *fmt4 = "%s: %s%s%s\n";
119: char *usage = "usage: cpdir [options] dir1 dir2";
120: char *devbound = "crossing device boundary";
121: char *writeerr = "write error";
122: char *readerr = "read error";
123: char *supressd = "suppressed";
124: char *linked = "linked";
125: char *notdir = "not a directory";
126: char *nomemory = "out of memory";
127: char *nopermit = "permission denied";
128: char *nomkdir = "cannot make directory";
129: char *nounlink = "cannot unlink ";
130: char *nolink = "cannot link ";
131: char *nocreate = "cannot create";
132: char *nofind = "cannot find";
133: char *noopen = "cannot open";
134:
135: /*
136: * Functions returning non_int.
137: */
138: long lseek();
139: char *tmalloc();
140: char *realloc();
141: char *rindex();
142: char *concat();
143: char *parent();
144: bool suppress();
145: bool isslash();
146: bool dirchecks();
147: bool linkattempt();
148: bool tgtunlink();
149: LINK *linklocate();
150: LINK *linkinstall();
151:
152: main(ac, av) int ac; char *av[];
153: {
154: ac = 0;
155: aarghh(av);
156: init();
157: cpdir();
158: report();
159: if (aflag)
160: printf("%72s\r", "");
161: return (exitval);
162: }
163:
164: aarghh(av)
165: register char *av[];
166: {
167: register char *cp;
168:
169: for (;;) {
170: if ((cp = *++av) == NULL) {
171: errprint(fmt1, usage);
172: exit(1);
173: }
174: if (*cp++ != '-')
175: break;
176: while (*cp)
177: switch (*cp++) {
178: case 'a':
179: aflag = TRUE;
180: break;
181: case 'd':
182: dflag = TRUE;
183: break;
184: case 'e':
185: eflag = TRUE;
186: break;
187: case 'r':
188: if (!isdigit(*cp)) {
189: rlimit = 1;
190: break;
191: }
192: *av = cp;
193: rlimit = new_atoi(av);
194: cp = *av;
195: break;
196: case 's':
197: sflag = TRUE;
198: strinstall(cp);
199: ++numsuppress;
200: goto NEXTARG;
201: break;
202: case 't':
203: tflag = wflag = eflag = TRUE;
204: break;
205: case 'u':
206: uflag = TRUE;
207: break;
208: case 'v':
209: vflag = wflag = TRUE;
210: break;
211: case 'V':
212: fprintf(stderr, "cpdir: V%s\n", VERSION);
213: break;
214: default:
215: errprint(fmt1, usage);
216: exit(1);
217: }
218: NEXTARG:;
219: }
220:
221: if ((dir1=*av++) == NULL || (dir2=*av++) == NULL || *av != NULL) {
222: errprint(fmt1, usage);
223: exit(1);
224: }
225: return;
226: }
227:
228: /*
229: * Actions: Initialize certain flags and the name buffers source and target.
230: * Verify dir1 and dir2 permissions. Dir2 is made if necessary.
231: * Side Effects: On return srcstat contains the status of dir1. If dir2
232: * exists tgtstat contains its status. In the case that tflag is set and dir2
233: * does not exist, tgt_dev and tgtstat.st_dev are the device of target's
234: * parent, the device that target would be created on except for tflag.
235: */
236: init()
237: {
238: struct stat outstat;
239: struct stat errstat;
240:
241: uid = getuid();
242: gid = getgid();
243: root = (uid == ROOTUID);
244: if (root)
245: umask(0);
246:
247: errprefix = !isatty(fileno(stdin));
248: fstat(fileno(stdout), &outstat);
249: fstat(fileno(stderr), &errstat);
250: splitmsg = (outstat.st_ino != errstat.st_ino) ||
251: (outstat.st_dev != errstat.st_dev);
252:
253: dir1len = strlen(dir1);
254: srcsize = (dir1len + 1);
255: source = tmalloc(srcsize);
256: strcpy(source, dir1);
257: dir1slash = isslash(dir1);
258:
259: dir2len = strlen(dir2);
260: tgtsize = dir2len + 1;
261: target = tmalloc(tgtsize);
262: strcpy(target, dir2);
263: dir2slash = isslash(dir2);
264:
265: /*
266: * We must check boundary conditions before we call dirchecks().
267: * These are: source exists and is a directory, and if target does not
268: * exist that we have write and search permission on its parent and
269: * tgt_dev contains the device number of the parent.
270: */
271: if (stat(dir1, &srcstat) < 0) {
272: errprint(fmt2, dir1, nofind);
273: exit(1);
274: }
275: if ((srcstat.st_mode & S_IFMT) != S_IFDIR) {
276: errprint(fmt2, dir1, notdir);
277: exit(1);
278: }
279: if (access(dir2, 0) < 0) {
280: register char *cp;
281: cp = parent(dir2);
282: if (stat(cp, &tgtstat) < 0) {
283: errprint(fmt2, dir2, "cannot find parent");
284: exit(1);
285: }
286: if (access(cp, AWRITE|ASRCH) < 0) {
287: errprint(fmt2, dir2, nomkdir);
288: exit(1);
289: }
290: tgt_dev = tgtstat.st_dev;
291: }
292: if (!dirchecks())
293: exit(1);
294:
295: src_dev = srcstat.st_dev;
296: dir2_dev = tgt_dev = tgtstat.st_dev;
297: if (access(target, 0) == 0)
298: dir2_ino = tgtstat.st_ino;
299: return;
300: }
301:
302:
303: /*
304: * Assume: Source is a directory we can read and search. Srcstat contains its
305: * status. Target is a directory we can write and search. Tgtstat contains its
306: * status. Src_dev and tgt_dev are the devices of the parents of source and
307: * target. If tflag is on target may not exist. In this case tgtstat.st_dev
308: * contains the device where target would have been created if tflag were off.
309: */
310: cpdir()
311: {
312: register int n;
313: register int fd;
314: register DIRBUF *dbp;
315: DIRBUF dirbuf;
316: long address;
317: dev_t sdev;
318: dev_t tdev;
319: struct stat locsrcstat;
320: struct stat loctgtstat;
321:
322: /*
323: * Check for circular copy.
324: */
325: if (srcstat.st_ino == dir2_ino &&
326: srcstat.st_dev == dir2_dev) {
327: if (wflag)
328: printf(fmt2, source,
329: "not copied to avoid circular copy");
330: return;
331: }
332:
333: /*
334: * Open source, and prepare dirbuf.
335: */
336: if ((fd = open(source, 0)) < 0) {
337: errprint(fmt2, source, noopen);
338: return;
339: }
340: dbp = &dirbuf;
341: dbp->cbuf[SDSIZ] = '\0';
342:
343: /*
344: * Save srcstat, src_dev, tgtstat, tgt_dev to restore before exit.
345: */
346: locsrcstat = srcstat;
347: loctgtstat = tgtstat;
348: tdev = tgt_dev;
349: sdev = src_dev;
350:
351: /*
352: * Detect the crossing of device boundaries.
353: */
354: if (tgt_dev != tgtstat.st_dev) {
355: if (wflag)
356: printf(fmt2, target, devbound);
357: tgt_dev = tgtstat.st_dev;
358: }
359: if (src_dev != srcstat.st_dev) {
360: if (wflag)
361: printf(fmt2, source, devbound);
362: src_dev = srcstat.st_dev;
363: }
364:
365: /*
366: * Loop through the directory source.
367: */
368: while ((n = read(fd, dbp->cbuf, SDSIZ)) > 0) {
369: if (n != SDSIZ) {
370: errprint(fmt2, source, readerr);
371: close(fd);
372: goto OUT;
373: }
374:
375: canino(dbp->db_ino);
376: if (dbp->db_ino == INODE0 ||
377: !strcmp(dbp->db_name, dot) ||
378: !strcmp(dbp->db_name, dotdot))
379: continue;
380:
381: grow(dbp->db_name);
382: if (sflag && suppress()) {
383: if (vflag)
384: printf(fmt2, source, supressd);
385: shrink();
386: continue;
387: }
388: if (stat(source, &srcstat) < 0) {
389: errprint(fmt2, source, nofind);
390: shrink();
391: continue;
392: }
393:
394: switch (srcstat.st_mode & S_IFMT) {
395: default:
396: errprint(fmt2, source, "unknown file type");
397: shrink();
398: continue;
399: case S_IFCHR:
400: case S_IFBLK:
401: cpnode();
402: shrink();
403: continue;
404: case S_IFPIP:
405: srcstat.st_rdev = DEV0;
406: cpnode();
407: shrink();
408: continue;
409: case S_IFREG:
410: cpfile();
411: shrink();
412: continue;
413: case S_IFDIR:
414: if (rlevel == rlimit) {
415: if (vflag)
416: printf(fmt2, source, supressd);
417: shrink();
418: continue;
419: }
420: if (!dirchecks()) {
421: shrink();
422: continue;
423: }
424:
425: address = lseek(fd, 0L, 1);
426: close(fd);
427: ++rlevel;
428: cpdir();
429: --rlevel;
430: shrink();
431: if ((fd = open(source, 0)) < 0) {
432: errprint(fmt2, source,
433: "cannot reopen, copy incomplete");
434: goto OUT;
435: }
436: lseek(fd, address, 0);
437: continue;
438: }
439: }
440: close(fd);
441:
442: OUT:
443: vprintf();
444: srcstat = locsrcstat;
445: tgtstat = loctgtstat;
446: tgt_dev = tdev;
447: src_dev = sdev;
448: adjust();
449: return;
450: }
451:
452: /*
453: * Assume source names the file to be copied, srcstat contains its status,
454: * and target is the file to copy to. Target may or may not exist.
455: */
456: cpfile()
457: {
458: #ifndef SLOW
459: register char *ip;
460: #endif
461: register int n;
462: register int i;
463: register int fd1;
464: register int fd2;
465: register fsize_t size;
466: #ifndef SLOW
467: register char *wp; /* write pointer */
468: register int wflag; /* write flag */
469: static char buf[CPBUFSIZ]; /* copy buffer */
470: #else
471: static char buf[BUFSIZ];
472: #endif
473: int intflag, hupflag;
474:
475: if (access(source, AREAD) < 0) {
476: errprint(fmt2, source, noopen);
477: return;
478: }
479:
480: if (uflag && stat(target, &tgtstat) == 0)
481: if (srcstat.st_mtime <= tgtstat.st_mtime) {
482: if (vflag)
483: printf(fmt2, target, "no update");
484: return;
485: }
486:
487: if (!tgtunlink())
488: return;
489: if (srcstat.st_nlink > 1)
490: if (linkattempt())
491: return;
492:
493: if (tflag) {
494: vprintf();
495: return;
496: }
497:
498: intflag = catch(SIGINT);
499: hupflag = catch(SIGHUP);
500: if ((fd1 = open(source, 0)) < 0) {
501: errprint(fmt2, source, noopen);
502: return;
503: }
504: if ((fd2 = creat(target, 0)) < 0) {
505: close(fd1);
506: errprint(fmt2, target, nocreate);
507: return;
508: }
509:
510: size = srcstat.st_size;
511: #ifndef SLOW
512: while ((n = read(fd1, buf, sizeof(buf))) > 0) {
513: #else
514: while ((n = read(fd1, buf, BUFSIZ)) > 0) {
515: #endif
516: /*
517: * Check for blocks of zeroes (holes in a sparse file).
518: * However, a block of zeroes at the end of a file must be
519: * written so the file has correct length.
520: */
521: #ifndef SLOW
522: wp = ip = buf;
523: size -= n;
524: while ((n-BUFSIZ) > 0 || ((n-BUFSIZ) == 0 && size != 0)) {
525: n -= BUFSIZ;
526: wflag = FALSE;
527: ip = wp;
528: for (i = 0; i < BUFSIZ; ++i)
529: if (*ip++ != '\0') {
530: wflag = TRUE;
531: break;
532: }
533: if (wflag) {
534: if (write(fd2, wp, BUFSIZ) < BUFSIZ) {
535: errprint(fmt2, target, writeerr);
536: close(fd1);
537: close(fd2);
538: return (FALSE);
539: }
540: } else {
541: lseek(fd2, (long)BUFSIZ, 1);
542: }
543: wp += BUFSIZ;
544: }
545: if (write(fd2, wp, n) < n) {
546: errprint(fmt2, target, writeerr);
547: close(fd1);
548: close(fd2);
549: return (FALSE);
550: }
551: #else
552: if ((size -= n) == (fsize_t)0)
553: goto WRITE;
554: for (i = 0; i < n; ++i)
555: if (buf[i] != '\0')
556: goto WRITE;
557: lseek(fd2, (long)BUFSIZ, 1);
558: continue;
559:
560: WRITE:
561: if (write(fd2, buf, n) < n) {
562: errprint(fmt2, target, writeerr);
563: close(fd1);
564: close(fd2);
565: return (FALSE);
566: }
567: #endif
568: }
569: close(fd1);
570: close(fd2);
571: adjust();
572: if (intflag)
573: signal(SIGINT, SIG_DFL);
574: if (hupflag)
575: signal(SIGHUP, SIG_DFL);
576: if (interrupted)
577: exit(1);
578:
579: if (n < 0)
580: errprint(fmt2, source, readerr);
581: else vprintf();
582: return;
583: }
584:
585: /*
586: * Copy special nodes and named pipes.
587: */
588: cpnode()
589: {
590: if (!root) {
591: if (vflag)
592: printf(fmt2, source, "not the super-user");
593: return;
594: }
595: if (!tgtunlink())
596: return;
597: if (srcstat.st_nlink > 1)
598: if (linkattempt())
599: return;
600: if (!tflag) {
601: if (mknod(target, srcstat.st_mode, srcstat.st_rdev) < 0) {
602: errprint(fmt2, target, "cannot make node");
603: return;
604: }
605: adjust();
606: }
607: if (vflag)
608: printf(fmt2, target, "copied node");
609: else if (aflag)
610: printf(fmt1a, target);
611: return;
612: }
613:
614:
615: /*
616: * Grow each of target and source by appending '/' and cp.
617: */
618: grow(cp)
619: register char *cp;
620: {
621: register int a;
622: register int b;
623:
624: a = strlen(cp) + 2;
625:
626: b = strlen(source);
627: if (a+b > srcsize) {
628: if ((source = realloc(source, a+b)) == NULL) {
629: errprint(fmt1, nomemory);
630: exit(1);
631: }
632: srcsize = a+b;
633: }
634: if (rlevel > 1 || !dir1slash)
635: source[b++] = '/';
636: strcpy(source+b, cp);
637:
638: b = strlen(target);
639: if (a+b > tgtsize) {
640: if ((target = realloc(target, a+b)) == NULL) {
641: errprint(fmt1, nomemory);
642: exit(1);
643: }
644: tgtsize = a+b;
645: }
646: if (rlevel > 1 || !dir2slash)
647: target[b++] = '/';
648: strcpy(target+b, cp);
649: }
650:
651: /*
652: * Shrink source and target down by the last pathname component.
653: */
654: shrink()
655: {
656: if (rlevel == 1 && dir1slash)
657: source[dir1len] = '\0';
658: else
659: *rindex(source, '/') = '\0';
660: if (rlevel == 1 && dir2slash)
661: target[dir2len] = '\0';
662: else
663: *rindex(target, '/') = '\0';
664: return;
665: }
666:
667:
668: /*
669: * Returns a value equal to atoi(*cpp). Positive decimal integers only.
670: * Leaves *cpp pointing to the character that terminated the digit string.
671: */
672: new_atoi(cpp)
673: char **cpp;
674: {
675: register int sum = 0;
676: register int c;
677: register char *cp;
678:
679: sum = 0;
680: cp = *cpp;
681: while (isdigit(c = *cp++)) {
682: sum *= 10;
683: sum -= '0';
684: sum += c;
685: }
686: *cpp = cp-1;
687: return (sum);
688: }
689:
690: errprint(arg)
691: char *arg[];
692: {
693: register char *format;
694:
695: format = (errprefix) ? "cpdir: %r" : "%r";
696: fprintf(stderr, format, &arg);
697: if (wflag && splitmsg)
698: printf(format, &arg);
699: if (!eflag)
700: exit(1);
701: exitval = 1;
702: return;
703: }
704:
705: /*
706: * Interface to malloc to check for bad returns.
707: */
708: char *
709: tmalloc(n)
710: int n;
711: {
712: register char *cp;
713: if ((cp = malloc(n)) == NULL) {
714: errprint(fmt1, nomemory);
715: exit(1);
716: }
717: return (cp);
718: }
719:
720: /*
721: * Assume: source is a dir, srcstat has its status, we have write and search
722: * permission on target's parent directory, tgt_dev is the device of target's
723: * parent.
724: * Actions: Check permissions on source. Check permissions on target if it
725: * exists. If non-extant and tflag is off, make it.
726: * Side Effects: On return, if target exists, tgtstat contains its status. If
727: * it does not exist, tgtstat.st_dev is the device it would have been created
728: * on if tflag were off.
729: * Return TRUE if everything Aok, FALSE otherwise.
730: */
731: bool
732: dirchecks()
733: {
734: register int n;
735: static int status;
736:
737: if (access(source, AREAD | ASRCH) < 0) {
738: errprint(fmt2, source, nopermit);
739: return (FALSE);
740: }
741:
742: if (stat(target, &tgtstat) == 0) {
743: if ((tgtstat.st_mode & S_IFMT) != S_IFDIR) {
744: errprint(fmt3, source, "target is ", notdir);
745: return (FALSE);
746: }
747: if (access(target, AWRITE | ASRCH) < 0) {
748: errprint(fmt2, target, nopermit);
749: return (FALSE);
750: }
751: return (TRUE);
752: }
753:
754: if (tflag) {
755: tgtstat.st_dev = tgt_dev;
756: return (TRUE);
757: }
758:
759: if (mkdir(target, 0700)) {
760: errprint(fmt2, target, nomkdir);
761: return (FALSE);
762: }
763:
764: if (stat(target, &tgtstat) < 0) {
765: errprint(fmt2, target, "made but cannot stat");
766: return (FALSE);
767: }
768: return (TRUE);
769: }
770:
771: strinstall(cp)
772: register char *cp;
773: {
774: register STR *sp;
775: register int n;
776:
777: n = strhash(cp);
778: for (sp = strtab[n]; sp != NULL; sp = sp->s_next)
779: if (strcmp(cp, sp->s_str) == 0)
780: return;
781: sp = (STR *) tmalloc(sizeof(STR) + strlen(cp) + 1);
782: sp->s_next = strtab[n];
783: strtab[n] = sp;
784: strcpy(sp->s_str, cp);
785: return;
786: }
787:
788: bool
789: suppress()
790: {
791: register char *cp;
792: register STR *sp;
793: register STR **spp;
794:
795: cp = source + dir1len;
796: if (!dir1slash)
797: ++cp;
798: spp = strtab + strhash(cp);
799: if ((sp = *spp) == NULL)
800: return (FALSE);
801: while (sp != NULL) {
802: if (strcmp(cp, sp->s_str) == 0) {
803: *spp = sp->s_next;
804: free(sp);
805: if (--numsuppress == 0)
806: sflag = FALSE;
807: return (TRUE);
808: }
809: spp = &(sp->s_next);
810: sp = *spp;
811: }
812: return (FALSE);
813: }
814:
815: strhash(cp)
816: register uchar *cp;
817: {
818: register uint sum = 0;
819: for (sum = 0; *cp != '\0'; sum += *cp++)
820: ;
821: return (sum % HASHSIZE);
822: }
823:
824: LINK *
825: linklocate(flag)
826: int flag;
827: {
828: register LINK *lp;
829: register struct stat *stp;
830:
831: if (flag == SOURCE) {
832: stp = &srcstat;
833: lp = srctab[hash(stp->st_ino)];
834: }
835: else {
836: stp = &tgtstat;
837: lp = tgttab[hash(stp->st_ino)];
838: }
839:
840: for ( ; lp != NULL; lp = lp->l_next) {
841: if (lp->l_ino != stp->st_ino)
842: continue;
843: if (lp->l_dev != stp->st_dev)
844: continue;
845: --(lp->l_nlink);
846: return (lp);
847: }
848: return (NULL);
849: }
850:
851: LINK *
852: linkinstall(flag)
853: int flag;
854: {
855: register LINK **lpp;
856: register LINK *lp;
857: register struct stat *stp;
858:
859: if (flag == SOURCE) {
860: ++srclinks;
861: stp = &srcstat;
862: lpp = hash(stp->st_ino) + srctab;
863: }
864: else {
865: ++tgtlinks;
866: stp = &tgtstat;
867: lpp = hash(stp->st_ino) + tgttab;
868: }
869:
870: lp = (LINK *) tmalloc(sizeof(LINK) + strlen(target) - dir2len + 1);
871: if (!dir2slash)
872: strcpy(lp->l_name, target + dir2len + 1);
873: else
874: strcpy(lp->l_name, target + dir2len);
875: lp->l_dev = stp->st_dev;
876: lp->l_ino = stp->st_ino;
877: lp->l_tdev = tgt_dev;
878: lp->l_nlink = stp->st_nlink - 1;
879: lp->l_next = *lpp;
880: *lpp = lp;
881: return (lp);
882: }
883:
884: linkpurge(flag, lp)
885: int flag;
886: register LINK *lp;
887: {
888: register LINK *lp1;
889: register LINK **lpp;
890:
891: if (flag == SOURCE) {
892: --srclinks;
893: lpp = hash(srcstat.st_ino) + srctab;
894: }
895: else {
896: --tgtlinks;
897: lpp = hash(tgtstat.st_ino) + tgttab;
898: }
899:
900: for (lp1 = *lpp; lp1 != NULL; *lpp = lp1, lp1 = lp1->l_next) {
901: if (lp1 != lp)
902: continue;
903: *lpp = lp1->l_next;
904: free((char *)lp1);
905: return;
906: }
907: return;
908: }
909:
910: bool
911: linkattempt()
912: {
913: register LINK *lp;
914: register bool ret;
915: register char *cp;
916:
917: if ((lp = linklocate(SOURCE)) == NULL) {
918: linkinstall(SOURCE);
919: return (FALSE);
920: }
921: cp = concat(dir2, lp->l_name);
922:
923: if (tflag) {
924: if (tgt_dev != lp->l_tdev) {
925: errprint(fmt4, target, nolink, " to ", cp);
926: ++broken;
927: ret = FALSE;
928: }
929: else {
930: vprintf();
931: ret = TRUE;
932: }
933: }
934: else if (link(cp, target) == 0) {
935: vprintf();
936: ret = TRUE;
937: }
938: else {
939: errprint(fmt4, target, nolink, " to ", cp);
940: ++broken;
941: ret = FALSE;
942: }
943:
944: if (lp->l_nlink == 0)
945: linkpurge(SOURCE, lp);
946: return (ret);
947: }
948:
949: bool
950: tgtunlink()
951: {
952: register LINK *lp;
953:
954: if (stat(target, &tgtstat) < 0)
955: return (TRUE);
956: if ((tgtstat.st_mode & S_IFMT) == S_IFDIR) {
957: errprint(fmt3, target, nounlink, "directory");
958: return (FALSE);
959: }
960: else if ((tgtstat.st_mode & S_IFMT) != (srcstat.st_mode & S_IFMT)) {
961: errprint(fmt3, source, "file type mismatch with ", target);
962: return (FALSE);
963: }
964:
965: if (!tflag)
966: if (unlink(target) < 0) {
967: errprint(fmt2, target, nounlink);
968: return (FALSE);
969: }
970: if (tflag)
971: printf(fmt2, target, "unlinked");
972:
973: if ((lp = linklocate(TARGET)) != NULL) {
974: if (lp->l_nlink == 0)
975: linkpurge(TARGET, lp);
976: }
977: else if (tgtstat.st_nlink > 1)
978: linkinstall(TARGET);
979: return (TRUE);
980: }
981:
982: report()
983: {
984: register LINK *lp;
985: register LINK **lpp;
986: static char *fmtlinks = "%s external links into hierarchy %s:\n";
987:
988: if (!wflag)
989: return;
990: if (broken)
991: printf("%d internal link%s broken\n", broken,
992: (broken == 1) ? "" : "s");
993: if (srclinks) {
994: printf(fmtlinks, "missed", dir1);
995: for (lpp = srctab; lpp < srctab + HASHSIZE; ++lpp)
996: for (lp = *lpp; lp != NULL; lp = lp->l_next)
997: printf("\t%d\t%s (inode %d)\n", lp->l_nlink,
998: concat(dir1, lp->l_name), lp->l_ino);
999: }
1000: if (tgtlinks) {
1001: printf(fmtlinks, "broken", target);
1002: for (lpp = tgttab; lpp < tgttab + HASHSIZE; ++lpp)
1003: for (lp = *lpp; lp != NULL; lp = lp->l_next)
1004: printf("\t%d\t%s (inode %d)\n", lp->l_nlink,
1005: concat(dir2, lp->l_name), lp->l_ino);
1006: }
1007: return;
1008: }
1009:
1010: /*
1011: * Chown, chmod, and chdate target. Assume srcstat has status of source,
1012: * and tgtstat has status of target if it exists.
1013: */
1014: adjust()
1015: {
1016: time_t date[2];
1017:
1018: if (tflag)
1019: return;
1020: if (root)
1021: chown(target, srcstat.st_uid, srcstat.st_gid);
1022: else
1023: chown(target, uid, gid);
1024: chmod(target, srcstat.st_mode & (root ? 07777 : 06777));
1025: if (dflag) {
1026: time(&date[0]);
1027: date[1] = srcstat.st_mtime;
1028: utime(target, date);
1029: }
1030: return;
1031: }
1032:
1033: /*
1034: * Concatenate pieces of pathnames, a and b. If a is not "/" a '/' char
1035: * is placed between the names. Previous return is freed.
1036: */
1037: char *
1038: concat(a, b)
1039: register char *a;
1040: char *b;
1041: {
1042: static char *ret;
1043: register int a1;
1044: register char *rp;
1045:
1046: if (ret != NULL)
1047: free(ret);
1048: a1 = strlen(a);
1049: rp = ret = tmalloc(a1 + strlen(b) + 2);
1050: strcpy(rp, a);
1051: rp += a1;
1052: if (!isslash(ret))
1053: *rp++ = '/';
1054: strcpy(rp, b);
1055: return (ret);
1056: }
1057:
1058: char *
1059: parent(cp)
1060: register char *cp;
1061: {
1062: static char *ret;
1063: register char *cp0;
1064:
1065: if (ret != NULL)
1066: free(ret);
1067: if ((cp0 = rindex(cp, '/')) == NULL)
1068: return (dot);
1069: ret = tmalloc(cp0 - cp + 1);
1070: strncpy(ret, cp, cp0 - cp);
1071: return (ret);
1072: }
1073:
1074: bool
1075: isslash(cp)
1076: register char *cp;
1077: {
1078: register int c;
1079: while ((c = *cp++) != '\0')
1080: if (c != '/')
1081: return (FALSE);
1082: return (TRUE);
1083: }
1084:
1085: /*
1086: * Routine exectuted when SIGINT or SIGHUP caught.
1087: * Set the interrupted flag.
1088: */
1089: onintr()
1090: {
1091: signal(SIGINT, SIG_IGN);
1092: signal(SIGHUP, SIG_IGN);
1093: ++interrupted;
1094: }
1095:
1096: /*
1097: * If sig's handler is currently SIG_DFL,
1098: * catch it with onintr and return 1.
1099: * If not, leave its handler unchanged and return 0.
1100: */
1101: int
1102: catch(sig) int sig;
1103: {
1104: int (*old)();
1105:
1106: if ((old = signal(sig, SIG_IGN)) == SIG_DFL) {
1107: signal(sig, onintr);
1108: return 1;
1109: }
1110: signal(sig, old);
1111: return 0;
1112: }
1113:
1114: vprintf()
1115: {
1116: if (vflag)
1117: printf(fmt1, target);
1118: else if (aflag) {
1119: printf(fmt1a, target);
1120: fflush(stdout);
1121: }
1122: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.