/* Buffer management for tar.
- Copyright (C) 1988 Free Software Foundation
+ Copyright (C) 1988, 1992 Free Software Foundation
This file is part of GNU Tar.
* Buffer management for tar.
*
* Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
- *
- * @(#) buffer.c 1.28 11/6/87 - gnu
*/
#include <stdio.h>
#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
#include <sys/types.h> /* For non-Berkeley systems */
-#include <sys/stat.h>
#include <signal.h>
+#include <time.h>
+time_t time();
-#ifndef MSDOS
+#ifdef HAVE_SYS_MTIO_H
#include <sys/ioctl.h>
-#if !defined(USG) || defined(HAVE_MTIO)
#include <sys/mtio.h>
#endif
+
+#ifdef BSD42
+#include <sys/file.h>
+#else
+#ifndef V7
+#include <fcntl.h>
+#endif
#endif
-#ifdef MSDOS
-# include <fcntl.h>
+#ifdef __MSDOS__
#include <process.h>
-#else
-# ifdef XENIX
-# include <sys/inode.h>
-# endif
-# include <sys/file.h>
#endif
-extern int errno;
+#ifdef XENIX
+#include <sys/inode.h>
+#endif
#include "tar.h"
#include "port.h"
#define PREAD 0 /* Read file descriptor from pipe() */
#define PWRITE 1 /* Write file descriptor from pipe() */
-#ifdef __STDC__
-extern void *malloc();
-extern void *valloc();
-#else
-extern char *malloc();
-extern char *valloc();
-#endif
-extern time_t time();
-
-extern char *index(), *strcat();
-extern char *strcpy();
-
-/*
- * V7 doesn't have a #define for this.
- */
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-#ifndef O_RDWR
-#define O_RDWR 2
-#endif
-#ifndef O_CREAT
-#define O_CREAT 0
-#endif
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
#define MAGIC_STAT 105 /* Magic status returned by child, if
it can't exec. We hope compress/sh
never return this status! */
+char *valloc();
+
void writeerror();
void readerror();
void ck_pipe();
void ck_close();
+int backspace_output();
extern void finish_header();
+void flush_archive();
+int isfile();
+int new_volume();
+void verify_volume();
extern void to_oct();
#ifndef __MSDOS__
/*
* Have we hit EOF yet?
*/
-static int eof;
+static int hit_eof;
+
+/* Checkpointing counter */
+static int checkpoint;
/* JF we're reading, but we just read the last record and its time to update */
extern time_to_start_writing;
static int volno = 1; /* JF which volume of a multi-volume tape
we're on */
+static int global_volno = 1; /* Volume number to print in external messages. */
char *save_name = 0; /* Name of the file we are currently writing */
long save_totsize; /* total size of file we are writing. Only
void
reset_eof()
{
- if(eof) {
- eof=0;
+ if(hit_eof) {
+ hit_eof=0;
ar_record=ar_block;
ar_last=ar_block+blocking;
ar_reading=0;
findrec()
{
if (ar_record == ar_last) {
- if (eof)
+ if (hit_eof)
return (union record *)NULL; /* EOF */
flush_archive();
if (ar_record == ar_last) {
- eof++;
+ hit_eof++;
return (union record *)NULL; /* EOF */
}
}
}
}
-#ifdef MSDOS
+#ifdef __MSDOS__
void
child_open()
{
- fprintf(stderr,"MSDOS %s can't use compressed or remote archives\n",tar);
+ fprintf(stderr,"MS-DOS %s can't use compressed or remote archives\n",tar);
exit(EX_ARGSBAD);
}
#else
{
int pipe[2];
int err = 0;
+ int nar;
int kidpipe[2];
int kidchildpid;
2: the file is to be accessed by rmt (compress doesn't know how)
3: the file is not a plain file */
#ifdef NO_REMOTE
- if(!(ar_file[0]=='-' && ar_file[1]=='\0') && isfile(ar_file))
+ if(!(ar_files[0][0]=='-' && ar_files[0][1]=='\0') && isfile(ar_files[0]))
#else
- if(!(ar_file[0]=='-' && ar_file[1]=='\0') && !_remdev(ar_file) && isfile(ar_file))
+ if(!(ar_files[0][0]=='-' && ar_file[0][1]=='\0') && !_remdev(ar_files[0]) && isfile(ar_files[0]))
#endif
{
/* We don't need a child tar. Open the archive */
if(ar_reading) {
- archive=open(ar_file, O_RDONLY|O_BINARY, 0666);
+ archive=open(ar_files[0], O_RDONLY|O_BINARY, 0666);
if(archive<0) {
- msg_perror("can't open archive %s",ar_file);
+ msg_perror("can't open archive %s",ar_files[0]);
exit(EX_BADARCH);
}
dupto(archive,STDIN,"archive to stdin");
/* close(archive); */
} else {
- archive=creat(ar_file,0666);
+ archive=creat(ar_files[0],0666);
if(archive<0) {
- msg_perror("can't open archive %s",ar_file);
+ msg_perror("can't open archive %s",ar_files[0]);
exit(EX_BADARCH);
}
dupto(archive,STDOUT,"archive to stdout");
else
archive = STDOUT;
} else /* This can't happen if (ar_reading==2)
- archive = rmtopen(ar_file, O_RDWR|O_CREAT|O_BINARY, 0666);
+ archive = rmtopen(ar_files[0], O_RDWR|O_CREAT|O_BINARY, 0666);
else */if(ar_reading)
- archive = rmtopen(ar_file, O_RDONLY|O_BINARY, 0666);
+ archive = rmtopen(ar_files[0], O_RDONLY|O_BINARY, 0666);
else
- archive = rmtcreat(ar_file, 0666);
+ archive = rmtcreat(ar_files[0], 0666);
if (archive < 0) {
- msg_perror("can't open archive %s",ar_file);
+ msg_perror("can't open archive %s",ar_files[0]);
exit(EX_BADARCH);
}
/* return non-zero if p is the name of a directory */
+int
isfile(p)
char *p;
{
if(stat(p,&stbuf)<0)
return 1;
- if((stbuf.st_mode&S_IFMT)==S_IFREG)
+ if(S_ISREG(stbuf.st_mode))
return 1;
return 0;
}
* reading or writing.
*/
/* JF if the arg is 2, open for reading and writing. */
+void
open_archive(reading)
int reading;
{
exit(EX_ARGSBAD);
}
- if(ar_file==0) {
+ if(n_ar_files==0) {
msg("No archive name given, what should I do?");
exit(EX_BADARCH);
}
msg("cannot update or verify compressed archives");
exit(EX_ARGSBAD);
}
+ if (f_multivol) {
+ msg ("cannot use multi-volume compressed archives");
+ exit (EX_ARGSBAD);
+ }
child_open();
- if(!reading && ar_file[0]=='-' && ar_file[1]=='\0')
+ if(!reading && ar_files[0][0]=='-' && ar_files[0][1]=='\0')
msg_file = stderr;
/* child_open(rem_host, rem_file); */
- } else if (ar_file[0] == '-' && ar_file[1] == '\0') {
+ } else if (ar_files[0][0] == '-' && ar_files[0][1] == '\0') {
f_reblock++; /* Could be a pipe, be safe */
if(f_verify) {
msg("can't verify stdin/stdout archive");
msg_file = stderr;
}
} else if (reading==2 || f_verify) {
- archive = rmtopen(ar_file, O_RDWR|O_CREAT|O_BINARY, 0666);
+ archive = rmtopen(ar_files[0], O_RDWR|O_CREAT|O_BINARY, 0666);
} else if(reading) {
- archive = rmtopen(ar_file, O_RDONLY|O_BINARY, 0666);
+ archive = rmtopen(ar_files[0], O_RDONLY|O_BINARY, 0666);
} else {
- archive = rmtcreat(ar_file, 0666);
+ archive = rmtcreat(ar_files[0], 0666);
+ }
+ if (archive < 0) {
+ msg_perror("can't open %s",ar_files[0]);
+ exit(EX_BADARCH);
}
#ifndef __MSDOS__
if(!_isrmt(archive)) {
struct stat tmp_stat;
fstat(archive,&tmp_stat);
- if((tmp_stat.st_mode&S_IFMT)==S_IFREG) {
+ if(S_ISREG(tmp_stat.st_mode)) {
ar_dev=tmp_stat.st_dev;
ar_ino=tmp_stat.st_ino;
}
}
#endif
- if (archive < 0) {
- msg_perror("can't open %s",ar_file);
- exit(EX_BADARCH);
- }
-#ifdef MSDOS
+#ifdef __MSDOS__
setmode(archive, O_BINARY);
#endif
* adding (baserec+ar_record), doing a 9-bit shift of baserec, then
* subtracting ar_block from that, shifting it back, losing the top 9 bits.
*/
+void
saverec(pointer)
union record **pointer;
{
}
*/
+void
fl_write()
{
int err;
int copy_back;
static long bytes_written = 0;
+ if (f_checkpoint && ! (++checkpoint % 10))
+ msg ("Write checkpoint %d\n", checkpoint);
if(tape_length && bytes_written >= tape_length * 1024) {
errno = ENOSPC;
err = 0;
real_s_sizeleft = 0;
return;
}
-#ifdef MSDOS
+#ifdef __MSDOS__
if(save_name[1]==':')
save_name+=2;
#endif
/* We're multivol Panic if we didn't get the right kind of response */
/* ENXIO is for the UNIX PC */
- if(err>0 || (err<0 && errno!=ENOSPC && errno!=EIO && errno!=ENXIO))
+ if(err<0 && errno!=ENOSPC && errno!=EIO && errno!=ENXIO)
writeerror(err);
+ /* If error indicates a short write, we just move to the next tape. */
+
if(new_volume(0)<0)
return;
bytes_written=0;
else if((real_s_sizeleft+RECORDSIZE-1)/RECORDSIZE<=copy_back)
real_s_name[0] = '\0';
else {
-#ifdef MSDOS
+#ifdef __MSDOS__
if(save_name[1]==':')
save_name+=2;
#endif
int err;
{
if (err < 0) {
- msg_perror("can't write to %s",ar_file);
+ msg_perror("can't write to %s",ar_files[cur_ar_file]);
exit(EX_BADARCH);
} else {
- msg("only wrote %u of %u bytes to %s",err,blocksize,ar_file);
+ msg("only wrote %u of %u bytes to %s",err,blocksize,ar_files[cur_ar_file]);
exit(EX_BADARCH);
}
}
read_error_flag++; /* Tell callers */
- msg_perror("read error on %s",ar_file);
+ msg_perror("read error on %s",ar_files[cur_ar_file]);
if (baserec == 0) {
/* First block of tape. Probably stupidity error */
/*
* Perform a read to flush the buffer.
*/
+void
fl_read()
{
int err; /* Result from system call */
int left; /* Bytes left */
char *more; /* Pointer to next byte to read */
+ if (f_checkpoint && ! (++checkpoint % 10))
+ msg ("Read checkpoint %d\n", checkpoint);
+
/*
* Clear the count of errors. This only applies to a single
* call to fl_read. We leave read_error_flag alone; it is
if(f_multivol) {
if(save_name) {
if(save_name!=real_s_name) {
-#ifdef MSDOS
+#ifdef __MSDOS__
if(save_name[1]==':')
save_name+=2;
#endif
if (err == blocksize)
return;
- if((err == 0 || (err<0 && errno==ENOSPC)) && f_multivol) {
+ if((err == 0 || (err<0 && errno==ENOSPC) || (err > 0 && !f_reblock)) && f_multivol) {
union record *head;
try_volume:
msg("Volume mismatch! %s!=%s",f_volhdr,
head->header.name);
--volno;
+ --global_volno;
goto try_volume;
}
if(strcmp(ptr,head->header.name)) {
msg("Volume mismatch! %s!=%s",ptr,head->header.name);
--volno;
+ --global_volno;
free(ptr);
goto try_volume;
}
if(head->header.linkflag!=LF_MULTIVOL || strcmp(head->header.name,real_s_name)) {
msg("%s is not continued on this volume!",real_s_name);
--volno;
+ --global_volno;
goto try_volume;
}
if(real_s_totsize!=from_oct(1+12,head->header.size)+from_oct(1+12,head->header.offset)) {
from_oct(1+12,head->header.size),
from_oct(1+12,head->header.offset));
--volno;
+ --global_volno;
goto try_volume;
}
if(real_s_totsize-real_s_sizeleft!=from_oct(1+12,head->header.offset)) {
msg("This volume is out of sequence");
--volno;
+ --global_volno;
goto try_volume;
}
head++;
goto error2loop; /* Try again */
}
if (err == 0) {
- msg("archive %s EOF not on block boundary",ar_file);
+ msg("archive %s EOF not on block boundary",ar_files[cur_ar_file]);
exit(EX_BADARCH);
}
left -= err;
goto again;
}
} else {
- msg("only read %d bytes from archive %s",err,ar_file);
+ msg("only read %d bytes from archive %s",err,ar_files[cur_ar_file]);
exit(EX_BADARCH);
}
}
/*
* Flush the current buffer to/from the archive.
*/
+void
flush_archive()
{
int c;
if(file_to_switch_to>=0) {
if((c=rmtclose(archive))<0)
- msg_perror("Warning: can't close %s(%d,%d)",ar_file,archive,c);
+ msg_perror("Warning: can't close %s(%d,%d)",ar_files[cur_ar_file],archive,c);
archive=file_to_switch_to;
} else
/* Backspace the archive descriptor by one blocks worth.
If its a tape, MTIOCTOP will work. If its something else,
we try to seek on it. If we can't seek, we lose! */
+int
backspace_output()
{
long cur;
/*
* Close the archive file.
*/
+void
close_archive()
{
int child;
if (time_to_start_writing || !ar_reading)
flush_archive();
if(cmd_mode==CMD_DELETE) {
- long pos;
+ off_t pos;
pos = rmtlseek(archive,0L,1);
-#ifndef MSDOS
- /* FIXME does ftruncate really take an INT?! */
- (void) ftruncate(archive,(int)pos);
+#ifndef __MSDOS__
+ (void) ftruncate(archive,pos);
#else
(void)rmtwrite(archive,"",0);
#endif
verify_volume();
if((c=rmtclose(archive))<0)
- msg_perror("Warning: can't close %s(%d,%d)",ar_file,archive,c);
+ msg_perror("Warning: can't close %s(%d,%d)",ar_files[cur_ar_file],archive,c);
-#ifndef MSDOS
+#ifndef __MSDOS__
if (childpid) {
/*
* Loop waiting for the right child to die, or for
;
if (child != -1) {
- switch (TERM_SIGNAL(status)) {
+ switch (WTERMSIG(status)) {
case 0:
/* Child voluntarily terminated -- but why? */
- if (TERM_VALUE(status) == MAGIC_STAT) {
+ if (WEXITSTATUS(status) == MAGIC_STAT) {
exit(EX_SYSTEM);/* Child had trouble */
}
- if (TERM_VALUE(status) == (SIGPIPE + 128)) {
+ if (WEXITSTATUS(status) == (SIGPIPE + 128)) {
/*
* /bin/sh returns this if its child
* dies with SIGPIPE. 'Sok.
*/
break;
- } else if (TERM_VALUE(status))
+ } else if (WEXITSTATUS(status))
msg("child returned status %d",
- TERM_VALUE(status));
+ WEXITSTATUS(status));
case SIGPIPE:
break; /* This is OK. */
default:
msg("child died with signal %d%s",
- TERM_SIGNAL(status),
- TERM_COREDUMP(status)? " (core dumped)": "");
+ WTERMSIG(status),
+ WIFCOREDUMPED(status)? " (core dumped)": "");
}
}
}
-#endif /* MSDOS */
+#endif /* __MSDOS__ */
}
}
#endif
+/* Called to initialize the global volume number. */
+int
+init_volume_number ()
+{
+ FILE *vf;
+
+ vf = fopen (f_volno_file, "r");
+ if (!vf && errno != ENOENT)
+ msg_perror ("%s", f_volno_file);
+
+ if (vf)
+ {
+ fscanf (vf, "%d", &global_volno);
+ fclose (vf);
+ }
+}
+
+/* Called to write out the closing global volume number. */
+int
+closeout_volume_number ()
+{
+ FILE *vf;
+
+ vf = fopen (f_volno_file, "w");
+ if (!vf)
+ msg_perror ("%s", f_volno_file);
+ else
+ {
+ fprintf (vf, "%d\n", global_volno);
+ fclose (vf);
+ }
+}
+
/* We've hit the end of the old volume. Close it and open the next one */
/* Values for type: 0: writing 1: reading 2: updating */
+int
new_volume(type)
int type;
{
extern int now_verifying;
extern char TTY_NAME[];
char *getenv();
+ static int looped = 0;
if(!read_file && !f_run_script_at_end)
read_file = (archive==0) ? fopen(TTY_NAME, "r") : stdin;
if(f_verify)
verify_volume();
if((c=rmtclose(archive))<0)
- msg_perror("Warning: can't close %s(%d,%d)",ar_file,archive,c);
+ msg_perror("Warning: can't close %s(%d,%d)",ar_files[cur_ar_file],archive,c);
+ global_volno++;
volno++;
+ cur_ar_file++;
+ if (cur_ar_file == n_ar_files)
+ {
+ cur_ar_file = 0;
+ looped = 1;
+ }
+
tryagain:
- if (f_run_script_at_end)
- system(info_script);
- else for(;;) {
- fprintf(msg_file,"\007Prepare volume #%d and hit return: ",volno);
- fflush(msg_file);
- if(fgets(inbuf,sizeof(inbuf),read_file)==0) {
- fprintf(msg_file,"EOF? What does that mean?");
- if(cmd_mode!=CMD_EXTRACT && cmd_mode!=CMD_LIST && cmd_mode!=CMD_DIFF)
- msg("Warning: Archive is INCOMPLETE!");
- exit(EX_BADARCH);
- }
- if(inbuf[0]=='\n' || inbuf[0]=='y' || inbuf[0]=='Y')
- break;
-
- switch(inbuf[0]) {
- case '?':
- {
- fprintf(msg_file,"\
+ if (looped)
+ {
+ /* We have to prompt from now on. */
+ if (f_run_script_at_end)
+ system(info_script);
+ else for(;;) {
+ fprintf(msg_file,"\007Prepare volume #%d for %s and hit return: ",global_volno, ar_files[cur_ar_file]);
+ fflush(msg_file);
+ if(fgets(inbuf,sizeof(inbuf),read_file)==0) {
+ fprintf(msg_file,"EOF? What does that mean?");
+ if(cmd_mode!=CMD_EXTRACT && cmd_mode!=CMD_LIST && cmd_mode!=CMD_DIFF)
+ msg("Warning: Archive is INCOMPLETE!");
+ exit(EX_BADARCH);
+ }
+ if(inbuf[0]=='\n' || inbuf[0]=='y' || inbuf[0]=='Y')
+ break;
+
+ switch(inbuf[0]) {
+ case '?':
+ {
+ fprintf(msg_file,"\
n [name] Give a new filename for the next (and subsequent) volume(s)\n\
q Abort tar\n\
! Spawn a subshell\n\
? Print this list\n");
- }
- break;
-
- case 'q': /* Quit */
- fprintf(msg_file,"No new volume; exiting.\n");
- if(cmd_mode!=CMD_EXTRACT && cmd_mode!=CMD_LIST && cmd_mode!=CMD_DIFF)
- msg("Warning: Archive is INCOMPLETE!");
- exit(EX_BADARCH);
-
- case 'n': /* Get new file name */
- {
- char *q,*r;
- static char *old_name;
-
- for(q= &inbuf[1];*q==' ' || *q=='\t';q++)
- ;
- for(r=q;*r;r++)
- if(*r=='\n')
- *r='\0';
- if(old_name)
- free(old_name);
- old_name=p=(char *)malloc((unsigned)(strlen(q)+2));
- if(p==0) {
- msg("Can't allocate memory for name");
- exit(EX_SYSTEM);
- }
- (void) strcpy(p,q);
- ar_file=p;
- }
- break;
-
- case '!':
-#ifdef MSDOS
- spawnl(P_WAIT,getenv("COMSPEC"),"-",0);
-#else
- /* JF this needs work! */
- switch(fork()) {
- case -1:
- msg_perror("can't fork!");
- break;
- case 0:
- p=getenv("SHELL");
- if(p==0) p="/bin/sh";
- execlp(p,"-sh","-i",0);
- msg_perror("can't exec a shell %s",p);
- _exit(55);
- default:
- wait(0);
- break;
- }
-#endif
- break;
- }
+ }
+ break;
+
+ case 'q': /* Quit */
+ fprintf(msg_file,"No new volume; exiting.\n");
+ if(cmd_mode!=CMD_EXTRACT && cmd_mode!=CMD_LIST && cmd_mode!=CMD_DIFF)
+ msg("Warning: Archive is INCOMPLETE!");
+ exit(EX_BADARCH);
+
+ case 'n': /* Get new file name */
+ {
+ char *q,*r;
+ static char *old_name;
+
+ for(q= &inbuf[1];*q==' ' || *q=='\t';q++)
+ ;
+ for(r=q;*r;r++)
+ if(*r=='\n')
+ *r='\0';
+ old_name=p=(char *)malloc((unsigned)(strlen(q)+2));
+ if(p==0) {
+ msg("Can't allocate memory for name");
+ exit(EX_SYSTEM);
+ }
+ (void) strcpy(p,q);
+ ar_files[cur_ar_file]=p;
+ }
+ break;
+
+ case '!':
+ #ifdef __MSDOS__
+ spawnl(P_WAIT,getenv("COMSPEC"),"-",0);
+ #else
+ /* JF this needs work! */
+ switch(fork()) {
+ case -1:
+ msg_perror("can't fork!");
+ break;
+ case 0:
+ p=getenv("SHELL");
+ if(p==0) p="/bin/sh";
+ execlp(p,"-sh","-i",0);
+ msg_perror("can't exec a shell %s",p);
+ _exit(55);
+ default:
+ wait(0);
+ break;
+ }
+ #endif
+ break;
+ }
+ }
}
+
if(type==2 || f_verify)
- archive=rmtopen(ar_file,O_RDWR|O_CREAT,0666);
+ archive=rmtopen(ar_files[cur_ar_file],O_RDWR|O_CREAT,0666);
else if(type==1)
- archive=rmtopen(ar_file,O_RDONLY,0666);
+ archive=rmtopen(ar_files[cur_ar_file],O_RDONLY,0666);
else if(type==0)
- archive=rmtcreat(ar_file,0666);
+ archive=rmtcreat(ar_file[cur_ar_file],0666);
else
archive= -1;
if(archive<0) {
- msg_perror("can't open %s",ar_file);
+ msg_perror("can't open %s",ar_files[cur_ar_file]);
goto tryagain;
}
-#ifdef MSDOS
+#ifdef __MSDOS__
setmode(archive,O_BINARY);
#endif
return 0;