📄 buffer.c
字号:
/* Buffer management for tar.
Copyright (C) 1988 Free Software Foundation
This file is part of GNU Tar.
GNU Tar is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU Tar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Tar; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* 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>
#include <sys/types.h> /* For non-Berkeley systems */
#include <sys/stat.h>
#include <signal.h>
#ifndef MSDOS
#include <sys/ioctl.h>
#if !defined(USG) || defined(HAVE_MTIO)
#include <sys/mtio.h>
#endif
#endif
#ifdef MSDOS
# include <fcntl.h>
#include <process.h>
#else
# ifdef XENIX
# include <sys/inode.h>
# endif
# include <sys/file.h>
#endif
extern int errno;
#include "tar.h"
#include "port.h"
#include "rmt.h"
#include "regex.h"
/* Either stdout or stderr: The thing we write messages (standard msgs, not
errors) to. Stdout unless we're writing a pipe, in which case stderr */
FILE *msg_file = stdout;
#define STDIN 0 /* Standard input file descriptor */
#define STDOUT 1 /* Standard output file descriptor */
#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! */
void writeerror();
void readerror();
void ck_pipe();
void ck_close();
extern void finish_header();
extern void to_oct();
#ifndef __MSDOS__
/* Obnoxious test to see if dimwit is trying to dump the archive */
dev_t ar_dev;
ino_t ar_ino;
#endif
/*
* The record pointed to by save_rec should not be overlaid
* when reading in a new tape block. Copy it to record_save_area first, and
* change the pointer in *save_rec to point to record_save_area.
* Saved_recno records the record number at the time of the save.
* This is used by annofile() to print the record number of a file's
* header record.
*/
static union record **save_rec;
union record record_save_area;
static long saved_recno;
/*
* PID of child program, if f_compress or remote archive access.
*/
static int childpid = 0;
/*
* Record number of the start of this block of records
*/
long baserec;
/*
* Error recovery stuff
*/
static int r_error_count;
/*
* Have we hit EOF yet?
*/
static int eof;
/* JF we're reading, but we just read the last record and its time to update */
extern time_to_start_writing;
int file_to_switch_to= -1; /* If remote update, close archive, and use
this descriptor to write to */
static int volno = 1; /* JF which volume of a multi-volume tape
we're on */
char *save_name = 0; /* Name of the file we are currently writing */
long save_totsize; /* total size of file we are writing. Only
valid if save_name is non_zero */
long save_sizeleft; /* Where we are in the file we are writing.
Only valid if save_name is non-zero */
int write_archive_to_stdout;
/* Used by fl_read and fl_write to store the real info about saved names */
static char real_s_name[NAMSIZ];
static long real_s_totsize;
static long real_s_sizeleft;
/* Reset the EOF flag (if set), and re-set ar_record, etc */
void
reset_eof()
{
if(eof) {
eof=0;
ar_record=ar_block;
ar_last=ar_block+blocking;
ar_reading=0;
}
}
/*
* Return the location of the next available input or output record.
* Return NULL for EOF. Once we have returned NULL, we just keep returning
* it, to avoid accidentally going on to the next file on the "tape".
*/
union record *
findrec()
{
if (ar_record == ar_last) {
if (eof)
return (union record *)NULL; /* EOF */
flush_archive();
if (ar_record == ar_last) {
eof++;
return (union record *)NULL; /* EOF */
}
}
return ar_record;
}
/*
* Indicate that we have used all records up thru the argument.
* (should the arg have an off-by-1? XXX FIXME)
*/
void
userec(rec)
union record *rec;
{
while(rec >= ar_record)
ar_record++;
/*
* Do NOT flush the archive here. If we do, the same
* argument to userec() could mean the next record (if the
* input block is exactly one record long), which is not what
* is intended.
*/
if (ar_record > ar_last)
abort();
}
/*
* Return a pointer to the end of the current records buffer.
* All the space between findrec() and endofrecs() is available
* for filling with data, or taking data from.
*/
union record *
endofrecs()
{
return ar_last;
}
/*
* Duplicate a file descriptor into a certain slot.
* Equivalent to BSD "dup2" with error reporting.
*/
void
dupto(from, to, msg)
int from, to;
char *msg;
{
int err;
if (from != to) {
err=close(to);
if(err<0 && errno!=EBADF) {
msg_perror("Cannot close descriptor %d",to);
exit(EX_SYSTEM);
}
err = dup(from);
if (err != to) {
msg_perror("cannot dup %s",msg);
exit(EX_SYSTEM);
}
ck_close(from);
}
}
#ifdef MSDOS
void
child_open()
{
fprintf(stderr,"MSDOS %s can't use compressed or remote archives\n",tar);
exit(EX_ARGSBAD);
}
#else
void
child_open()
{
int pipe[2];
int err = 0;
int kidpipe[2];
int kidchildpid;
#define READ 0
#define WRITE 1
ck_pipe(pipe);
childpid=fork();
if(childpid<0) {
msg_perror("cannot fork");
exit(EX_SYSTEM);
}
if(childpid>0) {
/* We're the parent. Clean up and be happy */
/* This, at least, is easy */
if(ar_reading) {
f_reblock++;
archive=pipe[READ];
ck_close(pipe[WRITE]);
} else {
archive = pipe[WRITE];
ck_close(pipe[READ]);
}
return;
}
/* We're the kid */
if(ar_reading) {
dupto(pipe[WRITE],STDOUT,"(child) pipe to stdout");
ck_close(pipe[READ]);
} else {
dupto(pipe[READ],STDIN,"(child) pipe to stdin");
ck_close(pipe[WRITE]);
}
/* We need a child tar only if
1: we're reading/writing stdin/out (to force reblocking)
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))
#else
if(!(ar_file[0]=='-' && ar_file[1]=='\0') && !_remdev(ar_file) && isfile(ar_file))
#endif
{
/* We don't need a child tar. Open the archive */
if(ar_reading) {
archive=open(ar_file, O_RDONLY|O_BINARY, 0666);
if(archive<0) {
msg_perror("can't open archive %s",ar_file);
exit(EX_BADARCH);
}
dupto(archive,STDIN,"archive to stdin");
/* close(archive); */
} else {
archive=creat(ar_file,0666);
if(archive<0) {
msg_perror("can't open archive %s",ar_file);
exit(EX_BADARCH);
}
dupto(archive,STDOUT,"archive to stdout");
/* close(archive); */
}
} else {
/* We need a child tar */
ck_pipe(kidpipe);
kidchildpid=fork();
if(kidchildpid<0) {
msg_perror("child can't fork");
exit(EX_SYSTEM);
}
if(kidchildpid>0) {
/* About to exec compress: set up the files */
if(ar_reading) {
dupto(kidpipe[READ],STDIN,"((child)) pipe to stdin");
ck_close(kidpipe[WRITE]);
/* dup2(pipe[WRITE],STDOUT); */
} else {
/* dup2(pipe[READ],STDIN); */
dupto(kidpipe[WRITE],STDOUT,"((child)) pipe to stdout");
ck_close(kidpipe[READ]);
}
/* ck_close(pipe[READ]); */
/* ck_close(pipe[WRITE]); */
/* ck_close(kidpipe[READ]);
ck_close(kidpipe[WRITE]); */
} else {
/* Grandchild. Do the right thing, namely sit here and
read/write the archive, and feed stuff back to compress */
tar="tar (child)";
if(ar_reading) {
dupto(kidpipe[WRITE],STDOUT,"[child] pipe to stdout");
ck_close(kidpipe[READ]);
} else {
dupto(kidpipe[READ],STDIN,"[child] pipe to stdin");
ck_close(kidpipe[WRITE]);
}
if (ar_file[0] == '-' && ar_file[1] == '\0') {
if (ar_reading)
archive = STDIN;
else
archive = STDOUT;
} else /* This can't happen if (ar_reading==2)
archive = rmtopen(ar_file, O_RDWR|O_CREAT|O_BINARY, 0666);
else */if(ar_reading)
archive = rmtopen(ar_file, O_RDONLY|O_BINARY, 0666);
else
archive = rmtcreat(ar_file, 0666);
if (archive < 0) {
msg_perror("can't open archive %s",ar_file);
exit(EX_BADARCH);
}
if(ar_reading) {
for(;;) {
char *ptr;
int max,count;
r_error_count = 0;
error_loop:
err=rmtread(archive, ar_block->charptr,(int)(blocksize));
if(err<0) {
readerror();
goto error_loop;
}
if(err==0)
break;
ptr = ar_block->charptr;
max = err;
while(max) {
count = (max<RECORDSIZE) ? max : RECORDSIZE;
err=write(STDOUT,ptr,count);
if(err!=count) {
if(err<0) {
msg_perror("can't write to compress");
exit(EX_SYSTEM);
} else
msg("write to compress short %d bytes",count-err);
count = (err<0) ? 0 : err;
}
ptr+=count;
max-=count;
}
}
} else {
for(;;) {
int n;
char *ptr;
n=blocksize;
ptr = ar_block->charptr;
while(n) {
err=read(STDIN,ptr,(n<RECORDSIZE) ? n : RECORDSIZE);
if(err<=0)
break;
n-=err;
ptr+=err;
}
/* EOF */
if(err==0) {
if(f_compress<2)
blocksize-=n;
else
bzero(ar_block->charptr+blocksize-n,n);
err=rmtwrite(archive,ar_block->charptr,blocksize);
if(err!=(blocksize))
writeerror(err);
if(f_compress<2)
blocksize+=n;
break;
}
if(n) {
msg_perror("can't read from compress");
exit(EX_SYSTEM);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -