Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / pax / copy.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: copy.c /main/3 1995/11/01 16:59:36 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
34 *           This software is licensed by AT&T Corp.            *
35 *       under the terms and conditions of the license in       *
36 *       http://www.research.att.com/orgs/ssr/book/reuse        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46
47 /* : : generated by proto : : */
48
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__      "C"
53 #else
54 #define __MANGLE__
55 #endif
56 #define __STDARG__
57 #define __PROTO__(x)    x
58 #define __OTORP__(x)
59 #define __PARAM__(n,o)  n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
62 #define const
63 #endif
64 #define signed
65 #define void            int
66 #define volatile
67 #define __V_            char
68 #else
69 #define __V_            void
70 #endif
71 #else
72 #define __PROTO__(x)    ()
73 #define __OTORP__(x)    x
74 #define __PARAM__(n,o)  o
75 #define __MANGLE__
76 #define __V_            char
77 #define const
78 #define signed
79 #define void            int
80 #define volatile
81 #endif
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__      ...
84 #else
85 #define __VARARG__
86 #endif
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a)       va_start(p,a)
89 #else
90 #define __VA_START__(p,a)       va_start(p)
91 #endif
92 #endif
93 #include "pax.h"
94
95 /*
96  * copy files in from archive
97  */
98
99 void
100 copyin __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
101         register File_t*        f = &ap->file;
102
103         deltabase(ap);
104         while (getprologue(ap))
105         {
106                 while (getheader(ap, f))
107                 {
108                         if (selectfile(ap, f)) filein(ap, f);
109                         else fileskip(ap, f);
110                         gettrailer(ap, f);
111                 }
112                 getepilogue(ap);
113         }
114         deltaverify(ap);
115 }
116
117 /*
118  * copy a single file out to the archive
119  * called by ftwalk()
120  */
121
122 int
123 copyout __PARAM__((register Ftw_t* ftw), (ftw)) __OTORP__(register Ftw_t* ftw;){
124         register Archive_t*     ap = state.out;
125         register File_t*        f = &ap->file;
126
127         if (getfile(ap, f, ftw))
128         {
129                 if (selectfile(ap, f) && (!state.verify || verify(ap, f)))
130                 {
131                         f->fd = openin(ap, f);
132                         deltaout(NiL, ap, f);
133                 }
134                 else ftw->status = FTW_SKIP;
135         }
136         return(0);
137 }
138
139 /*
140  * fileout() record support
141  */
142
143 static void
144 recordout __PARAM__((Archive_t* ap, File_t* f, Sfio_t* fp), (ap, f, fp)) __OTORP__(Archive_t* ap; File_t* f; Sfio_t* fp;){
145         register int    c;
146         register char*  p;
147         register char*  recdat;
148         register char*  blkdat;
149         char*           rec;
150         char*           blk;
151         int             span;
152
153         int             count = 0;
154         int             partial = 0;
155         int             truncated = 0;
156
157         static char     span_out[] = "0132";
158         static char*    pardat;
159
160         if (!fp) error(3, "cannot handle record output from buffer");
161         ap->record = f;
162         f->record.blocks = 0;
163         span = 0;
164         blk = state.tmp.buffer;
165
166         /*
167          * file loop
168          */
169
170         for (;;)
171         {
172                 p = blk;
173                 switch (state.record.format)
174                 {
175                 case 'V':
176                         p += 4;
177                         break;
178                 }
179                 blkdat = p;
180
181                 /*
182                  * block loop
183                  */
184
185                 for (;;)
186                 {
187                         rec = p;
188                         switch (state.record.format)
189                         {
190                         case 'D':
191                         case 'V':
192                                 p += 4;
193                                 break;
194                         case 'S':
195                                 p += 5;
196                                 break;
197                         }
198                         recdat = p;
199
200                         /*
201                          * check for partial record from previous block
202                          */
203
204                         if (partial)
205                         {
206                                 memcpy(recdat, pardat, partial);
207                                 p += partial;
208                                 partial = 0;
209                         }
210
211                         /*
212                          * record loop
213                          */
214
215                         span &= 01;
216                         span <<= 1;
217                         for (;;)
218                         {
219                                 if (p >= &rec[state.record.size] && state.record.size)
220                                 {
221                                         if (state.record.line)
222                                         {
223                                                 truncated++;
224                                                 while ((c = sfgetc(fp)) != EOF && c != '\n');
225                                         }
226                                         break;
227                                 }
228                                 else if (p >= &blk[state.blocksize])
229                                 {
230                                         if (state.record.format == 'S' || state.record.format == 'V')
231                                         {
232                                                 if (p > recdat)
233                                                 {
234                                                         span |= 01;
235                                                         break;
236                                                 }
237                                         }
238                                         else if (partial = p - recdat)
239                                         {
240                                                 /*
241                                                  * save partial record for next block
242                                                  */
243
244                                                 if (!pardat && !(pardat = newof(0, char, state.blocksize, 0)))
245                                                         error(3, "out of space [record pushback buffer]");
246                                                 memcpy(pardat, recdat, partial);
247                                         }
248                                         p = rec;
249                                         goto eob;
250                                 }
251                                 else if ((c = sfgetc(fp)) == EOF)
252                                 {
253                                         if (p == recdat)
254                                         {
255                                                 if (rec == blkdat) goto eof;
256                                                 p = rec;
257                                                 goto eob;
258                                         }
259                                         break;
260                                 }
261                                 else if (c == '\n' && state.record.line) break;
262                                 else *p++ = c;
263                         }
264                         switch (state.record.format)
265                         {
266                         case 'D':
267                                 c = recdat[0];
268                                 sfsprintf(rec, 4, "%04d", p - rec);
269                                 recdat[0] = c;
270                                 break;
271                         case 'F':
272                                 if (c != EOF || state.record.pad)
273                                 {
274                                         memset(p, ' ', state.record.size - (p - rec));
275                                         p = rec + state.record.size;
276                                 }
277                                 break;
278                         case 'S':
279                                 c = recdat[0];
280                                 sfsprintf(rec, 4, "%c%04d", span_out[span], p - rec);
281                                 recdat[0] = c;
282                                 break;
283                         case 'U':
284                                 if (p == recdat) *p++ = ' ';
285                                 break;
286                         case 'V':
287                                 rec[0] = ((p - rec) >> 8) & 0xff;
288                                 rec[1] = (p - rec) & 0xff;
289                                 rec[2] = span;
290                                 rec[3] = 0;
291                                 break;
292                         }
293                         if (state.record.charset && ap->format == IBMAR) mematoe(recdat, recdat, p - recdat);
294                         count++;
295                         if (p >= &blk[state.blocksize] || state.record.format == 'U') break;
296                 }
297         eob:
298                 switch (state.record.format)
299                 {
300                 case 'D':
301                 case 'S':
302                         if (state.record.pad)
303                         {
304                                 memset(p, '^', state.blocksize - (p - blk));
305                                 p = blk + state.blocksize;
306                         }
307                         break;
308                 case 'V':
309                         blk[0] = ((p - blk) >> 8) & 0xff;
310                         blk[1] = (p - blk) & 0xff;
311                         blk[2] = 0;
312                         blk[3] = 0;
313                         break;
314                 }
315                 bwrite(ap, blk, p - blk);
316                 f->record.blocks++;
317         }
318  eof:
319         ap->record = 0;
320         if (truncated) error(1, "%s: %d out of %d record%s truncated", f->name, truncated, count, count == 1 ? "" : "s");
321 }
322
323 /*
324  * low level for copyout()
325  * if rfd<0 && st_size>0 then input from bread()
326  */
327
328 void
329 fileout __PARAM__((register Archive_t* ap, register File_t* f), (ap, f)) __OTORP__(register Archive_t* ap; register File_t* f;){
330         register int    n;
331         register long   c;
332         int             err;
333         Buffer_t*       bp;
334         Sfio_t*         rfp;
335
336         if (f->delta.op == DELTA_verify)
337         {
338                 ap->selected--;
339                 if (f->fd >= 0) close(f->fd);
340         }
341         else
342         {
343                 putheader(ap, f);
344                 switch (ap->format)
345                 {
346                 case ALAR:
347                 case IBMAR:
348                         if (ap->io.blocked)
349                         {
350                                 if (f->st->st_size > 0)
351                                 {
352                                         if (state.record.format == 'F' && !state.record.line)
353                                         {
354                                                 /*
355                                                  * this is faster than recordout()
356                                                  */
357
358                                                 ap->record = f;
359                                                 err = 0;
360                                                 c = f->st->st_size;
361                                                 while (c > 0)
362                                                 {
363                                                         n = c > state.record.size ? state.record.size : c;
364
365                                                         /*
366                                                          * NOTE: we expect that all but the last
367                                                          *       read returns state.record.size
368                                                          *       if not the the intermediate short
369                                                          *       reads are filled with 0's
370                                                          */
371
372                                                         if (!err)
373                                                         {
374                                                                 if (f->fd >= 0) n = read(f->fd, state.tmp.buffer, n);
375                                                                 else if (bp = getbuffer(f->fd))
376                                                                 {
377                                                                         memcpy(ap->io.next, bp->next, n);
378                                                                         bp->next += n;
379                                                                 }
380                                                                 else if (bread(f->ap, state.tmp.buffer, 0L, (long)n, 1) <= 0) n = -1;
381                                                         }
382                                                         if (n <= 0)
383                                                         {
384                                                                 if (n) error(ERROR_SYSTEM|2, "%s: read error", f->path);
385                                                                 else error(2, "%s: file size changed", f->path);
386                                                                 memzero(state.tmp.buffer, state.record.size);
387                                                                 err = 1;
388                                                         }
389                                                         else
390                                                         {
391                                                                 c -= n;
392                                                                 if (n < state.record.size && (c > 0 || state.record.pad))
393                                                                 {
394                                                                         memzero(state.tmp.buffer + n, state.record.size - n);
395                                                                         n = state.record.size;
396                                                                 }
397                                                                 bwrite(ap, state.tmp.buffer, n);
398                                                         }
399                                                 }
400                                                 ap->record = 0;
401                                                 if (f->fd >= 0) close(f->fd);
402                                         }
403                                         else if (f->fd < 0) recordout(ap, f, NiL);
404                                         else if (!(rfp = sfnew(NiL, NiL, SF_UNBOUND, f->fd, SF_READ)))
405                                         {
406                                                 error(1, "%s: cannot read", f->path);
407                                                 close(f->fd);
408                                         }
409                                         else
410                                         {
411                                                 recordout(ap, f, rfp);
412                                                 sfclose(rfp);
413                                         }
414                                 }
415                                 break;
416                         }
417                         /*FALLTHROUGH*/
418                 default:
419                         err = 0;
420                         c = f->st->st_size;
421                         while (c > 0)
422                         {
423                                 n = c > state.buffersize ? state.buffersize : c;
424                                 if (!err)
425                                 {
426                                         if (f->fd >= 0) n = read(f->fd, ap->io.next, n);
427                                         else if (bp = getbuffer(f->fd))
428                                         {
429                                                 memcpy(ap->io.next, bp->next, n);
430                                                 bp->next += n;
431                                         }
432                                         else if (bread(f->ap, ap->io.next, 0L, (long)n, 1) <= 0) n = -1;
433                                 }
434                                 if (n <= 0)
435                                 {
436                                         if (n) error(ERROR_SYSTEM|2, "%s: read error", f->path);
437                                         else error(2, "%s: file size changed", f->path);
438                                         memzero(ap->io.next, state.buffersize);
439                                         err = 1;
440                                 }
441                                 else
442                                 {
443                                         c -= n;
444                                         bput(ap, n);
445                                 }
446                         }
447                         if (f->fd >= 0) close(f->fd);
448                         break;
449                 }
450                 puttrailer(ap, f);
451         }
452         if (state.acctime && f->type != X_IFLNK)
453                 settime(f->name, f->st->st_atime, f->st->st_mtime);
454 }
455
456 /*
457  * filein() record support
458  */
459
460 static void
461 recordin __PARAM__((register Archive_t* ap, register File_t* f, int wfd), (ap, f, wfd)) __OTORP__(register Archive_t* ap; register File_t* f; int wfd;){
462         register long                   n;
463         register long                   size;
464         int                             c;
465         int                             i;
466         int                             j;
467         int                             k;
468         int                             nl;
469         long                            m;
470         Sfio_t*                         wfp;
471
472         if (wfd < 0) wfp = 0;
473         else if (!(wfp = sfnew(NiL, NiL, SF_UNBOUND, wfd, SF_WRITE)))
474                 error(1, "%s: cannot write", f->name);
475         ap->io.empty = 0;
476         nl = state.record.line;
477         size = 0;
478         for (;;)
479         {
480                 if (ap->io.blocked) n = bread(ap, state.tmp.buffer, 0L, (long)state.buffersize, 0);
481                 else if ((m = f->st->st_size - size) <= 0) n = 0;
482                 else if (wfp) 
483                 {
484                         if (m > state.buffersize) m = state.buffersize;
485                         n = bread(ap, state.tmp.buffer, 0L, m, 1);
486                 }
487                 else n = bread(ap, NiL, 0L, m, 1);
488                 if (n < 0) break;
489                 if (n == 0)
490                 {
491                         k = 1;
492                         ap->sum--;
493                         while (getlabel(ap, f))
494                         {
495                                 if (strneq(alar_header, "EOV1", 4)) k = 0;
496                                 else if (!strneq(alar_header, "EOF", 3) && !strneq(alar_header, "EOV", 3) && !strneq(alar_header, "UTL", 3) && ++n >= 16 && !state.keepgoing)
497                                         error(3, "%s: %s: %d invalid %s end of file/volume labels detected", ap->name, f->name, n, format[ap->format].name);
498                         }
499                         if (n) error(1, "%s: %s: %d invalid %s end of file/volume labels detected", ap->name, f->name, n, format[ap->format].name);
500                         if (k)
501                         {
502                                 ap->sum++;
503                                 break;
504                         }
505                         f->record.section++;
506                         f->id = strcpy(state.tmp.buffer, f->id);
507                         f->name = strcpy(state.tmp.buffer + ALAR_NAMESIZE + 1, f->name);
508                         for (;;)
509                         {
510                                 newio(ap, 0, 0);
511                                 if (getprologue(ap))
512                                 {
513                                         File_t          v;
514                                         struct stat     st;
515
516                                         v.st = &st;
517                                         if (getheader(ap, &v))
518                                         {
519                                                 if (streq(f->id, v.id) && streq(f->name, v.name) && f->record.section == v.record.section)
520                                                 {
521                                                         f->id = v.id;
522                                                         f->name = v.name;
523                                                         break;
524                                                 }
525                                                 error(1, "volume containing %s id %s section %d required", f->name, f->id, f->record.section);
526                                         }
527                                         ap->volume--;
528                                 }
529                                 ap->part--;
530                         }
531                         ap->sum++;
532                         continue;
533                 }
534                 if (f->record.format == 'V')
535                 {
536                         if ((k = ((unsigned char*)state.tmp.buffer)[0] << 8 | ((unsigned char*)state.tmp.buffer)[1]) != n)
537                                 error(3, "%s: invalid %s V format block descriptor [%d!=%d]", f->name, format[ap->format].name, k, n);
538                         i = 4;
539                 }
540                 else i = 0;
541                 while (i < n)
542                 {
543                         i += state.record.offset;
544                         if (state.tmp.buffer[i] == '^') switch (f->record.format)
545                         {
546                         case 'F':
547                                 if (ap->format == IBMAR) break;
548                                 for (j = i; j < n && state.tmp.buffer[j] == '^'; j++);
549                                 if (j < n) break;
550                                 /*FALLTHROUGH*/
551                         case 'D':
552                         case 'S':
553                                 i = n;
554                                 continue;
555                         }
556
557                         /*
558                          * get record size
559                          */
560
561                         switch (f->record.format)
562                         {
563                         case 'D':
564                                 if (sscanf(&state.tmp.buffer[i], "%4d", &k) != 1) k = -1;
565                                 j = i + 4;
566                                 break;
567                         case 'F':
568                                 if (i + state.record.size > n) k = n - i;
569                                 else if (state.record.line || state.record.offset) k = state.record.size;
570                                 else k = n;
571                                 j = i;
572                                 break;
573                         case 'S':
574                                 switch (state.tmp.buffer[i])
575                                 {
576                                 case '0':
577                                 case '3':
578                                         nl = 1;
579                                         break;
580                                 default:
581                                         nl = 0;
582                                         break;
583                                 }
584                                 if (sscanf(&state.tmp.buffer[i + 1], "%4d", &k) != 1) k = -1;
585                                 j = i + 5;
586                                 break;
587                         case 'U':
588                                 k = n;
589                                 j = i;
590                                 break;
591                         case 'V':
592                                 nl = !(state.tmp.buffer[i + 2] & 01);
593                                 k = ((unsigned char*)state.tmp.buffer)[i] << 8 | ((unsigned char*)state.tmp.buffer)[i + 1];
594                                 j = i + 4;
595                                 break;
596                         }
597                         if (k < 0)
598                         {
599                                 error(2, "invalid %s %c record size", format[ap->format].name, f->record.format);
600                                 break;
601                         }
602                         m = i += k;
603                         if (state.record.charset && ap->format == IBMAR) memetoa(&state.tmp.buffer[j], &state.tmp.buffer[j], m - j);
604                         if (state.record.line) switch (f->record.format)
605                         {
606                         case 'F':
607                         case 'U':
608                                 while (--m >= j && state.tmp.buffer[m] == ' ');
609                                 m++;
610                                 break;
611                         }
612                         k = m - j + nl;
613                         size += k;
614                         if (wfp)
615                         {
616                                 if (nl)
617                                 {
618                                         c = state.tmp.buffer[m];
619                                         state.tmp.buffer[m] = '\n';
620                                 }
621                                 if (sfwrite(wfp, &state.tmp.buffer[j], k) != k)
622                                 {
623                                         error(ERROR_SYSTEM|1, "%s: write error", f->name);
624                                         break;
625                                 }
626                                 if (nl) state.tmp.buffer[m] = c;
627                         }
628                 }
629         }
630         if (f->st->st_size && f->st->st_size != size)
631                 error(1, "%s: header size %ld does not match data size %ld", f->name, f->st->st_size, size);
632         f->st->st_size = size;
633         if (wfp)
634         {
635                 sfclose(wfp);
636                 setfile(ap, f);
637         }
638         if (n < 0) error(ERROR_SYSTEM|3, "%s: %s: archive read error", ap->name, f->name);
639 }
640
641 #if SAVESET
642
643 /*
644  * filein() saveset support
645  */
646
647 static void
648 savesetin __PARAM__((register Archive_t* ap, register File_t* f, int wfd), (ap, f, wfd)) __OTORP__(register Archive_t* ap; register File_t* f; int wfd;){
649         register long           c;
650         int                     i;
651         int                     j;
652         int                     k;
653         Sfio_t*                 wfp;
654
655         if (wfd < 0) wfp = 0;
656         else if (!(wfp = sfnew(NiL, NiL, SF_UNBOUND, wfd, SF_WRITE)))
657                 error(1, "%s: cannot write", f->name);
658         j = 0;
659         k = 0;
660         c = 0;
661         while (getsaveset(ap, f, 0))
662         {
663                 /*
664                  * this part transcribed from vmsbackup
665                  */
666
667                 i = 0;
668                 if (wfp) while ((c + i) < f->st->st_size && i < state.saveset.lastsize) switch (state.saveset.recfmt)
669                 {
670                 case 1: /* fixed length         */
671                         if (j <= 0) j = state.saveset.reclen;
672                         sfputc(wfp, state.saveset.bp[i]);
673                         i++;
674                         j--;
675                         break;
676                 case 2: /* variable length      */
677                 case 3: /* with fixed control   */
678                         if (j <= 0)
679                         {
680                                 j = k = swapget(1, &state.saveset.bp[i], 2);
681                                 i += 2;
682                                 if (state.saveset.recfmt == 3)
683                                 {
684                                         i += state.saveset.recvfc;
685                                         j -= state.saveset.recvfc;
686                                 }
687                         }
688                         else
689                         {
690                                 if (j == k && state.saveset.recatt == 1)
691                                 {
692                                         if (state.saveset.bp[i] == '0') state.saveset.bp[i] = '\n';
693                                         else if (state.saveset.bp[i] == '1') state.saveset.bp[i] = '\f';
694                                 }
695                                 sfputc(wfp, state.saveset.bp[i]);
696                                 i++;
697                                 j--;
698                         }
699                         if (j <= 0)
700                         {
701                                 sfputc(wfp, '\n');
702                                 if (i & 1) i++;
703                         }
704                         break;
705                 case 4: /* seq stream           */
706                 case 5: /* seq LF stream        */
707                         if (j <= 0) j = 512;
708                         if (state.saveset.bp[i] == '\n') j = 0;
709                         else j--;
710                         sfputc(wfp, state.saveset.bp[i]);
711                         i++;
712                         break;
713                 case 6: /* seq CR stream        */
714                         if (state.saveset.bp[i] == '\r') state.saveset.bp[i] = '\n';
715                         sfputc(wfp, state.saveset.bp[i]);
716                         i++;
717                         break;
718                 default:
719                         error(state.keepgoing ? 1 : 3, "%s: invalid %s format data record format=%d", f->name, format[ap->format].name, state.saveset.recfmt);
720                         goto next;
721                 }
722         next:
723                 c += i;
724         }
725         if (wfp)
726         {
727                 sfclose(wfp);
728                 setfile(ap, f);
729         }
730 }
731
732 #endif
733
734 /*
735  * low level for copyin()
736  */
737
738 void
739 filein __PARAM__((register Archive_t* ap, register File_t* f), (ap, f)) __OTORP__(register Archive_t* ap; register File_t* f;){
740         register long   c;
741         register int    n;
742         register char*  s;
743         int             dfd;
744         int             wfd;
745         long            checksum;
746         struct stat     st;
747
748         if (f->skip) goto skip;
749         else if (state.list)
750         {
751                 listentry(f);
752                 goto skip;
753         }
754         else switch (f->delta.op)
755         {
756         case DELTA_create:
757                 if (f->delta.base)
758                         error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
759                 if (ap->delta->format != COMPRESS && ap->delta->format != DELTA) goto regular;
760                 if ((wfd = openout(ap, f)) < 0) goto skip;
761                 else paxdelta(NiL, ap, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, f->st->st_size, 0);
762                 break;
763         case DELTA_update:
764                 if (!f->delta.base || (unsigned long)f->delta.base->mtime >= (unsigned long)f->st->st_mtime)
765                         error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
766                 c = f->st->st_size;
767                 if ((wfd = openout(ap, f)) < 0)
768                         goto skip;
769                 if (state.ordered)
770                 {
771                         if (f->delta.base->expand < 0)
772                                 paxdelta(NiL, ap, f, DELTA_SRC|DELTA_BIO|DELTA_SIZE, ap->delta->base, f->delta.base->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0);
773                         else if (!paxdelta(NiL, ap, f, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap->delta->base, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0))
774                                 paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, f->delta.base->expand, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0);
775                 }
776                 else if (f->delta.base->expand < 0)
777                         paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io.fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0);
778                 else if (!paxdelta(NiL, ap, f, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io.fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0))
779                         paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, f->delta.base->expand, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0);
780                 break;
781         case DELTA_verify:
782                 if (!f->delta.base || f->delta.base->mtime != f->st->st_mtime)
783                         error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
784                 if ((*state.statf)(f->name, &st))
785                         error(2, "%s: not copied from base archive", f->name);
786                 else if (st.st_size != f->delta.base->size || state.modtime && st.st_mtime != f->st->st_mtime)
787                         error(1, "%s: changed from base archive", f->name);
788                 break;
789         case DELTA_delete:
790                 if (!f->delta.base)
791                         error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
792                 /*FALLTHROUGH*/
793         default:
794         regular:
795                 wfd = openout(ap, f);
796                 switch (ap->format)
797                 {
798                 case ALAR:
799                 case IBMAR:
800                         recordin(ap, f, wfd);
801                         break;
802 #if SAVESET
803                 case SAVESET:
804                         savesetin(ap, f, wfd);
805                         break;
806 #endif
807                 default:
808                         if (wfd >= 0)
809                         {
810                                 checksum = 0;
811                                 holeinit(wfd);
812                                 for (c = f->st->st_size; c > 0; c -= n)
813                                 {
814                                         n = (c > state.buffersize) ? state.buffersize : c;
815                                         if (!(s = bget(ap, n)))
816                                         {
817                                                 error(ERROR_SYSTEM|2, "%s: read error", f->name);
818                                                 break;
819                                         }
820                                         if (holewrite(wfd, s, n) != n)
821                                         {
822                                                 error(ERROR_SYSTEM|2, "%s: write error", f->name);
823                                                 break;
824                                         }
825                                         if (ap->format == ASCHK) checksum = asc_checksum(s, n, checksum);
826                                 }
827                                 holedone(wfd);
828                                 close(wfd);
829                                 setfile(ap, f);
830                                 if (ap->format == ASCHK && checksum != f->checksum)
831                                         error(1, "%s: %s checksum error (0x%08x != 0x%08x)", f->name, format[ap->format].name, checksum, f->checksum);
832                         }
833                         else goto skip;
834                         break;
835                 }
836         }
837         listentry(f);
838         return;
839  skip:
840         fileskip(ap, f);
841 }
842
843 /*
844  * skip over archive member f file data
845  */
846
847 void
848 fileskip __PARAM__((register Archive_t* ap, register File_t* f), (ap, f)) __OTORP__(register Archive_t* ap; register File_t* f;){
849         switch (ap->format)
850         {
851         case ALAR:
852         case IBMAR:
853                 recordin(ap, f, -1);
854                 break;
855 #if SAVESET
856         case SAVESET:
857                 savesetin(ap, f, -1);
858                 break;
859 #endif
860         default:
861                 if (bread(ap, NiL, 0L, f->st->st_size, 1) < 0)
862                         error(ERROR_SYSTEM|2, "%s: skip error", f->name);
863                 break;
864         }
865 }
866
867 /*
868  * single file copyin() and copyout() smashed together
869  * called by ftwalk()
870  */
871
872 int
873 copyinout __PARAM__((Ftw_t* ftw), (ftw)) __OTORP__(Ftw_t* ftw;){
874         register long           c;
875         register long           n;
876         register int            rfd;
877         register int            wfd;
878         register File_t*        f = &state.out->file;
879
880         static char             path[PATH_MAX];
881
882         if (getfile(state.out, f, ftw) && selectfile(state.out, f))
883         {
884                 strcpy(path, state.pwd);
885                 strcpy(path + state.pwdlen, f->name + (*f->name == '/'));
886                 f->name = path;
887                 if ((wfd = openout(state.out, f)) >= 0)
888                 {
889                         if ((rfd = openin(state.out, f)) >= 0)
890                         {
891                                 holeinit(wfd);
892                                 for (c = f->st->st_size; c > 0; c -= n)
893                                 {
894                                         if ((n = read(rfd, state.tmp.buffer, (c > state.buffersize) ? state.buffersize : c)) <= 0)
895                                         {
896                                                 error(ERROR_SYSTEM|2, "%s: read error", f->name);
897                                                 break;
898                                         }
899                                         if (holewrite(wfd, state.tmp.buffer, n) != n)
900                                         {
901                                                 error(ERROR_SYSTEM|2, "%s: write error", f->name);
902                                                 break;
903                                         }
904                                         state.out->io.count += n;
905                                 }
906                                 holedone(wfd);
907                                 close(rfd);
908                                 setfile(state.out, f);
909                                 listentry(f);
910                         }
911                         close(wfd);
912                 }
913                 else if (wfd != -1) listentry(f);
914         }
915         return(0);
916 }
917
918 /*
919  * compare ft1 and ft2 for ftwalk() sort
920  */
921
922 int
923 cmpftw __PARAM__((Ftw_t* ft1, Ftw_t* ft2), (ft1, ft2)) __OTORP__(Ftw_t* ft1; Ftw_t* ft2;){
924         return(strcoll(ft1->name, ft2->name));
925 }
926
927
928 /*
929  * copy files out using copyfile
930  */
931
932 typedef int (*Ftw_cmp_t) __PROTO__((Ftw_t*, Ftw_t*));
933
934 void
935 copy __PARAM__((register Archive_t* ap, register int (*copyfile)(Ftw_t*)), (ap, copyfile)) __OTORP__(register Archive_t* ap; register int (*copyfile)();){
936         register char*  s;
937         register int    n;
938
939         if (ap)
940         {
941                 deltabase(ap);
942                 putprologue(ap);
943         }
944         if (state.files) n = ftwalk((char*)state.files, copyfile, state.ftwflags|FTW_MULTIPLE, state.exact ? (Ftw_cmp_t)0 : cmpftw);
945         else for (;;)
946         {
947                 if (s = state.peekfile)
948                         state.peekfile = 0;
949                 else if (!(s = sfgetr(sfstdin, '\n', 1)))
950                         break;
951                 if (ftwalk(s, copyfile, state.ftwflags, NiL))
952                 {
953                         error(2, "%s: not completely copied", s);
954                         break;
955                 }
956         }
957         if (ap)
958         {
959                 deltadelete(ap);
960                 putepilogue(ap);
961         }
962 }
963
964 /*
965  * position archive for appending
966  */
967
968 void
969 append __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
970         if (state.update) initdelta(ap);
971         ap->format = IN_DEFAULT;
972         copyin(ap);
973         state.append = 0;
974 }