⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 buffer.c

📁 unix 下tar 执行程序的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 + -