create.c

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

C
696
字号
/****************************************************************************
*
*                            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!
*
****************************************************************************/


/*
 * Create a tar archive.
 *
 * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
 * MS-DOS port 2/87 by Eric Roskos.
 * Minix  port 3/88 by Eric Roskos.
 *
 * @(#)create.c 1.19 9/9/86 Public Domain - gnu
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "tar.h"
#include "create.h"
#include "list.h"
#include "buffer.h"

#ifndef MSDOS
#include <pwd.h>
#include <grp.h>
#else                                                   /* ifdef MSDOS */
#include <assert.h>
#endif

#ifdef BSD42
#include <sys/dir.h>
#else
/*
 * FIXME: On other systems there is no standard place for the header file
 * for the portable directory access routines.  Change the #include line
 * below to bring it in from wherever it is.  Of course, where it is
 * on BSD is the standard place ... :-)?
 */
#ifdef V7
#include "dir.h"
#else
#ifdef __WATCOMC__
#include "direct.h"
#else
#include "ndir.h"
#endif /* __WATCOMC__ */
#endif /* V7 */
#endif /* !BSD42 */

#ifdef USG
#ifdef MSDOS
/* DOS doesn't have minor device numbers */
#ifndef major
    #define major(n)        n
#endif
#ifndef minor
    #define minor(n)        0
#endif
#else
#include <sys/sysmacros.h>              /* major() and minor() defined here */
#endif
#endif

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

/*
 * If there are no symbolic links, there is no lstat().  Use stat().
 */
#ifndef S_IFLNK
#define lstat stat
#endif

#include <errno.h>

union record   *start_header( char *name, struct stat *st );

void create_archive( void )
{
        char  *p;

        open_archive(0);                        /* Open for writing */

        while (p = name_next()) {
                dump_file(p);
        }

        write_eot();
        close_archive();
        name_close();
}

#ifdef MSDOS
/*
 * count the number of bytes in file f.  This is done because, with DOS,
 * the results of the stat call may not reflect the actual file size, due
 * to conversion of CR/LF pairs to plain LF's.  The *only* way to find this
 * out is to read the whole file in order to let the MSC library routines
 * determine how many characters will actually be in the file...
 */
long countbytes( int f )
{
        long            cb;
        int             n;
        char            buf[512];

        assert(lseek(f, 0L, 1) == 0L);

        for (cb = 0; (n = read(f, buf, sizeof(buf))) > 0;)
                cb += n;
        lseek(f, 0L, 0);

        assert(lseek(f, 0L, 1) == 0L);

        return (cb);
}

#endif

/*
 * Dump a single file.  If it's a directory, recurse.
 * Result is 1 for success, 0 for failure.
 */
