cpio.c revision b0ee9efa1f4ab0654aa51c968022f84aa53d894e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2012 Milan Jurik. All rights reserved.
* Copyright (c) 2012 Gary Mills
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
* under license from the Regents of the University of California.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <utime.h>
#include <pwd.h>
#include <grp.h>
#include <signal.h>
#include <ctype.h>
#include <locale.h>
#include "cpio.h"
#include <sys/resource.h>
#include <fnmatch.h>
#include <libgen.h>
#include <libintl.h>
#include <dirent.h>
#include <limits.h>
#include <aclutils.h>
#if defined(_PC_SATTR_ENABLED)
#include <libnvpair.h>
#include <attr.h>
#include <libcmdutils.h>
#endif /* _PC_SATTR_ENABLED */
#ifdef SOLARIS_PRIVS
#include <priv.h>
#endif /* SOLARIS_PRIVS */
/*
* Special kludge for off_t being a signed quantity.
*/
#if _FILE_OFFSET_BITS == 64
typedef u_longlong_t u_off_t;
#else
#endif
#define SECMODE 0xe080
#define XATTRHDR ".hdr"
#define NAMELEN 32
#define TYPELEN 16
#define PERMLEN 4
#define FILE_COPIED 1
#define FILE_LINKED 2
#define FILE_PASS_ERR -1
#define ARCHIVE_NORMAL 0
#define ARCHIVE_ACL 1
#define ARCHIVE_XATTR 2
#define ARCHIVE_SPARSE 3
#ifndef VIEW_READONLY
#define VIEW_READONLY "SUNWattr_ro"
#endif
#ifndef VIEW_READWRITE
#define VIEW_READWRITE "SUNWattr_rw"
#endif
/*
* These limits reflect the maximum size regular file that
* can be archived, depending on the archive type. For archives
* with character-format headers (odc, tar, ustar) we use
* CHAR_OFFSET_MAX. For archives with SVR4 ASCII headers (-c, -H crc)
* we store filesize in an 8-char hexadecimal string and use
* ASC_OFFSET_MAX. Otherwise, we are limited to the size that will
* fit in a signed long value.
*/
#define POSIXMODES 07777
static char aclchar = ' ';
static int bfill(void);
static void bflush(void);
static int ckname(int);
static int creat_hdr(void);
static int creat_spec(int dirfd);
static void data_out(void);
static void data_pass(void);
static void file_in(void);
static int file_out(void);
static int file_pass(void);
static void flush_lnks(void);
static int gethdr(void);
static int getname(void);
static int matched(void);
static long mklong(short v[]);
static void rstbuf(void);
static void scan4trail(void);
static void usage(void);
static void write_trail(void);
static int ustar_dir(void);
static int ustar_spec(void);
static void read_bar_vol_hdr(void);
static void read_bar_file_hdr(void);
static void setup_uncompress(FILE **);
static void skip_bar_volhdr(void);
static void bar_file_in(void);
static int g_read(int, int, char *, unsigned);
static int g_write(int, int, char *, unsigned);
static int is_floppy(int);
static int is_tape(int);
static int remove_dir(char *);
static int save_cwd(void);
static void xattrs_out(int (*func)());
static char *get_component(char *path);
static int open_dirfd();
static void close_dirfd();
static void write_xattr_hdr();
static int read_xattr_hdr();
static void chop_endslashes(char *path);
/* helpful types */
static
*Rpw_p, /* Password entry for -R option */
*dpasswd;
static
*dgroup;
/* Data structure for buffered I/O. */
static
struct buf_info {
char *b_base_p, /* Pointer to base of buffer */
*b_out_p, /* Position to take bytes from buffer at */
*b_in_p, /* Position to put bytes into buffer at */
*b_end_p; /* Pointer to end of buffer */
long b_cnt, /* Count of unprocessed bytes */
b_size; /* Size of buffer in bytes */
} Buffr;
/* Generic header format */
static
struct gen_hdr {
g_ino, /* Inode number of file */
g_mode, /* Mode of file */
g_uid, /* Uid of file */
g_gid, /* Gid of file */
g_nlink, /* Number of links */
g_mtime; /* Modification time */
g_namesz, /* Length of filename */
g_cksum; /* Checksum of file */
char g_gname[32],
g_uname[32],
g_version[2],
g_tmagic[6],
char *g_tname,
*g_prefix,
*g_nam_p, /* Filename */
*g_attrparent_p, /* attribute parent */
*g_attrpath_p, /* attribute path */
*g_attrnam_p, /* attribute */
*g_attrfnam_p, /* Real file name attr belongs to */
*g_linktoattrfnam_p, /* file linked attribute belongs to */
*g_linktoattrnam_p, /* attribute g_attrnam_p is linked to */
*g_dirpath; /* dirname currently opened */
int g_dirfd; /* directory file descriptor */
int g_passdirfd; /* directory fd to pass to */
int g_rw_sysattr; /* read-write system attribute */
int g_baseparent_fd; /* base file's parent fd */
/* Data structure for handling multiply-linked files */
static
static
struct Lnk {
short L_cnt, /* Number of links encountered */
L_data; /* Data has been encountered if 1 */
*L_bck_p, /* Previous file in list */
*L_lnk_p; /* Next link for this file */
} Lnk_hd;
static
/*
* -------------------------------------------------------------------------
* Stuff needed to pre-view the name stream
*
* issymlink is used to remember that the current file is a symlink between
* getname() and file_pass(); the former trashes this information immediately
* when -L is specified.
*/
static
int issymlink = 0;
static
typedef struct sl_info
{
int bal; /* Subtree balance factor */
int sl_ftype; /* file type of inode */
} sl_info_t;
typedef struct data_in
{
int data_in_errno;
char data_in_swapfile;
char data_in_proc_mode;
char data_in_rd_eof;
char data_in_wr_part;
char data_in_compress_flag;
long data_in_cksumval;
} data_in_t;
/*
* The following structure maintains a hash entry for the
* balancing trees which are allocated for each device nodes.
*/
typedef struct sl_info_link
{
struct sl_info_link *next;
#define SL_INFO_ALLOC_CHUNK 1024
#define NDEVHENTRY 0x40
/*
* For remapping dev,inode for -Hodc archives.
*/
typedef struct sl_remap
{
int inode_count; /* # inodes seen on dev */
} sl_remap_t;
/* forward declarations */
static sl_info_t *sl_info_alloc(void);
static void sl_preview_synonyms(void);
static void sl_remember_tgt(const struct stat *, int, int);
/* global storage */
/*
* -------------------------------------------------------------------------
*/
static
SrcSt, /* stat(2) information of source file */
DesSt, /* stat(2) of destination file */
/*
* bin_mag: Used to validate a binary magic number,
* by combining to bytes into an unsigned short.
*/
static
union bin_mag {
unsigned char b_byte[2];
} Binmag;
static
static struct gen_hdr Gen_bar_vol;
/*
* swpbuf: Used in swap() to swap bytes within a halfword,
* halfwords within a word, or to reverse the order of the
* bytes within a word. Also used in mklong() and mkshort().
*/
static
union swpbuf {
unsigned char s_byte[4];
} *Swp_p;
static
char *myname, /* program name */
Adir, /* Flags object as a directory */
Hiddendir, /* Processing hidden attribute directory */
Aspec, /* Flags object as a special file */
Do_rename, /* Indicates rename() is to be used */
*Buf_p, /* Buffer for file system I/O */
*Full_p, /* Pointer to full pathname */
*Efil_p, /* -E pattern file string */
*Eom_p = "Change to part %d and press RETURN key. [q] ",
*Fullnam_p, /* Full pathname */
*Attrfile_p, /* attribute file */
*Hdr_p, /* -H header type string */
*Lnkend_p, /* Pointer to end of Lnknam_p */
*Lnknam_p, /* Buffer for linking files with -p option */
*Nam_p, /* Array to hold filename */
*Savenam_p, /* copy of filename xattr belongs to */
*Own_p, /* New owner login id string */
*Renam_p, /* Buffer for renaming files */
*Renam_attr_p, /* Buffer for renaming attr with sys attrs */
*Renametmp_p, /* Tmp Buffer for renaming files */
*Symlnk_p, /* Buffer for holding symbolic link name */
*Over_p, /* Holds temporary filename when overwriting */
**Pat_pp = 0, /* Pattern strings */
bar_linkflag, /* flag to indicate if the file is a link */
static
int Append = 0, /* Flag set while searching to end of archive */
Archive, /* File descriptor of the archive */
Buf_error = 0, /* I/O error occurred during buffer fill */
Compress_sparse = 0, /* Compress sparse files */
Device, /* Device type being accessed (used with libgenIO) */
Error_cnt = 0, /* Cumulative count of I/O errors */
Hdr_type, /* Flag to indicate type of header selected */
Ifile, /* File des. of file being archived */
Ofile, /* File des. of file being extracted from archive */
Use_old_stat = 0, /* Create an old style -Hodc hdr (small dev's) */
Onecopy = 0, /* Flags old vs. new link handling */
Pad_val = 0, /* Indicates the number of bytes to pad (if any) */
PageSize = 0, /* The native page size, used for figuring block size */
Verbcnt = 0, /* Count of number of dots '.' output */
Eomflag = 0,
Dflag = 0,
Compressed, /* Flag to indicate if the bar archive is compressed */
Bar_vol_num = 0, /* Volume number count for bar archive */
privileged = 0, /* Flag set if running with higher privileges */
static
static
static
long Args, /* Mask of selected options */
static
static
*Rtty_p, /* Input file pointer for interactive rename */
*Wtty_p; /* Output file ptr for interactive rename */
static
/* ACL support */
static struct sec_attr {
char attr_type;
char attr_len[7];
char attr_info[1];
} *attr;
static int Pflag = 0; /* flag indicates that acl is preserved */
static int acl_is_set = 0; /* True if an acl was set on the file */
#if defined(O_XATTR)
typedef enum {
#endif
#if defined(O_XATTR)
typedef enum {
} arc_action_t;
#endif
/*
*
* cpio has been changed to support extended attributes.
*
* As part of this change cpio has been changed to use the new *at() syscalls
* such as openat, fchownat(), unlinkat()...
*
* This was done so that attributes can be handled with as few code changes
* as possible.
*
* What this means is that cpio now opens the directory that a file or directory
* resides in and then performs *at() functions to manipulate the entry.
*
* For example a new file is now created like this:
*
* dfd = open(<some dir path>)
* fd = openat(dfd, <name>,....);
*
* or in the case of an extended attribute
*
* dfd = attropen(<pathname>, ".", ....)
*
* Once we have a directory file descriptor all of the *at() functions can
* be applied to it.
*
* unlinkat(dfd, <component name>,...)
* fchownat(dfd, <component name>,..)
*
* This works for both normal namespace files and extended attribute file
*
*/
/*
* Extended attribute layout
*
* Extended attributes are stored in two pieces.
* 1. An attribute header which has information about
* what file the attribute is for and what the attribute
* is named.
* 2. The attribute record itself. Stored as a normal file type
* of entry.
* associated with them.
*
* The names of the header in the archive look like:
*
* The name of the attribute looks like:
*
* This is done so that an archiver that doesn't understand these formats
* can just dispose of the attribute records unless the user chooses to
* rename them via cpio -r or pax -i
*
* The format is composed of a fixed size header followed
* by a variable sized xattr_buf. If the attribute is a hard link
* to another attribute, then another xattr_buf section is included
* for the link.
*
* The xattr_buf is used to define the necessary "pathing" steps
* to get to the extended attribute. This is necessary to support
* a fully recursive attribute model where an attribute may itself
* have an attribute.
*
* The basic layout looks like this.
*
* --------------------------------
* | |
* | xattr_hdr |
* | |
* --------------------------------
* --------------------------------
* | |
* | xattr_buf |
* | |
* --------------------------------
* --------------------------------
* | |
* | (optional link info) |
* | |
* --------------------------------
* --------------------------------
* | |
* | attribute itself |
* | stored as normal tar |
* | or cpio data with |
* | special mode or |
* | typeflag |
* | |
* --------------------------------
*
*/
/*
* Extended attributes structures
*
* xattrhead is the complete extended attribute header, as read of off
*
* xattrp is basically an offset into xattrhead that points to the
* "pathing" section which defines how to get to the attribute.
*
* xattr_linkp is identical to xattrp except that it is used for linked
* attributes. It provides the pathing steps to get to the linked
* attribute.
*
* These structures are updated when an extended attribute header is read off
*/
static struct xattr_buf *xattr_linkp;
static int xattrbadhead; /* is extended attribute header bad? */
static int append_secattr(char **, int *, acl_t *);
/*
* Note regarding cpio and changes to ensure cpio doesn't try to second
* guess whether it runs with sufficient privileges or not:
*
* cpio has been changed so that it doesn't carry a second implementation of
* the kernel's policy with respect to privileges. Instead of attempting
* to restore uid and gid from an archive only if cpio is run as uid 0,
* cpio now *always* tries to restore the uid and gid from the archive
* except when the -R option is specified. When the -R is specified,
* the uid and gid of the restored file will be changed to those of the
* login id specified. In addition, chown(), set_tym(), and chmod() should
* only be executed once during archive extraction, and to ensure
* executed before chmod().
*
* Note regarding debugging mechanism for cpio:
*
* The following mechanism is provided to allow us to debug cpio in complicated
* situations, like when it is part of a pipe. The idea is that you compile
* with -DWAITAROUND defined, and then add the "-z" command line option to the
* target cpio invocation. If stderr is available, it will tell you to which
* pid to attach the debugger; otherwise, use ps to find it. Attach to the
* process from the debugger, and, *PRESTO*, you are there!
*
* Simply assign "waitaround = 0" once you attach to the process, and then
* proceed from there as usual.
*/
#ifdef WAITAROUND
int waitaround = 0; /* wait for rendezvous with the debugger */
#endif
/*
* main: Call setup() to process options and perform initializations,
* and then select either copy in (-i), copy out (-o), or pass (-p) action.
*/
int
{
int i;
int passret;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
case OCi: /* COPY IN */
/*
* Save the current working directory, so
* we can change back here after cd'ing into
* the attribute directory when processing
* attributes.
*/
if ((attr_baseparent_fd = save_cwd()) < 0) {
}
}
while ((i = gethdr()) != 0) {
if (i == 1) {
file_in();
/*
* Any ACL info for this file would or should
* have been used after file_in(); clear out
* aclp so it is is not erroneously used on
* the next file.
*/
}
acl_is_set = 0;
}
}
/* Do not count "extra" "read-ahead" buffered data */
break;
case OCo: /* COPY OUT */
scan4trail();
}
while ((i = getname()) != 0) {
if (i == 1) {
(void) file_out();
}
}
}
acl_is_set = 0;
}
}
write_trail();
break;
case OCp: /* PASS */
Compress_sparse = 1;
while (getname()) {
/*
* If file is a fully qualified path then
* file_pass will strip off the leading '/'
* and we need to save off the unstripped
* name for attribute traversal.
*/
}
acl_is_set = 0;
}
}
if (passret != FILE_LINKED) {
}
}
}
break;
default:
}
if (Ofile > 0) {
}
if (Archive > 0) {
}
0x1FF) >> 9;
}
if (Error_cnt)
return (EXIT_CODE);
}
/*
* add_lnk: Add a linked file's header to the linked file data structure, by
* either adding it to the end of an existing sub-list or starting
* a new sub-list. Each sub-list saves the links to a given file.
*
* Directly returns a pointer to the new entry; returns a pointer to the head
* of the sub-list in which that entry is located through the argument.
*/
static struct Lnk *
{
/* found */
break;
}
}
/* start new sub-list */
} else {
/* add to existing sub-list */
}
}
return (new_entry);
}
/*
* bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
* moving them to rd_buf_p. When there are no bytes left in the I/O buffer,
* Fillbuf is set and the I/O buffer is filled. The variable dist is the
* distance to lseek if an I/O error is encountered with the -k option set
* (converted to a multiple of Bufsize).
*/
static int
bfill(void)
{
int i = 0, rv;
static int eof = 0;
if (!Dflag) {
errno = 0;
(Eomflag == 0)) {
Eomflag = 1;
return (1);
}
}
continue;
if (i++ > MX_SEEKS)
Error_cnt++;
Buf_error++;
rv = 0;
continue;
} else
} /* (rv = g_read(Device, Archive ... */
}
eof = 0;
Blocks++;
} else if (rv == 0) {
if (!eof) {
eof = 1;
break;
}
eof = 0; /* reset the eof after chgreel */
/*
* if spans multiple volume, skip the volume header of
* the next volume so that the file currently being
* extracted can continue to be extracted.
*/
}
continue;
} else {
eof = 0;
}
} /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
} else { /* Dflag */
errno = 0;
return (-1);
} /* (rv = g_read(Device, Archive ... */
eof = 0;
Blocks++;
} else if (!rv) {
if (!eof) {
eof = 1;
return (rv);
}
return (-1);
} else {
eof = 0;
}
}
return (rv);
}
/*
* bflush: Move wr_cnt bytes from data_p into the I/O buffer. When the
* I/O buffer is full, Flushbuf is set and the buffer is written out.
*/
static void
bflush(void)
{
int rv;
errno = 0;
Bufsize)) < 0) {
else
}
Blocks++;
else if (rv > 0)
}
rstbuf();
}
/*
* chgreel: Determine if end-of-medium has been reached. If it has,
* close the current medium and prompt the user for the next medium.
*/
static int
{
int tmpdev;
rv = 0;
"Can't read input: end of file encountered ",
"prior to expected end of archive.");
}
}
Archive = 0;
Volcnt++;
for (;;) {
do { /* tryagain */
if (IOfil_p) {
do {
askagain = 0;
switch (*str) {
case '\n':
break;
case 'q':
default:
askagain = 1;
}
} while (askagain);
} else {
Bar_vol_num++;
"ready.");
if (!*str)
}
tryagain = 0;
tryagain = 1;
}
} while (tryagain);
break;
else { /* dir == OUTPUT */
errno = 0;
break;
else
"Unable to write this medium, try "
"another.");
}
} /* ;; */
Eomflag = 0;
return (rv);
}
/*
* ckname: Check filenames against user specified patterns,
*/
static int
{
int lastchar;
/* Re-visit tar size issues later */
return (F_SKIP);
}
}
return (F_SKIP);
/* rename interactively */
/* remove trailing '\n' */
if (*Renametmp_p == '\0') {
gettext(" Attribute "),
}
if (Renam_attr_p) {
*Renam_attr_p = '\0';
}
return (F_SKIP);
}
}
if (Renam_attr_p) {
*Renam_attr_p = '\0';
}
rename_bufsz) > rename_bufsz) ||
rename_bufsz) > rename_bufsz)) {
}
} else {
if (Renam_attr_p) {
if (strlcpy(Renam_attr_p,
rename_bufsz) {
"buffer overflow");
}
}
}
}
} else {
*Renam_p = '\0';
}
if (Renam_attr_p) {
*Renam_attr_p = '\0';
}
}
}
}
return (F_SKIP);
return (F_EXTR);
}
/*
* ckopts: Check the validity of all command line options.
*/
static void
{
int oflag;
char *t_p;
long errmsk;
#ifdef SOLARIS_PRIVS
#endif /* SOLARIS_PRIVS */
} else {
errmsk = 0;
}
if (errmsk) {
/* if non-zero, invalid options were specified */
Error_cnt++;
}
}
}
}
}
}
}
}
}
if (Bufsize <= 0) {
}
}
t_p++;
}
Max_namesz = CPATH;
Onecopy = 0;
Use_old_stat = 1;
Max_namesz = CPATH;
Onecopy = 0;
Use_old_stat = 1;
Compress_sparse = 1;
Max_namesz = APATH;
Onecopy = 1;
Compress_sparse = 1;
Max_namesz = APATH;
Onecopy = 1;
} else {
}
Onecopy = 0;
Onecopy = 0;
"Header type bar can only be used with -i");
}
"Can't preserve using bar header");
}
Onecopy = 0;
} else {
}
}
}
}
}
}
"Cannot open \"%s\" for append",
IOfil_p);
}
} else {
"Cannot open \"%s\" for output",
IOfil_p);
}
}
}
#ifdef SOLARIS_PRIVS
} else {
if (zones_privset != NULL) {
} else {
}
}
}
#else
privileged = (Euid == 0);
#endif /* SOLARIS_PRIVS */
"id matches login id of user executing cpio");
}
}
}
/*
* We are in pass mode with no block size specified. Use the
* larger of the native page size and 8192.
*/
}
}
/*
* cksum: Calculate the simple checksum of a file (CRC) or header
* (TARTYP (TAR and USTAR)). For -o and the CRC header, the file is opened and
* the checksum is calculated. For -i and the CRC header, the checksum
* is calculated as each block is transferred from the archive I/O buffer
* to the file system I/O buffer. The TARTYP (TAR and USTAR) headers calculate
* the simple checksum of the header (with the checksum field of the
* header initialized to all spaces (\040).
*/
static long
{
int cnt;
*err = 0;
switch (hdr) {
case CRC:
break;
}
/* OCo - do checksum of file */
while (lcnt > 0) {
errno = 0;
*err = 1;
break;
}
}
break;
case TARTYP: /* TAR and USTAR */
*crc_p = '\040';
crc_p++;
}
/*
* tar uses unsigned checksum, so we must use unsigned
* here in order to be able to read tar archives.
*/
crc_p++;
}
break;
default:
} /* hdr */
return (checksum);
}
/*
* creat_hdr: Fill in the generic header structure with the specific
* header information based on the value of Hdr_type.
*
* return (1) if this process was successful, and (0) otherwise.
*/
static int
creat_hdr(void)
{
int fullnamesize;
switch (Hdr_type) {
case BIN:
break;
case CHR:
break;
case ASC:
break;
case CRC:
break;
case USTAR:
/*
* If the length of the full name is greater than 256,
* print out a message and return.
*/
return (0);
} else if (fullnamesize > NAMSIZ) {
/*
* The length of the full name is greater than
* 100, so we must split the filename from the
* path
*/
char *lastslash;
sizeof (namebuff));
} else {
presize = 0;
}
/*
* If the filename is greater than 100 we can't
* archive the file
*/
"%s: filename is greater than %d",
return (0);
}
namesize);
/*
* If the prefix is greater than 155 we can't
* archive the file.
*/
"%s: prefix is greater than %d",
return (0);
}
presize);
} else {
}
"cpio: could not get passwd information "
"for %s%s%s",
gettext(" System Attribute ") :
gettext(" Attribute "),
/* make name null string */
} else {
}
"cpio: could not get group information "
"for %s%s%s",
gettext(" System Attribute ") :
gettext(" Attribute "),
/* make name null string */
} else {
}
/* FALLTHROUGH */
case TAR:
break;
default:
}
/*
* When processing extended attributes, creat_hdr()
* can get called multiple times which means that
* SrcSt.st.st_dev would have gotten converted to
* -Hodc format. We should always use the original
* device here as we need to be able to match on
* the original device id from the file that was
* previewed in sl_preview_synonyms().
*/
} else {
}
if (Use_old_stat) {
}
if (Use_old_stat) {
/* -Hodc */
"for -Hodc format",
gettext(" System Attribute ") :
gettext(" Attribute "),
return (0);
}
} else {
}
else
return (1);
}
/*
* creat_lnk: Create a link from the existing name1_p to name2_p.
*/
static
int
{
int cnt = 0;
do {
errno = 0;
acl_is_set = 0;
}
cnt = 0;
break;
/*
* Check to see if we are trying to link this
* file to itself. If so, count the effort as
* successful. If the two files are different,
* or if either lstat is unsuccessful, proceed
* as we would have otherwise; the appropriate
* error will be reported subsequently.
*/
name1_p);
} else {
"destination file %s", name2_p);
} else {
name2_p);
return (0);
}
}
}
name2_p);
name2_p);
}
cnt++;
if (!cnt) {
char *newname;
char *fromname;
char *attrname;
if (attrname) {
} else {
}
}
} else {
}
} else if (cnt == 1)
"Unable to create directory for \"%s\"", name2_p);
else if (cnt == 2)
return (cnt);
}
/*
* creat_spec:
* Create one of the following:
* directory
* character special file
* block special file
* fifo
* socket
*/
static int
creat_spec(int dirfd)
{
char *nam_p;
char *curdir;
char *lastslash;
Do_rename = 0; /* creat_tmp() may reset this */
} else {
}
/*
* Is this the extraction of the hidden attribute directory?
* If we are processing the hidden attribute directory of an
* attribute, then just return as modes and times cannot be set.
* Otherwise, if we are processing a hidden attribute, just set
*/
if (Hiddendir) {
"Cannot chown() \"attribute "
"directory of file %s\"",
G_p->g_attrfnam_p);
}
"Cannot chown() \"attribute directory of "
}
"Cannot chmod() \"attribute directory of "
}
acl_is_set = 0;
"failed to set acl on attribute"
" directory of %s ",
G_p->g_attrfnam_p);
} else {
acl_is_set = 1;
}
}
}
return (1);
}
/*
* The archive file is a directory.
* Skip "." and ".."
*/
lastslash++;
} else {
}
return (1);
}
}
if (result == 0) {
/* A file by the same name exists. */
/* Take care of ACLs */
acl_is_set = 0;
"\"%s\": failed to set acl",
nam_p);
} else {
acl_is_set = 1;
}
}
/*
* We are creating directories. Keep the
* existing file.
*/
}
/* Report success. */
return (1);
}
} else {
/* The archive file is not a directory. */
if (result == 0) {
/*
* A file by the same name exists. Move it to a
* temporary file.
*/
/*
* We weren't able to create the temp file.
* Report failure.
*/
return (0);
}
}
}
/*
* This pile tries to create the file directly, and, if there is a
* problem, creates missing directories, and then tries to create the
* file again. Two strikes and you're out.
*/
cnt = 0;
do {
/* The archive file is a directory. */
} else if (ustar_spec() || Aspec) {
/*
* The archive file is block special,
* char special, socket, or a fifo.
* Note that, for a socket, the third
* parameter to mknod() is ignored.
*/
}
if (result >= 0) {
/*
* The file creation succeeded. Take care of the ACLs.
*/
acl_is_set = 0;
"\"%s\": failed to set acl", nam_p);
} else {
acl_is_set = 1;
}
}
cnt = 0;
break;
}
cnt++;
switch (cnt) {
case 0:
rv = 1;
break;
case 1:
"Cannot create directory for \"%s\"", nam_p);
if (*Over_p == '\0') {
}
break;
case 2:
} else if (ustar_spec() || Aspec) {
}
if (*Over_p == '\0') {
}
break;
default:
}
return (rv);
}
/*
* creat_tmp:
*/
static int
{
char *t_p;
int cwd;
return (-1);
}
return (-1);
}
/* Make the temporary file name. */
break;
t_p--;
}
/*
* Save our current directory, so we can go into
* the attribute directory to make the temp file
* and then return.
*/
}
/* Return to the current directory. */
}
if (*Over_p == '\0') {
/* mktemp reports a failure. */
return (-1);
}
/*
* If it's a regular file, write to the temporary file, and then rename
* in order to accommodate potential executables.
*
* Note: g_typeflag is only defined (set) for USTAR archive types. It
* defaults to 0 in the cpio-format-regular file case, so this test
* succeeds.
*/
if (G_p->g_typeflag == 0 &&
/*
* The archive file and the filesystem file are both regular
* files. We write to the temporary file in this case.
*/
} else {
Attrfile_p = Over_p;
}
} else {
Attrfile_p = Over_p;
}
}
} else {
}
Do_rename = 1;
} else {
/*
* Either the archive file or the filesystem file is not a
* regular file.
*/
Do_rename = 0;
/*
* The filesystem file is a directory.
*
* Save the current working directory because we will
* want to restore it back just in case remove_dir()
* fails or get confused about where we should be.
*/
*Over_p = '\0';
if (remove_dir(nam_p) < 0) {
"Cannot remove the directory \"%s\"",
nam_p);
/*
* Restore working directory back to the one
* saved earlier.
*/
return (-1);
}
/*
* Restore working directory back to the one
* saved earlier
*/
} else {
/*
* The file is not a directory. Will use the original
* namefs, link would fail with EXDEV. Therefore, we
* use rename() first to back up the file.
*/
/*
* If rename failed, try old construction
* method.
*/
"Cannot rename temporary file "
*Over_p = '\0';
return (-1);
}
"Cannot unlink() current \"%s\"",
nam_p);
*Over_p = '\0';
return (-1);
}
}
}
}
return (1);
}
/*
* Copy the datasize amount of data from the input file to buffer.
*
* ifd - Input file descriptor.
* buffer - Buffer (allocated by caller) to copy data to.
* datasize - The amount of data to read from the input file
* and copy to the buffer.
* error - When reading from an Archive file, indicates unreadable
* data was encountered, otherwise indicates errno.
* data_in_info - Information needed when called from data_in().
*/
static ssize_t
{
} else {
if (data_in_info->data_in_swapfile)
/*
* if the bar archive is compressed, set up a pipe and
* do the de-compression while reading in the file
*/
if (data_in_info->data_in_compress_flag == 0 &&
Compressed) {
&(data_in_info->data_in_pipef));
}
}
}
return (datasize);
}
}
/*
* Read as much data as we can.
*
* ifd - input file descriptor.
* buf - Buffer (allocated by caller) to copy data to.
* bytes - The amount of data to read from the input file
* and copy to the buffer.
* rdblocksz - The size of the chunk of data to read.
*
* Return number of bytes failed to read.
* Return -1 when buffer is empty and read failed.
*/
static int
{
/*
* Read the data from either the input file descriptor
* or the archive file. read_chunk() will only return
* <= 0 if data_copy() was called from data_pass().
*/
data_in_info)) <= 0) {
/*
* We come here only in the pass mode.
* If data couldn't be read from the input file
* descriptor, return number of bytes in the buf.
* If buffer is empty, return -1.
*/
if (bytesread == 0) {
if (got == 0) /* EOF */
return (-1);
}
}
}
return (0);
}
/*
* Write as much data as we can.
*
* ofd - output file descriptor.
* buf - Source buffer to output data from.
* maxwrite - The amount of data to write to the output.
*
* return 0 upon success.
*/
static int
{
errno = 0;
/*
* data_in() needs to know if it was an actual write(2)
* failure, or if we just couldn't write all of the data
* requested so that we know that the rest of the file's
* data can be read but not written.
*/
if (cnt != -1)
return (1);
}
return (0);
}
/*
* Perform I/O for given byte size with using limited i/o block size
* and supplied buffer.
*
* buf - buffer to be used for i/o
* wrblocksz - Output block size.
* rdblocksz - Read block size.
*
* Return 0 upon success. Return negative if read failed.
* Return positive non-zero if write failed.
*/
static int
{
int error = 0;
while (bytes > 0) {
/*
* If the number of bytes left to write is smaller than
* the preferred I/O size, then we're about to do our final
* write to the file, so just set wrblocksz to the number of
* bytes left to write.
*/
/* Read input till satisfy output block size */
if (sz < 0)
return (sz);
if (write_it) {
if (rv != 0) {
/*
* If we wrote partial, we return and quits.
* Otherwise, read through the rest of input
* to go to the next file.
*/
return (rv);
} else {
write_it = 0;
}
error = 1;
}
}
}
return (error);
}
/*
* Write zeros for give size.
*
* ofd - output file descriptor
* buf - buffer to fill with zeros
* bytes - Amount to write
* wrblocksz - Write block size
*
* return 0 upon success.
*/
static int
{
int rv;
while (bytes > 0) {
if (rv != 0)
return (rv);
}
return (0);
}
/*
* To figure out the size of the buffer used to accumulate data from
* readtape() and to write to the file, we need to determine the largest
* chunk of data to be written to the file at one time. This is determined
* based on the following three things:
* 1) The size of the archived file.
* 2) The preferred I/O size of the file.
* 3) If the file is a read-write system attribute file.
* If the size of the file is less than the preferred I/O size or it's a
* read-write system attribute file, which must be written in one operation,
* then set the maximum write size to the size of the archived file.
* Otherwise, the maximum write size is preferred I/O size.
*/
static int
{
} else {
} else {
}
}
return (maxwrite);
}
/*
* data_copy() and data_copy_with_holes() copy data from the input
* file to output file descriptor. If ifd is -1, then the input file is
* the archive file.
*
* Parameters
* ifd - Input file descriptor to read from.
* ofd - Output file descriptor of extracted file.
* rw_sysattr - Flag indicating if a file is an extended
* system attribute file.
* blocksize - Amount of data to read at a time from either
* the input file descriptor or from the archive.
* data_in_info - information needed while reading data when
* called by data_in().
* holes - Information of holes in the input file.
*
* Return code
* 0 Success
* < 0 An error occurred during the read of the input
* file
* > 0 An error occurred during the write of the output
* file descriptor.
*/
static int
{
char *buf;
int rv;
/* No data to copy. */
if (bytes == 0)
return (0);
return (rv);
}
static int
{
char *buf;
if (bytes == 0)
return (0);
error = 0;
curpos = 0;
/* adjust output position */
/*
* Can't seek to the target, try to adjust
* position by filling with zeros.
*/
if (rv != 0)
goto errout;
}
/*
* Data is contiguous in the archive, but fragmented
* in the regular file, so we also adjust the input
* file position in pass mode.
*/
/* adjust input position */
}
}
if (datasize == 0) {
/*
* There is a hole at the end of file. To create
* such hole, we append one byte, and truncate the
* last block. This is necessary because ftruncate(2)
* alone allocates one block on the end of file.
*/
if (rv != 0)
goto errout;
break;
}
if (rv != 0) {
/*
* Return if we got a read error or in pass mode,
* or failed with partial write. Otherwise, we'll
* read through the input stream till next file.
*/
return (rv);
}
error = 1;
break;
}
}
/*
* We should read through the input data to go to the next
* header when non-fatal error occured.
*/
if (rv != 0)
break;
}
}
return (error);
}
/*
* Strip off the sparse file information that is prepended to
* the compressed sparse file. The information is in the following
* format:
* <prepended info size><SP><orig file size><SP><holes info>
* where prepended info size is long right justified in 10 bytes.
* Holesdata consists of the series of offset pairs:
* <data offset><SP><hole offset><SP><data offset><SP><hole offset>...
* prepended info size and original file size have been read in gethdr().
* We read the rest of holes information here in this function.
*/
static int
{
char *holesdata;
/* We've already read the header. */
"sparse file information", nam_p);
return (1);
}
/*
* This function is called only in OCi mode. Therefore,
* read_bytes() won't fail, and won't return if error occurs in
* input stream. See rstbuf().
*/
*fileszp -= holesdata_sz;
/* The string should be terminated. */
return (1);
}
goto invalid;
/* sanity check */
goto invalid;
return (0);
}
/*
* data_in: If proc_mode == P_PROC, bread() the file's data from the archive
* and write(2) it to the open fdes gotten from openout(). If proc_mode ==
* P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data
* and ignore it. If the user specified any of the "swap" options (b, s or S),
* and the length of the file is not appropriate for that action, do not
* perform the "swap", otherwise perform the action on a buffer by buffer basis.
* If the CRC header was selected, calculate a running checksum as each buffer
* is processed.
*/
static void
{
char *nam_p;
int error = 0;
int swapfile = 0;
int cstatus = 0;
} else {
}
}
swapfile = 1;
"Cannot swap bytes of \"%s\", odd number of bytes",
nam_p);
swapfile = 0;
}
"Cannot swap halfwords of \"%s\", odd number "
"of halfwords", nam_p);
swapfile = 0;
}
}
/* We've already read the header in gethdr() */
/*
* Strip rest of the sparse file information. This includes
* the holes in the file.
*/
/* holes info isn't necessary to skip file */
} else {
if (rv != 0) {
/*
* We got an error. Skip this file. holes info
* is no longer necessary.
*/
error = 1;
}
}
}
} else {
}
/* This writes out the file from the archive */
if (!error) {
"Cannot write \"%s%s%s\"",
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
}
/*
* We've failed to write to the file, and input data
* has been skiped to the next file. We'll need to restore
* the original file, and skip the rest of work.
*/
Ofile = 0;
if (cstatus != 0) {
}
}
/* we must use g_filesz for the amount of padding */
if (pad != 0) {
}
} else
} else {
}
Ofile = 0;
if (cstatus != 0) {
}
}
(void) free(data_in_info);
Finished = 1;
}
/*
* Read regular file. Return number of bytes which weren't read.
* Upon return, real_filesz will be real file size of input file.
* When read_exact is specified, read size is adjusted to the given
* file size.
*/
static off_t
{
int amount_read;
if (file_size == 0)
return (0);
do {
else
errno = 0;
gettext(" System Attribute ") :
gettext(" Attribute "),
break;
}
if (amount_read == 0) {
/* got EOF. the file has shrunk */
break;
} else if (amount_read > amt_to_read) {
/* the file has grown */
*real_filesz = file_size +
(amount_read - amt_to_read);
} else if (amount_read == amt_to_read) {
/* the file is the same size */
*real_filesz = file_size;
}
if (!read_exact &&
/*
* If the file size is multiple of CPIOBSZ, we may
* be able to read more from the file even though
* amt_to_read already gets 0.
*/
if (amount_read != 0) {
/* the file has grown */
}
}
} while (amt_to_read != 0);
return (amt_to_read);
}
/*
* Read through the data in files skipping holes.
*/
static off_t
{
curpos = 0;
/*
* No more data. There are two cases.
* - we have a hole toward the end of file.
* - file has been shrunk, and we've reached EOF.
*/
return (0);
/*
* File has been shrunk. Check the amount of data
* left.
*/
left = 0;
}
return (left);
}
/* found data */
/*
* File has been changed. We shouldn't read data
* from different offset since we've already put
* the holes data.
*/
*hole_changed = 1;
}
if (left != 0) {
/* file has been shrunk */
return (left);
}
}
/*
* We've read exact size of holes. We need to make sure
* that file hasn't grown by reading from the EOF.
*/
realsz = 0;
return (0);
}
/*
* data_out: open(2) the file to be archived, compute the checksum
* of it's data if the CRC header was specified and write the header.
* read(2) each block of data and bwrite() it to the archive. For TARTYP (TAR
* and USTAR) archives, pad the data with NULLs to the next 512 byte boundary.
*/
static void
data_out(void)
{
char *nam_p;
int errret = 0;
int hole_changed = 0;
if (Aspec) {
int len = 0;
/* append security attributes */
"can create security information");
}
/* call append_secattr() if more than one */
if (len > 0) {
/* write ancillary only if there is sec info */
}
}
return;
}
int size;
errno = 0;
/* Note that "size" and G_p->g_filesz are the same number */
0) {
return;
}
/*
* Note that it is OK not to add the NUL after the name read by
* readlink, because it is not being used subsequently.
*/
if (pad != 0) {
}
return;
int size;
/*
* G_p->g_filesz is the length of the right-hand side of
* the symlink "x -> y".
* The tar link field is only NAMSIZ long.
*/
"Symbolic link too long \"%s\"", nam_p);
return;
}
"Cannot read symbolic link \"%s\"", nam_p);
return;
}
return;
}
return;
}
/* save original file size */
/*
* Calculate the new compressed file size of a sparse file
* before any of the header information is written
* to the archive.
*/
/*
* If the file being processed is a sparse file, gather the
* hole information and the compressed file size.
* G_p->g_filesz will need to be changed to be the size of
* the compressed sparse file plus the the size of the hole
* information that will be prepended to the compressed file
* in the archive.
*/
"in current mode",
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
G_p->g_attrpath_p));
return; /* do not archive if it's too big */
}
}
/*
* Dump extended attribute header.
*/
}
if (errret != 0) {
gettext(" System Attribute ") :
gettext(" Attribute "),
return;
}
} else {
}
/*
* ACL has been retrieved in getname().
*/
if (Pflag) {
int len = 0;
/* append security attributes */
/* call append_secattr() if more than one */
if (len > 0) {
/* write ancillary only if there is sec info */
}
}
/*
* Write the header info with a modified c_mode field to
* indicate a compressed sparse file is being archived,
* as well as the new file size, including the size of the
* compressed file as well as all the prepended data.
*/
/* Prepend sparse file info */
} else {
}
real_filesz = 0;
} else {
&real_filesz, B_FALSE);
}
while (amt_to_read > 0) {
amt_to_read -= cnt;
}
if (pad != 0) {
}
if (hole_changed == 1) {
"File data and hole offsets of \"%s%s%s\" have changed",
}
if (real_filesz > orig_filesz) {
(real_filesz - orig_filesz));
}
if (real_filesz < orig_filesz) {
(orig_filesz - real_filesz));
}
}
/*
* data_pass: If not a special file (Aspec), open(2) the file to be
* transferred, read(2) each block of data and write(2) it to the output file
* Ofile, which was opened in file_pass().
*/
static void
data_pass(void)
{
int rv;
int cstatus;
}
if (Aspec) {
Ofile = 0;
if (cstatus != 0) {
}
return;
}
Ofile = 0;
if (cstatus != 0) {
}
return;
}
} else {
}
if (rv < 0) {
/* read error or unexpected EOF */
if (data_in_info->data_in_rd_eof) {
/*
* read has reached EOF unexpectedly, but this isn't
* an error since it's the latest shape of the file.
*/
gettext(" Attribute "),
/* It's not error. We'll use the new file */
rv = 0;
} else {
/* read error */
gettext(" Attribute "),
}
} else if (rv > 0) {
/* write error */
if (Do_rename) {
gettext(" Attribute "),
} else {
gettext(" Attribute "),
}
}
if (rv == 0) {
} else {
}
Ofile = 0;
if (cstatus != 0) {
}
Finished = 1;
}
/*
* file_in: Process an object from the archive. If a TARTYP (TAR or USTAR)
* archive and g_nlink == 1, link this file to the file name in t_linkname
* and return. Handle linked files in one of two ways. If Onecopy == 0, this
* is an old style (binary or -c) archive, create and extract the data for the
* first link found, link all subsequent links to this file and skip their data.
* If Oncecopy == 1, save links until all have been processed, and then
* process the links first to last checking their names against the patterns
* for xtraction is created and the data is read from the archive.
* All subsequent links that are accepted are linked to this file.
*/
static void
file_in(void)
{
int proc_file;
int typeflag;
char savacl;
int cwd;
/*
* Now that we've read the extended header,
* determine if we should restore attributes.
* Don't restore the attribute if we are extracting
* a file from an archive (as opposed to doing a table of
* contents) and any of the following are true:
* 1. neither -@ or -/ was specified.
* 2. -@ was specified, -/ wasn't specified, and we're
* processing a hidden attribute directory of an attribute
* or we're processing a read-write system attribute file.
* 3. -@ wasn't specified, -/ was specified, and the file
* we're processing it not a read-write system attribute file,
* or we're processing the hidden attribute directory of an
* attribute.
*
* We always process the attributes if we're just generating
* generating a table of contents, or if both -@ and -/ were
* specified.
*/
G_p->g_rw_sysattr)) ||
!G_p->g_rw_sysattr)))) {
return;
}
}
/*
* Open target directory if this isn't a skipped file
* and g_nlink == 1
*
* Links are handled further down in this function.
*/
/*
* Normally ckname() prints out the file as a side
* effect except for table of contents listing
* when its parameter is zero and Onecopy isn't
* Zero. Due to this we need to force the name
* to be printed here.
*/
if (Onecopy == 1) {
}
return;
}
return;
}
bar_file_in();
close_dirfd();
return;
}
/*
* For archives in USTAR format, the files are extracted according
* to the typeflag.
*/
int i;
NAMSIZ);
;
lname[i] = 0;
}
close_dirfd();
return;
}
typeflag == '6') {
}
close_dirfd();
return;
} else {
}
close_dirfd();
return;
}
}
if (Adir) {
}
close_dirfd();
if (Onecopy == 1) {
}
return;
}
if (Aspec) {
} else {
} else {
}
}
close_dirfd();
return;
}
close_dirfd();
cleanup = 1;
} else {
if (open_dirfd() != 0)
return;
if (!lnkem) {
if (Aspec) {
} else if ((Ofile =
close_dirfd();
} else {
close_dirfd();
}
} else {
/*
* Are we linking an attribute?
*/
cwd = -1;
} else {
}
close_dirfd();
if (cwd != -1)
}
}
} else { /* Onecopy */
cleanup = 1;
if (!cleanup) {
close_dirfd();
return; /* don't do anything yet */
}
/*
* ckname will clear aclchar. We need to keep aclchar for
* all links.
*/
if (open_dirfd() != 0) {
return;
}
} else if (Aspec) {
} else if ((Ofile =
} else {
}
} /* (proc_file = ckname(1)) != F_SKIP */
close_dirfd();
}
} /* tl_p->L_lnk_p != NULL */
}
}
if (cleanup) {
}
}
/*
* file_out: If the current file is not a special file (!Aspec) and it
* is identical to the archive, skip it (do not archive the archive if it
* is a regular file). If creating a TARTYP (TAR or USTAR) archive, the first
* time a link to a file is encountered, write the header and file out normally.
* Subsequent links to this file put this file name in their t_linkname field.
* Otherwise, links are handled in one of two ways, for the old headers
* (i.e. binary and -c), linked files are written out as they are encountered.
* For the new headers (ASC and CRC), links are saved up until all the links
* to each file are found. For a file with n links, write n - 1 headers with
* g_filesz set to 0, write the final (nth) header with the correct g_filesz
* value and write the data for the file to the archive.
*/
static
int
file_out(void)
{
int cleanup = 0;
return (1); /* do not archive the archive if it's a reg file */
/*
* If compressing sparse files, wait until the compressed file size
* is known to check if file size is too big.
*/
G_p->g_attrpath_p));
return (1); /* do not archive if it's too big */
}
if (Adir) {
}
write_hdr(ARCHIVE_NORMAL, 0);
return (0);
}
data_out();
return (0);
}
data_out();
return (0);
}
/*
* check if linkname is greater than 100 characters
*/
return (1);
}
/* find the lnk entry in sublist, unlink it, and free it */
break;
}
}
return (0);
}
if (Adir) {
/*
* ACL has been retrieved in getname().
*/
if (Pflag) {
int len = 0;
/* append security attributes */
/* call append_secattr() if more than one */
if (len > 0) {
/* write ancillary */
}
}
}
return (0);
}
data_out();
return (0);
} else {
cleanup = 1;
return (0); /* don't process data yet */
}
}
/* one link with the acl is sufficient */
}
if (open_dirfd() != 0)
return (1);
}
/* old style: has acl and data for every link */
data_out();
if (cleanup)
return (0);
}
/*
* Verify the underlying file system supports the attribute type.
* Only archive extended attribute files when '-@' was specified.
* Only archive system extended attribute files if '-/' was specified.
*/
#if defined(O_XATTR)
static attr_status_t
int *ext_attrflg)
{
/*
* need to check if we are processing a base file, not an
* extended attribute.
*/
if (attrflg) {
}
if (Atflag) {
#if defined(_PC_SATTR_ENABLED)
if (!*ext_attrflg) {
if (SysAtflag) {
/* Verify system attributes are supported */
if (sysattr_support(filename,
_PC_SATTR_ENABLED) != 1) {
return (ATTR_SATTR_ERR);
}
} else
return (ATTR_XATTR_ERR);
#else
return (ATTR_XATTR_ERR);
#endif /* _PC_SATTR_ENABLED */
}
#if defined(_PC_SATTR_ENABLED)
} else if (SysAtflag) {
/* Verify system attributes are supported */
return (ATTR_SATTR_ERR);
}
#endif /* _PC_SATTR_ENABLED */
} else {
return (ATTR_SKIP);
}
return (ATTR_OK);
}
#endif
#if defined(O_XATTR)
/*
* Verify the attribute, attrname, is an attribute we want to restore.
* Never restore read-only system attribute files. Only restore read-write
* system attributes files when -/ was specified, and only traverse into
* the 2nd level attribute directory containing only system attributes if
* -@ was specified. This keeps us from archiving
* <attribute name>/<read-write system attribute file>
* when -/ was specified without -@.
*
* attrname - attribute file name
* attrparent - attribute's parent name within the base file's
* attribute digrectory hierarchy
* arc_rwsysattr - flag that indicates that read-write system attribute
* file should be archived as it contains other than
* the default system attributes.
* rw_sysattr - on return, flag will indicate if attrname is a
* read-write system attribute file.
*/
static attr_status_t
int *rw_sysattr)
{
#if defined(_PC_SATTR_ENABLED)
int attr_supported;
/* Never restore read-only system attribute files */
*rw_sysattr = 0;
return (ATTR_SKIP);
} else {
}
/*
* Don't archive a read-write system attribute file if
* it contains only the default system attributes.
*/
if (*rw_sysattr && !arc_rwsysattr) {
return (ATTR_SKIP);
}
#else
/* Never restore read-only system attribute files */
return (ATTR_SKIP);
}
#endif /* _PC_SATTR_ENABLED */
/*
* Only restore read-write system attribute files
* when -/ was specified. Only restore extended
* attributes when -@ was specified.
*/
if (Atflag) {
if (!SysAtflag) {
/*
* we're processing the top level hidden attribute
* directory. We don't want to process the
* hidden attribute directory of the attribute
* directory that contains only extended system
* attributes.
*/
if (*rw_sysattr || (Hiddendir &&
(attrparent != NULL))) {
return (ATTR_SKIP);
}
}
} else if (SysAtflag) {
/*
* files of the base file.
*/
return (ATTR_SKIP);
}
} else {
return (ATTR_SKIP);
}
return (ATTR_OK);
}
#endif
#if defined(O_XATTR)
static int
{
int dirfd;
int ofilefd = -1;
struct stat parentstat;
int error;
/*
* We couldn't get to attrdir. See if its
* just a mode problem on the parent file.
* for example: a mode such as r-xr--r--
* on a ufs file system without extended
* system attribute support won't let us
* create an attribute dir if it doesn't
* already exist, and on a ufs file system
* with extended system attribute support
* won't let us open the attribute for
* write.
*
* If file has a non-trivial ACL, then save it
* off so that we can place it back on after doing
* chmod's.
*/
O_RDONLY)) == -1) {
return (-1);
}
return (-1);
}
return (-1);
}
if (aclp)
return (-1);
}
if (pdirfd == -1) {
/*
* We weren't able to create the attribute directory before.
* Now try again.
*/
} else {
/*
* We weren't able to create open the attribute before.
* Now try again.
*/
}
/*
* Put mode back to original
*/
}
if (aclp) {
if (error) {
}
}
/*
* Put back time stamps
*/
return (ofilefd);
}
#endif
#if defined(O_XATTR)
/*
* Recursively open attribute directories until the attribute directory
* containing the specified attribute, attrname, is opened.
*
* Currently, only 2 directory levels of attributes are supported, (i.e.,
* extended system attributes on extended attributes). The following are
* the possible input combinations:
* 1. Open the attribute directory of the base file (don't change
* into it).
* attr_parent = NULL
* attrname = '.'
* 2. Open the attribute directory of the base file and change into it.
* attr_parent = NULL
* attrname = <attr> | <sys_attr>
* 3. Open the attribute directory of the base file, change into it,
* then recursively call open_attr_dir() to open the attribute's
* parent directory (don't change into it).
* attr_parent = <attr>
* attrname = '.'
* 4. Open the attribute directory of the base file, change into it,
* then recursively call open_attr_dir() to open the attribute's
* parent directory and change into it.
* attr_parent = <attr>
* attrname = <attr> | <sys_attr>
*
* An attribute directory will be opened only if the underlying file system
* supports the attribute type, and if the command line specifications
* (f_extended_attr and f_sys_attr) enable the processing of the attribute
* type.
*
* On succesful return, attr_parentfd will be the file descriptor of the
* opened attribute directory. In addition, if the attribute is a read-write
* extended system attribute, rw_sysattr will be set to 1, otherwise
* it will be set to 0.
*
* Possible return values:
* ATTR_OK Successfully opened and, if needed, changed into the
* attribute directory containing attrname.
* ATTR_SKIP The command line specifications don't enable the
* processing of the attribute type.
* ATTR_CHDIR_ERR An error occurred while trying to change into an
* attribute directory.
* ATTR_OPEN_ERR An error occurred while trying to open an
* attribute directory.
* ATTR_XATTR_ERR The underlying file system doesn't support extended
* attributes.
* ATTR_SATTR_ERR The underlying file system doesn't support extended
* system attributes.
*/
static int
int *attr_parentfd, int *rw_sysattr)
{
int saveerrno;
int ext_attr;
/*
* open_attr_dir() was recursively called (input combination number 4),
* close the previously opened file descriptor as we've already changed
* into it.
*/
if (!firsttime) {
(void) close(*attr_parentfd);
*attr_parentfd = -1;
}
/*
* Verify that the underlying file system supports the restoration
* of the attribute.
*/
return (rc);
}
/* Open the base file's attribute directory */
/*
* Save the errno from the attropen so it can be reported
* if the retry of the attropen fails.
*/
(void) close(*attr_parentfd);
*attr_parentfd = -1;
return (ATTR_OPEN_ERR);
}
}
/*
* Change into the parent attribute's directory unless we are
* processing the hidden attribute directory of the base file itself.
*/
if (fchdir(*attr_parentfd) != 0) {
(void) close(*attr_parentfd);
*attr_parentfd = -1;
return (ATTR_CHDIR_ERR);
}
}
/* Determine if the attribute should be processed */
rw_sysattr)) != ATTR_OK) {
(void) close(*attr_parentfd);
*attr_parentfd = -1;
return (rc);
}
/*
* If the attribute is an extended system attribute of an attribute
* (i.e., <attr>/<sys_attr>), then recursively call open_attr_dir() to
* open the attribute directory of the parent attribute.
*/
}
return (ATTR_OK);
}
#endif
/*
* file_pass: If the -l option is set (link files when possible), and the
* source and destination file systems are the same, link the source file
* (G_p->g_nam_p) to the destination file (Fullnam) and return. If not a
* linked file, transfer the data. Otherwise, the first link to a file
* encountered is transferred normally and subsequent links are linked to it.
*/
static int
file_pass(void)
{
char *save_name;
int size;
int cwd;
return (FILE_PASS_ERR);
}
}
return (FILE_PASS_ERR);
}
} else {
int rw_sysattr;
/*
* Open the file's attribute directory.
* Change into the base file's starting directory then call
* open_attr_dir() to open the attribute directory of either
* the base file (if G_p->g_attrparent_p is NULL) or the
* attribute (if G_p->g_attrparent_p is set) of the base file.
*/
"Cannot open attribute directory of "
"%s%s%sfile \"%s\"",
gettext("attribute \""),
return (FILE_PASS_ERR);
}
}
/* We are linking back to the source directory. */
if (!Adir) {
char *existingfile = save_name;
/* We are chasing symlinks. */
MAXPATHLEN)) < 0) {
"Cannot read symbolic link \"%s\"",
return (FILE_PASS_ERR);
}
}
existingfile, Fullnam_p) == 0) {
return (FILE_LINKED);
}
}
}
}
/* The archive file is a symlink. */
errno = 0;
"Cannot read symbolic link \"%s\"", save_name);
return (FILE_PASS_ERR);
}
errno = 0;
"Cannot create \"%s\"",
}
return (FILE_PASS_ERR);
}
} else {
return (FILE_PASS_ERR);
}
} else {
"Error during chown() of \"%s\"",
}
"Error during chown() of \"%s\"",
}
}
return (FILE_PASS_ERR);
}
/* The archive file has hard links. */
/* The archive file was not found. */
} else {
/* The archive file was found. */
cwd = -1;
/* We are linking an attribute */
} else {
/* We are not linking an attribute */
}
if (cwd) {
}
}
return (FILE_LINKED);
}
}
/*
* The archive file is a directory, block special, char
* special or a fifo.
*/
}
data_pass();
}
return (FILE_COPIED);
}
/*
* flush_lnks: With new linked file handling, linked files are not archived
* until all links have been collected. When the end of the list of filenames
* to archive has been reached, all files that did not encounter all their links
* are written out with actual (encountered) link counts. A file with n links
* (that are archived) will be represented by n headers (one for each link (the
* first n - 1 have g_filesz set to 0)) followed by the data for the file.
*/
static void
flush_lnks(void)
{
(void) creat_hdr();
if (open_dirfd() != 0) {
break;
}
data_out();
break;
}
(off_t)0); /* header only */
}
} else /* stat(Gen.g_nam_p, &SrcSt) == 0 */
gettext(" System Attribute ") :
gettext(" Attribute "),
} /* l_p != &Lnk_hd */
}
#if defined(O_XATTR)
static int
is_sysattr(char *name)
{
}
#endif
/*
* gethdr: Get a header from the archive, validate it and check for the trailer.
* Any user specified Hdr_type is ignored (set to NONE in main). Hdr_type is
* set appropriately after a valid header is found. Unless the -k option is
* set a corrupted header causes an exit with an error. I/O errors during
* examination of any part of the header cause gethdr to throw away any current
* data and start over. Other errors during examination of any part of the
* header cause gethdr to advance one byte and continue the examination.
*/
static int
gethdr(void)
{
int bswap = 0;
char *preptr;
int k = 0;
int j;
int error;
int aclcnt;
do { /* hit == NONE && (Args & OCk) && Buffr.b_cnt > 0 */
switch (Hdr_type) {
case NONE:
case BIN:
bswap = 1;
break;
}
break;
/*FALLTHROUGH*/
case CHR:
break;
}
break;
/*FALLTHROUGH*/
case ASC:
Max_namesz = APATH;
break;
}
break;
/*FALLTHROUGH*/
case CRC:
Max_namesz = APATH;
break;
}
break;
/*FALLTHROUGH*/
case BAR:
break;
}
break;
}
/*FALLTHROUGH*/
case USTAR:
break;
}
break;
}
/*FALLTHROUGH*/
case TAR:
break;
}
break;
}
/*FALLTHROUGH*/
default:
} /* Hdr_type */
}
goodhdr = 1;
goodhdr = 0;
goodhdr = 0;
/* TAR and USTAR */
goodhdr = 1;
} else {
goodhdr = 0;
"Bad header - checksum "
"error.");
}
}
goodhdr = 0;
goodhdr = 0;
}
if (!goodhdr) {
break;
"Corrupt header, file(s) may be lost.");
} else {
}
} /* hit != NONE */
break;
if (!cnt++)
}
else
} else if (cnt > 0) {
}
switch (Hdr_type) {
case BIN:
if (bswap)
Max_namesz = CPATH;
Onecopy = 0;
break;
case CHR:
Max_namesz = CPATH;
Pad_val = 0;
Onecopy = 0;
break;
case ASC:
case CRC:
Max_namesz = APATH;
Onecopy = 1;
break;
case USTAR:
Onecopy = 0;
break;
case BAR:
case TAR:
Onecopy = 0;
break;
default:
} /* Hdr_type */
} /* Hdr_type == NONE */
return (0);
else {
if (k < PRESIZ) {
j = 0;
fullnam[k++] = '/';
'\0')) {
k++; j++;
}
fullnam[k] = '\0';
} else if (k >= PRESIZ) {
k = 0;
'\0')) {
k++;
}
fullnam[k++] = '/';
j = 0;
'\0')) {
k++; j++;
}
fullnam[k] = '\0';
}
} else
/*
* initialize the buffer so that the prefix will not
* applied to the next entry in the archive
*/
}
return (0);
}
#if defined(O_XATTR)
/* extended attribute support */
char *aname;
char *attrparent = NULL;
char *tapath;
char *taname;
if (xattrbadhead) {
xattr_linkp = NULL;
return (1);
}
/*
* At this point, the attribute path contains
* the path to the attribute rooted at the hidden
* attribute directory of the base file. This can
* be a simple attribute or extended attribute name,
* or it can be something like <attr>/<sys attr> if
* we are processing a system attribute of an attribute.
* Determine the attribute name and attribute parent
* (if there is one). When we are processing a simple
* attribute or extended attribute name, the attribute
* parent will be set to NULL. When we are processing
* something like <attr>/<sys attr>, the attribute
* parent will be contain <attr>, and the attribute
* name will contain <sys attr>.
*/
*taname = '\0';
attrparent = tapath;
} else {
}
}
}
}
}
} else {
}
if (attrparent != NULL) {
apathlen);
aname);
(void) free(attrparent);
} else {
}
} else {
}
if (xattr_linkp != NULL) {
}
}
} else {
}
aname);
xattr_linkp = NULL;
}
}
Hiddendir = 1;
} else {
Hiddendir = 0;
}
} else {
if (xattrbadhead == 0) {
(void) read_xattr_hdr();
return (2);
}
}
} else {
Hiddendir = 0;
}
#endif /* O_XATTR */
/* acl support: grab acl info */
/* this is an ancillary file */
char *secp;
int pad;
int cnt;
char *tp;
int attrsize;
if (Pflag) {
while (bytes > 0) {
}
if (pad != 0) {
}
/* got all attributes in secp */
do {
case UFSD_ACL:
case ACE_ACL:
/* header is 8 */
attrsize = 8 +
+ 1;
error =
&aclp);
if (error != 0) {
"aclfromtext failed: %s",
break;
}
break;
}
break;
/* SunFed case goes here */
default:
break;
}
/* next attributes */
} while (bytes > 0);
} else {
/* skip security info */
}
/*
* We already got the file content, dont call file_in()
* when return. The new return code(2) is used to
* indicate that.
*/
return (2);
} /* acl */
/*
* Sparse file support
* Read header of holesdata to get original file size.
* This is necessary because ckname() or file_in() shows file size
* with OCt before data_in() extracts the holesdata. data_in()
* actually doesn't extract the holesdata since proc_mode will be
* P_SKIP in the OCt mode.
*/
} else {
}
}
/*
* Skip any trailing slashes
*/
return (1);
}
/*
* getname: Get file names for inclusion in the archive. When end of file
* on the input stream of file names is reached, flush the link buffer out.
* For each filename, remove leading "./"s and multiple "/"s, and remove
* any trailing newline "\n". Finally, verify the existence of the file,
* and call creat_hdr() to fill in the gen_hdr structure.
*/
static int
getname(void)
{
char *s;
char *dir;
Hiddendir = 0;
while (!goodfile) {
err = 0;
issymlink = 0;
if (s[lastchar] != '\n') {
if (!err) {
"%s name too long.",
Nam_p);
}
goodfile = 0;
err = 1;
} else {
break;
}
} else {
s[lastchar] = '\0';
break;
}
}
if (s == NULL) {
}
flush_lnks();
}
return (0);
}
}
/*
* Skip any trailing slashes
*/
/*
* Figure out parent directory
*/
}
"Cannot open attribute directory"
continue;
}
} else {
#ifdef O_XATTR
}
"Cannot open directory %s", dir);
continue;
}
} else {
/*
* g_dirpath is the pathname cache maintaining
* the dirname which is currently opened.
* We first check the g_dirpath to see if the
* given dirname matches. If so, we don't need
* to open the dir, but we can use the g_dirfd
* as is if it is still available.
*/
/*
* It's the first time or it has
* all gone.
*/
} else {
dirpath) != 0) {
/* different directory */
}
}
/*
* We need to open the new directory.
* discard the pathname and dirfd
* for the previous directory.
*/
}
}
/* open the new dir */
"directory %s", dir);
continue;
}
}
}
#else
#endif
}
/* creat_hdr checks for USTAR filename length */
Max_namesz) {
if (!err) {
gettext(" System Attribute ") :
gettext(" Attribute "),
}
goodfile = 0;
err = 1;
}
if (err) {
continue;
} else {
goodfile = 1;
issymlink = 1;
errno = 0;
&SrcSt) < 0) {
"Cannot follow"
" \"%s%s%s\"",
(Gen.g_attrnam_p ==
NULL) ?
(Gen.g_attrnam_p ==
NULL) ? "" :
" System "
"Attribute ") :
" Attribute "),
(Gen.g_attrnam_p ==
NULL) ? "" :
goodfile = 0;
}
}
}
if (Use_old_stat) {
goodfile = 0;
}
}
} else {
"Error with fstatat() of \"%s%s%s\"",
gettext(" System Attribute ") :
gettext(" Attribute "),
}
}
}
/*
* Get ACL info: dont bother allocating space if there are only
* standard permissions, i.e. ACL count < 4
*/
}
/* else: only traditional permissions, so proceed as usual */
if (creat_hdr())
return (1);
else return (2);
}
/*
*/
static void
{
char **t_pp;
while (*largv) {
t_pp++;
largv++;
}
maxpat += 10;
maxpat * sizeof (char *));
}
t_pp++;
numpat++;
}
}
static void
{
int t_errno;
errno = 0;
if (dir) {
else
} else
} else
}
/*
* matched: Determine if a filename matches the specified pattern(s). If the
* pattern is matched (the second return), return 0 if -f was specified, else
* return != 0. If the pattern is not matched (the first and third
* returns), return 0 if -f was not specified, else return != 0.
*/
static int
matched(void)
{
/*
* Check for attribute
*/
}
/* match occurred */
}
}
}
/*
* missdir: Create missing directories for files.
* (Possible future performance enhancement, if missdir is called, we know
* that at least the very last directory of the path does not exist, therefore,
* scan the path from the end
*/
static int
{
char *c_p;
int cnt = 2;
char *lastp;
c_p++;
if (*lastp == '/')
*lastp = '\0';
if (*c_p == '/') {
*c_p = '\0';
if (cnt != 0) {
*c_p = '/';
return (cnt);
}
} else {
*c_p = '/';
return (-1);
}
}
*c_p = '/';
}
}
cnt = 0;
return (cnt);
}
/*
* mklong: Convert two shorts into one long. For VAX, Interdata ...
*/
static long
mklong(short v[])
{
} else {
}
}
/*
* mkshort: Convert a long into 2 shorts, for VAX, Interdata ...
*/
static void
{
/* LINTED alignment */
} else {
}
}
/*
* msg: Print either a message (no error) (POST), an error message with or
* without the errno (ERRN or ERR), or print an error message with or without
* the errno and exit (EXTN or EXT).
*/
void
{
Verbcnt = 0;
}
else
else {
Error_cnt++;
}
/* gettext replaces version of string */
gettext("insufficient privileges\n"));
"unsupported on underlying file system\n"));
} else {
perror("");
}
} else {
perror("");
}
} else
}
}
/*
* openout: Open files for output and set all necessary information.
* If the u option is set (unconditionally overwrite existing files),
* and the current file exists, get a temporary file name from mktemp(3C),
* link the temporary file to the existing file, and remove the existing file.
* Finally either creat(2), mkdir(2) or mknod(2) as appropriate.
*
*/
static int
{
char *nam_p;
Do_rename = 0; /* creat_tmp() may reset this */
} else {
} else {
}
}
if ((Max_filesz != RLIM_INFINITY) &&
/* ... divided by 512 ... */
return (-1);
}
/*
* A file by the same name exists. Move it to a temporary
* file unless it's a system attribute file. If we are
* restoring a system attribute file on a file system that
* supports system attributes, then the system attribute file
* will already exist (a default system attribute file will
* get created when the file it is associated with is created).
* If we create a temporary system attribute file, we can't
* overwrite the existing system attribute file using
* renameat(). In addition, only system attributes can exist
* for an attribute of a file, therefore, a temporary file
* cannot be created for a system attribute of an attribute.
* Thus, when restoring a system attribute, we won't move it
* to a temporary file, but will attempt to process it as if
* it didn't already exist.
*/
#if defined(_PC_SATTR_ENABLED)
if (G_p->g_rw_sysattr == 0)
#endif /* _PC_SATTR_ENABLED */
/*
* We weren't able to create the temp file.
* Report failure.
*/
return (-1);
}
}
if (Do_rename) {
/* nam_p was changed by creat_tmp() above. */
nam_p = Attrfile_p;
} else {
}
} else {
}
}
/*
* This pile tries to create the file directly, and, if there is a
* problem, creates missing directories, and then tries to create the
* file again. Two strikes and you're out.
*
* On XATTR system, the directory has already been created by
* open_dirfd(), so error shouldn't happen in the loop. However,
* case, we go to create missing directories.
*/
cnt = 0;
do {
errno = 0;
/* The archive file is a TAR symlink. */
if ((result =
cnt = 0;
get_component(Over_p), 0);
*Over_p = '\0';
}
break;
/* The attempt to symlink failed. */
"Cannot create symbolic link \"%s\" -> "
"\"%s\"",
if (*Over_p != '\0') {
}
return (-1);
}
cnt = 0;
get_component(Over_p), 0);
*Over_p = '\0';
}
break;
/* The attempt to symlink failed. */
"Cannot create symbolic link \"%s\" -> "
"\"%s\"",
if (*Over_p != '\0') {
}
return (-1);
}
}
cnt = 0;
get_component(Over_p), 0);
*Over_p = '\0';
}
break;
/* The attempt to symlink failed. */
"Cannot create symbolic link \"%s\" -> "
"\"%s\"",
if (*Over_p != '\0') {
}
return (-1);
}
} else {
int saveerrno;
}
}
if (result < 0) {
/* The attempt to open failed. */
nam_p);
if (*Over_p != '\0') {
}
return (-1);
}
} else {
/* acl support */
acl_is_set = 0;
"\"%s\": failed to set acl",
nam_p);
} else {
acl_is_set = 1;
}
}
cnt = 0;
break;
}
}
cnt++;
switch (cnt) {
case 0:
}
AT_SYMLINK_NOFOLLOW) < 0) {
"Error during chown() of "
"\"%s%s%s\"",
gettext(" System Attribute ") :
gettext(" Attribute "),
"" : nam_p);
}
AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
"Error during chown() of \"%s%s%s\"",
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
}
}
break;
case 1:
if (Do_rename) {
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
} else {
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
}
break;
case 2:
if (Do_rename) {
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
Over_p);
} else {
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
}
break;
default:
}
Finished = 0;
return (result);
}
/*
* read_hdr: Transfer headers from the selected format
* in the archive I/O buffer to the generic structure.
*/
static
int
{
char tmpnull;
static int bar_read_cnt = 0;
}
}
switch (hdr) {
case BIN:
}
break;
case CHR:
"%6lo%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6o%11llo",
#define cpioMINOR(x) (int)(x & 0xFF)
if (Use_old_stat) {
/* needs error checking */
} else {
}
}
break;
case ASC:
case CRC:
"%6lx%8lx%8lx%8lx%8lx%8lx%8lx%8llx%8x%8x%8x%8x%8x%8lx",
}
break;
case USTAR: /* TAR and USTAR */
nambuf[0] = '\0';
} else {
else
case SYMTYPE:
/* Symbolic Link */
break;
case CHRTYPE:
break;
case BLKTYPE:
break;
case DIRTYPE:
break;
case FIFOTYPE:
break;
}
/* LINTED alignment */
/* LINTED alignment */
}
break;
case TAR:
nambuf[0] = '\0';
} else {
else
}
break;
case BAR:
if (Bar_vol_num == 0 && bar_read_cnt == 0) {
bar_read_cnt++;
}
else
break;
default:
}
}
return (rv);
}
/*
* reclaim: Reclaim linked file structure storage.
*/
static void
{
while (p != NULL) {
free(p);
p = new_p;
}
}
/*
* rstbuf: Reset the I/O buffer, move incomplete potential headers to
* the front of the buffer and force bread() to refill the buffer. The
* return value from bread() is returned (to identify I/O errors). On the
* 3B2, reads must begin on a word boundary, therefore, with the -i option,
* any remaining bytes in the buffer must be moved to the base of the buffer
* in such a way that the destination locations of subsequent reads are
* word aligned.
*/
static void
rstbuf(void)
{
int pad;
}
if (bfill() < 0)
} else { /* OCo */
}
}
static void
{
} else
} else
}
/*
* rstfiles: Perform final changes to the file. If the -u option is set,
* and overwrite == U_OVER, remove the temporary file, else if overwrite
* == U_KEEP, unlink the current file, and restore the existing version
* of the file. In addition, where appropriate, set the access or modification
* times, change the owner and change the modes of the file.
*
* Note that if Do_rename is set, then the roles of original and temporary
* file are reversed. If all went well, we will rename() the temporary file
* over the original in order to accommodate potentially executing files.
*/
static void
{
int error;
#if defined(_PC_SATTR_ENABLED)
/* Time or permissions cannot be set on system attribute files */
return;
}
#endif /* _PC_SATTR_ENABLED */
} else {
}
} else {
} else {
}
}
}
}
if (Do_rename) {
gettext(" Attribute "),
} else {
gettext(" Attribute "),
}
/* delete what we just built */
/* If the old file needs restoring, do the necessary links */
if (Do_rename) {
char *tmp_ptr;
} else {
}
Do_rename = 0; /* names now have original values */
} else {
"Cannot recover original version"
" of \"%s%s%s\"",
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
"" : nam_p);
}
"Cannot remove temp file "
"\"%s%s%s\"",
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
"" : Over_p);
}
}
}
*Over_p = '\0';
return;
if (Do_rename) {
char *tmp_ptr;
} else {
/*
* Over_p is pointing at g_attrnam_p
* which must be preserved.
*
* We don't want the tmp_ptr and so
* on to throw away our only copy of
* the name.
*/
Over_p = Attrfile_p;
}
} else {
}
Do_rename = 0; /* names now have original values */
} else {
"Cannot unlink() temp file \"%s%s%s\"",
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
}
}
*Over_p = '\0';
}
} else {
}
} else /* OCi only uses onam_p, OCo only uses inam_p */
} else {
}
/*
* Change the owner, time, and mode to those of the file
* originally created in the archive. Note: time and
* mode do not need to be restored for a symbolic link
* since rstfiles() is not called when the archived file
* is a symlink.
*/
AT_SYMLINK_NOFOLLOW) < 0) {
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
}
} else {
AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
}
}
}
/* Acl was not set, so we must chmod */
if (!acl_is_set) {
/*
* use fchmod for attributes, since
* we known they are always regular
* files, whereas when it isn't an
* attribute it could be for a fifo
* or something other that we don't
* open and don't have a valid Ofile
* for.
*/
if (privileged) {
} else {
}
} else {
}
if (error < 0) {
"Cannot chmod() \"%s%s%s\"",
G_p->g_rw_sysattr ?
gettext(" System Attribute ") :
gettext(" Attribute "),
}
if (!privileged) {
}
}
}
/*
* Use dirfd since we are updating original file
* and not just created file
*/
}
}
/*
* scan4trail: Scan the archive looking for the trailer.
* When found, back the archive up over the trailer and overwrite
* the trailer with the files to be added to the archive.
*/
static void
scan4trail(void)
{
int rv;
Append = 1;
while (gethdr()) {
}
Append = 0;
}
/*
* setup: Perform setup and initialization functions. Parse the options
* using getopt(3C), call ckopts to check the options and initialize various
* structures and pointers. Specifically, for the -i option, save any
* patterns, for the -o option, check (via stat(2)) the archive, and for
* the -p option, validate the destination directory.
*/
static void
{
extern int optind;
extern char *optarg;
#if defined(O_XATTR)
#if defined(_PC_SATTR_ENABLED)
#ifdef WAITAROUND
char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
#else
char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
#endif /* WAITAROUND */
#else /* _PC_SATTR_ENABLED */
#ifdef WAITAROUND
char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
#else
char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
#endif /* WAITAROUND */
#endif /* _PC_SATTR_ENABLED */
#else /* O_XATTR */
#ifdef WAITAROUND
char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
#else
char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
#endif /* WAITAROUND */
#endif /* O_XATTR */
char *dupl_p = "Only one occurrence of -%c allowed";
int option;
int blk_cnt, blk_cnt_max;
/* Remember the native page size. */
if (PageSize == -1) {
/*
* This sysconf call will almost certainly never fail. The
* symbol PAGESIZE itself resolves to the above sysconf call,
* so we should go ahead and define our own constant.
*/
PageSize = 8192;
}
switch (option) {
#ifdef WAITAROUND
case 'z':
/* rendezvous with the debugger */
waitaround = 1;
break;
#endif
case 'a': /* reset access time */
break;
case 'b': /* swap bytes and halfwords */
break;
case 'c': /* select character header */
Max_namesz = APATH;
Onecopy = 1;
break;
case 'd': /* create directories as needed */
break;
case 'f': /* select files not in patterns */
break;
case 'i': /* "copy in" */
Archive = 0;
break;
case 'k': /* retry after I/O errors */
break;
case 'l': /* link files when possible */
break;
case 'm': /* retain modification time */
break;
case 'o': /* "copy out" */
Archive = 1;
break;
case 'p': /* "pass" */
Max_namesz = APATH;
break;
case 'q': /* "quiet" */
break;
case 'r': /* rename files interactively */
break;
case 's': /* swap bytes */
break;
case 't': /* table of contents */
break;
case 'u': /* copy unconditionally */
break;
case 'v': /* verbose - print file names */
break;
case 'A': /* append to existing archive */
break;
case 'B': /* set block size to 5120 bytes */
Bufsize = 5120;
break;
case 'C': /* set arbitrary block size */
else {
}
break;
case 'D':
Dflag = 1;
break;
case 'E': /* alternate file for pattern input */
else {
}
break;
case 'H': /* select header type */
else {
}
break;
case 'I': /* alternate file for archive input */
else {
}
break;
case 'L': /* follow symbolic links */
break;
case 'M': /* specify new end-of-media message */
else {
}
break;
case 'O': /* alternate file for archive output */
else {
}
break;
case 'P': /* preserve acls */
Pflag++;
break;
else {
}
break;
case 'S': /* swap halfwords */
break;
case 'V': /* print a dot '.' for each file */
break;
case '6': /* for old, sixth-edition files */
break;
#if defined(O_XATTR)
case '@':
Atflag++;
break;
#if defined(_PC_SATTR_ENABLED)
case '/':
SysAtflag++;
break;
#endif /* _PC_SATTR_ENABLED */
#endif /* O_XATTR */
default:
Error_cnt++;
} /* option */
} /* (option = getopt(largc, largv, opts_p)) != EOF */
#ifdef WAITAROUND
if (waitaround) {
" %d\n"), getpid());
while (waitaround) {
(void) sleep(10);
}
}
#endif
if (!Error_cnt) {
#if defined(_PC_SATTR_ENABLED)
#endif
}
}
if (largc > 0) /* save patterns for -i option, if any */
if (largc != 0) /* error if arguments left with -o */
Error_cnt++;
switch (Hdr_type) {
case BIN:
break;
case CHR:
Pad_val = 0;
break;
case ASC:
case CRC:
break;
case TAR:
/* FALLTHROUGH */
case USTAR: /* TAR and USTAR */
break;
default:
}
} else { /* directory must be specified */
if (largc != 1)
Error_cnt++;
/*
* EACCES is ignored here as it may occur
* when any directory component of the path
* does not have write permission, even though
* the destination subdirectory has write
* access. Writing to a read only directory
* is handled later, as in "copy in" mode.
*/
"Error during access() of \"%s\"", *largv);
}
}
if (Error_cnt)
usage(); /* exits! */
if (!Dflag) {
"Error during initialization");
} else {
"Error during initialization");
}
}
if (blk_cnt_max < MX_BUFS) {
}
break;
}
}
}
}
/*
* Now that Bufsize has stabilized, we can allocate our i/o buffer
*/
}
if (*Full_p != '/') {
Full_p++;
*Full_p = '/';
}
Full_p++;
*Full_p = '\0';
}
/*
*/
static void
{
"Unable to reset access time for \"%s%s%s\"",
gettext(" Attribute "),
} else {
"Unable to reset modification time for \"%s%s%s\"",
gettext(" Attribute "),
}
}
}
/*
* sigint: Catch interrupts. If an interrupt occurs during the extraction
* of a file from the archive with the -u option set, and the filename did
* exist, remove the current file and restore the original file. Then exit.
*/
/*ARGSUSED*/
static void
{
char *nam_p;
if (!Finished) {
else /* OCp */
"Cannot remove incomplete \"%s\"", nam_p);
}
"Cannot recover original \"%s\"",
nam_p);
}
"Cannot remove temp file \"%s\"",
Over_p);
}
}
"Cannot remove incomplete \"%s\"", nam_p);
*Over_p = '\0';
}
}
/*
* swap: Swap bytes (-s), halfwords (-S) or or both halfwords and bytes (-b).
*/
static void
{
unsigned char tbyte;
int tcnt;
int rcnt;
cnt /= 4;
/* LINTED alignment */
while (tcnt-- > 0) {
Swp_p++;
}
if (rcnt >= 2) {
}
}
/* LINTED alignment */
while (tcnt-- > 0) {
Swp_p++;
}
}
}
/*
* usage: Print the usage message on stderr and exit.
*/
static void
usage(void)
{
#if defined(O_XATTR)
"\tcpio -i[bcdfkmqrstuv@BSV6] [-C size] "
"[-E file] [-H hdr] [-I file [-M msg]] "
"[-R id] [patterns]\n"
"\tcpio -o[acv@ABLV] [-C size] "
"[-H hdr] [-O file [-M msg]]\n"
"\tcpio -p[adlmuv@LV] [-R id] directory\n"));
#else
"\tcpio -i[bcdfkmqrstuvBSV6] [-C size] "
"[-E file] [-H hdr] [-I file [-M msg]] "
"[-R id] [patterns]\n"
"\tcpio -o[acvABLV] [-C size] "
"[-H hdr] [-O file [-M msg]]\n"
"\tcpio -p[adlmuvLV] [-R id] directory\n"));
#endif
}
/*
* verbose: For each file, print either the filename (-v) or a dot (-V).
* If the -t option (table of contents) is set, print either the filename,
* or if the -v option is also set, print an "ls -l"-like listing.
*/
static void
{
int i, j, temp;
char modestr[12];
/*
* The printf format and associated arguments to print the current
* filename. Normally, just nam_p. If we're processing an extended
* attribute, these are overridden.
*/
char *name_fmt = "%s";
/*
* Translation note:
* 'attribute' is a noun.
*/
if (Gen.g_rw_sysattr) {
} else {
}
} else {
}
}
/* dont print ancillary file */
aclchar = '+';
return;
}
for (i = 0; i < 11; i++)
modestr[i] = '-';
modestr[i] = '\0';
aclchar = ' ';
for (i = 0; i < 3; i++) {
j = (i * 3) + 1;
modestr[j] = 'r';
}
switch (temp) {
case (S_IFIFO):
modestr[0] = 'p';
break;
case (S_IFSOCK):
modestr[0] = 's';
break;
case (S_IFCHR):
modestr[0] = 'c';
break;
case (S_IFDIR):
modestr[0] = 'd';
break;
case (S_IFBLK):
modestr[0] = 'b';
break;
case (S_IFREG): /* was initialized to '-' */
break;
case (S_IFLNK):
modestr[0] = 'l';
break;
default:
}
} else { /* bar */
switch (temp) {
case (S_IFIFO):
modestr[0] = 'p';
break;
case (S_IFSOCK):
modestr[0] = 's';
break;
case (S_IFCHR):
modestr[0] = 'c';
break;
case (S_IFDIR):
modestr[0] = 'd';
break;
case (S_IFBLK):
modestr[0] = 'b';
break;
}
if (bar_linkflag == SYMTYPE)
modestr[0] = 'l';
}
else
(void) printf("-1 ");
else
} else {
} else {
}
}
(void) printf("-1 ");
else
} else {
} else {
}
}
/* print file size */
else
} else
else {
}
}
if (bar_linkflag == SYMTYPE)
else if (bar_linkflag == '1')
}
gettext(" attribute "),
}
(void) printf("\n");
} else { /* OCV */
Verbcnt = 0;
}
}
}
#define MK_USHORT(a) (a & 00000177777)
/*
* write_hdr: Transfer header information for the generic structure
* into the format for the selected header and bwrite() the header.
*/
static void
{
const char warnfmt[] = "%s%s%s : %s";
switch (arcflag) {
case ARCHIVE_ACL:
break;
case ARCHIVE_XATTR:
case ARCHIVE_NORMAL:
/*
* If attribute is being archived in cpio format then
* zap off the file type bits since those are truly a
* mask and reset them with _XATTR_CPIO_MODE
*/
/*
* len is the value of g_filesz for normal files
* and the length of the special header buffer in
* the case of acl and xattr headers.
*/
} else {
}
if (arcflag != ARCHIVE_XATTR) {
}
break;
case ARCHIVE_SPARSE:
break;
}
/*
* Handle EFT uids and gids. If they get too big
* to be represented in a particular format, force 'em to 'nobody'.
*/
switch (Hdr_type) {
case BIN: /* 16-bits of u_short */
uid = UID_NOBODY;
gid = GID_NOBODY;
break;
case CHR: /* %.6lo => 262143 base 10 */
uid = UID_NOBODY;
gid = GID_NOBODY;
break;
case ASC: /* %.8lx => full 32 bits */
case CRC:
break;
case USTAR:
case TAR: /* %.7lo => 2097151 base 10 */
uid = UID_NOBODY;
gid = GID_NOBODY;
break;
default:
}
/*
* Since cpio formats -don't- encode the symbolic names, print
* a warning message when we map the uid or gid this way.
* Also, if the ownership just changed, clear set[ug]id bits
*
* (Except for USTAR format of course, where we have a string
* representation of the username embedded in the header)
*/
gettext("uid too large for archive format"));
}
gettext("gid too large for archive format"));
}
switch (Hdr_type) {
case BIN:
case CHR:
case ASC:
case CRC:
break;
case TAR:
/*FALLTHROUGH*/
case USTAR: /* TAR and USTAR */
break;
default:
}
switch (Hdr_type) {
case BIN:
break;
case CHR:
/*LINTED*/
"%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11lo%.6lo%."
break;
case ASC:
case CRC:
/*LINTED*/
"%.6lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%."
"8lx%.8lx%.8lx%.8lx%s",
break;
case USTAR:
if (arcflag == ARCHIVE_ACL) {
} else if (arcflag == ARCHIVE_XATTR ||
} else {
}
if (T_lname[0] != '\0') {
/*
* if not a symbolic link
*/
"%011lo", 0L);
}
}
} else {
}
break;
case TAR:
if (T_lname[0] != '\0') {
} else {
}
break;
default:
} /* Hdr_type */
if (pad != 0) {
}
}
/*
* write_trail: Create the appropriate trailer for the selected header type
* and bwrite the trailer. Pad the buffer with nulls out to the next Bufsize
* boundary, and force a write. If the write completes, or if the trailer is
* completely written (but not all of the padding nulls (as can happen on end
* of medium)) return. Otherwise, the trailer was not completely written out,
* so re-pad the buffer with nulls and try again.
*/
static void
write_trail(void)
{
switch (Hdr_type) {
case BIN:
break;
case CHR:
break;
case ASC:
break;
case CRC:
break;
}
switch (Hdr_type) {
case BIN:
case CHR:
case ASC:
case CRC:
break;
case TAR:
/*FALLTHROUGH*/
case USTAR: /* TAR and USTAR */
}
break;
default:
}
need = 0;
while (need > 0) {
}
bflush();
}
}
/*
* if archives in USTAR format, check if typeflag == '5' for directories
*/
static int
ustar_dir(void)
{
return (1);
}
return (0);
}
/*
* if archives in USTAR format, check if typeflag == '3' || '4' || '6'
* for character, block, fifo special files
*/
static int
ustar_spec(void)
{
int typeflag;
return (1);
}
return (0);
}
/*
* The return value is a pointer to a converted copy of the information in
* FromStat if the file is representable in -Hodc format, and NULL otherwise.
*/
static struct stat *
{
/*
* Encountered a problem representing the rdev information.
* Don't archive it.
*/
"types on %s%s%s",
return (NULL);
}
/*
* track links in this case; break them all into separate
* files.
*/
"Warning: file %s%s%s has large "
"device number - linked "
"files will be restored as "
"separate files",
/* ensure no links */
}
/* Start converting values */
} else {
}
/* -actual- not truncated uid */
/* -actual- not truncated gid */
return (&ToSt);
}
/*
* In the beginning of each bar archive, there is a header which describes the
* current volume being created, followed by a header which describes the
* current file being created, followed by the file itself. If there is
* more than one file to be created, a separate header will be created for
* each additional file. This structure may be repeated if the bar archive
* contains multiple volumes. If a file spans across volumes, its header
* will not be repeated in the next volume.
* +------------------+
* | vol header |
* |------------------|
* | file header i | i = 0
* |------------------|
* | <file i> |
* |------------------|
* | file header i+1 |
* |------------------|
* | <file i+1> |
* |------------------|
* | . |
* | . |
* | . |
* +------------------+
*/
/*
* read in the header that describes the current volume of the bar archive
* to be extracted.
*/
static void
read_bar_vol_hdr(void)
{
}
} else {
"bar error: cannot read volume header\n"));
exit(1);
}
/* set the compress flag */
Compressed = 1;
else
Compressed = 0;
/*
* not the first volume; exit
*/
gettext("error: This is not volume 1. "));
exit(1);
}
}
/*
* read in the header that describes the current file to be extracted
*/
static void
read_bar_file_hdr(void)
{
char *start_of_name, *name_p;
char *tmp;
exit(0);
}
#define to_new_minor(x) (int)((x) & OMAXMIN)
while (*name_p++ = *start_of_name++)
;
*name_p = '\0';
}
/*
* if the bar archive is compressed, set up a pipe and do the de-compression
* as the compressed file is read in.
*/
static void
{
char *cmd_buf;
"chmod +w '%s'; uncompress -c > '%s'; "
"chmod 0%o '%s'",
} else {
}
exit(1);
}
}
/*
* if the bar archive spans multiple volumes, read in the header that
* describes the next volume.
*/
static void
skip_bar_volhdr(void)
{
char *buff;
"error in skip_bar_volhdr\n"));
} else {
}
} else {
gettext("cpio error: cannot read bar volume "
"header\n"));
exit(1);
}
&Gen_bar_vol.g_uid);
&Gen_bar_vol.g_gid);
Compressed = 1;
else
Compressed = 0;
}
/*
* Now put the rest of the bytes read in into the data buffer.
*/
}
/*
* check the linkflag which indicates the type of the file to be extracted,
* invoke the corresponding routine to extract the file.
*/
static void
bar_file_in(void)
{
/*
* the file is a directory
*/
if (Adir) {
}
return;
}
switch (bar_linkflag) {
case REGTYPE:
/* regular file */
} else {
}
break;
case LNKTYPE:
/* hard link */
break;
}
break;
case SYMTYPE:
/* symbolic link */
} else {
}
break;
case CHRTYPE:
/* character device or FIFO */
}
break;
default:
break;
}
}
/*
* XXX And it is very broken.
*/
#include <ftw.h>
/* #include <libgenIO.h> */
/*
* g_init: Determine the device being accessed, set the buffer size,
* and perform any device specific initialization. Since at this point
* Sun has no system call to read the configuration, the major numbers
* are assumed to be static and types are figured out as such. However,
* as a rough estimate, the buffer size for all types is set to 512
* as a default.
*/
static int
{
int bufsize;
bufsize = -1;
return (-1);
bufsize = 512;
} else {
/* find block size for this file system */
bufsize = -1;
} else
}
return (bufsize);
/*
* We'll have to add a remote attribute to stat but this
* should work for now.
*/
return (512);
bufsize = 512;
}
}
return (bufsize);
}
/*
*/
/*
* g_read: Read nbytes of data from fdes (of type devtype) and place
* data in location pointed to by buf. In case of end of medium,
* translate (where necessary) device specific EOM indications into
* the generic EOM indication of rv = -1, errno = ENOSPC.
*/
static int
{
int rv;
return (-1);
}
/* st devices return 0 when no space left */
errno = 0;
rv = 0;
}
return (rv);
}
/*
*/
/*
* g_write: Write nbytes of data to fdes (of type devtype) from
* the location pointed to by buf. In case of end of medium,
* translate (where necessary) device specific EOM indications into
* the generic EOM indication of rv = -1, errno = ENOSPC.
*/
static int
{
int rv;
return (-1);
}
/* st devices return 0 when no more space left */
rv = -1;
}
return (rv);
}
/*
* Test for tape
*/
static int
{
/*
* try to do a generic tape ioctl, just to see if
* the thing is in fact a tape drive(er).
*/
/* the ioctl succeeded, must have been a tape */
return (1);
}
return (0);
}
/*
* Test for floppy
*/
static int
{
/*
* try to get the floppy drive characteristics, just to see if
* the thing is in fact a floppy drive(er).
*/
/* the ioctl succeeded, must have been a floppy */
return (1);
}
return (0);
}
/*
* New functions for ACLs and other security attributes
*/
/*
* The function appends the new security attribute info to the end of
* existing secinfo.
*/
static int
char **secinfo, /* existing security info */
int *secinfo_len, /* length of existing security info */
{
char *new_secinfo;
char *attrtext;
int oldsize;
/* no need to add */
return (0);
}
case ACLENT_T:
case ACE_T:
return (-1);
}
/* header: type + size = 8 */
return (-1);
}
/* acl entry count */
break;
/* SunFed's case goes here */
default:
return (-1);
}
/* old security info + new attr header(8) + new attr */
oldsize = *secinfo_len;
*secinfo_len += newattrsize;
if (new_secinfo == NULL) {
*secinfo_len -= newattrsize;
return (-1);
}
*secinfo = new_secinfo;
return (0);
}
/*
* Append size amount of data from buf to the archive.
*/
static void
{
if (len == 0)
return;
while (len > 0) {
errno = 0;
}
if (padding) {
if (pad != 0) {
}
}
}
static int
remove_dir(char *path)
{
char *path_copy;
#define MSG1 "remove_dir() failed to stat(\"%s\") "
#define MSG2 "remove_dir() failed to remove_dir(\"%s\") "
#define MSG3 "remove_dir() failed to unlink(\"%s\") "
/*
* Open the directory for reading.
*/
return (-1);
}
return (-1);
}
/*
* Read every directory entry.
*/
/*
* Ignore "." and ".." entries.
*/
continue;
return (-1);
}
return (-1);
}
} else {
return (-1);
}
}
}
/*
* Close the directory we just finished reading.
*/
/*
* Change directory to the parent directory...
*/
return (-1);
}
/*
* ...and finally remove the directory; note we have to
* make a copy since basename is free to modify its input.
*/
return (-1);
}
return (-1);
}
return (0);
}
static int
save_cwd(void)
{
}
static void
{
}
#if defined(O_XATTR)
static void
xattrs_out(int (*func)())
{
int dirpfd;
int filefd;
int arc_rwsysattr = 0;
int rw_sysattr = 0;
int ext_attr = 0;
int slen;
int plen;
char *apathp;
char *filename;
if (attrparent == NULL) {
} else {
}
/*
* If the underlying file system supports it, then
* archive the extended attributes if -@ was specified,
* and the extended system attributes if -/ was
* specified.
*/
return;
}
#if defined(_PC_SATTR_ENABLED)
if (SysAtflag) {
int filefd;
/*
* Determine if there are non-transient system
* attributes.
*/
errno = 0;
if (attrparent == NULL) {
"unable to open %s%s%sfile %s",
gettext("attribute "),
G_p->g_attrfnam_p);
}
}
arc_rwsysattr = 1;
}
(void) nvlist_free(slist);
}
}
/*
* If we aren't archiving extended system attributes, and we are
* processing an attribute, or if we are archiving extended system
* attributes, and there are are no extended attributes, then there's
* no need to open up the attribute directory of the file unless the
* extended system attributes are not transient (i.e, the system
* attributes are not the default values).
*/
return;
}
#endif /* _PC_SATTR_ENABLED */
/*
* If aclp still exists then free it since it is was set when base
* file was extracted.
*/
acl_is_set = 0;
}
return;
}
if (attrparent == NULL) {
} else {
}
return;
}
return;
}
if (attrparent == NULL) {
}
continue;
}
continue;
}
Hiddendir = 1;
} else {
Hiddendir = 0;
}
"Could not fstatat(2) attribute \"%s\" of"
continue;
}
if (Use_old_stat) {
"Could not convert to old stat format");
continue;
}
}
/*
* Set up dummy header name
*
* One piece is written with .hdr, which
* contains the actual xattr hdr or pathing information
* then the name is updated to drop the .hdr off
* and the actual file itself is archived.
*/
continue;
}
}
continue;
}
}
/*
* Get attribute's ACL info: don't bother allocating space
* if there are only standard permissions, i.e. ACL count < 4
*/
if (Pflag) {
if (filefd == -1) {
"Could not open attribute \"%s\" of"
continue;
}
"Error with acl() on %s",
}
}
(void) creat_hdr();
(void) (*func)();
#if defined(_PC_SATTR_ENABLED)
/*
* Recursively call xattrs_out() to process the attribute's
* hidden attribute directory and read-write system attributes.
*/
}
#endif /* _PC_SATTR_ENABLED */
}
Gen.g_rw_sysattr = 0;
}
acl_is_set = 0;
}
}
if (attrparent == NULL) {
}
Hiddendir = 0;
}
#else
static void
xattrs_out(int (*func)())
{
}
#endif
/*
* Return the parent directory of a given path.
*
* Examples:
* / returns .
* /usr returns /
* file returns .
*
* dir is assumed to be at least as big as path.
*/
static void
{
char *s;
}
} else {
s = skipslashes(s, tmpdir);
*s = '\0';
if (s == tmpdir)
else
}
}
#if defined(O_XATTR)
static void
char **attrbuf,
char *filename,
char *attrpath,
char typeflag,
int *rlen)
{
char *bufhead; /* ptr to full buffer */
char *aptr;
int totalen; /* total buffer length */
int len; /* length returned to user */
int stringlen; /* length of filename + attr */
/*
* length of filename + attr
* in link section
*/
int linkstringlen;
int complen; /* length of pathing section */
int linklen; /* length of link section */
int attrnames_index; /* attrnames starting index */
/*
* Release previous buffer if any.
*/
}
/*
* First add in fixed size stuff
*/
/*
* Add space for two nulls
*/
/*
* Now add on space for link info if any
*/
/*
* Again add space for two nulls
*/
} else {
linklen = 0;
}
/*
* Now add padding to end to fill out TBLOCK
*
* Function returns size of real data and not size + padding.
*/
/*
* Now we can fill in the necessary pieces
*/
/*
* first fill in the fixed header
*/
/*
* Now fill in the filename + attrnames section
* The filename and attrnames section can be composed of two or more
* path segments separated by a null character. The first segment
* is the path to the parent file that roots the entire sequence in
* the normal name space. The remaining segments describes a path
* rooted at the hidden extended attribute directory of the leaf file of
* the previous segment, making it possible to name attributes on
* attributes. Thus, if we are just archiving an extended attribute,
* the second segment will contain the attribute name. If we are
* archiving a system attribute of an extended attribute, then the
* second segment will contain the attribute name, and a third segment
* will contain the system attribute name. The attribute pathing
* information is obtained from 'attrpath'.
*/
/*
* Split the attrnames section into two segments if 'attrpath'
* contains pathing information for a system attribute of an
* extended attribute. We split them by replacing the '/' with
* a '\0'.
*/
*aptr = '\0';
}
/*
* Now fill in the optional link section if we have one
*/
(void) strcpy(
}
}
#endif /* O_XATTR */
static char
{
switch (type) {
case S_IFDIR:
return (DIRTYPE);
case S_IFLNK:
return (SYMTYPE);
case S_IFIFO:
return (FIFOTYPE);
case S_IFCHR:
return (CHRTYPE);
case S_IFBLK:
return (BLKTYPE);
case S_IFREG:
return (REGTYPE);
default:
return ('\0');
}
}
#if defined(O_XATTR)
static int
{
} else {
}
}
#else
static int
{
}
#endif
#if defined(O_XATTR)
static int
{
int namelen;
int asz;
int cnt;
char *tp;
char *xattrapath;
int pad;
int parentfilelen;
/*
* Include any padding in the read. We need to be positioned
* at beginning of next header.
*/
"Insufficient memory for extended attribute\n"));
return (1);
}
while (bytes > 0) {
}
if (pad != 0) {
}
/*
* Validate that we can handle header format
*/
gettext("Unknown extended attribute format encountered\n"));
gettext("Disabling extended attribute header parsing\n"));
xattrbadhead = 1;
return (1);
}
sizeof (struct xattr_hdr));
if (link_len > 0) {
} else {
xattr_linkp = NULL;
}
/*
* Gather the attribute path from the filename and attrnames section.
* The filename and attrnames section can be composed of two or more
* path segments separated by a null character. The first segment
* is the path to the parent file that roots the entire sequence in
* the normal name space. The remaining segments describes a path
* rooted at the hidden extended attribute directory of the leaf file of
* the previous segment, making it possible to name attributes on
* attributes.
*/
/*
* The attrnames section contains a system attribute on an
* attribute. Save the name of the attribute for use later,
* and replace the null separating the attribute name from
* the system attribute name with a '/' so that xattrapath can
* be used to display messages with the full attribute path name
* rooted at the hidden attribute directory of the base file
* in normal name space.
*/
}
return (0);
}
#endif
static mode_t
{
switch (type) {
case '\0':
case REGTYPE:
case LNKTYPE:
break;
case SYMTYPE:
break;
case CHRTYPE:
break;
case BLKTYPE:
break;
case DIRTYPE:
break;
case FIFOTYPE:
break;
case CONTTYPE:
default:
mode = 0;
}
return (mode);
}
#if defined(O_XATTR)
static char *
get_component(char *path)
{
char *ptr;
return (path);
} else {
/*
* Handle trailing slash
*/
return (ptr);
else
return (ptr + 1);
}
}
#else
static char *
get_component(char *path)
{
return (path);
}
#endif
static int
{
int fd = -1;
int cnt = 0;
char *dir;
/*
* open directory; creating missing directories along the way.
*/
do {
if (fd != -1) {
return (fd);
}
cnt++;
return (-1);
}
static int
{
#ifdef O_XATTR
close_dirfd();
int rw_sysattr;
/*
* Open the file's attribute directory.
* Change into the base file's starting directory then
* call open_attr_dir() to open the attribute directory
* of either the base file (if G_p->g_attrparent_p is
* NULL) or the attribute (if G_p->g_attrparent_p is
* set) of the base file.
*/
}
"Cannot open attribute directory "
"of %s%s%sfile \"%s\"",
gettext("attribute \""),
gettext("\" of "),
G_p->g_attrfnam_p);
return (FILE_PASS_ERR);
}
} else {
return (1);
}
}
} else {
}
#else
#endif
return (0);
}
static void
{
}
}
static void
{
int attrlen = 0;
char *namep;
/*
* namep was allocated in xattrs_out. It is big enough to hold
* either the name + .hdr on the end or just the attr name
*/
#if defined(O_XATTR)
(void) creat_hdr();
break; /* found */
}
}
/*LINTED*/
}
(void) creat_hdr();
#endif
}
/*
* skip over extra slashes in string.
*
* For example:
*
* would return pointer at
* ^
*/
static char *
{
string--;
}
return (string);
}
static sl_info_t *
sl_info_alloc(void)
{
static int num_left;
if (num_left > 0) {
}
}
/*
* If a match for the key values was found in the tree, return a pointer to it.
* If a match was not found, insert it and return a pointer to it. This is
* based on Knuth's Algorithm A in Vol 3, section 6.2.3.
*/
{
sl_info_t *p; /* moves down the tree */
sl_info_t *q; /* scratch */
sl_info_t *r; /* scratch */
sl_info_t *s; /* pt where rebalancing may be needed */
sl_info_t *t; /* father of s */
int a; /* used to hold balance factors */
int done; /* loop control */
int cmpflg; /* used to hold the result of a comparison */
/* initialize */
head = sl_info_alloc();
p->sl_count = 0;
p->bal = 0;
return (p);
}
t = head;
/* compare */
case -1:
/* move left */
q = p->llink;
if (q == NULL) {
q = sl_info_alloc();
p->llink = q;
done = 1;
continue;
}
break;
case 0:
/* found it */
return (p);
case 1:
/* move right */
q = p->rlink;
if (q == NULL) {
q = sl_info_alloc();
p->rlink = q;
done = 1;
continue;
}
break;
}
if (q->bal != 0) {
t = p;
s = q;
}
p = q;
}
/* insert */
q->sl_count = 0;
q->bal = 0;
/* adjust balance factors */
r = p = s->llink;
} else {
r = p = s->rlink;
}
while (p != q) {
case -1:
p->bal = -1;
p = p->llink;
break;
case 0:
break;
case 1:
p->bal = 1;
p = p->rlink;
break;
}
}
/* balancing act */
if (cmpflg < 0) {
a = -1;
} else {
a = 1;
}
if (s->bal == 0) {
s->bal = a;
return (q);
} else if (s->bal == -a) {
s->bal = 0;
return (q);
}
/*
* (s->bal == a)
*/
if (r->bal == a) {
/* single rotation */
p = r;
if (a == -1) {
r->rlink = s;
} else if (a == 1) {
r->llink = s;
}
} else if (r->bal == -a) {
/* double rotation */
if (a == -1) {
p = r->rlink;
p->llink = r;
p->rlink = s;
} else if (a == 1) {
p = r->llink;
p->rlink = r;
p->llink = s;
}
if (p->bal == 0) {
s->bal = 0;
r->bal = 0;
} else if (p->bal == -a) {
s->bal = 0;
r->bal = a;
} else if (p->bal == a) {
s->bal = -a;
r->bal = 0;
}
p->bal = 0;
}
/* finishing touch */
if (s == t->rlink) {
t->rlink = p;
} else {
t->llink = p;
}
return (q);
}
/*
* sl_numlinks: return the number of links that we saw during our preview.
*/
static ulong_t
{
if (p) {
return (p->sl_count);
} else {
return (1);
}
}
/*
* Preview extended and extended system attributes.
*
* Return 0 if successful, otherwise return 1.
*/
#if defined(O_XATTR)
static int
preview_attrs(char *s, char *attrparent)
{
int dirfd;
int tmpfd;
int islnk;
int rc = 0;
int arc_rwsysattr = 0;
int rw_sysattr = 0;
int ext_attr = 0;
/*
* If the underlying file system supports it, then
* archive the extended attributes if -@ was specified,
* and the extended system attributes if -/ was
* specified.
*/
return (1);
}
#if defined(_PC_SATTR_ENABLED)
if (SysAtflag) {
int filefd;
/* Determine if there are non-transient system attributes. */
errno = 0;
return (1);
}
arc_rwsysattr = 1;
}
(void) nvlist_free(slist);
}
}
return (1);
}
#endif /* _PC_SATTR_ENABLED */
/*
* We need to open the attribute directory of the
* file, and preview all of the file's attributes as
* attributes of the file can be hard links to other
* attributes of the file.
*/
if (dirfd == -1)
return (1);
if (tmpfd == -1) {
return (1);
}
return (1);
}
Hiddendir = 1;
continue;
} else {
Hiddendir = 0;
}
} else {
Hiddendir = 0;
}
AT_SYMLINK_NOFOLLOW) < 0) {
continue;
}
continue;
}
islnk = 0;
islnk = 1;
&sb, 0) < 0) {
continue;
}
}
}
/*
* Recursively call preview_attrs() to preview extended
* system attributes of attributes.
*/
}
}
return (rc);
}
#endif /* O_XATTR */
/*
* sl_preview_synonyms: Read the file list from the input stream, remembering
* each reference to each file.
*/
static void
sl_preview_synonyms(void)
{
char *s;
char *suffix = "/cpioXXXXXX";
char *tmpfname;
tmpdir = "/tmp";
}
}
}
}
}
}
/* pre-process the name */
continue;
} else {
s[lastchar] = '\0';
}
while (s[0] == '.' && s[1] == '/') {
s += 2;
while (s[0] == '/') {
s++;
}
}
continue;
}
islnk = 0;
islnk = 1;
continue;
}
}
}
#if defined(O_XATTR)
(void) preview_attrs(s, NULL);
}
#endif /* O_XATTR */
}
}
}
}
/*
* those we've seen before.
*
* being pointed to. A count is kept of the number of references encountered
* so far.
*/
static void
{
sl_info_t *p;
int ftype;
/* Determine whether we've seen this one before */
if (p->sl_count > 0) {
/*
* It appears as if have seen this file before as we found a
* matching device, inode, and file type as a file already
* processed. Since there can possibly be files with the
* same device, inode, and file type, but aren't hard links
* (e.g., read-write system attribute files will always have
* the same inode), we need to only attempt to add one to the
* link count if the file we are processing is a hard link
* (i.e., st_nlink > 1).
*
* Note that if we are not chasing symlinks, and this one is a
* symlink, it is identically the one we saw before (you cannot
* have hard links to symlinks); in this case, we leave the
* count alone, so that we don't wind up archiving a symlink to
* itself.
*/
p->sl_count++;
}
} else {
/* We have not seen this file before */
p->sl_count = 1;
if (Use_old_stat) {
/* -Hodc: remap inode (-1 on overflow) */
sl_remap_t *q;
q = q->next) {
/* do nothing */
}
if (q == NULL) {
q->next = (sl_remap_head) ?
sl_remap_head = q;
} else {
if ((size_t)q->inode_count <=
/* fits in o_ino_t */
p->sl_ino2 = ++(q->inode_count);
} else {
}
}
}
}
}
/*
* A faster search, which does not insert the key values into the tree.
* If the a match was found in the tree, return a pointer to it. If it was not
* found, return NULL.
*/
{
sl_info_t *p; /* moves down the tree */
int c; /* comparison value */
p->sl_ftype)) == 0) {
retval = p;
break;
} else if (c < 0) {
p = p->llink;
} else {
p = p->rlink;
}
}
}
return (retval);
}
static sl_info_t *
{
int key;
static sl_info_link_t *devcache;
}
}
}
return (NULL);
}
static void
{
}
static void
chop_endslashes(char *path)
{
*ptr = '\0';
}
}
}
#if !defined(O_XATTR)
int
{
}
int
{
}
int
{
if (flag == AT_SYMLINK_NOFOLLOW)
else
}
int
{
}
int
{
}
int
{
if (flag == AT_REMOVEDIR) {
} else {
}
}
int
{
if (flag == AT_SYMLINK_NOFOLLOW)
else
}
int
{
return (-1);
}
#endif