Sun's version
[unix-history] / usr / src / old / cpio / cpio.c
CommitLineData
76bbb78b
KB
1/* Copyright (c) 1988 AT&T */
2/* All Rights Reserved */
3
4/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
5/* The copyright notice above does not evidence any */
6/* actual or intended publication of such source code. */
7
8#ident "@(#)cpio:cpio.c 1.30.1.11"
9/* /sccs/src/cmd/s.cpio.c
10 cpio.c 1.30.1.11 1/11/86 13:46:48
11 Reworked cpio which uses getopt(3) to interpret flag arguments and
12 changes reels to the save file name.
13 Performance and size improvements.
14*/
15
16/* cpio COMPILE: cc -O cpio.c -s -i -o cpio -lgen -lerr
17 cpio -- copy file collections
18
19*/
76bbb78b
KB
20#include <errno.h>
21#include <fcntl.h>
22#include <memory.h>
23#include <stdio.h>
24#include <string.h>
25#include <signal.h>
26#include <varargs.h>
fd2d2fec
KB
27#include <sys/param.h>
28#include <sys/types.h>
76bbb78b
KB
29#include <sys/stat.h>
30
fd2d2fec
KB
31struct utimbuf {
32 time_t actime;
33 time_t modtime;
34};
35#ifndef S_IFIFO
36#define S_IFIFO 010000
37#endif
38
76bbb78b
KB
39#define EQ(x,y) (strcmp(x,y)==0)
40
41 /* MKSHORT: for VAX, Interdata, ... */
42 /* Take a 4-byte long, lv, and turn it */
43 /* into an array of two 2-byte shorts, v*/
44#define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];}
45
46#define MAGIC 070707 /* cpio magic number */
fd2d2fec 47#define BSMAGIC 0143561 /* byte-swapped cpio magic number */
76bbb78b
KB
48#define IN 'i' /* copy in */
49#define OUT 'o' /* copy out */
50#define PASS 'p' /* direct copy */
51#define HDRSIZE (Hdr.h_name - (char *)&Hdr) /* header size minus filename field */
52#define LINKS 500 /* no. of links allocated per bunch */
53#define CHARS 76 /* ASCII header size minus filename field */
54#define BUFSIZE 512 /* In u370, can't use BUFSIZ or BSIZE */
55#define CPIOBSZ 4096 /* file read/write */
56#define MK_USHORT(a) (a & 00000177777) /* Make unsigned shorts for portable */
57 /* header. Hardware may only know */
58 /* integer operations and sign extend */
59 /* the large unsigned short resulting */
60 /* in 8 rather than 6 octal char in */
61 /* the header. */
62
63static struct stat Statb, Xstatb;
64
65 /* Cpio header format */
66static struct header {
67 short h_magic;
68 short h_dev;
69 ushort h_ino;
70 ushort h_mode,
71 h_uid,
72 h_gid;
73 short h_nlink;
74 short h_rdev;
75 short h_mtime[2],
76 h_namesize,
77 h_filesize[2];
78 char h_name[256];
79} Hdr;
80
fd2d2fec 81char Symlbuf[MAXPATHLEN + 1]; /* target of symbolic link */
76bbb78b
KB
82static unsigned Bufsize = BUFSIZE; /* default record size */
83static char Buf[CPIOBSZ], *Cbuf;
84static char *Cp;
85
86
87static
88short Option,
89 Dir,
90 Uncond,
91 PassLink,
92 Rename,
93 Toc,
94 Verbose,
95 Mod_time,
96 Acc_time,
97 Cflag,
98 fflag,
99 Swap,
100 byteswap,
76bbb78b
KB
101 halfswap;
102
103static
104int Ifile,
105 Ofile,
106 Input = 0,
107 Output = 1;
108 /* sBlocks: short Blocks. Cumulative character */
109 /* count for short reads in bread(). Encountered */
110 /* with communication lines and pipes as in: */
111 /* split -100 cpio_archive; cat xa* | cpio -icd */
112static
113long sBlocks,
114 Blocks,
115 Longfile,
116 Longtime;
117
118static
119char Fullname[256],
120 Name[256];
121static
122int Pathend;
123static
124char *swfile;
125static
126char *eommsg = "Change to part %d and press RETURN key. [q] ";
127
128static
129FILE *Rtty,
130 *Wtty;
131static
132char ttyname[] = "/dev/tty";
133
134static
135char **Pattern = 0;
136static
137char Chdr[500];
138static
139short Dev;
140ushort Uid,
141 A_directory,
142 A_special,
fd2d2fec 143 A_symlink,
76bbb78b
KB
144 Filetype = S_IFMT;
145
146extern errno;
147extern void exit();
76bbb78b
KB
148char *malloc();
149FILE *popen();
150
fd2d2fec
KB
151static char *smemcpy();
152
76bbb78b
KB
153static
154union {
155 long l;
156 short s[2];
157 char c[4];
158} U;
159
160/* for VAX, Interdata, ... */
161static
162long mklong(v)
163short v[];
164{
165 U.l = 1;
166 if(U.c[0])
167 U.s[0] = v[1], U.s[1] = v[0];
168 else
169 U.s[0] = v[0], U.s[1] = v[1];
170 return U.l;
171}
172
173main(argc, argv)
174char **argv;
175{
176 register ct;
177 long filesz;
fd2d2fec 178 int symlsz;
76bbb78b
KB
179 register char *fullp;
180 register i;
181 int ans;
fd2d2fec 182 register char *symlinkp;
76bbb78b
KB
183 short select; /* set when files are selected */
184 extern char *optarg;
185 extern int optind;
186
fd2d2fec
KB
187 signal(SIGSYS, SIG_IGN);
188 if(argc <= 1 || *argv[1] != '-')
76bbb78b
KB
189 usage();
190 Uid = getuid();
76bbb78b 191
fd2d2fec 192 while( (ans = getopt( argc, argv, "aBC:ifopcdlmrSsbtuvM:6eI:O:")) != EOF ) {
76bbb78b
KB
193
194 switch( ans ) {
195 case 'a': /* reset access time */
196 Acc_time++;
197 break;
198 case 'B': /* change record size to 5120 bytes */
199 Bufsize = 5120;
200 break;
201 case 'C': /* reset buffer size to arbitrary valu
202 */
203 Bufsize = atoi( optarg );
fd2d2fec
KB
204 if( Bufsize == 0 ) {
205 fperr("Illegal argument to -%c, '%s'",
76bbb78b 206 ans, optarg );
fd2d2fec
KB
207 exit(2);
208 }
76bbb78b
KB
209 break;
210 case 'i':
211 Option = IN;
212 break;
213 case 'f': /* copy files not matched by patterns */
214 fflag++;
215 break;
216 case 'o':
217 Option = OUT;
218 break;
219 case 'p':
220 Option = PASS;
221 break;
222 case 'c': /* ASCII header */
223 Cflag++;
224 break;
225 case 'd': /* create directories when needed */
226 Dir++;
227 break;
228 case 'l': /* link files, when necessary */
229 PassLink++;
230 break;
231 case 'm': /* retain mod time */
232 Mod_time++;
233 break;
234 case 'r': /* rename files interactively */
235 Rename++;
236 Rtty = fopen(ttyname, "r");
237 Wtty = fopen(ttyname, "w");
238 if(Rtty==NULL || Wtty==NULL) {
fd2d2fec 239 fperrno("Cannot rename (%s missing)",
76bbb78b 240 ttyname );
fd2d2fec 241 exit(2);
76bbb78b
KB
242 }
243 break;
244 case 'S': /* swap halfwords */
245 halfswap++;
246 Swap++;
247 break;
248 case 's': /* swap bytes */
249 byteswap++;
250 Swap++;
251 break;
252 case 'b': /* swap both bytes and halfwords */
fd2d2fec
KB
253 halfswap++;
254 byteswap++;
76bbb78b
KB
255 Swap++;
256 break;
257 case 't': /* table of contents */
258 Toc++;
259 break;
260 case 'u': /* copy unconditionally */
261 Uncond++;
262 break;
263 case 'v': /* verbose - print out file names */
fd2d2fec 264 Verbose++;
76bbb78b
KB
265 break;
266 case 'M': /* alternate message for end-of-media */
267 eommsg = optarg;
268 break;
269 case '6': /* for old, sixth-edition files */
270 Filetype = 060000;
271 break;
272 case 'I':
273 chkswfile( swfile, ans, Option );
fd2d2fec
KB
274 if( (i = open( optarg, O_RDONLY ) ) < 0) {
275 fperrno("Cannot open <%s> for input", optarg);
276 exit(2);
277 }
278 if( dup2(i, Input ) < 0 ) {
279 fperrno("Cannot dup to standard input");
280 exit(2);
281 }
76bbb78b
KB
282 swfile = optarg;
283 break;
284 case 'O':
285 chkswfile( swfile, ans, Option );
fd2d2fec
KB
286 if( (i = open( optarg, O_WRONLY | O_CREAT | O_TRUNC,
287 0666 ) ) < 0) {
288 fperrno("Cannot open <%s> for output", optarg);
289 exit(2);
290 }
291 if( dup2(i, Output ) < 0 ) {
292 fperrno("Cannot dup to standard output");
293 exit(2);
294 }
76bbb78b
KB
295 swfile = optarg;
296 break;
297 default:
298 usage();
299 }
300 }
301 if(!Option) {
fd2d2fec
KB
302 (void) fprintf(stderr,
303 "Options must include one of -o, -i, or -p\n");
304 exit(2);
76bbb78b
KB
305 }
306
307 if(Option == PASS) {
308 if(Rename) {
fd2d2fec
KB
309 (void) fprintf(stderr,
310 "Pass and Rename cannot be used together\n");
311 exit(2);
76bbb78b
KB
312 }
313 if( Bufsize != BUFSIZE ) {
314 fprintf( stderr, "`B' or `C' option is irrelevant with the '-p' option\n");
315 Bufsize = BUFSIZE;
316 }
317
318 }else {
fd2d2fec
KB
319 Cp = Cbuf = (char *)malloc(Bufsize);
320 if(Cp == NULL) {
321 perror("cpio");
322 exit(2);
323 }
76bbb78b
KB
324 }
325 argc -= optind;
326 argv += optind;
327
328 switch(Option) {
329 case OUT:
330 if(argc != 0)
331 usage();
332 /* get filename, copy header and file out */
333 while(getname()) {
334 if( mklong(Hdr.h_filesize) == 0L) {
335 if( Cflag )
336 bwrite(Chdr,CHARS+Hdr.h_namesize);
337 else
338 bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
339 if(Verbose)
fd2d2fec
KB
340 (void) fprintf(stderr, "%s\n",
341 Hdr.h_name);
342 continue;
343 } else if( A_symlink ) {
344 symlsz = (int) mklong(Hdr.h_filesize);
345 if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
346 fperrno("Cannot read symbolic link <%s>",
347 Hdr.h_name);
348 continue;
349 }
350 Symlbuf[symlsz] = '\0';
351 bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
352 bwrite(Symlbuf, symlsz);
353 if(Verbose)
354 (void) fprintf(stderr, "%s\n",
355 Hdr.h_name);
76bbb78b
KB
356 continue;
357 }
358 if((Ifile = open(Hdr.h_name, 0)) < 0) {
fd2d2fec 359 fperrno("Cannot open <%s>", Hdr.h_name);
76bbb78b
KB
360 continue;
361 }
362 if ( Cflag )
363 bwrite(Chdr,CHARS+Hdr.h_namesize);
364 else
365 bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
366 for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
367 ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
368 if(read(Ifile, Buf, ct) < 0) {
fd2d2fec 369 fperrno("Cannot read %s", Hdr.h_name);
76bbb78b
KB
370 continue;
371 }
372 bwrite(Buf,ct);
373 }
374 close(Ifile);
fd2d2fec
KB
375 if(Acc_time) {
376 struct utimbuf utb;
377
378 utb.actime = Statb.st_atime;
379 utb.modtime = Statb.st_mtime;
380 (void)utime(Hdr.h_name, &utb);
381 }
76bbb78b 382 if(Verbose)
fd2d2fec 383 (void) fprintf(stderr, "%s\n", Hdr.h_name);
76bbb78b
KB
384 }
385
386 /* copy trailer, after all files have been copied */
387 strcpy(Hdr.h_name, "TRAILER!!!");
388 Hdr.h_magic = MAGIC;
389 MKSHORT(Hdr.h_filesize, 0L);
390 Hdr.h_namesize = strlen("TRAILER!!!") + 1;
391 if ( Cflag ) {
392 bintochar(0L);
393 bwrite(Chdr, CHARS+Hdr.h_namesize);
394 }
395 else
396 bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
397 bwrite(Cbuf, Bufsize);
398 break;
399
400 case IN:
401 if(argc > 0 ) { /* save patterns, if any */
402 Pattern = argv;
403 }
404 pwd();
405 chkhdr();
406 while(gethdr()) {
fd2d2fec
KB
407 if (A_symlink) {
408 symlsz = (int) mklong(Hdr.h_filesize);
409 bread(Symlbuf, symlsz);
410 Symlbuf[symlsz] = '\0';
411 if((void) ckname(Hdr.h_name) && !Toc)
412 (void)openout(Hdr.h_name, Symlbuf);
413 } else {
414 if( (select = ckname(Hdr.h_name)) && !Toc )
415 Ofile = openout(Hdr.h_name, (char *)0);
416 else
417 Ofile = 0;
418 for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
419 ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
420 bread(Buf, ct);
421 if(Ofile) {
422 if(Swap)
423 swap(Buf,ct,byteswap,halfswap);
424 if(write(Ofile, Buf, ct) < 0) {
425 fperrno("Cannot write %s", Hdr.h_name);
426 continue;
427 }
76bbb78b
KB
428 }
429 }
fd2d2fec
KB
430 if( Ofile ) {
431 (void) close(Ofile);
432 if(chmod(Hdr.h_name, Hdr.h_mode) < 0)
433 fperrno("Cannot change mode of <%s>",
434 Hdr.h_name);
435 set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
436 }
76bbb78b
KB
437 }
438 if(select) {
439 if(Verbose)
440 if(Toc)
441 pentry(Hdr.h_name);
442 else
fd2d2fec 443 puts(Hdr.h_name);
76bbb78b
KB
444 else if(Toc)
445 puts(Hdr.h_name);
446 }
447 }
448 break;
449
450 case PASS: /* move files around */
451 if(argc != 1)
452 usage();
453 if(access(argv[0], 2) == -1) {
fd2d2fec
KB
454 (void) fperrno("Cannot write in <%s>", argv[0]);
455 exit(2);
76bbb78b
KB
456 }
457 strcpy(Fullname, argv[0]); /* destination directory */
fd2d2fec
KB
458 if(stat(Fullname, &Xstatb) < 0) {
459 fperrno("Cannot stat <%s>", Fullname);
460 exit(2);
461 }
462 if((Xstatb.st_mode&S_IFMT) != S_IFDIR) {
463 (void) fprintf(stderr, "<%s> is not a directory",
464 Fullname);
465 exit(2);
466 }
76bbb78b
KB
467 Dev = Xstatb.st_dev;
468 if( Fullname[ strlen(Fullname) - 1 ] != '/' )
469 strcat(Fullname, "/");
470 fullp = Fullname + strlen(Fullname);
471
472 while(getname()) {
473 if (A_directory && !Dir)
fd2d2fec 474 fperr("Use `-d' option to copy <%s>",
76bbb78b
KB
475 Hdr.h_name);
476 if(!ckname(Hdr.h_name))
477 continue;
478 i = 0;
479 while(Hdr.h_name[i] == '/')
480 i++;
481 strcpy(fullp, &(Hdr.h_name[i]));
482
483 if( PassLink && !A_directory && Dev == Statb.st_dev ) {
484 if(link(Hdr.h_name, Fullname) < 0) {
485 switch(errno) {
486 case ENOENT:
487 if(missdir(Fullname) != 0) {
fd2d2fec
KB
488 fperrno("Cannot create directory for <%s>",
489 Fullname);
76bbb78b
KB
490 continue;
491 }
492 break;
493 case EEXIST:
494 if(unlink(Fullname) < 0) {
fd2d2fec
KB
495 fperrno("Cannot unlink <%s>",
496 Fullname);
76bbb78b
KB
497 continue;
498 }
499 break;
500 default:
fd2d2fec
KB
501 fperrno("Cannot link <%s> to <%s>",
502 Hdr.h_name, Fullname);
76bbb78b
KB
503 continue;
504 }
505 if(link(Hdr.h_name, Fullname) < 0) {
fd2d2fec
KB
506 fperrno("Cannot link <%s> to <%s>",
507 Hdr.h_name, Fullname);
76bbb78b
KB
508 continue;
509 }
510 }
511
512 goto ckverbose;
513 }
fd2d2fec
KB
514 if( A_symlink ) {
515 symlsz = (int) mklong(Hdr.h_filesize);
516 if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
517 fperrno("Cannot read symbolic link <%s>",
518 Hdr.h_name);
519 continue;
520 }
521 Symlbuf[symlsz] = '\0';
522 if(!openout(Fullname, Symlbuf))
523 continue;
524 Blocks += ((symlsz + (BUFSIZE - 1)) / BUFSIZE);
525 if(Verbose)
526 puts(Fullname);
527 continue;
528 }
529 if(!(Ofile = openout(Fullname, (char *)0)))
76bbb78b 530 continue;
fd2d2fec
KB
531 if((Ifile = open(Hdr.h_name, 0)) < 0) {
532 fperrno("Cannot open <%s>", Hdr.h_name);
76bbb78b
KB
533 close(Ofile);
534 continue;
535 }
536 filesz = Statb.st_size;
537 for(; filesz > 0; filesz -= CPIOBSZ) {
538 ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
539 if(read(Ifile, Buf, ct) < 0) {
fd2d2fec 540 fperrno("Cannot read %s", Hdr.h_name);
76bbb78b
KB
541 break;
542 }
fd2d2fec
KB
543 if(write(Ofile, Buf, ct) < 0) {
544 fperrno("Cannot write %s", Hdr.h_name);
545 break;
546 }
547 /* Removed u370 ifdef which caused cpio */
548 /* to report blocks in terms of 4096 bytes. */
76bbb78b
KB
549
550 Blocks += ((ct + (BUFSIZE - 1)) / BUFSIZE);
551 }
552 close(Ifile);
fd2d2fec
KB
553 if(Acc_time) {
554 struct utimbuf utb;
555
556 utb.actime = Statb.st_atime;
557 utb.modtime = Statb.st_mtime;
558 (void)utime(Hdr.h_name, &utb);
559 }
76bbb78b
KB
560 if(Ofile) {
561 close(Ofile);
fd2d2fec
KB
562 if(chmod(Fullname, Hdr.h_mode) < 0)
563 fperrno("Cannot change mode of <%s>",
564 Fullname);
76bbb78b
KB
565 set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
566ckverbose:
567 if(Verbose)
fd2d2fec 568 puts(Fullname);
76bbb78b
KB
569 }
570 }
571 }
572 /* print number of blocks actually copied */
573 Blocks += ((sBlocks + (BUFSIZE - 1)) / BUFSIZE);
fd2d2fec 574 (void) fprintf(stderr, "%ld blocks\n", Blocks * (Bufsize>>9));
76bbb78b
KB
575 exit(0);
576}
577
578static
579usage()
580{
fd2d2fec
KB
581 (void) fprintf("Usage: %s\n %s\n %s\n %s\n %s\n",
582 "cpio -o[acvB] <name-list >collection",
583 "cpio -o[acvB] -Ocollection <name-list",
584 "cpio -i[cdmrstuvfB6] [ pattern ... ] <collection",
585 "cpio -i[cdmrstuvfB6] -Icollection [ pattern ... ]",
586 "cpio -p[adlmruv] directory <name-list");
76bbb78b
KB
587}
588
589static
590chkswfile( sp, c, option )
591char *sp;
592char c;
593short option;
594{
fd2d2fec
KB
595 if( !option ) {
596 fperr( "-%c must be specified before -%c option",
76bbb78b 597 c == 'I' ? 'i' : 'o', c );
fd2d2fec
KB
598 exit(2);
599 }
600 if( (c == 'I' && option != IN) || (c == 'O' && option != OUT) ) {
601 fperr( "-%c option not permitted with -%c option", c,
76bbb78b 602 option );
fd2d2fec
KB
603 exit(2);
604 }
76bbb78b
KB
605 if( !sp )
606 return;
fd2d2fec
KB
607 fperr("No more than one -I or -O flag permitted");
608 exit(2);
76bbb78b
KB
609}
610
611static
612getname() /* get file name, get info for header */
613{
614 register char *namep = Name;
615 register ushort ftype;
fd2d2fec 616 struct stat Lstatb;
76bbb78b
KB
617 long tlong;
618
619 for(;;) {
620 if(gets(namep) == NULL)
621 return 0;
622 while(*namep == '.' && namep[1] == '/') {
623 namep++;
624 while(*namep == '/') namep++;
625 }
626 strcpy(Hdr.h_name, namep);
fd2d2fec
KB
627 if(lstat(namep, &Statb) < 0) {
628 fperrno("Cannot stat <%s>", Hdr.h_name);
76bbb78b
KB
629 continue;
630 }
631 ftype = Statb.st_mode & Filetype;
632 A_directory = (ftype == S_IFDIR);
633 A_special = (ftype == S_IFBLK)
634 || (ftype == S_IFCHR)
635 || (ftype == S_IFIFO);
fd2d2fec 636 A_symlink = (ftype == S_IFLNK);
76bbb78b
KB
637 Hdr.h_magic = MAGIC;
638 Hdr.h_namesize = strlen(Hdr.h_name) + 1;
639 Hdr.h_uid = Statb.st_uid;
640 Hdr.h_gid = Statb.st_gid;
641 Hdr.h_dev = Statb.st_dev;
642 Hdr.h_ino = Statb.st_ino;
643 Hdr.h_mode = Statb.st_mode;
644 MKSHORT(Hdr.h_mtime, Statb.st_mtime);
645 Hdr.h_nlink = Statb.st_nlink;
fd2d2fec
KB
646 tlong = ((Hdr.h_mode&S_IFMT) == S_IFREG ||
647 (Hdr.h_mode&S_IFMT) == S_IFLNK)? Statb.st_size: 0L;
76bbb78b
KB
648 MKSHORT(Hdr.h_filesize, tlong);
649 Hdr.h_rdev = Statb.st_rdev;
650 if( Cflag )
651 bintochar(tlong);
652 return 1;
653 }
654}
655
656static
657bintochar(t) /* ASCII header write */
658long t;
659{
660 sprintf(Chdr,"%.6o%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
661 MAGIC, MK_USHORT(Statb.st_dev), MK_USHORT(Statb.st_ino), Statb.st_mode, Statb.st_uid,
662 Statb.st_gid, Statb.st_nlink, MK_USHORT(Statb.st_rdev),
663 Statb.st_mtime, (short)strlen(Hdr.h_name)+1, t, Hdr.h_name);
664}
665
666static
667chartobin() /* ASCII header read */
668{
669 sscanf(Chdr, "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
670 &Hdr.h_magic, &Hdr.h_dev, &Hdr.h_ino, &Hdr.h_mode, &Hdr.h_uid,
671 &Hdr.h_gid, &Hdr.h_nlink, &Hdr.h_rdev, &Longtime,
672 &Hdr.h_namesize, &Longfile);
673 MKSHORT(Hdr.h_filesize, Longfile);
674 MKSHORT(Hdr.h_mtime, Longtime);
675}
676
677
678/* Check the header for the magic number. Switch modes automatically to
679 match the type of header found.
680*/
681static
682chkhdr()
683{
684 bread(Chdr, CHARS);
685 chartobin();
686 if( Hdr.h_magic == MAGIC )
687 Cflag = 1;
688 else {
689 breread(&Hdr.h_magic, sizeof Hdr.h_magic);
fd2d2fec 690 if( Hdr.h_magic == MAGIC || Hdr.h_magic == (short)BSMAGIC )
76bbb78b 691 Cflag = 0;
fd2d2fec
KB
692 else {
693 fperr("This is not a cpio file. Bad magic number.");
694 exit(2);
695 }
76bbb78b
KB
696 }
697 breread(Chdr, 0);
698}
699
700
701static
702gethdr() /* get file headers */
703{
704 register ushort ftype;
705
706 if (Cflag) {
707 bread(Chdr, CHARS);
708 chartobin();
709 }
710 else
711 bread(&Hdr, HDRSIZE);
712
fd2d2fec
KB
713 if(Hdr.h_magic == (short)BSMAGIC)
714 swap((char *)&Hdr, HDRSIZE, 1, 0);
715 else if( Hdr.h_magic != MAGIC ) {
716 fperr("Out of phase--get help");
717 exit(2);
76bbb78b
KB
718 }
719 bread(Hdr.h_name, Hdr.h_namesize);
720 if(EQ(Hdr.h_name, "TRAILER!!!"))
721 return 0;
722 ftype = Hdr.h_mode & Filetype;
723 A_directory = (ftype == S_IFDIR);
724 A_special = (ftype == S_IFBLK)
725 || (ftype == S_IFCHR)
726 || (ftype == S_IFIFO);
fd2d2fec 727 A_symlink = (ftype == S_IFLNK);
76bbb78b
KB
728 return 1;
729}
730
731static
732ckname(namep) /* check filenames with patterns given on cmd line */
733register char *namep;
734{
735 char buf[sizeof Hdr.h_name];
736
737 if(fflag ^ !nmatch(namep, Pattern)) {
738 return 0;
739 }
740 if(Rename && !A_directory) { /* rename interactively */
741 fprintf(Wtty, "Rename <%s>\n", namep);
742 fflush(Wtty);
743 fgets(buf, sizeof buf, Rtty);
744 if(feof(Rtty))
745 exit(2);
746 buf[strlen(buf) - 1] = '\0';
747 if(EQ(buf, "")) {
748 strcpy(namep,buf);
749 printf("Skipped\n");
750 return 0;
751 }
752 else if(EQ(buf, "."))
753 printf("Same name\n");
754 else
755 strcpy(namep,buf);
756 }
757 return 1;
758}
759
760static
fd2d2fec 761openout(namep, symlname) /* open files for writing, set all necessary info */
76bbb78b 762register char *namep;
fd2d2fec 763char *symlname;
76bbb78b
KB
764{
765 register f;
766 register char *np;
767 int ans;
768
769 if(!strncmp(namep, "./", 2))
770 namep += 2;
771 np = namep;
772 if(A_directory) {
773 if( !Dir || Rename || EQ(namep, ".") || EQ(namep, "..") )
774 /* do not consider . or .. files */
775 return 0;
776 if(stat(namep, &Xstatb) == -1) {
777
778/* try creating (only twice) */
779 ans = 0;
780 do {
fd2d2fec 781 if(mkdir(namep, Hdr.h_mode) != 0) {
76bbb78b
KB
782 ans += 1;
783 }else {
784 ans = 0;
785 break;
786 }
787 }while(ans < 2 && missdir(namep) == 0);
788 if(ans == 1) {
789 fperrno("Cannot create directory for <%s>",
790 namep);
791 return(0);
792 }else if(ans == 2) {
793 fperrno("Cannot create directory <%s>", namep);
794 return(0);
795 }
796 }
797
798ret:
fd2d2fec
KB
799 if(chmod(namep, Hdr.h_mode) < 0)
800 fperrno("Cannot change mode of <%s>", namep);
76bbb78b 801 if(Uid == 0)
fd2d2fec
KB
802 if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
803 fperrno("Cannot change ownership of <%s>",
804 namep);
76bbb78b
KB
805 set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
806 return 0;
807 }
808 if(Hdr.h_nlink > 1)
809 if(!postml(namep, np))
810 return 0;
fd2d2fec 811 if(lstat(namep, &Xstatb) == 0) {
76bbb78b
KB
812 if(Uncond && !((!(Xstatb.st_mode & S_IWRITE) || A_special) && (Uid != 0))) {
813 if(unlink(namep) < 0) {
814 fperrno("cannot unlink current <%s>", namep);
815 }
816 }
817 if(!Uncond && (mklong(Hdr.h_mtime) <= Xstatb.st_mtime)) {
818 /* There's a newer or same aged version of file on destination */
fd2d2fec 819 fperr("current <%s> newer or same age", np);
76bbb78b
KB
820 return 0;
821 }
822 }
823 if( Option == PASS
824 && Hdr.h_ino == Xstatb.st_ino
825 && Hdr.h_dev == Xstatb.st_dev) {
fd2d2fec
KB
826 fperr("Attempt to pass file to self!");
827 exit(2);
828 }
829 if(A_symlink) {
830/* try symlinking (only twice) */
831 ans = 0;
832 do {
833 if(symlink(
834symlname, namep) < 0) {
835 ans += 1;
836 }else {
837 ans = 0;
838 break;
839 }
840 }while(ans < 2 && missdir(np) == 0);
841 if(ans == 1) {
842 fperrno("Cannot create directory for <%s>", namep);
843 return(0);
844 }else if(ans == 2) {
845 fperrno("Cannot symlink <%s> and <%s>", namep, symlname);
846 return(0);
847 }
848
849 return 0;
76bbb78b
KB
850 }
851 if(A_special) {
852 if((Hdr.h_mode & Filetype) == S_IFIFO)
853 Hdr.h_rdev = 0;
854
855/* try creating (only twice) */
856 ans = 0;
857 do {
858 if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
859 ans += 1;
860 }else {
861 ans = 0;
862 break;
863 }
864 }while(ans < 2 && missdir(np) == 0);
865 if(ans == 1) {
866 fperrno("Cannot create directory for <%s>", namep);
867 return(0);
868 }else if(ans == 2) {
869 fperrno("Cannot mknod <%s>", namep);
870 return(0);
871 }
872
873 goto ret;
874 }
875
876/* try creating (only twice) */
877 ans = 0;
878 do {
879 if((f = creat(namep, Hdr.h_mode)) < 0) {
880 ans += 1;
881 }else {
882 ans = 0;
883 break;
884 }
885 }while(ans < 2 && missdir(np) == 0);
886 if(ans == 1) {
887 fperrno("Cannot create directory for <%s>", namep);
888 return(0);
889 }else if(ans == 2) {
890 fperrno("Cannot create <%s>", namep);
891 return(0);
892 }
893
894 if(Uid == 0)
fd2d2fec
KB
895 if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
896 fperrno("Cannot change ownership of <%s>", namep);
76bbb78b
KB
897 return f;
898}
899
900
901/* Shared by bread() and breread()
902*/
903static int nleft = 0; /* unread chars left in Cbuf */
904static char *ip; /* pointer to next char to be read from Cbuf */
905
906/* Reread the current buffer Cbuf.
907 A character count, c, of 0 simply resets the pointer so next bread gets
908 the same data again.
909*/
910static
911breread(b, c)
912char *b;
913int c;
914{
915 ip = Cbuf;
916 if( nleft )
917 nleft = Bufsize;
918 if( !c )
919 return;
920 bread(b, c);
921}
922
923static
924bread(b, c)
925register char *b;
926register int c;
927{
928 register int rv;
929 register char *p = ip;
930
931 if( !Cflag ) {
932 /* round c up to an even number */
933 c = (c+1)/2;
934 c *= 2;
935 }
936 while( c ) {
937 if( nleft == 0 ) {
938 while( (rv = read(Input, Cbuf, Bufsize)) == 0 ) {
939 Input = chgreel(0, Input, rv);
940 }
941 if( rv == Bufsize ) {
942 nleft = Bufsize;
943 p = Cbuf;
944 ++Blocks;
945 }
fd2d2fec
KB
946 else if( rv == -1 ) {
947 fperrno("Read error on archive");
948 exit(2);
949 }
76bbb78b
KB
950 else if( rv < Bufsize ) { /* short read */
951 smemcpy( &Cbuf[ Bufsize - rv ], Cbuf, rv );
952 nleft = rv;
953 p = &Cbuf[ Bufsize - rv ];
954 sBlocks += rv;
955 }
76bbb78b
KB
956 }
957 if( nleft <= c ) {
958 memcpy( b, p, nleft );
959 c -= nleft;
960 b += nleft;
961 p += nleft;
962 nleft = 0;
963 }
964 else {
965 memcpy( b, p, c );
966 nleft -= c;
967 b += c;
968 p += c;
969 c = 0;
970 }
971 }
972 ip = p;
973}
974
975
976static
977bwrite(rp, c)
978register char *rp;
979register c;
980{
981 register char *cp = Cp;
982 static unsigned Ccnt = 0;
983 register unsigned Cleft;
984 register int rv;
985
986 if( !Cflag ) {
987 /* round c up to an even number */
988 c = (c+1)/2;
989 c *= 2;
990 }
991 while( c ) {
992 if( (Cleft = Bufsize - Ccnt) <= c ) {
993 memcpy( cp, rp, Cleft );
994 rv = write(Output, Cbuf, Bufsize);
995 if( rv == 0 || ( rv == -1 && errno == ENXIO ) ) {
996 rv = eomchgreel();
997 }
998 if( rv == Bufsize ) {
999 Ccnt = 0;
1000 cp = Cbuf;
1001 }
fd2d2fec
KB
1002 else if( rv == -1 ) {
1003 fperrno("Write error on archive");
1004 exit(2);
1005 }
76bbb78b
KB
1006 else if( rv < Bufsize ) {
1007 Output = chgreel(1, Output, 0);
1008 smemcpy( Cbuf, &Cbuf[ Bufsize - rv ], rv );
1009 Ccnt = Bufsize - rv;
1010 cp = &Cbuf[ rv ];
1011 }
76bbb78b
KB
1012 ++Blocks;
1013 rp += Cleft;
1014 c -= Cleft;
1015 }
1016 else {
1017 memcpy( cp, rp, c );
1018 Ccnt += c;
1019 cp += c;
1020 rp += c;
1021 c = 0;
1022 }
1023 }
1024 Cp = cp;
1025}
1026
1027
1028static int reelcount = 1; /* used below and in chgreel() */
1029
1030/* Change reel due to reaching end-of-media.
1031 Keep trying to get a successful write before considering the
1032 change-of-reel as successful.
1033*/
1034static
1035int
1036eomchgreel()
1037{
1038 int rv;
1039
1040 while( 1 ) {
1041 Output = chgreel(1, Output, 0);
1042 rv = write(Output, Cbuf, Bufsize);
1043 if( rv == Bufsize )
1044 return rv;
fd2d2fec
KB
1045 if( rv == -1 )
1046 fperrno( "Unable to write this medium" );
1047 else
1048 fperr( "Unable to write this medium: Premature EOF" );
1049 (void) fprintf(stderr, "Try again.\n");
76bbb78b
KB
1050 reelcount--;
1051 }
1052 /*NOTREACHED*/
1053}
1054
1055
1056static
1057postml(namep, np) /* linking funtion: Postml() is called after */
1058register char *namep, *np; /* namep is created. Postml() checks to see */
1059{ /* if namep should be linked to np. If so, */
1060 /* postml() removes the independent instance */
1061 register i; /* of namep and links namep to np. */
1062 static struct ml {
1063 short m_dev;
1064 ushort m_ino;
1065 char m_name[2];
1066 } **ml = 0;
1067 register struct ml *mlp;
1068 static unsigned mlsize = 0;
1069 static unsigned mlinks = 0;
1070 char *lnamep;
1071 int ans;
1072
1073 if( !ml ) {
1074 mlsize = LINKS;
fd2d2fec 1075 ml = (struct ml **) malloc(mlsize * sizeof(struct ml));
76bbb78b
KB
1076 }
1077 else if( mlinks == mlsize ) {
1078 mlsize += LINKS;
fd2d2fec
KB
1079 ml = (struct ml **) realloc((char *) ml,
1080 mlsize * sizeof(struct ml));
1081 }
1082 if (ml == NULL) {
1083 fperr("Out of memory for links");
1084 exit(2);
76bbb78b
KB
1085 }
1086 for(i = 0; i < mlinks; ++i) {
1087 mlp = ml[i];
1088 if(mlp->m_ino==Hdr.h_ino && mlp->m_dev==Hdr.h_dev) {
76bbb78b 1089 if(Verbose)
fd2d2fec
KB
1090 printf("%s linked to %s\n", ml[i]->m_name,
1091 np);
76bbb78b
KB
1092 unlink(namep);
1093 if(Option == IN && *(mlp->m_name) != '/') {
1094 Fullname[Pathend] = '\0';
1095 strcat(Fullname, mlp->m_name);
1096 lnamep = Fullname;
1097 }
1098 lnamep = mlp->m_name;
1099
1100/* try linking (only twice) */
1101 ans = 0;
1102 do {
1103 if(link(lnamep, namep) < 0) {
1104 ans += 1;
1105 }else {
1106 ans = 0;
1107 break;
1108 }
1109 }while(ans < 2 && missdir(np) == 0);
1110 if(ans == 1) {
1111 fperrno("Cannot create directory for <%s>", np);
1112 return(0);
1113 }else if(ans == 2) {
1114 fperrno("Cannot link <%s> & <%s>", lnamep, np);
1115 return(0);
1116 }
1117
1118 set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
1119 return 0;
1120 }
1121 }
fd2d2fec 1122 if( !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) {
76bbb78b
KB
1123 static int first=1;
1124
1125 if(first)
fd2d2fec 1126 fperr("Out of memory for links");
76bbb78b
KB
1127 first = 0;
1128 return 1;
1129 }
1130 ml[mlinks]->m_dev = Hdr.h_dev;
1131 ml[mlinks]->m_ino = Hdr.h_ino;
1132 strcpy(ml[mlinks]->m_name, np);
1133 ++mlinks;
1134 return 1;
1135}
1136
1137static
1138pentry(namep) /* print verbose table of contents */
1139register char *namep;
1140{
1141
1142 static short lastid = -1;
1143#include <pwd.h>
1144 static struct passwd *pw;
1145 struct passwd *getpwuid();
1146 static char tbuf[32];
1147 char *ctime();
1148
1149 printf("%-7o", MK_USHORT(Hdr.h_mode));
1150 if(lastid == Hdr.h_uid)
1151 printf("%-6s", pw->pw_name);
1152 else {
1153 setpwent();
1154 if(pw = getpwuid((int)Hdr.h_uid)) {
1155 printf("%-6s", pw->pw_name);
1156 lastid = Hdr.h_uid;
1157 } else {
1158 printf("%-6d", Hdr.h_uid);
1159 lastid = -1;
1160 }
1161 }
1162 printf("%7ld ", mklong(Hdr.h_filesize));
1163 U.l = mklong(Hdr.h_mtime);
1164 strcpy(tbuf, ctime((long *)&U.l));
1165 tbuf[24] = '\0';
fd2d2fec
KB
1166 printf(" %s %s", &tbuf[4], namep);
1167 if (A_symlink)
1168 printf(" -> %s", Symlbuf);
1169 putchar('\n');
76bbb78b
KB
1170}
1171
1172 /* pattern matching functions */
1173static
1174nmatch(s, pat)
1175char *s, **pat;
1176{
1177 if( !pat )
1178 return 1;
1179 while(*pat) {
1180 if((**pat == '!' && !gmatch(s, *pat+1))
1181 || gmatch(s, *pat))
1182 return 1;
1183 ++pat;
1184 }
1185 return 0;
1186}
1187
1188
1189static
1190gmatch(s, p)
1191register char *s, *p;
1192{
1193 register int c;
1194 register cc, ok, lc, scc;
1195
1196 scc = *s;
1197 lc = 077777;
1198 switch (c = *p) {
1199
1200 case '[':
1201 ok = 0;
1202 while (cc = *++p) {
1203 switch (cc) {
1204
1205 case ']':
1206 if (ok)
1207 return(gmatch(++s, ++p));
1208 else
1209 return(0);
1210
1211 case '-':
1212 ok |= ((lc <= scc) && (scc <= (cc=p[1])));
1213 }
1214 if (scc==(lc=cc)) ok++;
1215 }
1216 return(0);
1217
1218 case '?':
1219 caseq:
1220 if(scc) return(gmatch(++s, ++p));
1221 return(0);
1222 case '*':
1223 return(umatch(s, ++p));
1224 case 0:
1225 return(!scc);
1226 }
1227 if (c==scc) goto caseq;
1228 return(0);
1229}
1230
1231
1232
1233static
1234umatch(s, p)
1235register char *s, *p;
1236{
1237 if(*p==0) return(1);
1238 while(*s)
1239 if (gmatch(s++,p)) return(1);
1240 return(0);
1241}
1242
fd2d2fec
KB
1243swap(buf, bytecount, bytes, halfwords) /* swap halfwords, bytes or both */
1244char *buf;
1245int bytecount;
1246int bytes, halfwords;
76bbb78b 1247{
fd2d2fec
KB
1248 register int count;
1249 int n, i;
1250
1251 if(bytes) {
1252 register union swpbytes {
1253 short shortw;
1254 char charv[2];
1255 } *pbuf;
1256 register char c;
1257
1258 count = bytecount;
1259 pbuf = (union swpbytes *)buf;
1260 if (count % sizeof(union swpbytes))
1261 pbuf->charv[count] = 0;
1262 count = (count + (sizeof(union swpbytes) - 1)) / sizeof(union swpbytes);
1263 while (count--) {
1264 c = pbuf->charv[0];
1265 pbuf->charv[0] = pbuf->charv[1];
1266 pbuf->charv[1] = c;
1267 ++pbuf;
76bbb78b
KB
1268 }
1269 }
fd2d2fec
KB
1270 if (halfwords) {
1271 register union swphalf {
1272 long longw;
1273 short shortv[2];
1274 char charv[4];
1275 } *pbuf;
1276 register short cc;
1277
1278 count = bytecount;
1279 pbuf = (union swphalf *)buf;
1280 if (n = count % sizeof(union swphalf))
1281 if(bytes && n % 2)
1282 for(i = count + 1; i <= count + (sizeof(union swphalf) - n); i++)
1283 pbuf->charv[i] = 0;
1284 else
1285 for (i = count; i < count + (sizeof(union swphalf) - n); i++)
1286 pbuf->charv[i] = 0;
1287 count = (count + (sizeof(union swphalf) - 1)) / sizeof(union swphalf);
1288 while (count--) {
76bbb78b
KB
1289 cc = pbuf->shortv[0];
1290 pbuf->shortv[0] = pbuf->shortv[1];
1291 pbuf->shortv[1] = cc;
1292 ++pbuf;
1293 }
1294 }
1295}
1296
1297
1298static
1299set_time(namep, atime, mtime) /* set access and modification times */
1300register char *namep;
1301time_t atime, mtime;
1302{
fd2d2fec 1303 static struct utimbuf timevec;
76bbb78b
KB
1304
1305 if(!Mod_time)
1306 return;
fd2d2fec
KB
1307 timevec.actime = atime;
1308 timevec.modtime = mtime;
1309 (void)utime(namep, &timevec);
76bbb78b
KB
1310}
1311
1312
1313
1314static
1315chgreel(x, fl, rv)
1316{
1317 register f;
1318 char str[BUFSIZ];
1319 struct stat statb;
1320
1321 fstat(fl, &statb);
1322 if((statb.st_mode&S_IFMT) != S_IFCHR) {
1323 fperrno("Can't %s: ", x? "write output": "read input");
1324 exit(2);
1325 }
1326 if( rv == 0 ||
1327 ( rv == -1 && ( errno == ENOSPC || errno == ENXIO ) ) )
fd2d2fec 1328 fperr( "\007Reached end of medium on %s",
76bbb78b
KB
1329 x? "output":"input" );
1330 else {
1331 fperrno( "\007Encountered an error on %s",
1332 x? "output":"input" );
1333 exit(2);
1334 }
fd2d2fec
KB
1335 if( Rtty == NULL ) {
1336 Rtty = fopen(ttyname, "r");
1337 if( Rtty == NULL ) {
1338 fperrno("Cannot prompt (can't open %s)", ttyname);
1339 exit(2);
1340 }
1341 }
76bbb78b
KB
1342 close(fl);
1343 reelcount++;
1344again:
1345 if( swfile ) {
1346 askagain:
1347 fperr( eommsg, reelcount );
1348 fgets(str, sizeof str, Rtty);
1349 switch( *str ) {
1350 case '\n':
1351 strcpy( str, swfile );
1352 break;
1353 case 'q':
1354 exit(2);
1355 default:
1356 goto askagain;
1357 }
1358 }
1359 else {
fd2d2fec 1360 fperr("If you want to go on, type device/file name when ready.");
76bbb78b
KB
1361 fgets(str, sizeof str, Rtty);
1362 str[strlen(str) - 1] = '\0';
1363 if(!*str)
1364 exit(2);
1365 }
1366 if((f = open(str, x? 1: 0)) < 0) {
fd2d2fec 1367 fperrno("Can't open <%s>", str);
76bbb78b
KB
1368 goto again;
1369 }
1370 return f;
1371}
1372
1373
1374
1375static
1376missdir(namep)
1377register char *namep;
1378{
1379 register char *np;
1380 register ct = 2;
1381
1382 for(np = namep; *np; ++np)
1383 if(*np == '/') {
1384 if(np == namep) continue; /* skip over 'root slash' */
1385 *np = '\0';
1386 if(stat(namep, &Xstatb) == -1) {
1387 if(Dir) {
fd2d2fec 1388 if((ct = mkdir(namep, 0777)) != 0) {
76bbb78b
KB
1389 *np = '/';
1390 return(ct);
1391 }
1392 }else {
fd2d2fec 1393 fperr("missing 'd' option");
76bbb78b
KB
1394 return(-1);
1395 }
1396 }
1397 *np = '/';
1398 }
1399 if (ct == 2) ct = 0; /* the file already exists */
1400 return ct;
1401}
1402
1403
1404
1405static
1406pwd() /* get working directory */
1407{
fd2d2fec
KB
1408 if (getwd(Fullname) == 0) {
1409 (void)fprintf(stderr, "cpio: %s\n",
1410 Fullname);
76bbb78b 1411 exit(2);
76bbb78b 1412 }
fd2d2fec
KB
1413 Pathend = strlen(Fullname);
1414 Fullname[Pathend++] = '/';
1415 Fullname[Pathend] = '\0';
76bbb78b
KB
1416}
1417
1418
1419/*
1420 print message on the stderr
1421*/
1422static
1423fperr( va_alist )
1424va_dcl
1425{
1426 va_list args;
1427 char *fmt;
1428
76bbb78b 1429 va_start( args );
fd2d2fec 1430 fprintf( stderr, "cpio: ");
76bbb78b
KB
1431 fmt = va_arg( args, char * );
1432 vfprintf( stderr, fmt, args );
fd2d2fec 1433 putc( '\n', stderr);
76bbb78b
KB
1434 fflush( stderr );
1435}
1436
1437/*
1438 print message on the stderr followed by error number and meaning.
1439*/
1440static
1441fperrno( va_alist )
1442va_dcl
1443{
1444 va_list args;
1445 char *fmt;
1446
76bbb78b 1447 va_start( args );
fd2d2fec 1448 fprintf( stderr, "cpio: ");
76bbb78b
KB
1449 fmt = va_arg( args, char * );
1450 vfprintf( stderr, fmt, args );
fd2d2fec 1451 fprintf( stderr, ": " );
76bbb78b
KB
1452 fflush( stderr );
1453 perror("");
1454}
1455
1456
fd2d2fec
KB
1457/* Safe memory copy.
1458 Fast if the to and from strings do not overlap,
1459 slower but safe if they do.
1460*/
1461
1462static char *
1463smemcpy( to, from, count )
1464register char *to, *from;
1465register unsigned count;
76bbb78b 1466{
fd2d2fec 1467 char *savedto;
76bbb78b 1468
fd2d2fec
KB
1469 if( &to[ count ] <= from || &from[ count ] <= to )
1470 return memcpy( to, from, count );
76bbb78b 1471
fd2d2fec
KB
1472 if( to == from )
1473 return to;
1474
1475 savedto = to;
1476 if( to < from )
1477 while( count-- )
1478 *(to++) = *(from++);
1479 else {
1480 to += count;
1481 from += count;
1482 while( count-- )
1483 *(--to) = *(--from);
1484 }
1485
1486 return savedto;
76bbb78b 1487}