2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $XConsortium: copy.c /main/3 1995/11/01 16:59:36 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
31 * Copyright (c) 1995 AT&T Corp. *
32 * All Rights Reserved *
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 *
38 * This software was created by the *
39 * Software Engineering Research Department *
40 * AT&T Bell Laboratories *
42 * For further information contact *
43 * gsf@research.att.com *
45 ***************************************************************/
47 /* : : generated by proto : : */
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__ "C"
57 #define __PROTO__(x) x
59 #define __PARAM__(n,o) n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
72 #define __PROTO__(x) ()
73 #define __OTORP__(x) x
74 #define __PARAM__(n,o) o
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__ ...
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a) va_start(p,a)
90 #define __VA_START__(p,a) va_start(p)
96 * copy files in from archive
100 copyin __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
101 register File_t* f = &ap->file;
104 while (getprologue(ap))
106 while (getheader(ap, f))
108 if (selectfile(ap, f)) filein(ap, f);
109 else fileskip(ap, f);
118 * copy a single file out to the archive
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;
127 if (getfile(ap, f, ftw))
129 if (selectfile(ap, f) && (!state.verify || verify(ap, f)))
131 f->fd = openin(ap, f);
132 deltaout(NiL, ap, f);
134 else ftw->status = FTW_SKIP;
140 * fileout() record support
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;){
147 register char* recdat;
148 register char* blkdat;
157 static char span_out[] = "0132";
160 if (!fp) error(3, "cannot handle record output from buffer");
162 f->record.blocks = 0;
164 blk = state.tmp.buffer;
173 switch (state.record.format)
188 switch (state.record.format)
201 * check for partial record from previous block
206 memcpy(recdat, pardat, partial);
219 if (p >= &rec[state.record.size] && state.record.size)
221 if (state.record.line)
224 while ((c = sfgetc(fp)) != EOF && c != '\n');
228 else if (p >= &blk[state.blocksize])
230 if (state.record.format == 'S' || state.record.format == 'V')
238 else if (partial = p - recdat)
241 * save partial record for next block
244 if (!pardat && !(pardat = newof(0, char, state.blocksize, 0)))
245 error(3, "out of space [record pushback buffer]");
246 memcpy(pardat, recdat, partial);
251 else if ((c = sfgetc(fp)) == EOF)
255 if (rec == blkdat) goto eof;
261 else if (c == '\n' && state.record.line) break;
264 switch (state.record.format)
268 sfsprintf(rec, 4, "%04d", p - rec);
272 if (c != EOF || state.record.pad)
274 memset(p, ' ', state.record.size - (p - rec));
275 p = rec + state.record.size;
280 sfsprintf(rec, 4, "%c%04d", span_out[span], p - rec);
284 if (p == recdat) *p++ = ' ';
287 rec[0] = ((p - rec) >> 8) & 0xff;
288 rec[1] = (p - rec) & 0xff;
293 if (state.record.charset && ap->format == IBMAR) mematoe(recdat, recdat, p - recdat);
295 if (p >= &blk[state.blocksize] || state.record.format == 'U') break;
298 switch (state.record.format)
302 if (state.record.pad)
304 memset(p, '^', state.blocksize - (p - blk));
305 p = blk + state.blocksize;
309 blk[0] = ((p - blk) >> 8) & 0xff;
310 blk[1] = (p - blk) & 0xff;
315 bwrite(ap, blk, p - blk);
320 if (truncated) error(1, "%s: %d out of %d record%s truncated", f->name, truncated, count, count == 1 ? "" : "s");
324 * low level for copyout()
325 * if rfd<0 && st_size>0 then input from bread()
329 fileout __PARAM__((register Archive_t* ap, register File_t* f), (ap, f)) __OTORP__(register Archive_t* ap; register File_t* f;){
336 if (f->delta.op == DELTA_verify)
339 if (f->fd >= 0) close(f->fd);
350 if (f->st->st_size > 0)
352 if (state.record.format == 'F' && !state.record.line)
355 * this is faster than recordout()
363 n = c > state.record.size ? state.record.size : c;
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
374 if (f->fd >= 0) n = read(f->fd, state.tmp.buffer, n);
375 else if (bp = getbuffer(f->fd))
377 memcpy(ap->io.next, bp->next, n);
380 else if (bread(f->ap, state.tmp.buffer, 0L, (long)n, 1) <= 0) n = -1;
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);
392 if (n < state.record.size && (c > 0 || state.record.pad))
394 memzero(state.tmp.buffer + n, state.record.size - n);
395 n = state.record.size;
397 bwrite(ap, state.tmp.buffer, n);
401 if (f->fd >= 0) close(f->fd);
403 else if (f->fd < 0) recordout(ap, f, NiL);
404 else if (!(rfp = sfnew(NiL, NiL, SF_UNBOUND, f->fd, SF_READ)))
406 error(1, "%s: cannot read", f->path);
411 recordout(ap, f, rfp);
423 n = c > state.buffersize ? state.buffersize : c;
426 if (f->fd >= 0) n = read(f->fd, ap->io.next, n);
427 else if (bp = getbuffer(f->fd))
429 memcpy(ap->io.next, bp->next, n);
432 else if (bread(f->ap, ap->io.next, 0L, (long)n, 1) <= 0) n = -1;
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);
447 if (f->fd >= 0) close(f->fd);
452 if (state.acctime && f->type != X_IFLNK)
453 settime(f->name, f->st->st_atime, f->st->st_mtime);
457 * filein() record support
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;){
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);
476 nl = state.record.line;
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;
484 if (m > state.buffersize) m = state.buffersize;
485 n = bread(ap, state.tmp.buffer, 0L, m, 1);
487 else n = bread(ap, NiL, 0L, m, 1);
493 while (getlabel(ap, f))
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);
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);
506 f->id = strcpy(state.tmp.buffer, f->id);
507 f->name = strcpy(state.tmp.buffer + ALAR_NAMESIZE + 1, f->name);
517 if (getheader(ap, &v))
519 if (streq(f->id, v.id) && streq(f->name, v.name) && f->record.section == v.record.section)
525 error(1, "volume containing %s id %s section %d required", f->name, f->id, f->record.section);
534 if (f->record.format == 'V')
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);
543 i += state.record.offset;
544 if (state.tmp.buffer[i] == '^') switch (f->record.format)
547 if (ap->format == IBMAR) break;
548 for (j = i; j < n && state.tmp.buffer[j] == '^'; j++);
561 switch (f->record.format)
564 if (sscanf(&state.tmp.buffer[i], "%4d", &k) != 1) k = -1;
568 if (i + state.record.size > n) k = n - i;
569 else if (state.record.line || state.record.offset) k = state.record.size;
574 switch (state.tmp.buffer[i])
584 if (sscanf(&state.tmp.buffer[i + 1], "%4d", &k) != 1) k = -1;
592 nl = !(state.tmp.buffer[i + 2] & 01);
593 k = ((unsigned char*)state.tmp.buffer)[i] << 8 | ((unsigned char*)state.tmp.buffer)[i + 1];
599 error(2, "invalid %s %c record size", format[ap->format].name, f->record.format);
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)
608 while (--m >= j && state.tmp.buffer[m] == ' ');
618 c = state.tmp.buffer[m];
619 state.tmp.buffer[m] = '\n';
621 if (sfwrite(wfp, &state.tmp.buffer[j], k) != k)
623 error(ERROR_SYSTEM|1, "%s: write error", f->name);
626 if (nl) state.tmp.buffer[m] = c;
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;
638 if (n < 0) error(ERROR_SYSTEM|3, "%s: %s: archive read error", ap->name, f->name);
644 * filein() saveset support
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;){
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);
661 while (getsaveset(ap, f, 0))
664 * this part transcribed from vmsbackup
668 if (wfp) while ((c + i) < f->st->st_size && i < state.saveset.lastsize) switch (state.saveset.recfmt)
670 case 1: /* fixed length */
671 if (j <= 0) j = state.saveset.reclen;
672 sfputc(wfp, state.saveset.bp[i]);
676 case 2: /* variable length */
677 case 3: /* with fixed control */
680 j = k = swapget(1, &state.saveset.bp[i], 2);
682 if (state.saveset.recfmt == 3)
684 i += state.saveset.recvfc;
685 j -= state.saveset.recvfc;
690 if (j == k && state.saveset.recatt == 1)
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';
695 sfputc(wfp, state.saveset.bp[i]);
705 case 4: /* seq stream */
706 case 5: /* seq LF stream */
708 if (state.saveset.bp[i] == '\n') j = 0;
710 sfputc(wfp, state.saveset.bp[i]);
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]);
719 error(state.keepgoing ? 1 : 3, "%s: invalid %s format data record format=%d", f->name, format[ap->format].name, state.saveset.recfmt);
735 * low level for copyin()
739 filein __PARAM__((register Archive_t* ap, register File_t* f), (ap, f)) __OTORP__(register Archive_t* ap; register File_t* f;){
748 if (f->skip) goto skip;
754 else switch (f->delta.op)
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);
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__);
767 if ((wfd = openout(ap, f)) < 0)
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);
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);
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);
791 error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
795 wfd = openout(ap, f);
800 recordin(ap, f, wfd);
804 savesetin(ap, f, wfd);
812 for (c = f->st->st_size; c > 0; c -= n)
814 n = (c > state.buffersize) ? state.buffersize : c;
815 if (!(s = bget(ap, n)))
817 error(ERROR_SYSTEM|2, "%s: read error", f->name);
820 if (holewrite(wfd, s, n) != n)
822 error(ERROR_SYSTEM|2, "%s: write error", f->name);
825 if (ap->format == ASCHK) checksum = asc_checksum(s, n, checksum);
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);
844 * skip over archive member f file data
848 fileskip __PARAM__((register Archive_t* ap, register File_t* f), (ap, f)) __OTORP__(register Archive_t* ap; register File_t* f;){
857 savesetin(ap, f, -1);
861 if (bread(ap, NiL, 0L, f->st->st_size, 1) < 0)
862 error(ERROR_SYSTEM|2, "%s: skip error", f->name);
868 * single file copyin() and copyout() smashed together
873 copyinout __PARAM__((Ftw_t* ftw), (ftw)) __OTORP__(Ftw_t* ftw;){
878 register File_t* f = &state.out->file;
880 static char path[PATH_MAX];
882 if (getfile(state.out, f, ftw) && selectfile(state.out, f))
884 strcpy(path, state.pwd);
885 strcpy(path + state.pwdlen, f->name + (*f->name == '/'));
887 if ((wfd = openout(state.out, f)) >= 0)
889 if ((rfd = openin(state.out, f)) >= 0)
892 for (c = f->st->st_size; c > 0; c -= n)
894 if ((n = read(rfd, state.tmp.buffer, (c > state.buffersize) ? state.buffersize : c)) <= 0)
896 error(ERROR_SYSTEM|2, "%s: read error", f->name);
899 if (holewrite(wfd, state.tmp.buffer, n) != n)
901 error(ERROR_SYSTEM|2, "%s: write error", f->name);
904 state.out->io.count += n;
908 setfile(state.out, f);
913 else if (wfd != -1) listentry(f);
919 * compare ft1 and ft2 for ftwalk() sort
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));
929 * copy files out using copyfile
932 typedef int (*Ftw_cmp_t) __PROTO__((Ftw_t*, Ftw_t*));
935 copy __PARAM__((register Archive_t* ap, register int (*copyfile)(Ftw_t*)), (ap, copyfile)) __OTORP__(register Archive_t* ap; register int (*copyfile)();){
944 if (state.files) n = ftwalk((char*)state.files, copyfile, state.ftwflags|FTW_MULTIPLE, state.exact ? (Ftw_cmp_t)0 : cmpftw);
947 if (s = state.peekfile)
949 else if (!(s = sfgetr(sfstdin, '\n', 1)))
951 if (ftwalk(s, copyfile, state.ftwflags, NiL))
953 error(2, "%s: not completely copied", s);
965 * position archive for appending
969 append __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
970 if (state.update) initdelta(ap);
971 ap->format = IN_DEFAULT;