xref: /original-bsd/local/local.cmd/dl.c (revision a4d3ae46)
1 static char *sccsid = "@(#)dl.c	4.2\t12/20/87";
2 
3 #include <stdio.h>
4 #include <sys/param.h>
5 #include <sys/stat.h>
6 #include <sys/dir.h>
7 #include <errno.h>
8 #include <signal.h>
9 
10 #define	DELIM	'/'
11 #define MODEBITS 07777
12 #define	ISDIR(st)	(((st).st_mode&S_IFMT) == S_IFDIR)
13 #define	ISLNK(st)	(((st).st_mode&S_IFMT) == S_IFLNK)
14 #define	ISREG(st)	(((st).st_mode&S_IFMT) == S_IFREG)
15 #define	ISDEV(st) \
16 	(((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
17 
18 struct	stat s1, s2, buf;
19 extern	unsigned errno;
20 int	errcode;
21 char    *path;
22 char    *path2;
23 char    line[1024];
24 int     cflag = 0;   /* "copy" - same as cp  */
25 int     dflag = 0;   /* "debug" - enable trace printf statements */
26 int     fflag = 0;   /* "force" option: override protection, no messages */
27 int     mflag = 0;   /* "move" - same as mv  */
28 int     cs = 0;      /* flag used with cflag to prevent endless recursion */
29 int     ms = 0;      /* flag used with mflag to prevent endless recursion */
30 int     tflag = 0;   /* restore original time stamp */
31 
32 main(argc, argv)     /* dl.c - delete, undelete, move, copy */
33 char *argv[];
34 {
35 	register char *arg;
36 	char *s;
37 	int mode;
38 	int aflg = 0;   /* "all" option: undelete all deleted files */
39 	int iflg = 0;	/* "interactive" option: send messages to user */
40 	int rflg = 0;   /* "recursive" opt., used only with n */
41 	int sflg = 0;   /* do not delete previous dlsave file */
42 	int uflg = 0;   /* undelete named files and/or directories */
43 	int nflg = 0;   /* do not provide back-up files */
44 
45 	if (isatty(0) == 0)	/* if standard i/o is not a terminal, */
46 		fflag++;		/*  turn on the f flag                */
47 
48 	if (strcmp(*argv,"ud") == 0)
49 		uflg++;
50 
51 	if (strcmp(*argv,"copy") == 0)
52 		cflag++;
53 
54 	if (strcmp(*argv,"move") == 0)
55 		mflag++;
56 
57 	while(argc>1 && argv[1][0]=='-') {
58 		arg = *++argv;
59 		argc--;
60 
61 		/*
62 		 *  all arguments following a null option (- ) are
63 		 *   treated as file names, so that file names may
64 		 *   begin with a minus sign (-).
65 		 */
66 		if (*(arg+1) == '\0') break;
67 
68 		while(*++arg != '\0')
69 			switch(*arg) {
70 			case 'a':	/* "all" */
71 				aflg++;
72 				break;
73 			case 'c':	/* "copy" */
74 				cflag++;
75 				break;
76 			case 'd':	/* "debug" */
77 				dflag++;
78 				break;
79 			case 'f':	/* "force" */
80 				fflag++;
81 				break;
82 			case 'i':	/* "interactive" */
83 				iflg++;
84 				break;
85 			case 'r':	/* "recursive" */
86 				rflg++;
87 				break;
88 			case 's':	/* "save" */
89 				sflg++;
90 				break;
91 			case 't':	/* "time" stamp */
92 				tflag++;
93 				break;
94 			case 'u':	/* "undelete" */
95 				uflg++;
96 				break;
97 			case 'm':	/* "move" */
98 				mflag++;
99 				break;
100 			case 'n':	/* "not save" */
101 				nflg++;
102 				break;
103 			default:
104 				printf("dl: unknown option %s\n", *argv);
105 				exit(1);
106 			}
107 	}
108 	if (cflag || mflag || nflg)  sflg++;
109 	/*
110 	 * set up home directory pathname
111 	 */
112 	setpath();
113 	/*
114 	 * process "undelete all" request
115 	 */
116 	if(aflg) {
117 		undelete_all(iflg);
118 		exit;
119 	}
120 	/*
121 	 * remove previously saved files unless "save" option,
122 	 *  or ud or rm mode
123 	 */
124 	if(!sflg && !uflg)
125 		dldir(path,0);
126 	if(!nflg && lstat(path,&buf) != 0) {
127 		/*
128 		 * set up .dlsave directory
129 	 	 */
130 		mode = 0777;
131           	if (mkdir(path,mode) != 0) {
132 		       	   fprintf(stderr,"dl: cannot mkdir ~/.dlsave\n");
133 			   perror(s);
134 			   exit(1);
135 		}
136 	}
137      	while(--argc > 0) {
138 		if(!strcmp(*++argv, "..")) {
139 		    	if(!fflag)
140 				fprintf(stderr, "dl: cannot remove `..'\n");
141 			continue;
142 		}
143 	       /*
144 	 	* process "undelete" request(s)
145 	 	*/
146 		if(uflg) {
147 			undelete(*argv,iflg);
148 			exit;
149 		}
150 		else {
151 		/*
152 		 * process delete request(s)
153 		 */
154 			if (cflag) {
155 				copy(*argv,argv[argc-1],iflg,rflg);
156 				exit(errcode);
157 			}
158 			if (mflag) {
159 				move(*argv,argv[argc-1],iflg);
160 				exit(errcode);
161 			}
162 			if (nflg)
163 				rm(*argv, iflg, rflg);
164 			else
165 				dl(*argv, iflg);
166 		}
167 	}
168 	exit(errcode);
169 }
170 
171 setpath()
172 {
173 	char *home;
174 	char *suffix;
175 	char *getenv();
176 
177 	home = "HOME";
178 	if ((path=getenv(home)) == NULL) {
179 		fprintf(stderr,"dl: getenv failed\n");
180 		exit(1);
181 	}
182 	suffix = "/.dlsave";
183 	strcat(path,suffix);
184 	return;
185 }
186 
187 package(argu)
188 char argu[];
189 {
190 	register int i, j, k;
191 	char  *slash, *slashdot;
192 	char  *place;
193 	char  line2[512];
194 
195 	place = line2;
196 	strcpy(place,argu);
197 	path2 = line;
198 	strcpy(path2,path);
199 	slashdot = "/.#";
200 	strcat(path2,slashdot);
201 	i = strlen(argu);
202 	slash = "/";
203 	k = 0;
204 	for (j=0;j<i;j++) {
205 		if (place[j] == *slash) {
206 			k = j + 1;
207 		}
208 	}
209 	strcat(path2,argu+k);
210 	return;
211 }
212 
213 undelete_all(iflg)
214 {
215 	struct direct *dp;
216 	DIR *dirp;
217 	char *filename;
218 	int x;
219 
220 	/*
221 	 * undelete all saved files (a option)
222 	 */
223 	if((dirp = opendir(path)) == NULL) {
224 		if(!fflag)
225 			printf("uda: cannot read %s?\n", path);
226 		exit(1);
227 	}
228 	while((dp = readdir(dirp)) != NULL) {
229              	if(dp->d_ino != 0 && !dotname(dp->d_name)) {
230 			filename = (dp->d_name)+2;
231 			package(filename);
232 			if(iflg) {
233 				printf("uda: undelete %s?", filename);
234 				if (!yes())
235 					goto no;
236 			}
237 			if(lstat(filename, &buf) == 0) {
238 				printf("uda: %s exists. Override?", filename);
239 				if(!yes())
240 					goto no;
241 			}
242 			x = move(path2,filename,0);
243 			if(iflg) {
244 			        if (x >= 0)
245 				       printf("uda: %s undeleted.\n", filename);
246 				else
247 				       printf("uda: unable to undelete %s\n", filename);
248 			}
249 no:		continue;
250 	        }
251 	}
252 	closedir(dirp);
253 	return;
254 }
255 
256 undelete(arg,iflg)
257 char arg[];
258 {
259 	struct stat buf1, buf2;
260 	int x;
261 
262 	/*
263 	 * undelete a saved file (u option)
264 	 */
265 	package(arg);
266 	if(lstat(path2, &buf1)) {
267 		if (!fflag)
268 			printf("ud: %s nonexistent\n", path2);
269 		++errcode;
270 	    	return;
271 	}
272 	if(iflg) {
273 		printf("ud: undelete %s?", arg);
274 		if(!yes())
275 			return;
276 	}
277 	if(lstat(arg, &buf2) == 0) {
278 			printf("ud: %s exists: overwrite?", arg);
279 			if(!yes())
280 				return;
281 	}
282         x = move(path2,arg,0);
283 	if(iflg) {
284 		if (x >= 0)
285       	      		printf("ud: %s undeleted.\n", arg);
286         	else
287        	      		printf("ud: unable to undelete %s\n", arg);
288 	}
289 	return;
290 }
291 
292 rm(arg, iflg, rflg)
293 char arg[];
294 {
295 	if (dflag) printf("rm entered: arg=%s fflag=%d iflg=%d rflg=%d\n",arg,fflag,iflg,rflg);
296 	if(lstat(arg, &buf)) {
297 		if (!fflag)
298 			printf("rm: %s nonexistent\n", arg);
299 		++errcode;
300 	    	return;
301 	}
302 	/*
303 	 * unlink file named by arg
304 	 */
305 	if ((buf.st_mode&S_IFMT) == S_IFDIR || rflg) {
306 		if(iflg) {
307 			printf("rm: remove directory %s?", arg);
308 			if(!yes())
309 				return;
310 		}
311 		dldir(arg, iflg);
312 		return;
313 	}
314 	if (!fflag && iflg) {
315 		printf("rm: remove %s?", arg);
316 		if (!yes())
317 			return;
318 	}
319 	else if (!fflag) {
320 		if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, 02) < 0) {
321 			printf("rm: override protection %o for %s?\n",buf.st_mode&0777,arg);
322 			if (!yes())
323 				return;
324 		}
325 	}
326 	if (unlink(arg) && !fflag) {
327 		printf ("rm: %s not removed.\n",arg);
328 		++errcode;
329 	}
330 	else {
331 		if (!fflag && iflg)
332 			printf ("rm: %s removed.\n",arg);
333 	}
334 	return;
335 }
336 
337 dl(arg, iflg)
338 char arg[];
339 {
340 	/*
341 	 * move the argument (file or directory) to
342 	 *  .dlsave directory in user's home directory
343 	 */
344 	if (dflag) printf("dl entered: arg=%s fflag=%d iflg=%d\n",arg,fflag,iflg);
345 	package(arg);
346 	move(arg,path2,iflg);
347 	return;
348 }
349 
350 dldir(arg, iflg)
351 char arg[];
352 {
353 	struct  stat  buf1, buf2;
354 	struct direct *dp;
355 	DIR *dirp;
356 	char name[BUFSIZ];
357 
358 	if (dflag) printf("dldir entered: arg=%s fflag=%d iflg=%d\n",arg,fflag,iflg);
359 	if(lstat(arg, &buf1)) {
360 		if (!fflag && iflg)
361 			printf("dldir: %s nonexistent\n", arg);
362 		++errcode;
363 	    	return;
364 	}
365 	/*
366 	 * if the argument is a directory,
367 	 * recursively remove the directory's contents
368 	 * and then the directory.
369 	 */
370 	if ((buf1.st_mode&S_IFMT) == S_IFDIR) {
371 		if (access(arg, 02) < 0) {
372 			if(!fflag) {
373 			 	printf("dldir: %s not accessable\n",arg);
374 			}
375 			errcode++;
376 			return;
377 		}
378 		if((dirp = opendir(arg)) == NULL)
379 			exit(1);
380 		while((dp = readdir(dirp)) != NULL) {
381 			if(dp->d_ino != 0 && !dotname(dp->d_name)) {
382 				(void) sprintf(name, "%s/%s", arg, dp->d_name);
383 				if (dflag) printf("dldir: name= %s\n",name);
384 				if(lstat(name, &buf2)) {
385 					if (!fflag)
386 					   printf("dldir: %s nonexistent\n", name);
387 					++errcode;
388 	    				return;
389 				}
390 				if ((buf2.st_mode&S_IFMT) == S_IFDIR) {
391     				if(!fflag && iflg) {
392 					printf("dldir: delete directory %s?", name);
393 					if(!yes())
394 						return;
395    				}
396   				dldir(name, iflg);
397 				}
398 				else {
399     					if(!fflag && iflg) {
400 					   printf("dldir: delete file %s?", name);
401 						if(!yes())
402 							return;
403    					}
404 			       		/*
405 	 				 * permanently remove the file
406 	 				 */
407 					if (unlink(name)) {
408 					  if (!fflag)
409 					   printf("dldir: %s not removed\n", name);
410 					   ++errcode;
411 					}
412 					else {
413 					   if (!fflag && iflg)
414 					     printf("dldir: %s removed.\n", name);
415 					}
416 				}
417 			}
418 		}
419 		closedir(dirp);
420 		if (dotname(arg))
421 			return;
422 		if (rmdir(arg) < 0) {
423 			if(!fflag && iflg) {
424 				fprintf(stderr, "dldir: rmdir:");
425 				perror(arg);
426 			}
427 			errcode++;
428 		}
429 		else {
430 			if(!fflag && iflg)
431 				printf("dldir: directory %s removed.\n",arg);
432 		}
433 	return;
434 	}
435 }
436 
437 dotname(s)
438 char *s;
439 {
440 	if(s[0] == '.')
441 		if(s[1] == '.')
442 			if(s[2] == '\0')
443 				return(1);
444 			else
445 				return(0);
446 		else if(s[1] == '\0')
447 			return(1);
448 	return(0);
449 }
450 
451 yes()
452 {
453 	int i, b;
454 
455 	i = b = getchar();
456 	while(b != '\n' && b != EOF)
457 		b = getchar();
458 	return(i == 'y');
459 }
460 
461 move(source, target, iflag)
462 	char *source, *target;
463 {
464 	int targetexists;
465 	int sw = 0;
466 
467 	if (dflag) printf("move entered: source=%s target=%s fflag=%d iflag=%d\n",source,target,fflag,iflag);
468 	if (lstat(source, &s1) < 0) {
469 		if (!fflag)
470 			error("cannot access %s", source);
471 		return (1);
472 	}
473 	if (dflag) printf("move: lstat(%s) successful\n",source);
474 	/*
475 	 * First, try to rename source to target.
476 	 */
477 	targetexists = lstat(target, &s2) >= 0;
478 	if (targetexists) {
479 		if (dflag) printf("move: lstat(%s) successful\n",target);
480 		if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
481 			if (!fflag)
482 			      error("%s and %s are identical", source, target);
483 			return (1);
484 		}
485 		if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) {
486 			if (query("override protection %o for %s? ",
487 			  s2.st_mode & MODEBITS, target) == 0)
488 				return (1);
489 			sw++;
490 		}
491 		if (mflag && ms == 0) {
492 			if (ISREG(s2)) {
493 				if (!fflag && sw == 0) {
494 		   		printf("overwrite file %s?", target);
495 				if(!yes())
496 					return;
497 				}
498 			ms = 1;
499 			dl (target, 0);
500 			}
501 			else
502 			if (s1.st_dev != s2.st_dev && ISDIR(s2))
503 				goto copyit;
504 		}
505 	}
506 	if (!fflag && iflag && !mflag) {
507 		if (ISDIR(s1))
508 			printf("dl: delete directory %s?", source);
509 		else
510 			printf("dl: delete file %s?", source);
511 		if(!yes())
512 			return;
513 	}
514 	if(dflag) printf("move(1)rename: source=%s, target=%s\n",source, target);
515 	if (rename(source, target) >= 0) {
516 		if (!fflag && iflag && !mflag)
517 			printf("dl: %s deleted. \n",source);
518 		if (dflag) printf("move: %s renamed %s.\n",source,target);
519 		return (0);
520 	}
521 	if (dflag) printf("move/rename: errno=%d\n",errno);
522 	if (errno != EXDEV) {
523 		if (!fflag && iflag) {
524 			Perror2(source, "rename");
525 		}
526 		goto copyit;
527 	}
528 	if (targetexists && unlink(target) < 0) {
529 		if(!fflag)
530 			error("cannot unlink %s", target);
531 		return (1);
532 	}
533 	if (dflag) printf("move: target unlinked\n");
534 
535 	/*
536 	 * If file or directory cannot be renamed:
537 	 *  If directory, copy it with r option
538 	 *   and delete the source
539 	 */
540 copyit:	if (ISDIR(s1)) {
541 	     if (dflag) printf("move: directory copy %s to %s\n",source,target);
542 		copy (source, target, iflag, 1);
543 		dldir (source, iflag);
544 		return(0);
545 	}
546 
547 	/*
548 	 *  If link, recreate symbolic link
549 	 */
550 	if (ISLNK(s1)) {
551 		register m;
552 		char symln[MAXPATHLEN];
553 
554 		if (readlink(source, symln, sizeof (symln)) < 0) {
555 			if (!fflag)
556 				Perror(source);
557 				return (1);
558 		}
559 		m = umask(~(s1.st_mode & MODEBITS));
560 		if (symlink(symln, target) < 0) {
561 			if (!fflag)
562 				Perror(target);
563 				return (1);
564 		}
565 		if (dflag) printf("move: symlink to target successful\n");
566 		(void) umask(m);
567 		goto cleanup;
568 	}
569 
570 	/*
571 	 *  If device
572 	 */
573 	if (ISDEV(s1)) {
574 		if (mknod(target, s1.st_mode, s1.st_rdev) < 0) {
575 			if (!fflag)
576 				Perror(target);
577 			return (1);
578 		}
579 		if (dflag) printf("move: mknod for target successful\n");
580 		goto cleanup;
581 	}
582 
583 	/*
584 	 *  If regular file, copy it
585 	 */
586 	if (ISREG(s1)) {
587 	     	if(dflag) printf("move: file copy %s to %s\n",source,target);
588 		copy(source, target, iflag, 0);
589 		goto cleanup;
590  	}
591 
592 	if (!fflag)
593 		error("%s: unknown file type %o", source, s1.st_mode);
594 	return (1);
595 
596 	/*
597 	 *  If a move has been successful, erase the source
598 	 */
599 cleanup:
600 	if (dflag) printf("move: cleanup\n");
601 	if (unlink(source) < 0) {
602 		if (!fflag)
603 			error("cannot unlink %s", source);
604 		return (1);
605 	}
606 	if (dflag) printf("move: %s unlinked.\n",source);
607 	if (!fflag && iflag && !mflag)
608 		printf("dl: %s deleted.\n",source);
609 	return (0);
610 }
611 
612 /*VARARGS*/
613 query(prompt, a1, a2)
614 	char *a1;
615 {
616 	register char i, c;
617 
618 	fprintf(stderr, prompt, a1, a2);
619 	i = c = getchar();
620 	while (c != '\n' && c != EOF)
621 		c = getchar();
622 	return (i == 'y');
623 }
624 
625 error(fmt, a1, a2)
626 	char *fmt;
627 {
628 	fprintf(stderr, "dl: ");
629 	fprintf(stderr, fmt, a1, a2);
630 	fprintf(stderr, "\n");
631 }
632 
633 Perror(s)
634 	char *s;
635 {
636 	char buf[MAXPATHLEN + 10];
637 
638 	(void) sprintf(buf, "move: %s", s);
639 	perror(buf);
640 }
641 
642 Perror2(s1, s2)
643 	char *s1, *s2;
644 {
645 	char buf[MAXPATHLEN + 20];
646 
647 	(void) sprintf(buf, "dl: %s: %s", s1, s2);
648 	perror(buf);
649 }
650 
651 #define	BSIZE	8192
652 
653 char	*rindex();
654 
655 copy(from, to, iflag, rflag)
656 	char *from, *to;
657 {
658 	int fold, fnew, n;
659 	char *last, destname[BSIZE], buf[BSIZE];
660 	struct stat stfrom, stto;
661 	time_t tv[2];
662 
663 	if (dflag) printf("copy entered: from=%s to=%s iflag=%d rflag=%d\n",from,to,iflag,rflag);
664 	fold = open(from, 0);
665 	if (fold < 0) {
666 		Cerror(from,fflag);
667 		return (1);
668 	}
669 	if (fstat(fold, &stfrom) < 0) {
670 		Cerror(from,fflag);
671 		(void) close(fold);
672 		return (1);
673 	}
674 	if (dflag) printf("copy: fstat(%s) OK.\n",from);
675 	if (stat(to, &stto) >= 0 &&
676 	   (stto.st_mode&S_IFMT) == S_IFDIR) {
677 		last = rindex(from, '/');
678 		if (last) last++; else last = from;
679 		if (strlen(to) + strlen(last) >= BSIZE - 1) {
680 			fprintf(stderr, "cp: %s/%s: Name too long", to, last);
681 			(void) close(fold);
682 			return(1);
683 		}
684 		(void) sprintf(destname, "%s/%s", to, last);
685 		if (dflag) printf("copy: stat %s & %s is dir., to=%s.\n",to,to,destname);
686 		to = destname;
687 	}
688 	if (!rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
689 		fprintf(stderr, "cp: %s is a directory, and option -r not chosen.  Job aborted.\n", from);
690 		return(1);
691 	}
692 	if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
693 		(void) close(fold);
694 		if (dflag) printf("copy: rflag & from is dir., %s closed.\n",from);
695 		if (stat(to, &stto) < 0) {
696 			if (mkdir(to, (int)stfrom.st_mode) < 0) {
697 				Cerror(to,fflag);
698 				return (1);
699 			}
700 			if (dflag) printf("copy: stat(%s) failed & mkdir % successful.\n",to,to);
701 		}
702 		else {
703 			if (!fflag) {
704 				if ((stto.st_mode&S_IFMT) == S_IFDIR) {
705 				dl(to, iflag);
706 				}
707 				else {
708 			      		fprintf(stderr, "cp: %s: Not a directory.\n", to);
709 			      		return (1);
710 				}
711 			}
712 		}
713 		if (dflag) printf("copy: return with rcopy(%s,%s,%d,%d)\n",from,to,iflag,rflag);
714 		return (rcopy(from, to, iflag, rflag));
715 	}
716 	if (stat(to, &stto) >= 0) {
717 		if (dflag) printf("cp:stat(%s) o.k.\n",to);
718 		if (stfrom.st_dev == stto.st_dev &&
719 		   stfrom.st_ino == stto.st_ino) {
720 			fprintf(stderr, "cp: Cannot copy file to itself.\n");
721 			(void) close(fold);
722 			return (1);
723 		}
724 		if (cflag && cs == 0) {
725 			if (!fflag)
726 			     fprintf (stderr, "cp: %s exists: overwrite? ", to);
727 			     if (!yes()) {
728 			        	(void) close(fold);
729 					return(1);
730 			}
731 			dl(to, 0);
732 			cs = 1;
733 		}
734 	}
735 	fnew = creat(to, (int)stfrom.st_mode);
736 	if (fnew < 0) {
737 		Cerror(to,fflag);
738 		(void) close(fold); return(1);
739 	}
740 	if (dflag) printf("copy: creat(%s,%d) successful.\n",to,stfrom.st_mode);
741 	for (;;) {
742 		n = read(fold, buf, BSIZE);
743 		if (n == 0)
744 			break;
745 		if (n < 0) {
746 			Cerror(from,fflag);
747 			(void) close(fold); (void) close(fnew); return (1);
748 		}
749 		if (write(fnew, buf, n) != n) {
750 			Cerror(to,fflag);
751 			(void) close(fold); (void) close(fnew); return (1);
752 		}
753 	}
754 	if (dflag) printf("copy: %s copied to %s.\n",from,to);
755 	if (!tflag) {
756 		/* restore original time-stamp */
757 		tv[0] = stfrom.st_atime;
758 		tv[1] = stfrom.st_mtime;
759 		(void) utime(to, tv);
760 		if (dflag) printf("copy: tflag on, tv[0]=%d, tv[1]=%d.\n",tv[0], tv[1]);
761 	}
762 	if (dflag) printf("copy: returning from copy, from=%s, to=%s.\n",from,to);
763 	(void) close(fold); (void) close(fnew); return (0);
764 }
765 
766 rcopy(from, to, iflag, rflag)
767 	char *from, *to;
768 {
769 	DIR *fold = opendir(from);
770 	struct direct *dp;
771 	int errs = 0;
772 	char fromname[BUFSIZ];
773 
774 	if (dflag) printf("rcopy: entered: from=%s, to=%s.\n",from,to);
775 	if (fold == 0) {
776 		Cerror(from,fflag);
777 		return (1);
778 	}
779 	for (;;) {
780 		dp = readdir(fold);
781 		if (dp == 0) {
782 			closedir(fold);
783 			return (errs);
784 		}
785 		if (dp->d_ino == 0)
786 			continue;
787 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
788 			continue;
789 		if (strlen(from) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
790 			if (!fflag) {
791 				fprintf(stderr, "cp: %s/%s: Name too long.\n",
792 			    		from, dp->d_name);
793 			}
794 			errs++;
795 			continue;
796 		}
797 		(void) sprintf(fromname, "%s/%s", from, dp->d_name);
798 		if (dflag) printf("rcopy: copy(%s,%s,%d,%d)\n",fromname,to,iflag,rflag);
799 		errs += copy(fromname, to, iflag, rflag);
800 	}
801 }
802 
803 Cerror(s)
804 	char *s;
805 {
806 	if (!fflag) {
807 	 	fprintf(stderr, "cp: ");
808 		perror(s);
809 	}
810 }
811