int dump_file( char *fname )
{
        struct stat     statbuff[1];
        struct stat    *statbuf = statbuff;
        union record   *header;
        char            type;

        /*
         * Use stat if following (rather than dumping) 4.2BSD's symbolic links.
         * Otherwise, use lstat (which, on non-4.2 systems, is #define'd to stat
         * anyway.
         */
        if (0 != f_follow_links ? stat(fname, statbuf) : lstat(fname, statbuf))
        {
badperror:
                perror(fname);
badfile:
                errors++;
                return 0;
        }

        switch (statbuf->st_mode & S_IFMT)
        {

        case S_IFREG:                           /* Regular file */
                {
                        int     f;      /* File descriptor */
                        int     bufsize, count;
                        long    sizeleft;
                        long    exp, actl;      /* byte counts for file size errs */
                        int     need;           /* for block read loop */
                        int     n;      /* # bytes read in this read() call */
                        char    *bufp;           /* where to start this read in buf */
                        union record *start;

                        /*
                         * Handle a regular file with multiple links.
                         *
                         * We maintain a list of all such files that we've written so far.
                         * Any time we see another, we check the list and avoid dumping
                         * the data again if we've done it once already.
                         */
                        if (statbuf->st_nlink > 1)
                        {
                                struct link *lp;

                                /*
                                 * First quick and dirty.  Hashing, etc later FIXME
                                 */
                                for (lp = linklist; lp; lp = lp->next)
                                {
                                        if (lp->ino == statbuf->st_ino &&
                                                lp->dev == statbuf->st_dev)
                                        {
                                                /* We found a link. */
                                                statbuf->st_size = 0;
                                                header = start_header(fname, statbuf);
                                                if (header == NULL)
                                                        goto badfile;
                                                strcpy(header->header.linkname,
                                                        lp->name);
                                                header->header.linkflag = LF_LINK;
                                                finish_header(header);
                                                if (f_verbose)
                                                        annorec(stdout, (char *) NULL);
                                                printf("%s link to %s\n",
                                                        fname, lp->name);

                                                /*
                                                 * Maybe remove from list after all links found?
                                                 */

                                                /*
                                                 * If so, have to compare names in case he dumps
                                                 * twice.
                                                 */

                                                /*
                                                 * Later: I don't understand the above.  If she dumps
                                                 * the file twice, it would be BAD to dump it the
                                                 * second time as a link... gnu 25Jul86
                                                 */
                                                /* FIXME */
                                                goto donefile;
                                        }
                                }

                                /* Not found.  Add it to the list. */
                                lp = (struct link *) malloc((unsigned)
                                        (strlen(fname) + sizeof(struct link) - NAMSIZ));
                                lp->ino = statbuf->st_ino;
                                lp->dev = statbuf->st_dev;
                                strcpy(lp->name, fname);
                                lp->next = linklist;
                                linklist = lp;
                        }

                        sizeleft = statbuf->st_size;
#ifdef NOTDEF                                   /* don't understand reason for following,
                                                                 * causes abort */
                        /* Don't bother opening empty, world readable files. */
                        if (sizeleft > 0 || 0444 != (0444 & statbuf->st_mode))
                        {
#endif
                                f = open(fname, O_RDONLY | convmode(fname));
                                if (f < 0)
                                        goto badperror;
#ifdef NOTDEF
                        }
                        else
                        {
                                f = -1;
                        }
#endif

#ifdef MSDOS

                        /*
                         * See comment before countbytes(), above.
                         */
                        if (convmode(fname) & O_TEXT)
                        {
                                statbuf->st_size = countbytes(f);
                                sizeleft = statbuf->st_size;
                        }
#endif
                        exp = sizeleft;         /* number of bytes we expect to see */
                        actl = 0;                       /* number of bytes we really saw */

                        header = start_header(fname, statbuf);
                        if (header == NULL)
                                goto badfile;
                        finish_header(header);
                        while (sizeleft > 0)
                        {
                                start = findrec();
                                bufsize = endofrecs()->charptr - start->charptr;
                                if (sizeleft < bufsize)
                                        bufsize = sizeleft;

                                /*
                                 * use a read loop since reads < number requested do NOT
                                 * imply EOF as John assumed -- jer 22Aug87
                                 */
                                need = bufsize;
                                bufp = start->charptr;
                                count = 0;
                                do {
                                    n = read(f, bufp, need);
                                    if (n > 0) {
                                        count += n;
                                        bufp += n;
                                        need -= n;
                                    }
                                } while (need > 0 && n > 0);

                                if (n < 0)
                                {
                                        annorec(stderr, tar);
                                        fprintf(stderr,
                                                "read error at byte %ld, reading %d bytes, in file ",
                                                statbuf->st_size - sizeleft,
                                                bufsize);
                                        perror(fname);      /* FIXME */
                                        goto padit;
                                }

                                actl += count;
                                sizeleft -= count;

                                userec(start + (count - 1) / RECORDSIZE);
                                if (count == bufsize)
                                        continue;

                                annorec(stderr, tar);
                                fprintf(stderr,
                                        "%s: file size error: expected %ld, read %ld.\n",
                                        fname, exp, actl);
                                fprintf(stderr,
                                        "%s: file shrunk by %d bytes, padding with zeros.\n",
                                        fname, sizeleft);
                                goto padit;             /* Short read */
                        }
                        if (f >= 0)
                                (void) close(f);

                        /* Clear last block garbage to zeros, FIXME */

#ifdef OLDVERBOSE

⌨️ 快捷键说明

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