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