buffer.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 647 行 · 第 1/2 页

C
647
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


/*
 * Buffer management for public domain tar.
 *
 * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
 * MS-DOS port 2/87 by Eric Roskos.
 * Minix  port 3/88 by Eric Roskos.
 *
 * @(#) buffer.c 1.14 10/28/86 Public Domain - gnu
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>                  /* For non-Berkeley systems */
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <process.h>

#include "tar.h"
#include "port.h"
#include "buffer.h"

#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() */


/*
 * V7 doesn't have a #define for this.
 */
#ifndef O_RDONLY
#define O_RDONLY        0
#endif

#define MAGIC_STAT      105                     /* Magic status returned by child, if it
                                                                 * can't exec compress.  We hope compress
                                                                 * never returns this status! */
/*
 * 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;
static union record record_save_area;
static int      saved_recno;

#ifndef MSDOS
/*
 * PID of child compress program, if f_compress.
 */
static int      compress_pid;
#endif

/*
 * Record number of the start of this block of records
 */
static int      baserec;

/*
 * Error recovery stuff
 */
static int      r_error_count;


/*
 * Return the location of the next available input or output record.
 */
union record   *findrec( void )
{
    if (ar_record == ar_last) {
        flush_archive();
        if (ar_record == ar_last)
            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( 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( void )
{
    return ar_last;
}


/*
 * Open an archive file.  The argument specifies whether we are
 * reading or writing.
 *
 * With DOS, we ALWAYS open the archive in binary mode: whether or not
 * to do CRLF translations depends on whether we open the input files
 * as binary or ASCII, but we always write the archive without making
 * any translations from what this program saw when it did the write.
 */
void open_archive( int read )
{

        if (ar_file[0] == '-' && ar_file[1] == '\0')
        {
                if (read)
                        archive = STDIN;
                else
                        archive = STDOUT;
        }
        else
        if (read)
        {
#if defined(MSDOS) && !defined(__NO_PHYS__)
                archive = 9999; /* for debugging - invalid fd to cause err */

                if (!f_phys) /* don't open if we're doing direct drive I/O */
#endif
                        archive = open(ar_file, O_RDONLY
#ifdef MSDOS
                        | O_BINARY
#endif
                        );
        }
        else
        {
#if defined(MSDOS) && !defined(__NO_PHYS__)
                archive = 9999;

                if (!f_phys)
#endif
#ifdef V7
                        archive = creat(ar_file, 0666);
#else
                        archive = open(ar_file, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
                                0666);
#endif
        }

        if (archive < 0)
        {
                perror(ar_file);
                exit(EX_BADARCH);
        }

        /* NOSTRICT */
        ar_block = (union record *) valloc((unsigned) blocksize);
        if (!ar_block)
        {
                fprintf(stderr,
                        "tar: could not allocate memory for blocking factor %d\n",
                        blocking);
                exit(EX_ARGSBAD);
        }

        ar_record = ar_block;
        ar_last = ar_block + blocking;

        /*
         * Handle compressed archives.
         *
         * FIXME, currently supported for reading only. FIXME, writing involves
         * forking again for a small process that will reblock the output of
         * compress to the user's specs.
         */
#ifndef MSDOS
        if (f_compress)
        {
                int             pipes[2];
                int             err;

                if (!read)
                {
                        fprintf(stderr,
                                "tar: cannot write compressed archives yet.\n");
                        exit(EX_ARGSBAD);
                }

                /* Create a pipe to get compress's output to us */
                err = pipe(pipes);
                if (err < 0)
                {
                        perror("tar: cannot create pipe to compress");
                        exit(EX_SYSTEM);
                }

                /* Fork compress process */
                compress_pid = fork();
                if (compress_pid < 0)
                {
                        perror("tar: cannot fork compress");
                        exit(EX_SYSTEM);
                }

                /*
                 * Child process.
                 *
                 * Move input to stdin, write side of pipe to stdout, then exec
                 * compress.
                 */
                if (compress_pid == 0)
                {
                        (void) close(pipes[PREAD]);     /* We won't use it */
                        if (archive != STDIN)
                        {
                                (void) close(STDIN);
                                err = dup(archive);
                                if (err != 0)
                                {
                                        perror(
                                                "tar: cannot dup input to stdin");
                                        exit(EX_SYSTEM);
                                }
                                (void) close(archive);
                        }
                        if (pipes[PWRITE] != STDOUT)
                        {
                                (void) close(STDOUT);
                                err = dup(pipes[PWRITE]);
                                if (err != STDOUT)
                                {
                                        perror(
                                                "tar: cannot dup pipe output");
                                        exit(MAGIC_STAT);
                                }
                                (void) close(pipes[PWRITE]);
                        }
#ifdef V7
                        execl("/usr/bin/compress", "compress", "-d", (char *)0);
#else
                        execlp("compress", "compress", "-d", (char *) 0);
#endif
                        perror("tar: cannot exec compress");
                        exit(MAGIC_STAT);
                }

                /*
                 * Parent process.  Clean up. FIXME, note that this may leave
                 * standard input closed, if the compressed archive was on standard
                 * input.
                 */
                (void) close(archive);  /* Close compressed archive */
                (void) close(pipes[PWRITE]);    /* Close write side of pipe */
                archive = pipes[PREAD]; /* Read side is our archive */

#ifdef BSD42
                f_reblock++;                    /* Pipe will give random # of bytes */
#endif /* BSD42 */
        }
#endif                                                  /* MSDOS */

        ar_reading = read;
        if (read)
        {
                ar_last = ar_block;             /* Set up for 1st block = # 0 */
                flush_archive();
        }
}


/*
 * Remember a union record * as pointing to something that we
 * need to keep when reading onward in the file.  Only one such
 * thing can be remembered at once, and it only works when reading
 * an archive.
 */
void saverec(union record  **pointer)
{

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?