420 lines
13 KiB
C
420 lines
13 KiB
C
|
/* $Source: /u/mark/src/pax/RCS/fileio.c,v $
|
||
|
*
|
||
|
* $Revision: 1.2 $
|
||
|
*
|
||
|
* fileio.c - file I/O functions for all archive interfaces
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* These function all do I/O of some form or another. They are
|
||
|
* grouped here mainly for convienence.
|
||
|
*
|
||
|
* AUTHOR
|
||
|
*
|
||
|
* Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
|
||
|
*
|
||
|
* Sponsored by The USENIX Association for public distribution.
|
||
|
*
|
||
|
* Copyright (c) 1989 Mark H. Colburn.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms are permitted
|
||
|
* provided that the above copyright notice is duplicated in all such
|
||
|
* forms and that any documentation, advertising materials, and other
|
||
|
* materials related to such distribution and use acknowledge that the
|
||
|
* software was developed * by Mark H. Colburn and sponsored by The
|
||
|
* USENIX Association.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
*
|
||
|
* $Log: fileio.c,v $
|
||
|
* Revision 1.2 89/02/12 10:04:31 mark
|
||
|
* 1.2 release fixes
|
||
|
*
|
||
|
* Revision 1.1 88/12/23 18:02:09 mark
|
||
|
* Initial revision
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifndef lint
|
||
|
static char *ident = "$Id: fileio.c,v 1.2 89/02/12 10:04:31 mark Exp $";
|
||
|
static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
|
||
|
#endif /* ! lint */
|
||
|
|
||
|
|
||
|
/* Headers */
|
||
|
|
||
|
#include "pax.h"
|
||
|
|
||
|
int mknod (const char *path, mode_t mode, int dev);
|
||
|
|
||
|
/* open_archive - open an archive file.
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* Open_archive will open an archive file for reading or writing,
|
||
|
* setting the proper file mode, depending on the "mode" passed to
|
||
|
* it. All buffer pointers are reset according to the mode
|
||
|
* specified.
|
||
|
*
|
||
|
* PARAMETERS
|
||
|
*
|
||
|
* int mode - specifies whether we are reading or writing.
|
||
|
*
|
||
|
* RETURNS
|
||
|
*
|
||
|
* Returns a zero if successfull, or -1 if an error occured during
|
||
|
* the open.
|
||
|
*/
|
||
|
|
||
|
int open_archive(int mode)
|
||
|
{
|
||
|
#ifdef DF_TRACE_DEBUG
|
||
|
printf("DF_TRACE_DEBUG: int open_archive() in fileio.c\n");
|
||
|
#endif
|
||
|
if (ar_file[0] == '-' && ar_file[1] == '\0') {
|
||
|
if (mode == AR_READ) {
|
||
|
archivefd = STDIN;
|
||
|
bufend = bufidx = bufstart;
|
||
|
} else {
|
||
|
archivefd = STDOUT;
|
||
|
}
|
||
|
} else if (mode == AR_READ) {
|
||
|
archivefd = open(ar_file, O_RDONLY | O_BINARY);
|
||
|
bufend = bufidx = bufstart; /* set up for initial read */
|
||
|
} else if (mode == AR_WRITE) {
|
||
|
archivefd = open(ar_file, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, /* Xn */
|
||
|
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); /* Xn */
|
||
|
} else if (mode == AR_APPEND) {
|
||
|
archivefd = open(ar_file, O_RDWR | O_BINARY, /* Xn */
|
||
|
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); /* Xn */
|
||
|
bufend = bufidx = bufstart; /* set up for initial read */
|
||
|
}
|
||
|
|
||
|
if (archivefd < 0) {
|
||
|
warnarch(strerror(errno), (OFFSET) 0); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
++arvolume;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* close_archive - close the archive file
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* Closes the current archive and resets the archive end of file
|
||
|
* marker.
|
||
|
*/
|
||
|
|
||
|
void close_archive(void)
|
||
|
{
|
||
|
#ifdef DF_TRACE_DEBUG
|
||
|
printf("DF_TRACE_DEBUG: void close_archive() in fileio.c\n");
|
||
|
#endif
|
||
|
if (archivefd != STDIN && archivefd != STDOUT) {
|
||
|
close(archivefd);
|
||
|
}
|
||
|
areof = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* openout - open an output file
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* Openo opens the named file for output. The file mode and type are
|
||
|
* set based on the values stored in the stat structure for the file.
|
||
|
* If the file is a special file, then no data will be written, the
|
||
|
* file/directory/Fifo, etc., will just be created. Appropriate
|
||
|
* permission may be required to create special files.
|
||
|
*
|
||
|
* PARAMETERS
|
||
|
*
|
||
|
* char *name - The name of the file to create
|
||
|
* Stat *asb - Stat structure for the file
|
||
|
* Link *linkp; - pointer to link chain for this file
|
||
|
* int ispass - true if we are operating in "pass" mode
|
||
|
*
|
||
|
* RETURNS
|
||
|
*
|
||
|
* Returns the output file descriptor, 0 if no data is required or -1
|
||
|
* if unsuccessful. Note that UNIX open() will never return 0 because
|
||
|
* the standard input is in use.
|
||
|
*/
|
||
|
|
||
|
int openout(char *name, Stat *asb, Link *linkp, int ispass)
|
||
|
{
|
||
|
int exists;
|
||
|
int fd;
|
||
|
ushort perm;
|
||
|
ushort operm = 0;
|
||
|
Stat osb;
|
||
|
#ifdef S_IFLNK
|
||
|
int ssize;
|
||
|
char sname[PATH_MAX + 1];
|
||
|
#endif /* S_IFLNK */
|
||
|
|
||
|
#ifdef DF_TRACE_DEBUG
|
||
|
printf("DF_TRACE_DEBUG: int openout() in fileio.c\n");
|
||
|
#endif
|
||
|
if (exists = (LSTAT(name, &osb) == 0)) {
|
||
|
if (ispass && osb.sb_ino == asb->sb_ino && osb.sb_dev == asb->sb_dev) {
|
||
|
warn(name, "Same file");
|
||
|
return (-1);
|
||
|
} else if ((osb.sb_mode & S_IFMT) == (asb->sb_mode & S_IFMT)) {
|
||
|
operm = (ushort)(osb.sb_mode & S_IPERM);
|
||
|
} else if (REMOVE(name, &osb) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
} else {
|
||
|
exists = 0;
|
||
|
}
|
||
|
}
|
||
|
if (linkp) {
|
||
|
if (exists) {
|
||
|
if (asb->sb_ino == osb.sb_ino && asb->sb_dev == osb.sb_dev) {
|
||
|
return (0);
|
||
|
} else if (unlink(name) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
} else {
|
||
|
exists = 0;
|
||
|
}
|
||
|
}
|
||
|
if (link(linkp->l_name, name) != 0) {
|
||
|
if (errno == ENOENT) {
|
||
|
if (f_dir_create) {
|
||
|
if (dirneed(name) != 0 ||
|
||
|
link(linkp->l_name, name) != 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
warn(name,
|
||
|
"Directories are not being created (-d option)");
|
||
|
}
|
||
|
return (0);
|
||
|
} else if (errno != EXDEV) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
perm = (ushort)(asb->sb_mode & S_IPERM);
|
||
|
switch (asb->sb_mode & S_IFMT) {
|
||
|
case S_IFBLK:
|
||
|
case S_IFCHR:
|
||
|
fd = 0;
|
||
|
if (exists) {
|
||
|
if (REMOVE(name, &osb) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
} else {
|
||
|
exists = 0;
|
||
|
}
|
||
|
}
|
||
|
if (mknod(name, (int) asb->sb_mode, 0)) {
|
||
|
if (errno == ENOENT) {
|
||
|
if (f_dir_create) {
|
||
|
if (dirneed(name) < 0 || mknod(name, (int) asb->sb_mode,
|
||
|
0)) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
warn(name, "Directories are not being created (-d option)");
|
||
|
}
|
||
|
} else {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
return (0);
|
||
|
break;
|
||
|
case S_IFDIR:
|
||
|
if (exists) {
|
||
|
if (perm != operm && chmod(name, (int) perm) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else if (f_dir_create) {
|
||
|
if (dirmake(name, asb) < 0 || dirneed(name) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
warn(name, "Directories are not being created (-d option)");
|
||
|
}
|
||
|
return (0);
|
||
|
#ifdef S_IFIFO
|
||
|
case S_IFIFO:
|
||
|
fd = 0;
|
||
|
if (exists) {
|
||
|
if (perm != operm && chmod(name, (int) perm) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else if (mkfifo(name, asb->sb_mode) < 0) { /* Xn */
|
||
|
if (errno == ENOENT) {
|
||
|
if (f_dir_create) {
|
||
|
if (dirneed(name) < 0
|
||
|
|| mkfifo(name, asb->sb_mode) < 0) { /* Xn */
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
warn(name, "Directories are not being created (-d option)");
|
||
|
}
|
||
|
} else {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
return (0);
|
||
|
break;
|
||
|
#endif /* S_IFIFO */
|
||
|
#ifdef S_IFLNK
|
||
|
case S_IFLNK:
|
||
|
if (exists) {
|
||
|
if ((ssize = readlink(name, sname, sizeof(sname))) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
} else if (strncmp(sname, asb->sb_link, ssize) == 0) {
|
||
|
return (0);
|
||
|
} else if (REMOVE(name, &osb) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
} else {
|
||
|
exists = 0;
|
||
|
}
|
||
|
}
|
||
|
if (symlink(asb->sb_link, name) < 0) {
|
||
|
if (errno == ENOENT) {
|
||
|
if (f_dir_create) {
|
||
|
if (dirneed(name) < 0 || symlink(asb->sb_link, name) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
warn(name, "Directories are not being created (-d option)");
|
||
|
}
|
||
|
} else {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
return (0); /* Can't chown()/chmod() a symbolic link */
|
||
|
#endif /* S_IFLNK */
|
||
|
case S_IFREG:
|
||
|
if (exists) {
|
||
|
if (!f_unconditional && osb.sb_mtime > asb->sb_mtime) {
|
||
|
warn(name, "Newer file exists");
|
||
|
return (-1);
|
||
|
} else if (unlink(name) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
} else {
|
||
|
exists = 0;
|
||
|
}
|
||
|
}
|
||
|
if ((fd = creat(name, (int) perm)) < 0) {
|
||
|
if (errno == ENOENT) {
|
||
|
if (f_dir_create) {
|
||
|
if (dirneed(name) < 0 ||
|
||
|
(fd = creat(name, (int) perm)) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
/*
|
||
|
* the file requires a directory which does not exist
|
||
|
* and which the user does not want created, so skip
|
||
|
* the file...
|
||
|
*/
|
||
|
warn(name, "Directories are not being created (-d option)");
|
||
|
return (0);
|
||
|
}
|
||
|
} else {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
warn(name, "Unknown filetype");
|
||
|
return (-1);
|
||
|
}
|
||
|
if (f_owner) {
|
||
|
if (!exists || asb->sb_uid != osb.sb_uid || asb->sb_gid != osb.sb_gid) {
|
||
|
chown(name, (int) asb->sb_uid, (int) asb->sb_gid);
|
||
|
}
|
||
|
}
|
||
|
return (fd);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* openin - open the next input file
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* Openi will attempt to open the next file for input. If the file is
|
||
|
* a special file, such as a directory, FIFO, link, character- or
|
||
|
* block-special file, then the file size field of the stat structure
|
||
|
* is zeroed to make sure that no data is written out for the file.
|
||
|
* If the file is a special file, then a file descriptor of 0 is
|
||
|
* returned to the caller, which is handled specially. If the file
|
||
|
* is a regular file, then the file is opened and a file descriptor
|
||
|
* to the open file is returned to the caller.
|
||
|
*
|
||
|
* PARAMETERS
|
||
|
*
|
||
|
* char *name - pointer to the name of the file to open
|
||
|
* Stat *asb - pointer to the stat block for the file to open
|
||
|
*
|
||
|
* RETURNS
|
||
|
*
|
||
|
* Returns a file descriptor, 0 if no data exists, or -1 at EOF. This
|
||
|
* kludge works because standard input is in use, preventing open() from
|
||
|
* returning zero.
|
||
|
*/
|
||
|
|
||
|
int openin(char *name, Stat *asb)
|
||
|
{
|
||
|
int fd;
|
||
|
|
||
|
#ifdef DF_TRACE_DEBUG
|
||
|
printf("DF_TRACE_DEBUG: int openin() in fileio.c\n");
|
||
|
#endif
|
||
|
switch (asb->sb_mode & S_IFMT) {
|
||
|
case S_IFDIR:
|
||
|
asb->sb_size = 0;
|
||
|
return (0);
|
||
|
#ifdef S_IFLNK
|
||
|
case S_IFLNK:
|
||
|
if ((asb->sb_size = readlink(name,
|
||
|
asb->sb_link, sizeof(asb->sb_link) - 1)) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */
|
||
|
return (0);
|
||
|
}
|
||
|
asb->sb_link[asb->sb_size] = '\0';
|
||
|
return (0);
|
||
|
#endif /* S_IFLNK */
|
||
|
case S_IFREG:
|
||
|
if (asb->sb_size == 0) {
|
||
|
return (0);
|
||
|
}
|
||
|
if ((fd = open(name, O_RDONLY | O_BINARY)) < 0) {
|
||
|
warn(name, strerror(errno)); /* Xn */}
|
||
|
return (fd);
|
||
|
default:
|
||
|
asb->sb_size = 0;
|
||
|
return (0);
|
||
|
}
|
||
|
}
|