1549 lines
34 KiB
C
1549 lines
34 KiB
C
/************************************************************************
|
||
* *
|
||
* Copyright (c) 1984, Fred Fish *
|
||
* All Rights Reserved *
|
||
* *
|
||
* This software and/or documentation is protected by U.S. *
|
||
* Copyright Law (Title 17 United States Code). Unauthorized *
|
||
* reproduction and/or sales may result in imprisonment of up *
|
||
* to 1 year and fines of up to $10,000 (17 USC 506). *
|
||
* Copyright infringers may also be subject to civil liability. *
|
||
* *
|
||
************************************************************************
|
||
*/
|
||
|
||
|
||
/*
|
||
* FILE
|
||
*
|
||
* utils.c general utility routines
|
||
*
|
||
* SCCS
|
||
*
|
||
* @(#)utils.c 9.11 5/11/88
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Contains routines which are general in nature and didn't
|
||
* seem to fit in any other file.
|
||
*
|
||
*/
|
||
|
||
#include "autoconfig.h"
|
||
|
||
#include <stdio.h>
|
||
#include <limits.h>
|
||
|
||
#if (unix || xenix)
|
||
# include <sys/types.h>
|
||
# include <sys/stat.h>
|
||
# include <fcntl.h>
|
||
#else
|
||
# include "sys.h"
|
||
#endif
|
||
|
||
#include "typedefs.h" /* Locally defined types */
|
||
#include "dbug.h"
|
||
#include "manifest.h" /* Manifest constants */
|
||
#include "config.h" /* Configuration file */
|
||
#include "errors.h" /* Error codes */
|
||
#include "blocks.h" /* Archive structures */
|
||
#include "macros.h" /* Useful macros */
|
||
#include "finfo.h" /* File information structure */
|
||
#include "flags.h" /* Command line flags */
|
||
#include "bruinfo.h" /* Invocation information */
|
||
|
||
#if (unix || xenix)
|
||
#define TEMPLATE "%s/%s"
|
||
#else
|
||
#define TEMPLATE "%s%s"
|
||
#endif
|
||
|
||
|
||
/*
|
||
* External bru functions.
|
||
*/
|
||
|
||
extern S32BIT s_lseek (); /* Seek to location in file */
|
||
extern BOOLEAN execute (); /* Execute a child process */
|
||
extern int ar_vol (); /* Find current volume number */
|
||
extern LBA ar_tell (); /* Give current block number */
|
||
extern BOOLEAN file_access (); /* Test file for access */
|
||
extern BOOLEAN new_arfile (); /* Load a new volume */
|
||
extern VOID bru_error (); /* Report an error to user */
|
||
extern VOID done (); /* Wrapup and exit */
|
||
extern char *s_getenv (); /* Get an environment variable */
|
||
extern int s_link (); /* Link files */
|
||
extern VOID s_fflush (); /* Invoke library fflush function */
|
||
extern int s_chown (); /* Invoke library change owner func */
|
||
extern int s_utime (); /* Invoke library function utime */
|
||
extern char *s_malloc (); /* Allocate memory */
|
||
extern BOOLEAN iscondlink (); /* Decide if have a conditional sym link */
|
||
extern char *univlink (); /* Return the proper file for a non pyramid */
|
||
extern char *namelink (); /* Print what a cond link points to */
|
||
extern int s_mkdir (); /* System call to make a new directory */
|
||
extern char *getlinkname();
|
||
|
||
#if HAVE_SYMLINKS
|
||
extern int s_readlink (); /* Invoke library read symbolic link func */
|
||
extern int s_symlink (); /* Invoke library make symbolic link func */
|
||
#endif
|
||
|
||
#if pyr
|
||
extern int s_csymlink (); /* Invoke library make cond sym link func */
|
||
#endif
|
||
|
||
/*
|
||
* External bru variables.
|
||
*/
|
||
|
||
extern time_t ntime; /* Time for -n option */
|
||
extern uid_t uid; /* User ID derived via -o option */
|
||
extern struct cmd_flags flags; /* Command line flags */
|
||
extern char mode; /* Current execution mode */
|
||
extern struct bru_info info; /* Current invocation information */
|
||
extern FILE *logfp; /* Verbosity messages */
|
||
extern char* working_dir; /* pathname of current working dir */
|
||
|
||
int getsize_err; /* to distinguish err 0 return from normal 0 */
|
||
|
||
/*
|
||
* Functions defined here.
|
||
*/
|
||
|
||
VOID finfo_init (); /* Initialize a finfo structure */
|
||
|
||
|
||
/*
|
||
* NAME
|
||
*
|
||
* eoablk test block for end of archive marker block
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN eoablk (blkp)
|
||
* register union blk *blkp;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Test block to see if it is the end of archive terminator block.
|
||
*
|
||
* Note that there is some question about a logical return
|
||
* value if the pointer is NULL. It was arbitrarily
|
||
* decided to return TRUE in this case, as if the end
|
||
* of the archive was found.
|
||
*
|
||
*/
|
||
|
||
|
||
/*
|
||
* PSEUDO CODE
|
||
*
|
||
* Begin eoablk
|
||
* Set default return to TRUE
|
||
* If block pointer is valid then
|
||
* Test for end of block
|
||
* End if
|
||
* Return result
|
||
* End eoablk
|
||
*
|
||
*/
|
||
|
||
BOOLEAN eoablk (blkp)
|
||
register union blk *blkp;
|
||
{
|
||
register BOOLEAN result; /* Result of test */
|
||
|
||
DBUG_ENTER ("eoablk");
|
||
result = TRUE;
|
||
if (blkp == NULL) {
|
||
bru_error (ERR_BUG, "eoablk");
|
||
} else {
|
||
result = (FROMHEX (blkp -> HD.h_magic) == T_MAGIC);
|
||
}
|
||
DBUG_RETURN (result);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* zeroblk zero an archive block
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID zeroblk (blkp)
|
||
* register union blk *blkp;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to an archive block, zeros the block.
|
||
*
|
||
* At one time, when the block was treated as an array
|
||
* of BLKSIZE bytes, bru was spending about 10% of it's
|
||
* time simply zeroing the block one byte at a time.
|
||
* By going to longs, the time was considerably reduced.
|
||
* If the preprocessor define HAVE_MEMSET is nonzero then
|
||
* the library memset routine will be called instead of
|
||
* zeroblk.
|
||
*
|
||
*/
|
||
|
||
#if !HAVE_MEMSET
|
||
|
||
VOID zeroblk (blkp)
|
||
register union blk *blkp;
|
||
{
|
||
register long *lp;
|
||
|
||
DBUG_ENTER ("zeroblk");
|
||
if (blkp == NULL) {
|
||
bru_error (ERR_BUG, "zeroblk");
|
||
} else {
|
||
lp = blkp -> longs;
|
||
while (lp < OVERRUN (blkp -> longs)) {
|
||
*lp++ = 0L;
|
||
}
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
#endif /* !HAVE_MEMSET */
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* copyname copy a pathname from one place to another
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID copyname (out, in)
|
||
* char *out;
|
||
* char *in;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Copyname copies a pathname from one location to another,
|
||
* enforcing the current size limit on pathnames set by
|
||
* the manifest constant "NAMESIZE" in the configuration file.
|
||
*
|
||
* If however, the input name is too long, then the output
|
||
* will be truncated and null terminated such that the
|
||
* output still fits in an array of size "NAMESIZE".
|
||
*
|
||
* If the -Z command line option is given, we reduce the
|
||
* maximum name length by two characters, so that a ".Z" can
|
||
* always be tacked on later if necessary, without having
|
||
* to check again for overflow.
|
||
*
|
||
*/
|
||
|
||
VOID copyname (out, in)
|
||
char *out;
|
||
char *in;
|
||
{
|
||
BOOLEAN copy ();
|
||
int namesize = NAMESIZE;
|
||
|
||
DBUG_ENTER ("copyname");
|
||
if (out == NULL || in == NULL) {
|
||
bru_error (ERR_BUG, "copyname");
|
||
} else {
|
||
if (flags.Zflag) {
|
||
namesize -= 2;
|
||
}
|
||
if (!copy (out, in, namesize)) {
|
||
bru_error (ERR_BIGPATH, in);
|
||
}
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* mklink make a link to a file
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN mklink (exists, new)
|
||
* char *exists;
|
||
* char *new;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to the name of an existing file, and
|
||
* pointer to the name of a file to link to it, attempts
|
||
* to make the link, returning TRUE if successful, FALSE
|
||
* otherwise.
|
||
*
|
||
*/
|
||
|
||
BOOLEAN mklink (exists, new)
|
||
char *exists;
|
||
char *new;
|
||
{
|
||
register int rtnval;
|
||
|
||
if (s_link (exists, new) == SYS_ERROR) {
|
||
bru_error (ERR_MKLINK, new, exists);
|
||
rtnval = FALSE;
|
||
} else {
|
||
rtnval = TRUE;
|
||
}
|
||
return (rtnval);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* mksymlink make a symbolic link to a file
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN mksymlink (exists, new)
|
||
* char *exists;
|
||
* char *new;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to the name of an existing file, and
|
||
* pointer to the name of a file to link to it, attempts
|
||
* to make the symbolic link, returning TRUE if successful, FALSE
|
||
* otherwise.
|
||
*
|
||
* This is where we handle Pyramid style conditional symbolic
|
||
* links, and do hard links on a non-4.2BSD system. On a non-4.2
|
||
* system, be sure to do a hard link only if the file to be linked
|
||
* to exists, and is not a directory.
|
||
*
|
||
*/
|
||
|
||
|
||
/*
|
||
* PSEUDO CODE
|
||
*
|
||
* Begin mksymlink
|
||
* Initialize return value to TRUE
|
||
* If on a pyramid then
|
||
* set linking function to be csymlink
|
||
* Else if on a 4.2 system then
|
||
* get currect pathname
|
||
* set linking function to be symlink
|
||
* Else
|
||
* get currect pathname
|
||
* set linking function to be link
|
||
* If file to be linked to exists then
|
||
* If it is directory then
|
||
* return value = FALSE
|
||
* End if
|
||
* Else
|
||
* return value = FALSE
|
||
* End if
|
||
* End if
|
||
* If return value still TRUE and linking succeeds then
|
||
* return value = TRUE
|
||
* Else
|
||
* return value = FALSE
|
||
* End if
|
||
* End mksymlink
|
||
*/
|
||
|
||
|
||
BOOLEAN mksymlink (exists, new)
|
||
char *exists;
|
||
char *new;
|
||
{
|
||
register int rtnval = TRUE;
|
||
int (*linkfile)();
|
||
#if !HAVE_SYMLINKS && !pyr
|
||
struct finfo file;
|
||
struct stat64 sbuf;
|
||
#endif
|
||
|
||
DBUG_ENTER ("mksymlink");
|
||
DBUG_PRINT ("mksymlink", ("exists %s new %s", exists, new));
|
||
|
||
#if pyr
|
||
DBUG_PRINT ("symlink", ("on a pyramid"));
|
||
linkfile = s_csymlink;
|
||
#else
|
||
exists = univlink (exists);
|
||
#if HAVE_SYMLINKS
|
||
DBUG_PRINT ("symlink", ("under 4.2"));
|
||
linkfile = s_symlink;
|
||
#else
|
||
DBUG_PRINT ("symlink", ("under System V"));
|
||
linkfile = s_link;
|
||
if (file_access (exists, A_EXISTS, FALSE)) {
|
||
finfo_init (&file, exists, &sbuf);
|
||
if (file_stat (&file) && IS_DIR (sbuf.st_mode)) {
|
||
bru_error (ERR_SYMTODIR, new, exists, exists);
|
||
rtnval = FALSE;
|
||
}
|
||
} else {
|
||
bru_error (ERR_HARDLINK, new, exists, exists);
|
||
rtnval = FALSE;
|
||
}
|
||
DBUG_PRINT ("symlink", ("will try hard link of %s to %s", exists, new));
|
||
#endif
|
||
#endif
|
||
if (rtnval && (*linkfile)(exists, new) != SYS_ERROR) {
|
||
rtnval = TRUE;
|
||
} else {
|
||
rtnval = FALSE;
|
||
}
|
||
|
||
DBUG_RETURN (rtnval);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* regular_file see if a file is not a special file
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN regular_file (fname)
|
||
* char *fname;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to a file name, check to see if it is a regular file.
|
||
* Returns TRUE if the file exists and the stat bits indicate that
|
||
* the file is a regular file. If the file is a special file, or does
|
||
* not exist, then returns FALSE.
|
||
*
|
||
*/
|
||
|
||
BOOLEAN regular_file (fname)
|
||
char *fname;
|
||
{
|
||
register int rtnval = FALSE;
|
||
auto struct stat64 statbuf;
|
||
|
||
DBUG_ENTER ("regular_file");
|
||
DBUG_PRINT ("regfile", ("test '%s' for existing, regular file", fname));
|
||
if (s_stat (fname, &statbuf) != SYS_ERROR) {
|
||
if (IS_REG (statbuf.st_mode)) {
|
||
rtnval = TRUE;
|
||
}
|
||
}
|
||
DBUG_PRINT ("regfile", ("returns logical value %d", rtnval));
|
||
DBUG_RETURN (rtnval);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* file_stat do a stat on a file
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN file_stat (fip)
|
||
* register struct finfo *fip;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to a file information structure, attempts
|
||
* to stat the file to initialize the file information
|
||
* stat buffer and any machine dependent fields in the
|
||
* file information structure.
|
||
*
|
||
* Returns TRUE if successful, FALSE otherwise.
|
||
*
|
||
*/
|
||
|
||
BOOLEAN file_stat (fip)
|
||
register struct finfo *fip;
|
||
{
|
||
register int rtnval;
|
||
#if HAVE_SYMLINKS
|
||
register int nmlen;
|
||
static char linkbuf[NAMESIZE];
|
||
#endif
|
||
|
||
DBUG_ENTER ("file_stat");
|
||
DBUG_PRINT ("stat", ("stat %s", fip -> fname));
|
||
if (s_stat (fip -> fname, fip -> statp) == SYS_ERROR) {
|
||
bru_error (ERR_STAT, fip -> fname);
|
||
rtnval = FALSE;
|
||
} else {
|
||
rtnval = TRUE;
|
||
#if HAVE_SYMLINKS
|
||
if (IS_FLNK (fip -> statp -> st_mode)) {
|
||
nmlen = s_readlink (fip -> fname, linkbuf, sizeof linkbuf);
|
||
if (nmlen == SYS_ERROR) {
|
||
bru_error (ERR_RDLINK, fip -> fname);
|
||
rtnval = FALSE;
|
||
} else {
|
||
linkbuf[nmlen] = EOS;
|
||
fip -> lname = linkbuf;
|
||
DBUG_PRINT ("symlink", ("symlink is %s", fip -> lname));
|
||
}
|
||
}
|
||
#endif
|
||
#ifdef amiga
|
||
(VOID) getinfo (fip);
|
||
#endif
|
||
}
|
||
DBUG_RETURN (rtnval);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* verbosity issue a verbosity message
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID verbosity (fip)
|
||
* register struct finfo *fip;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to a file information structure, issues
|
||
* a verbosity message concerning current mode and file
|
||
* name, if verbosity enabled.
|
||
*
|
||
*/
|
||
|
||
VOID verbosity (fip)
|
||
register struct finfo *fip;
|
||
{
|
||
register LBA blocks;
|
||
register LBA total;
|
||
register ULONG kbytes;
|
||
register BOOLEAN linked;
|
||
register S64BIT zratio = 0LL;
|
||
char *tmpname;
|
||
|
||
DBUG_ENTER ("verbosity");
|
||
if (fip == NULL || fip -> fname == NULL || fip -> statp == NULL) {
|
||
bru_error (ERR_BUG, "verbosity");
|
||
} else if (flags.vflag > 0) {
|
||
if (fip -> lname != NULL && *fip -> lname != EOS) {
|
||
linked = TRUE;
|
||
} else {
|
||
linked = FALSE;
|
||
}
|
||
(VOID) s_fprintf (logfp, "%c", mode);
|
||
blocks = 1;
|
||
zratio = 0;
|
||
if (!linked && IS_REG (fip -> statp -> st_mode)) {
|
||
blocks += ZARBLKS (fip);
|
||
if (IS_COMPRESSED (fip)) {
|
||
zratio = fip -> zsize * 100; /* overflow possible (not anymore)*/
|
||
zratio /= fip -> statp -> st_size;
|
||
zratio = 100 - zratio;
|
||
}
|
||
}
|
||
if (flags.vflag > 0 && (fip -> fi_flags & FI_ZFLAG)) {
|
||
/*
|
||
* Added for xfs
|
||
*/
|
||
if (fip -> statp -> st_size == -1)
|
||
s_fprintf (logfp, " ( \?%%)");
|
||
else
|
||
s_fprintf (logfp, " (%2lld%%)", zratio);
|
||
}
|
||
kbytes = KBYTES (blocks);
|
||
(VOID) s_fprintf (logfp, " %6luk", kbytes);
|
||
total = ar_tell () + blocks;
|
||
if (mode == 'c') {
|
||
total++;
|
||
}
|
||
kbytes = KBYTES (total);
|
||
(VOID) s_fprintf (logfp, " of %7luk", kbytes);
|
||
(VOID) s_fprintf (logfp, " [%d]", ar_vol () + 1);
|
||
if( (flags.Xflag) && (working_dir != NULL) )
|
||
(VOID) s_fprintf (logfp, " %s/%s", working_dir, fip -> fname);
|
||
else
|
||
(VOID) s_fprintf (logfp, " %s", fip -> fname);
|
||
/* must test for symlinks first; we print a hardlink to a symlink
|
||
* as a hardlink if it wasn't the first instance in the archive.
|
||
* SGI seems to be one of the few vendors that allows hardlinks to
|
||
* symlinks... */
|
||
if (flags.vflag > 1 && IS_FLNK (fip -> statp -> st_mode) &&
|
||
(fip->statp->st_nlink==1 || !(tmpname=getlinkname(fip)) ||
|
||
!strcmp(fip->fname, tmpname))) {
|
||
(VOID) s_fprintf (logfp, " symbolic link to %s", namelink (fip -> lname));
|
||
} else if (flags.vflag > 1 && linked) {
|
||
(VOID) s_fprintf (logfp, " linked to %s", fip -> lname);
|
||
}
|
||
(VOID) s_fprintf (logfp, "\n");
|
||
s_fflush (logfp);
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* out_of_date check for existing file is out of date
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN out_of_date (fip)
|
||
* struct finfo *fip;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Checks to see if there is an existing file of the same name
|
||
* with an earlier modification date.
|
||
*
|
||
* If there is no existing file of the same name, then the
|
||
* result is TRUE.
|
||
*
|
||
* If there is an existing file but the date cannot be determined
|
||
* for any reason, then the result is FALSE.
|
||
*
|
||
* If there is an existing file and it has the same or a more recent
|
||
* modification date then the result is FALSE.
|
||
*
|
||
*/
|
||
|
||
BOOLEAN out_of_date (fip)
|
||
struct finfo *fip;
|
||
{
|
||
register BOOLEAN result;
|
||
auto struct stat64 sbuf;
|
||
auto struct finfo file;
|
||
|
||
DBUG_ENTER ("out_of_date");
|
||
result = FALSE;
|
||
if (fip == NULL || fip -> fname == NULL) {
|
||
bru_error (ERR_BUG, "out_of_date");
|
||
} else {
|
||
if (!file_access (fip -> fname, A_EXISTS, FALSE)) {
|
||
result = TRUE;
|
||
} else {
|
||
finfo_init (&file, fip -> fname, &sbuf);
|
||
if (file_stat (&file)) {
|
||
if (file.statp -> st_mtime < fip -> statp -> st_mtime) {
|
||
result = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
DBUG_RETURN (result);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* reset_times reset the access and modification times
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID reset_times (fip)
|
||
* struct finfo *fip;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Resets the access and modification times for the file
|
||
* according to the values in the stat buffer.
|
||
*
|
||
* This routine is primarily used to prevent files which
|
||
* have not been accessed in a long time by any other
|
||
* program from appearing to have been used recently.
|
||
*
|
||
* Note there is a possible race condition here in that
|
||
* the stat buffer is obtained prior to reading the file
|
||
* and the times are reset after the file is closed.
|
||
* If during this window, another program accesses or
|
||
* modifies the same file, the times will still be
|
||
* reset when bru is through. It is not likely that
|
||
* this circumstance will ever cause any problems though.
|
||
*
|
||
* BUGS
|
||
*
|
||
* The warning generation is suppressed because it appears
|
||
* that even if the executable is owned by root and has
|
||
* SUID bit set, utime will still return with EPERM.
|
||
* Is this a bug in the Unisoft kernel?
|
||
*
|
||
* NOTES
|
||
*
|
||
* Many of the unix sources (tar and cpio as examples) do
|
||
* NOT use the utime call correctly. They pass utime a pointer
|
||
* to the atime member of a stat structure, assuming that the
|
||
* next member of the stat structure is the mtime member.
|
||
* There is NO guarantee that atime and mtime are contiguous
|
||
* in the stat structure, and in fact, this is not true
|
||
* under 4.2BSD. Beware!
|
||
*
|
||
*/
|
||
|
||
|
||
struct utimbuf { /* Do it right, as given in User's Manual */
|
||
time_t actime; /* Do NOT pass pointer to atime in stat */
|
||
time_t modtime; /* structure instead */
|
||
};
|
||
|
||
VOID reset_times (fip)
|
||
struct finfo *fip;
|
||
{
|
||
auto struct utimbuf ftime;
|
||
|
||
DBUG_ENTER ("reset_times");
|
||
ftime.actime = fip -> statp -> st_atime;
|
||
ftime.modtime = fip -> statp -> st_mtime;
|
||
if (fip==NULL || fip->fname==NULL || *fip->fname==EOS || fip->statp==NULL) {
|
||
bru_error (ERR_BUG, "reset_times");
|
||
} else {
|
||
if (!flags.aflag) {
|
||
if (s_utime (fip -> fname, &ftime) == SYS_ERROR) {
|
||
/****** bru_error (ERR_STIMES, fip -> fname); ******/
|
||
}
|
||
}
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* selected apply selection criteria
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN selected (fip)
|
||
* struct finfo *fip;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to a file information structure,
|
||
* applies the selection criteria specified on the command line,
|
||
* such as date of modification, wildcard filename match, etc.
|
||
*
|
||
*/
|
||
|
||
BOOLEAN selected (fip)
|
||
struct finfo *fip;
|
||
{
|
||
register BOOLEAN select;
|
||
|
||
DBUG_ENTER ("selected");
|
||
select = TRUE;
|
||
if (flags.nflag) {
|
||
select &= fip -> statp -> st_mtime > ntime;
|
||
}
|
||
if (flags.oflag) {
|
||
select &= fip -> statp -> st_uid == uid;
|
||
}
|
||
if ((fip -> fi_flags & FI_AMIGA) && flags.Arflag) {
|
||
select &= !abit_set (fip);
|
||
}
|
||
DBUG_RETURN (select);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* getsize convert an ascii size string to internal long
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* S32BIT getsize (cp)
|
||
* char *cp;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to a string which is presumably an ascii
|
||
* numeric string with an optional scale factor, converts
|
||
* the string to an internal long and returns the value.
|
||
*
|
||
*/
|
||
|
||
ULONG getsize (cp)
|
||
char *cp;
|
||
{
|
||
register ULONG size;
|
||
auto char *scale;
|
||
|
||
DBUG_ENTER ("getsize");
|
||
scale = NULL;
|
||
size = strtoul (cp, &scale, 0);
|
||
DBUG_PRINT ("getsize", ("size from strtol is %d", size));
|
||
if (scale == NULL) {
|
||
bru_error (ERR_BUG, "getsize");
|
||
size = 0; /* paranoia */
|
||
getsize_err = 1; /* distinguish err 0 return from normal 0 */
|
||
} else if(scale == cp) {
|
||
bru_error (ERR_NOTNUM, cp, "");
|
||
done();
|
||
} else {
|
||
getsize_err = 0;
|
||
switch (*scale) {
|
||
case 'k':
|
||
case 'K':
|
||
size *= 1024;
|
||
break;
|
||
case 'b':
|
||
case 'B':
|
||
size *= 512;
|
||
break;
|
||
case 'm':
|
||
case 'M':
|
||
size *= (1024 * 1024);
|
||
break;
|
||
}
|
||
}
|
||
DBUG_RETURN (size);
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* The library function "strncpy" is almost what we need but not
|
||
* quite.
|
||
*
|
||
* Returns TRUE if copy was successful with no truncation, FALSE
|
||
* otherwise. Output string is always null terminated.
|
||
*
|
||
*/
|
||
|
||
BOOLEAN copy (out, in, outsize)
|
||
register char *out;
|
||
register char *in;
|
||
register int outsize;
|
||
{
|
||
DBUG_ENTER ("copy");
|
||
DBUG_PRINT ("copy", ("copy %s", in));
|
||
while (--outsize > 0) {
|
||
if (*in == EOS) {
|
||
break;
|
||
} else {
|
||
*out++ = *in++;
|
||
}
|
||
}
|
||
*out = EOS;
|
||
DBUG_RETURN (*in == EOS);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* unconditional test for unconditional selection
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN unconditional (fip)
|
||
* register struct finfo *fip;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given pointer to a file information structure, uses
|
||
* the information in the stat buffer for the file, along
|
||
* with flags set on the command line, to indicate
|
||
* if the file is to be unconditionally selected regardless
|
||
* of its modification date.
|
||
*
|
||
* Returns TRUE if the file is to be selected, FALSE otherwise.
|
||
*
|
||
*/
|
||
|
||
BOOLEAN unconditional (fip)
|
||
register struct finfo *fip;
|
||
{
|
||
register BOOLEAN rtnval;
|
||
register ushort stmode;
|
||
|
||
DBUG_ENTER ("unconditional");
|
||
rtnval = FALSE;
|
||
if (flags.uflag) {
|
||
stmode = fip -> statp -> st_mode;
|
||
if (IS_BSPEC (stmode)) {
|
||
rtnval = flags.ubflag;
|
||
} else if (IS_CSPEC (stmode)) {
|
||
rtnval = flags.ucflag;
|
||
} else if (IS_DIR (stmode)) {
|
||
rtnval = flags.udflag;
|
||
} else if (IS_FLNK (stmode)) {
|
||
rtnval = flags.ulflag;
|
||
} else if (IS_FIFO (stmode)) {
|
||
rtnval = flags.upflag;
|
||
} else if (IS_REG (stmode)) {
|
||
rtnval = flags.urflag;
|
||
}
|
||
}
|
||
DBUG_RETURN (rtnval);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* finfo_init initialize a file information structure
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID finfo_init (fip, name, statp)
|
||
* register struct finfo *fip;
|
||
* char *name;
|
||
* struct stat64 *statp;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Most file information structures are allocated on the stack.
|
||
* Such structures are not guaranteed to be in any particular state,
|
||
* thus this routine is available to initialize specific fields
|
||
* and zero the rest.
|
||
*
|
||
*/
|
||
|
||
VOID finfo_init (fip, name, statp)
|
||
register struct finfo *fip;
|
||
char *name;
|
||
struct stat64 *statp;
|
||
{
|
||
DBUG_ENTER ("finfo_init");
|
||
fip -> statp = statp;
|
||
fip -> fname = name;
|
||
fip -> lname = NULL;
|
||
fip -> fildes = 0;
|
||
fip -> flba = 0L;
|
||
fip -> chkerrs = 0L;
|
||
fip -> fi_flags = FI_FLAGS_INIT;
|
||
if (flags.Zflag) {
|
||
fip -> fi_flags |= FI_ZFLAG;
|
||
}
|
||
fip -> type = 0;
|
||
fip -> fib_Protection = 0L;
|
||
fip -> fib_Comment[0] = EOS;
|
||
fip -> zsize = 0;
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* swapbytes swap bytes in an archive block
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID swapbytes (blkp)
|
||
* register union blk *blkp;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Swaps each pair of bytes in an archive block.
|
||
*/
|
||
|
||
VOID swapbytes (blkp)
|
||
register union blk *blkp;
|
||
{
|
||
register char *cs1;
|
||
register char *cs2;
|
||
register char tmp;
|
||
|
||
DBUG_ENTER ("swapbytes");
|
||
cs1 = &blkp -> bytes[0];
|
||
cs2 = &blkp -> bytes[1];
|
||
while (cs1 < OVERRUN (blkp -> bytes)) {
|
||
tmp = *cs1;
|
||
*cs1++ = *cs2++;
|
||
*cs1++ = tmp;
|
||
cs2++;
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* swapshorts swap shorts in an archive block
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID swapshorts (blkp)
|
||
* register union blk *blkp;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Swaps each pair of shorts in an archive block.
|
||
*/
|
||
|
||
VOID swapshorts (blkp)
|
||
register union blk *blkp;
|
||
{
|
||
register short *ss1;
|
||
register short *ss2;
|
||
register short stmp;
|
||
|
||
DBUG_ENTER ("swapshorts");
|
||
ss1 = &blkp -> shorts[0];
|
||
ss2 = &blkp -> shorts[1];
|
||
while (ss1 < OVERRUN (blkp -> shorts)) {
|
||
stmp = *ss1;
|
||
*ss1++ = *ss2++;
|
||
*ss1++ = stmp;
|
||
ss2++;
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* get_memory ask system for more memory
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID *get_memory (size, quit)
|
||
* UINT size;
|
||
* BOOLEAN quit;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given number of bytes to allocate from system (size),
|
||
* issues the appropriate system call to get the memory.
|
||
*
|
||
* Returns pointer to the allocated memory if successful,
|
||
* NULL otherwise. Note that any memory allocated is guaranteed
|
||
* to be properly aligned for any use (see malloc(3C) in UPM).
|
||
* Get_memory is declared to return type "pointer to void" so
|
||
* that casting to any other type of object will not give
|
||
* lint messages about "possible pointer alignment problem".
|
||
* So instead of numerous bogus warnings, we will get exactly
|
||
* one lint warning here, for the conversion from (char *) to
|
||
* (void *).
|
||
*
|
||
* If the quit flag is set, and no memory can be allocated,
|
||
* the program will call the routine to clean up and exit.
|
||
*
|
||
* The memory allocated may be freed with the "free" system
|
||
* call.
|
||
*
|
||
* Note that the memory is NOT guaranteed to be zeroed.
|
||
*
|
||
*/
|
||
|
||
# ifdef sgi
|
||
# undef VOID
|
||
# define VOID char
|
||
# endif
|
||
|
||
VOID *get_memory (size, quit)
|
||
UINT size;
|
||
BOOLEAN quit;
|
||
{
|
||
register VOID *new;
|
||
|
||
new = (VOID *) s_malloc (size);
|
||
if (new == NULL && quit) {
|
||
bru_error (ERR_MALLOC, size);
|
||
done ();
|
||
}
|
||
return (new);
|
||
}
|
||
|
||
# ifdef sgi
|
||
# undef VOID
|
||
# define VOID void
|
||
# endif
|
||
|
||
|
||
/*
|
||
* In cases of extreme bugs, we can define DUMPBLK, which enables
|
||
* dumping of the contents of each archive block using the DBUG
|
||
* macro mechanism. We don't normally want this, as it results
|
||
* in overwhelming output...
|
||
*/
|
||
|
||
#ifdef DUMPBLK
|
||
|
||
do_dump (blkp)
|
||
register union blk *blkp;
|
||
{
|
||
register char *cp;
|
||
register int count;
|
||
|
||
DBUG_ENTER ("do_dump");
|
||
cp = blkp -> bytes;
|
||
count = 0;
|
||
while (cp < &blkp -> bytes[BLKSIZE]) {
|
||
if (*cp < '\040') {
|
||
(VOID) s_fprintf (DBUG_FILE, " ^%c", *cp | 0100);
|
||
} else if (*cp < '\177') {
|
||
(VOID) s_fprintf (DBUG_FILE, " %c", *cp);
|
||
} else {
|
||
(VOID) s_fprintf (DBUG_FILE, " \\%3.3o", *cp);
|
||
}
|
||
cp++;
|
||
count++;
|
||
if ((count % 16) == 0) {
|
||
(VOID) s_fprintf (DBUG_FILE, "\n");
|
||
}
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
VOID dump_blk (blkp, lba)
|
||
register union blk *blkp;
|
||
LBA lba;
|
||
{
|
||
DBUG_ENTER ("dump_blk");
|
||
DBUG_EXECUTE ("dump", {(VOID) s_fprintf (DEBUGFILE, "\nDump of block %ld\n\n", lba);});
|
||
DBUG_EXECUTE ("dump", {(VOID) do_dump (blkp);});
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
#endif /* DUMPBLK */
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* file_chown change ownership of a file
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID file_chown (path, owner, group)
|
||
* char *path;
|
||
* int owner, group;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Changes owner and group of a file pointed to by path.
|
||
* Returns no value but causes error message to be printed
|
||
* if any problems occur.
|
||
*
|
||
* Under 4.2 BSD the chown system call only works if called
|
||
* with effective uid of root. This is supposedly for accounting.
|
||
*
|
||
* The bru default is to always restore as much as possible,
|
||
* including the file ownership to the archived uid. This has
|
||
* obvious problems for normal users reading tapes from other sites
|
||
* where the numeric uid's most likely are completely different.
|
||
* For this case, we provide a special flag (-C) that chown's all
|
||
* the files to the uid of the user running bru. The reasoning
|
||
* behind which case to make the default and which case to make
|
||
* a special flag is given in the "ownership" file in the notes
|
||
* directory. Basically, the default is easier to correct, and
|
||
* potentially less damaging to the system, than the results of
|
||
* applying the -C flag.
|
||
*
|
||
*/
|
||
|
||
VOID file_chown (path, owner, group)
|
||
char *path;
|
||
int owner, group;
|
||
{
|
||
DBUG_ENTER ("file_chown");
|
||
|
||
if (flags.Cflag) {
|
||
owner = info.bru_uid;
|
||
group = info.bru_gid;
|
||
}
|
||
|
||
DBUG_PRINT ("chown", ("file %s, owner %d, group %d", path, owner, group));
|
||
|
||
if (s_chown (path, owner, group) == SYS_ERROR) {
|
||
bru_error (ERR_CHOWN, path);
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* reload reload first volume of multivolume archive
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* VOID reload (reason)
|
||
* char *reason;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Issues prompt for user to reload first volume of a multivolume
|
||
* archive for the reason (pass) specified. For example, a differences
|
||
* pass of a newly created archive.
|
||
*
|
||
*/
|
||
|
||
VOID reload (reason)
|
||
char *reason;
|
||
{
|
||
int vol;
|
||
extern int lastvolume;
|
||
|
||
DBUG_ENTER ("reload");
|
||
/* if lastvolume != 0, then we are doing -i or -d after a -c, and we
|
||
* had multiple tapes, so we need to prompt for the original volume.
|
||
*/
|
||
if(vol=(ar_vol()) || lastvolume) {
|
||
tty_printf ("%s: ready for %s pass\n", info.bru_name, reason);
|
||
(VOID) new_arfile (0);
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
VOID fork_shell ()
|
||
{
|
||
register char *dir;
|
||
register char *file;
|
||
register char *shell;
|
||
auto char *vector[2];
|
||
|
||
DBUG_ENTER ("fork_shell");
|
||
shell = s_getenv ("SHELL");
|
||
if (shell == NULL) {
|
||
#ifdef amiga
|
||
dir = NULL; /* Turn these into defines */
|
||
file = "c:newcli";
|
||
#else
|
||
dir = "/bin";
|
||
file = "sh";
|
||
#endif
|
||
} else {
|
||
dir = "";
|
||
file = shell;
|
||
}
|
||
vector[0] = file;
|
||
vector[1] = NULL;
|
||
(VOID) execute (dir, file, vector);
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* newdir make a directory node
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN newdir (fip)
|
||
* register struct finfo *fip;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Makes a directory with given stat and name. If an error occurs,
|
||
* print error message.
|
||
*
|
||
*/
|
||
|
||
|
||
BOOLEAN newdir (fip)
|
||
register struct finfo *fip;
|
||
{
|
||
register BOOLEAN filemade;
|
||
|
||
DBUG_ENTER ("newdir");
|
||
if (s_mkdir (fip -> fname, (int) fip->statp->st_mode) == SYS_ERROR) {
|
||
bru_error (ERR_MKDIR, fip -> fname);
|
||
} else {
|
||
filemade = TRUE;
|
||
}
|
||
DBUG_RETURN (filemade);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* magic_ok test a block to see if the magic value is recognized
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* BOOLEAN magic_ok (blkp)
|
||
* register union blk *blkp;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Test the block pointed to and return TRUE if the block has a
|
||
* recognized magic number, FALSE otherwise.
|
||
*
|
||
*/
|
||
|
||
BOOLEAN magic_ok (blkp)
|
||
register union blk *blkp;
|
||
{
|
||
register BOOLEAN rtnval;
|
||
register int mag;
|
||
|
||
DBUG_ENTER ("magic_ok");
|
||
rtnval = FALSE;
|
||
if (blkp == NULL) {
|
||
bru_error (ERR_BUG, "magic_ok");
|
||
} else {
|
||
mag = (int) FROMHEX (blkp -> HD.h_magic);
|
||
if (mag==A_MAGIC || mag==H_MAGIC || mag==D_MAGIC || mag==T_MAGIC) {
|
||
rtnval = TRUE;
|
||
}
|
||
}
|
||
DBUG_RETURN (rtnval);
|
||
}
|
||
|
||
|
||
/*
|
||
* Note that because the name buffer is static and reused on each call,
|
||
* we can only have one finfo structure, with an attached compressed
|
||
* file, active at any given time.
|
||
*/
|
||
|
||
BOOLEAN openzfile (fip)
|
||
struct finfo *fip;
|
||
{
|
||
int status = FALSE;
|
||
static char tname[NAMESIZE];
|
||
static char *tfilep;
|
||
#ifndef sgi
|
||
extern char *mktemp ();
|
||
#endif
|
||
|
||
DBUG_ENTER ("openzfile");
|
||
if (tfilep == NULL) {
|
||
tfilep = mktemp ("brutmpXXXXXX");
|
||
}
|
||
sprintf (tname, TEMPLATE, info.bru_tmpdir, tfilep);
|
||
DBUG_PRINT ("brutmpdir", ("use temp file '%s'", tname));
|
||
fip -> zfname = tname;
|
||
if ((fip -> zfildes = s_creat (fip -> zfname, 0600)) == SYS_ERROR) {
|
||
bru_error (ERR_OPEN, fip -> zfname);
|
||
} else {
|
||
status = TRUE;
|
||
}
|
||
DBUG_RETURN (status);
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* compressfip compress a file
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given file info pointer for an open uncompressed file, attempt
|
||
* to create a compressed version of the file in the directory
|
||
* set by the BRUTMPDIR environment variable. Returns TRUE if
|
||
* successful, FALSE if the compression fails for some reason.
|
||
*
|
||
* NOTES
|
||
*
|
||
* We play it safe before proceeding and unconditionally mark
|
||
* the fip as not having a compressed version of the file.
|
||
*
|
||
* Since we aren't bothering to check the return values of
|
||
* s_unlink and s_close, just do them at the end if we fail
|
||
* for some reason, and don't worry about whether or not
|
||
* the file descriptor is open or the file exists. This might
|
||
* be a potential problem on nonunix systems (closing nonopen
|
||
* descriptors or unlinking nonexistant files).
|
||
*
|
||
*/
|
||
|
||
/* global so openandchk can print write message if > LONG_MAX */
|
||
static struct stat64 comp_statbuf;
|
||
|
||
BOOLEAN compressfip (fip)
|
||
struct finfo *fip;
|
||
{
|
||
int status = FALSE;
|
||
|
||
DBUG_ENTER ("compressfip");
|
||
comp_statbuf.st_size = 0;
|
||
fip -> fi_flags &= ~FI_LZW;
|
||
if (openzfile (fip)) {
|
||
if (compress (fip)) {
|
||
(VOID) s_lseek (fip -> fildes, 0L, 0);
|
||
(VOID) s_close (fip -> zfildes);
|
||
fip -> zfildes = s_open (fip -> zfname, O_RDONLY, 0);
|
||
if (fip -> zfildes == SYS_ERROR) {
|
||
bru_error (ERR_OPEN, fip -> zfname);
|
||
} else {
|
||
if (s_stat (fip -> zfname, &comp_statbuf) == SYS_ERROR) {
|
||
bru_error (ERR_STAT, fip -> zfname);
|
||
} else {
|
||
/*
|
||
* Added for xfs
|
||
*/
|
||
if (comp_statbuf.st_size <= LONG_MAX){
|
||
status = TRUE;
|
||
fip -> fi_flags |= FI_LZW;
|
||
fip -> zsize = comp_statbuf.st_size;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!status) {
|
||
(VOID) s_close (fip -> zfildes);
|
||
(VOID) s_unlink (fip -> zfname);
|
||
}
|
||
}
|
||
DBUG_RETURN (status);
|
||
}
|
||
|
||
|
||
BOOLEAN decompfip (fip)
|
||
struct finfo *fip;
|
||
{
|
||
int status = FALSE;
|
||
|
||
DBUG_ENTER ("decompfip");
|
||
fip -> zfildes = s_open (fip -> zfname, O_RDONLY, 0);
|
||
if (fip -> zfildes == SYS_ERROR) {
|
||
bru_error (ERR_OPEN, fip -> zfname);
|
||
bru_error (ERR_ZXFAIL, fip -> fname);
|
||
} else {
|
||
fip -> fildes = s_creat (fip -> fname, 0600);
|
||
if (fip -> fildes == SYS_ERROR) {
|
||
bru_error (ERR_OPEN, fip -> fname);
|
||
bru_error (ERR_ZXFAIL, fip -> fname);
|
||
} else {
|
||
if (!decompress (fip)) {
|
||
bru_error (ERR_ZXFAIL, fip -> fname);
|
||
} else {
|
||
status = TRUE;
|
||
}
|
||
s_close (fip -> fildes);
|
||
}
|
||
s_close (fip -> zfildes);
|
||
}
|
||
s_unlink (fip -> zfname);
|
||
DBUG_RETURN (status);
|
||
}
|
||
|
||
/*
|
||
* Add the ".Z" extension to a name. Note that we only call addz
|
||
* on buffers which have previously been filled via copyname, which
|
||
* ensures that there is sufficient space for the ".Z" extension
|
||
* if the -Z command line option is given. Thus we don't need to
|
||
* check for a buffer overflow.
|
||
*/
|
||
|
||
VOID addz (fname)
|
||
char *fname;
|
||
{
|
||
register char *endp;
|
||
|
||
DBUG_ENTER ("addz");
|
||
DBUG_PRINT ("addz", ("add a .Z extension to '%s'", fname));
|
||
endp = fname + s_strlen (fname);
|
||
*endp++ = '.';
|
||
*endp++ = 'Z';
|
||
*endp = EOS;
|
||
DBUG_PRINT ("addz", ("final name '%s'", fname));
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
/*
|
||
* Strip the ".Z" extension from a name.
|
||
*/
|
||
|
||
VOID stripz (fname)
|
||
char *fname;
|
||
{
|
||
register char *endp;
|
||
|
||
DBUG_ENTER ("stripz");
|
||
DBUG_PRINT ("stripz", ("strip a .Z extension from '%s'", fname));
|
||
endp = fname + s_strlen (fname);
|
||
if ((*--endp == 'Z') && (*--endp == '.')) {
|
||
*endp = EOS;
|
||
}
|
||
DBUG_PRINT ("stripz", ("final name '%s'", fname));
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
*
|
||
* discard_zfile discard any compressed version of file
|
||
*
|
||
* SYNOPSIS
|
||
*
|
||
* static VOID discard_zfile (fip)
|
||
* struct finfo *fip;
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* Given a pointer to a file information structure, if there
|
||
* is a compressed version of the file associated with it,
|
||
* discard the compressed version and fix up the file info
|
||
* structure appropriately.
|
||
*
|
||
*/
|
||
|
||
VOID discard_zfile (fip)
|
||
struct finfo *fip;
|
||
{
|
||
DBUG_ENTER ("discard_zfile");
|
||
if (IS_COMPRESSED (fip)) {
|
||
fip -> fi_flags &= ~FI_LZW;
|
||
if (s_close (fip -> zfildes) == SYS_ERROR) {
|
||
bru_error (ERR_CLOSE, fip -> zfname);
|
||
}
|
||
if (s_unlink (fip -> zfname) == SYS_ERROR) {
|
||
bru_error (ERR_UNLINK, fip -> zfname);
|
||
}
|
||
}
|
||
DBUG_VOID_RETURN;
|
||
}
|
||
|
||
|
||
/* open a file, doing all the error checking, and possibly doing the
|
||
* compression. This code is used by both estimate and by
|
||
* create()
|
||
*/
|
||
BOOLEAN
|
||
openandchkcompress(struct finfo *fip)
|
||
{
|
||
BOOLEAN rval = FALSE;
|
||
|
||
if (IS_REG (fip->statp->st_mode) && fip->lname == NULL) {
|
||
if (file_access (fip->fname, A_READ, TRUE)) {
|
||
fip->fildes = s_open (fip->fname, O_RDONLY|O_NDELAY, 0);
|
||
if (fip->fildes == SYS_ERROR) {
|
||
bru_error (ERR_OPEN, fip->fname);
|
||
} else {
|
||
rval = TRUE;
|
||
if (flags.Zflag) {
|
||
if (!compressfip (fip)) {
|
||
if(comp_statbuf.st_size > LONG_MAX) {
|
||
bru_error (ERR_TOO_BIG, fip->fname);
|
||
rval = FALSE;
|
||
}
|
||
else {
|
||
bru_error (ERR_ZFAILED, fip->fname);
|
||
fprintf(stderr, "%llx < %llx\n",
|
||
(unsigned long long)comp_statbuf.st_size, (unsigned long long)LONG_MAX);
|
||
}
|
||
discard_zfile (fip);
|
||
s_lseek (fip->fildes, 0L, SEEK_SET);
|
||
} else {
|
||
if (fip->zsize > fip->statp->st_size) {
|
||
if (flags.vflag > 3)
|
||
bru_error (ERR_NOSHRINK, fip->fname);
|
||
discard_zfile (fip);
|
||
s_lseek (fip->fildes, 0L, SEEK_SET);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return rval;
|
||
}
|