/*
* 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 2015 Joyent, Inc.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1987, 1988 Microsoft Corporation */
/* 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 <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <locale.h>
#include <nl_types.h>
#include <langinfo.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <utime.h>
#include <stdlib.h>
#include <stdarg.h>
#include <widec.h>
#include <strings.h>
#include <deflt.h>
#include <limits.h>
#include <iconv.h>
#include <assert.h>
#include <libgen.h>
#include <libintl.h>
#include <aclutils.h>
#include <libnvpair.h>
#include <archives.h>
#if defined(__SunOS_5_6) || defined(__SunOS_5_7)
extern int defcntl();
#endif
#if defined(_PC_SATTR_ENABLED)
#include <attr.h>
#include <libcmdutils.h>
#endif
/* Trusted Extensions */
#include <zone.h>
#include "getresponse.h"
/*
* Source compatibility
*/
/*
* These constants come from archives.h and sys/fcntl.h
* and were introduced by the extended attributes project
* in Solaris 9.
*/
#if !defined(O_XATTR)
static int attropen();
static int fstatat();
static int renameat();
static int unlinkat();
static int openat();
static int fchownat();
static int futimesat();
#endif
/*
* Compiling with -D_XPG4_2 gets this but produces other problems, so
* explicitly doing the declaration here.
*/
#ifndef MINSIZE
#endif
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#ifdef BSIZE
#else /* BSIZE */
#endif /* BSIZE */
/* max value dblock.dbuf.efsize can store */
/*
* Symbols which specify the values at which the use of the 'E' function
* modifier is required to properly store a file.
*
* TAR_OFFSET_MAX - the largest file size we can archive
* OCTAL7CHAR - the limit for ustar gid, uid, dev
*/
#ifdef XHDR_DEBUG
/* tiny values which force the creation of extended header entries */
#else
/* normal values */
#endif
#define SYMLINK_LEV0 0
#define FALSE 0
#define NORMAL_FILE 0
#define PUT_NOTAS_LINK 0
#ifndef VIEW_READONLY
#endif
#ifndef VIEW_READWRITE
#endif
#if _FILE_OFFSET_BITS == 64
#else
#endif
/* ACL support */
static
struct sec_attr {
char attr_type;
} *attr;
#if defined(O_XATTR)
typedef enum {
#endif
#if defined(O_XATTR)
typedef enum {
} arc_action_t;
#endif
typedef struct attr_data {
char *attr_parent;
char *attr_path;
int attr_parentfd;
int attr_rw_sysattr;
} attr_data_t;
/*
*
* Tar has been changed to support extended attributes.
*
* As part of this change tar now uses 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 tar 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 Format
*
* 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.
*
* 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 |
* | |
* --------------------------------
*
*/
/*
* xattrhead is a pointer to the xattr_hdr
*
* xattrp is a pointer to the xattr_buf structure
* which contains the "pathing" steps to get to attributes
*
* xattr_linkp is a pointer to another xattr_buf structure that is
* only used when an attribute is actually linked to another attribute
*
*/
static char xattrbadhead;
/* Was statically allocated tbuf[NBLOCK] */
static
union hblock {
struct header {
/* <prefix>/<name>; otherwise */
/* <name> */
char typeflag;
/* the file: <prefix>/<name> */
} dbuf;
static
struct xtar_hdr {
} Xtarhdr;
static
struct gen_hdr {
} Gen;
static
struct linkbuf {
int count;
} *ihead;
/* see comments before build_table() */
typedef struct file_list {
} file_list_t;
static int append_secattr(char **, int *, int, char *, char);
static void write_ancillary(union hblock *, char *, int, char);
static void assert_string(char *s, char *msg);
static void backtape(void);
static void closevol(void);
static void done(int n);
static int is_directory(char *name);
static int has_dot_dot(char *name);
static int is_absolute(char *name);
static void flushtape(void);
static void getdir(void);
static void newvol(void);
static void passtape(void);
static void usage(void);
#ifdef EUC
#endif /* EUC */
static int checkupdate(char *arg);
static int cmp(char *b, char *s, int n);
static int notsame(void);
static int response(void);
static int build_dblock(const char *, const char *, const char,
static uid_t getuidbyname(char *);
static gid_t getgidbyname(char *);
attr_data_t **attrinfo);
static int get_xdata(void);
static int gen_utf8_names(const char *filename);
char *attrparent);
static void xattrs_put(char *, char *, char *, char *);
static void prepare_xattr(char **, char *, char *,
char, struct linkbuf *, int *);
/* Trusted Extensions */
static int check_ext_attr(char *filename);
static char *get_component(char *path);
static void chop_endslashes(char *path);
static pid_t compress_file(void);
static void compress_back(void);
static void decompress_file(void);
static pid_t uncompress_file(void);
static void *compress_malloc(size_t);
static void check_compression(void);
static char *bz_suffix(void);
static char *gz_suffix(void);
static char *xz_suffix(void);
static char *add_suffix();
static void verify_compress_opt(const char *t);
static void detect_compress(void);
static void dlog(const char *, ...);
static boolean_t should_enable_debug(void);
static char *myname;
static int checkflag = 0;
static int uflag;
static int errflag;
static int oflag;
/* Trusted Extensions */
static int ignored_aprivs = 0;
static int ignored_fprivs = 0;
static int ignored_fattrs = 0;
static int Errflg = 0;
static int exitflag = 0;
static char *tmpdir;
static char *tname;
static char *Xfile;
static char *usefile;
static char *xrec_ptr;
static int Xhdrflag;
static int charset_type = 0;
/* need to be in extended header. */
/* typeflag was followed by 'A' or non 'A' */
/* typeflag. */
/*
* UTF_8 encoding requires more space than the current codeset equivalent.
* Currently a factor of 2-3 would suffice, but it is possible for a factor
* of 6 to be needed in the future, so for saftey, we use that here.
*/
/*
* The following mechanism is provided to allow us to debug tar in complicated
* situations, like when it is part of a pipe. The idea is that you compile
* with -DWAITAROUND defined, and then add the 'D' function modifier to the
* target tar invocation, eg. "tar cDf tarfile file". 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
#endif
".tgz", ".taz"};
static char *suffix;
int
{
char *cp;
char *tmpdirp;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
if (argc < 2)
usage();
"tar: cannot allocate program name\n"));
exit(1);
}
if (init_yes() < 0) {
exit(2);
}
/*
* For XPG4 compatibility, we must be able to accept the "--"
* argument normally recognized by getopt; it is used to delimit
* the end opt the options section, and so can only appear in
* the position of the first argument. We simply skip it.
*/
argv++;
argc--;
if (argc < 3)
usage();
}
argv++;
/*
* Set up default values.
* Search the operand string looking for the first digit or an 'f'.
* If you find a digit, use the 'archive#' entry in DEF_FILE.
* If 'f' is given, bypass looking in DEF_FILE altogether.
* If no digit or 'f' is given, still look in DEF_FILE but use '0'.
*/
break;
if (*cp != 'f') {
nblock = 1;
blocklim = 0;
NotTape = 0;
}
}
}
switch (*cp) {
#ifdef WAITAROUND
case 'D':
/* rendezvous with the debugger */
waitaround = 1;
break;
#endif
case 'f':
"tar: tarfile must be specified with 'f' "
"function modifier\n"));
break;
case 'F':
Fflag++;
break;
case 'c':
cflag++;
rflag++;
update = 1;
break;
#if defined(O_XATTR)
case '@':
atflag++;
break;
#endif /* O_XATTR */
#if defined(_PC_SATTR_ENABLED)
case '/':
saflag++;
break;
#endif /* _PC_SATTR_ENABLED */
case 'u':
uflag++; /* moved code after signals caught */
rflag++;
update = 2;
break;
case 'r':
rflag++;
update = 2;
break;
case 'v':
vflag++;
break;
case 'w':
wflag++;
break;
case 'x':
xflag++;
break;
case 'X':
"tar: exclude file must be specified with 'X' "
"function modifier\n"));
Xflag = 1;
break;
case 't':
tflag++;
break;
case 'm':
mflag++;
break;
case 'p':
pflag++;
break;
case 'D':
Dflag++;
break;
case '-':
/* ignore this silently */
break;
case '0': /* numeric entries used only for defaults */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
break;
case 'b':
"tar: blocking factor must be specified "
"with 'b' function modifier\n"));
bflag++;
break;
case 'n': /* not a magtape (instead of 'k') */
NotTape++; /* assume non-magtape */
break;
case 'l':
linkerrok++;
break;
case 'e':
errflag++;
break;
case 'o':
oflag++;
break;
case 'h':
hflag++;
break;
case 'i':
iflag++;
break;
case 'B':
Bflag++;
break;
case 'P':
Pflag++;
break;
case 'E':
Eflag++;
Pflag++; /* Only POSIX archive made */
break;
case 'T':
Tflag++; /* Handle Trusted Extensions attrs */
pflag++; /* also set flag for ACL */
break;
case 'j': /* compession "bzip2" */
jflag = 1;
break;
case 'z': /* compression "gzip" */
zflag = 1;
break;
case 'Z': /* compression "compress" */
Zflag = 1;
break;
case 'J': /* compression "xz" */
Jflag = 1;
break;
case 'a':
break;
default:
"tar: %c: unknown function modifier\n"), *cp);
usage();
}
usage();
"tar: specify only one of [ctxru].\n"));
usage();
}
if (cflag) {
"tar: specify only one of [ajJzZ] to "
"create a compressed file.\n"));
usage();
}
}
/* Trusted Extensions attribute handling */
!is_system_labeled())) {
"tar: the 'T' option is only available with "
"Trusted Extensions\nand must be run from "
"the global zone.\n"));
usage();
}
/* alloc a buffer of the right size */
"tar: cannot allocate physio buffer\n"));
exit(1);
}
"tar: cannot allocate extended header buffer\n"));
exit(1);
}
#ifdef WAITAROUND
if (waitaround) {
" %d\n"), getpid());
while (waitaround) {
(void) sleep(10);
}
}
#endif
else {
/*
* Make sure that dir is no longer than what can
* fit in the prefix part of the header.
*/
"Ignoring TMPDIR\n"));
} else
}
if (rflag) {
/* Set the compression type */
if (aflag)
if (jflag) {
+ 1);
} else if (zflag) {
+ 1);
} else if (Zflag) {
} else if (Jflag) {
}
} else {
/*
* Decompress if the file is compressed for
* an update or replace.
*/
if (compress_opt != NULL) {
}
}
}
usage();
if (uflag) {
int tnum;
/*
* If the name is invalid or this isn't a directory,
* or the directory is not writable, then reset to
* a default temporary directory.
*/
tmpdir = "/tmp";
tmpdir = "/tmp";
}
"cannot create temporary file\n"));
}
}
if (cflag == 0)
"can only create standard output archives."));
++bflag;
} else {
if (cflag)
else
if (mt < 0) {
< 0)
}
}
/* Get inode and device number of output file */
(void) printf(
gettext("Suppressing absolute pathnames\n"));
comp_pid = compress_file();
/*
* for each argument, check to see if there is a "-I file" pair.
* if so, move the 3rd argument into "-I"'s place, build_table()
* using "file"'s name and increment argc one (the second
* increment appears in the for loop) which removes the two
* args "-I" and "file" from the argument vector.
*/
"tar: missing argument for -I flag\n"));
done(2);
} else {
Iflag = 1;
}
"missing argument for -C flag\n"));
done(2);
} else if (xtract_chdir != NULL) {
"extract should have only one -C "
"flag\n"));
done(2);
} else {
}
}
}
++bflag;
/* try to recover from short reads when reading stdin */
++Bflag;
/* Decompress if the file is compressed */
if (compress_opt != NULL)
comp_pid = uncompress_file();
}
if (xflag) {
if (xtract_chdir != NULL) {
if (tar_chdir(xtract_chdir) < 0) {
"directories to %s"), xtract_chdir);
}
}
"Suppressing absolute pathnames.\n"));
} else if (tflag)
}
else
usage();
/* Not reached: keep compiler quiet */
return (1);
}
static boolean_t
should_enable_debug(void)
{
const char *val;
const char *truth[] = {
"true",
"1",
"yes",
"y",
"please",
};
unsigned int i;
return (B_FALSE);
}
return (B_TRUE);
}
}
return (B_FALSE);
}
/*PRINTFLIKE1*/
static void
{
if (!debug_output) {
return;
}
}
static void
usage(void)
{
#if defined(O_XATTR)
#if defined(_PC_SATTR_ENABLED)
"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
#else
"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
#endif /* _PC_SATTR_ENABLED */
#else
"Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
#endif /* O_XATTR */
"[j|J|z|Z] "
"[blocksize] [tarfile] [size] [exclude-file...] "
"{file | -I include-file | -C directory file}...\n"));
done(1);
}
/*
* dorep - do "replacements"
*
* Dorep is responsible for creating ('c'), appending ('r')
* and updating ('u');
*/
static void
{
int archtype;
int ret;
if (!cflag) {
xhdr_flgs = 0;
getdir(); /* read header for next file */
if (Xhdrflag > 0) {
if (!Eflag)
" header. -E flag required.\n"));
/* and regular header */
} else {
if (Eflag)
" header. -E flag not allowed.\n"));
}
while (!endtape()) { /* changed from a do while */
passtape(); /* skip the file data */
if (term)
xhdr_flgs = 0;
getdir();
if (Xhdrflag > 0)
}
if (ret == 0) {
(xhdr_flgs != 0)) {
&Xtarhdr);
}
}
backtape(); /* was called by endtape */
/*
* Buffer size is calculated to be the size of the
* tmpdir string, plus 6 times the size of the tname
* string, plus a value that is known to be greater
* than the command pipeline string.
*/
char *buf;
"cannot create sort command file\n"));
}
"sort +0 -1 +1nr %s -o %s; awk '$1 "
"!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
}
}
dumping = 1;
if (mulvol) { /* SP-1 */
"Volume size not a multiple of block size."));
if (vflag)
FMT_blkcnt_t "K, blocking factor = %dK\n"),
}
/*
* Save the original directory before it gets
* changed.
*/
exit(1);
}
"missing file name for -I flag."));
continue;
continue;
} else {
*p = 0;
}
"can't change directories to %s"), *argv);
else
argv++;
continue;
} else
/*
* point cp2 to the last '/' in file, but not
* to a trailing '/'
*/
if (*cp == '/') {
++cp;
}
/* not trailing slash */
}
}
}
*cp2 = '\0';
"can't change directories to %s"), file);
continue;
}
*cp2 = '/';
cp2++;
}
LEV0, SYMLINK_LEV0);
#if defined(O_XATTR)
if (!exitflag) {
(archtype == PUT_NOTAS_LINK)) {
}
}
#endif
if (exitflag) {
/*
* If e function modifier has been specified
* write the files (that are listed before the
* file causing the error) to tape. exitflag is
* used because only some of the error conditions
* in putfile() recognize the e function modifier.
*/
break;
}
}
flushtape();
closevol(); /* SP-1 */
if (linkerrok == 1)
continue;
if (errflag)
done(1);
else
Errflg = 1;
}
}
/*
* endtape - check for tape at end
*
* endtape checks the entry in dblock.dbuf to see if its the
* special EOT entry. Endtape is usually called after getdir().
*
* endtape used to call backtape; it no longer does, he who
* wants it backed up must call backtape himself
* RETURNS: 0 if not EOT, tape position unaffected
* 1 if EOT, tape position unaffected
*/
static boolean_t
endtape(void)
{
/*
* The name field is populated.
*/
return (B_FALSE);
}
/*
* field is empty the prefix field is not.
*/
return (B_FALSE);
}
dlog("endtape(): found null header; EOT\n");
return (B_TRUE);
}
/*
* getdir - get directory entry from tar tape
*
* getdir reads the next tarblock off the tape and cracks
* it as a directory. The checksum must match properly.
*
* If tfile is non-null getdir writes the file name and mod date
* to tfile.
*/
static void
getdir(void)
{
#ifdef EUC
static int warn_chksum_sign = 0;
#endif /* EUC */
top:
return;
case '0':
case 0:
case _XATTR_HDRTYPE:
break;
case '1': /* hard link */
break;
case '2':
break;
case '3':
break;
case '4':
break;
case '5':
break;
case '6':
break;
default:
break;
}
}
} else {
Xhdrflag = 0;
}
} else {
extno = 0; /* tell others file not split */
extsize = 0;
extotal = 0;
}
#ifdef EUC
"tar: directory checksum error\n"));
if (iflag) {
Errflg = 2;
goto top;
}
done(2);
} else {
if (! warn_chksum_sign) {
warn_chksum_sign = 1;
"tar: warning: tar file made with signed checksum\n"));
}
}
}
#else
"tar: directory checksum error\n"));
if (iflag) {
Errflg = 2;
goto top;
}
done(2);
}
#endif /* EUC */
/*
* If an extended header is present, then time is available
* in nanoseconds in the extended header data, so set it.
* Otherwise, give an invalid value so that checkupdate will
* not test beyond seconds.
*/
else
else
}
#if defined(O_XATTR)
Hiddendir = 0;
if (xattrbadhead) {
xattr_linkp = NULL;
} else {
Hiddendir = 1;
}
}
}
#endif
}
/*
* passtape - skip over a file on the tape
*
* passtape skips over the next data file on the tape.
* The tape directory entry must be in dblock.dbuf. This
* routine just eats the number of blocks computed from the
* directory size entry; the tape must be (logically) positioned
* right after the directory info.
*/
static void
passtape(void)
{
/*
* Print some debugging information about the directory entry
* we are skipping over:
*/
}
}
/*
* Types link(1), sym-link(2), char special(3), blk special(4),
* directory(5), and FIFO(6) do not have data blocks associated
* with them so just skip reading the data block.
*/
return;
/* if operating on disk, seek instead of reading */
if (NotTape)
else
while (blocks-- > 0)
}
#if defined(O_XATTR)
static int
{
}
#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
* directory hierarchy
*/
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 {
}
#else
/*
* Only need to check if this attribute is an extended system
* attribute.
*/
return (ATTR_SKIP);
} else {
return (ATTR_OK);
}
#endif /* _PC_SATTR_ENABLED */
/*
* If the extended system attribute file is specified with the
* arc_rwsysattr flag, as being transient (default extended
* attributes), then don't archive it.
*/
if (*rw_sysattr && !arc_rwsysattr) {
return (ATTR_SKIP);
}
/*
* Only restore read-write system attribute files
* when -/ was specified. Only restore extended
* attributes when -@ was specified.
*/
if (atflag) {
if (!saflag) {
/*
* 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 (saflag) {
/*
* files of the base file.
*/
return (ATTR_SKIP);
}
} else {
return (ATTR_SKIP);
}
return (ATTR_OK);
}
#endif
static void
{
}
}
}
static int
{
char *bigbuf;
int maxread;
char *cp;
char *name;
int i;
int split;
int archtype = 0;
int rw_sysattr = 0;
char *tmpbuf;
char *lastslash;
int j;
int readlink_max;
xhdr_flgs = 0;
if (filetype == XATTR_FILE) {
} else {
}
if (dirfd == -1) {
"tar: unable to open%sdirectory %s%s%s%s\n"),
goto out;
}
gettext("tar: directory nesting too deep, %s not dumped\n"),
longname);
goto out;
}
goto out;
if (hflag) {
/*
* Catch nesting where a file is a symlink to its directory.
*/
if (symlink_lev++ >= MAXSYMLINKS) {
"tar: %s: Number of symbolic links "
"encountered during path name traversal "
"exceeds MAXSYMLINKS\n"), longname);
Errflg = 1;
goto out;
}
}
}
/*
* Check if the input file is the same as the tar file we
* are creating
*/
"tar: %s%s%s%s%s same as archive file\n"),
longname);
Errflg = 1;
goto out;
}
/*
* Check size limit - we can't archive files that
* exceed TAR_OFFSET_MAX bytes because of header
* limitations. Exclude file types that set
* st_size to zero below because they take no
* archive space to represent contents.
*/
(Eflag == 0)) {
"tar: %s%s%s%s%s too large to archive. "
"Use E function modifier.\n"),
longname);
if (errflag)
exitflag = 1;
Errflg = 1;
goto out;
}
goto out;
}
goto out;
}
if (Fflag &&
goto out;
if (Xflag) {
if (vflag) {
"a %s excluded\n"), longname);
}
goto out;
}
}
/*
* If the length of the fullname is greater than MAXNAM,
* print out a message and return (unless extended headers are used,
* in which case fullname is limited to PATH_MAX).
*/
"tar: %s: file name too long\n"), longname);
if (errflag)
exitflag = 1;
Errflg = 1;
goto out;
}
/*
* We split the fullname into prefix and name components if any one
* of three conditions holds:
* -- the length of the fullname exceeds NAMSIZ,
* -- the length of the fullname equals NAMSIZ, and the shortname
* is less than NAMSIZ, (splitting in this case preserves
* compatibility with 5.6 and 5.5.1 tar), or
* -- the length of the fullname equals NAMSIZ, the file is a
* directory and we are not in POSIX-conformant mode (where
* trailing slashes are removed from directories).
*/
/*
* Since path is limited to PRESIZ characters, look for the
* last slash within PRESIZ + 1 characters only.
*/
i = split; /* Length of name */
j = 0; /* Length of prefix */
goodbuf[0] = '\0';
} else {
i = split - j - 1;
}
/*
* If the filename is greater than NAMSIZ we can't
* archive the file unless we are using extended headers.
*/
!Pflag)) {
/* Determine which (filename or path) is too long. */
if (Eflag > 0) {
if (i <= NAMSIZ)
else
xhdr_count + 1);
} else {
"tar: %s: filename is greater than "
else
"tar: %s: prefix is greater than %d"
if (errflag)
exitflag = 1;
Errflg = 1;
goto out;
}
} else
} else {
}
if (Aflag) {
while (*prefix == '/')
++prefix;
else
while (*name == '/')
++name;
}
case S_IFDIR:
i = 0;
;
*--cp = '/';
*++cp = 0;
}
if (!oflag) {
goto out;
}
if (!Pflag) {
/*
* Old archives require a slash at the end
* of a directory name.
*
* XXX
* If directory name is too long, will
* slash overfill field?
*/
"tar: %s: filename is greater "
if (errflag)
exitflag = 1;
Errflg = 1;
goto out;
} else {
= '/';
} else
"%s/", name);
/*
* need to recalculate checksum
* because the name changed.
*/
}
}
goto out;
#if defined(O_XATTR)
/*
* Reset header typeflag when archiving directory, since
* build_dblock changed it on us.
*/
if (filetype == XATTR_FILE) {
} else {
}
#else
#endif
}
if (vflag) {
if (NotTape) {
}
gettext("a %s attribute %s "),
} else {
}
if (NotTape) {
K(blocks));
} else {
" tape blocks\n"), blocks);
}
}
/*
* If hidden dir then break now since xattrs_put() will do
* the iterating of the directory.
*
* At the moment, there can only be system attributes on
* attributes. There can be no attributes on attributes or
* directories within the attributes hidden directory hierarchy.
*/
if (filetype == XATTR_FILE)
break;
if (*shortname != '/')
else
goto out;
}
"can't open directory %s"), longname);
parent);
goto out;
}
/*
* Create a list of files (children) in this directory to avoid
* having to perform telldir()/seekdir().
*/
continue;
sizeof (file_list_t))) == NULL) ||
"Insufficient memory for directory "
"list entry %s/%s\n"),
}
/* Add the file to the list */
} else {
}
}
/*
* Archive each of the files in the current directory.
* If a file is a directory, putfile() is called
* recursively to archive the file hierarchy of the
* directory before archiving the next file in the
* current directory.
*/
if (!exitflag) {
(archtype == PUT_NOTAS_LINK)) {
}
}
if (exitflag)
break;
/* Free each child as we are done processing it. */
}
}
}
break;
case S_IFLNK:
if (Eflag > 0) {
xhdr_flgs |= _X_LINKPATH;
} else {
"tar: %s: symbolic link too long\n"),
longname);
if (errflag)
exitflag = 1;
Errflg = 1;
goto out;
}
}
/*
* Sym-links need header size of zero since you
* don't store any data for this type.
*/
if (i < 0) {
"can't read symbolic link %s"), longname);
goto out;
} else {
filetmp[i] = 0;
}
if (vflag)
"a %s symbolic link to %s\n"),
if (xhdr_flgs & _X_LINKPATH) {
goto out;
} else
goto out;
/*
* No acls for symlinks: mode is always 777
* dont call write ancillary
*/
rc = PUT_AS_LINK;
break;
case S_IFREG:
(filetype == XATTR_FILE) ?
goto out;
}
rc = PUT_AS_LINK;
goto out;
}
/* correctly handle end of volume */
/* split if floppy has some room and file is large */
goto out;
}
newvol(); /* not worth it--just get new volume */
}
blocks);
goto out;
}
if (vflag) {
if (NotTape) {
}
" attribute ") : "",
(filetype == XATTR_FILE) ?
longattrname : "");
if (NotTape)
K(blocks));
else
blocks);
}
goto out;
/*
* No need to reset typeflag for extended attribute here, since
* put_extra_attributes already set it and we haven't called
* build_dblock().
*/
}
while (((i = (int)
blocks) {
}
if (i < 0)
else if (blocks != 0 || i != 0) {
"tar: %s: file changed size\n"), longname);
if (errflag) {
exitflag = 1;
Errflg = 1;
} else if (!Dflag) {
Errflg = 1;
}
}
break;
case S_IFIFO:
rc = PUT_AS_LINK;
goto out;
}
goto out;
}
newvol();
}
blocks);
if (vflag) {
if (NotTape) {
} else {
}
}
goto out;
goto out;
break;
case S_IFCHR:
rc = PUT_AS_LINK;
goto out;
}
goto out;
}
newvol();
}
blocks);
if (vflag) {
if (NotTape) {
} else {
blocks);
}
}
goto out;
goto out;
break;
case S_IFBLK:
rc = PUT_AS_LINK;
goto out;
}
goto out;
}
newvol();
}
blocks);
if (vflag) {
if (NotTape) {
}
if (NotTape)
K(blocks));
else
}
goto out;
goto out;
break;
default:
"tar: %s is not a file. Not dumped\n"), longname);
if (errflag)
exitflag = 1;
Errflg = 1;
goto out;
}
out:
}
return (rc);
}
/*
* splitfile dump a large file across volumes
*
* splitfile(longname, fd);
* char *longname; full name of file
* int ifd; input file descriptor
*
* NOTE: only called by putfile() to dump a large file.
*/
static void
{
int i, extents;
/*
* # extents =
* size of file after using up rest of this floppy
* blocks - (blocklim - tapepos) + 1 (for header)
* plus roundup value before divide by blocklim-1
* + (blocklim - 1) - 1
* all divided by blocklim-1 (one block for each header).
* this gives
* (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
* which reduces to the expression used.
* one is added to account for this first extent.
*
* When one is dealing with extremely large archives, one may want
* to allow for a large number of extents. This code should be
* revisited to determine if extents should be changed to something
* larger than an int.
*/
"tar: %s needs unusual number of volumes to split\n"
return;
}
return;
/*
* The value contained in dblock.dbuf.efsize was formerly used when the
* v flag was specified in conjunction with the t flag. Although it is
* no longer used, older versions of tar will expect the former
* behaviour, so we must continue to write it to the archive.
*
* Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
* can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
* store 0.
*/
if (bytes <= TAR_EFSIZE_MAX)
else
"tar: large file %s needs %d extents.\n"
for (i = 1; i <= extents; i++) {
if (i > 1) {
newvol();
if (i == extents)
s = bytes; /* last ext. gets true bytes */
else
}
bytes -= s;
if (vflag)
"K [extent #%d of %d]\n"),
blocks--;
}
if (blocks != 0) {
"tar: %s: file changed size\n"), longname);
"tar: aborting split file %s\n"), longname);
return;
}
}
if (vflag)
extents);
}
/*
* convtoreg - determines whether the file should be converted to a
* regular file when extracted
*
* Returns 1 when file size > 0 and typeflag is not recognized
* Otherwise returns 0
*/
static int
{
return (1);
}
return (0);
}
#if defined(O_XATTR)
static int
save_cwd(void)
{
}
#endif
#if defined(O_XATTR)
static void
{
if (*cwd != -1) {
"Cannot fchdir to attribute directory"));
exit(1);
}
*cwd = -1;
}
}
#endif
/*
* 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 (!*ext_attrflg) {
#if defined(_PC_SATTR_ENABLED)
if (saflag) {
/* 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 (saflag) {
/* 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)
/*
* 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).
* attrinfo->parent = NULL
* attrname = '.'
* 2. Open the attribute directory of the base file and change into it.
* attrinfo->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).
* attrinfo->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.
* attrinfo->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 (atflag
* and saflag) enable the processing of the attribute type.
*
* On succesful return, attrinfo->parentfd will be the file descriptor of the
* opened attribute directory. In addition, if the attribute is a read-write
* extended system attribute, attrinfo->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 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) {
}
/*
* 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.
*/
/*
* Reset typeflag back to real value so passtape
* will skip ahead correctly.
*/
return (ATTR_OPEN_ERR);
}
}
/*
* Change into the parent attribute's directory unless we are
* processing the hidden attribute directory of the base file itself.
*/
return (ATTR_CHDIR_ERR);
}
}
/* Determine if the attribute should be processed */
return (rc);
}
/*
* If the attribute is an extended attribute, or 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
static void
{
int ofile;
int dir;
int rw_sysattr;
int saveerrno;
int error;
int symflag;
int want;
int dircreate;
int convflag;
/* reset Trusted Extensions variables */
rpath_flag = 0;
lk_rpath_flag = 0;
dir_flag = 0;
mld_flag = 0;
orig_namep = 0;
dumping = 0; /* for newvol(), et al: we are not writing */
for (;;) {
convflag = 0;
symflag = 0;
dir = 0;
Hiddendir = 0;
rw_sysattr = 0;
ofile = -1;
if (dirfd != -1) {
dirfd = -1;
}
if (ofile != -1) {
}
#if defined(O_XATTR)
if (cwd != -1) {
}
#endif
/* namep is set by wantit to point to the full name */
&attrinfo)) == 0) {
#if defined(O_XATTR)
xattr_linkp = NULL;
}
#endif
continue;
}
if (want == -1)
break;
/* Trusted Extensions */
/*
* During tar extract (x):
* If the pathname of the restored file has been
* reconstructed from the ancillary file,
* use it to process the normal file.
*/
if (mld_flag) { /* Skip over .MLD. directory */
mld_flag = 0;
passtape();
continue;
}
if (rpath_flag) {
rpath_flag = 0; /* reset */
}
if (dirfd != -1)
#if defined(O_XATTR)
int rc;
if (cwd == -1) {
"unable to save current working "
"directory while processing "
"attribute %s of %s"),
gettext("tar: cannot open "
"%sattribute %s of file %s: %s\n"),
"system ") : "",
}
xattr_linkp = NULL;
passtape();
continue;
} else {
}
} else {
}
#else
#endif
if (dirfd == -1) {
"tar: cannot open %s: %s\n"),
passtape();
continue;
}
if (xhdr_flgs & _X_LINKPATH)
else {
#if defined(O_XATTR)
} else {
}
#else
#endif
}
if (Fflag) {
passtape();
continue;
}
}
passtape();
continue;
}
if (once) {
checkflag = 1;
pflag = 1;
} else {
/* get file creation mask */
}
once = 0;
} else {
pflag = 1;
checkflag = 2;
}
if (!pflag) {
/* get file creation mask */
}
once = 0;
}
}
#if defined(O_XATTR)
/*
* Handle extraction of hidden attr dir.
* Dir is automatically created, we only
* need to update mode and perm's.
*/
if (vflag) {
gettext(" attribute "),
gettext("bytes"));
if (NotTape)
else
FMT_blkcnt_t " tape blocks\n"),
blocks);
}
/*
* Set the permissions and mode of the attribute
* unless the attribute is a system attribute (can't
* successfully do this) or the hidden attribute
* directory (".") of an attribute (when the attribute
* is restored, the hidden attribute directory of an
* attribute is transient). Note: when the permissions
* and mode are set for the hidden attribute directory
* of a file on a system supporting extended system
* attributes, even though it returns successfully, it
* will not have any affect since the attribute
* directory is transient.
*/
"%s%s%s: failed to set ownership "
"of attribute directory"), namep,
}
"%s%s%s: failed to set permissions "
"of attribute directory"), namep,
}
}
goto filedone;
}
#endif
dir = 1;
if (vflag) {
if (NotTape)
else
FMT_blkcnt_t " tape blocks\n"),
(blkcnt_t)0);
}
goto filedone;
}
}
linkp++;
"tar: %s: cannot link\n"), namep);
continue;
}
if (vflag)
"x %s linked to %s\n"), namep,
linkp);
xcnt++; /* increment # files extracted */
continue;
}
(int)Gen.g_devmajor) < 0) {
continue;
}
if (vflag) {
if (NotTape)
"K\n", K(blocks));
else
FMT_blkcnt_t " tape blocks\n"),
blocks);
}
goto filedone;
}
}
linkp++;
"tar: %s: cannot link\n"), namep);
continue;
}
if (vflag)
"x %s linked to %s\n"), namep,
linkp);
xcnt++; /* increment # files extracted */
continue;
}
"%s: mknod failed"), namep);
continue;
}
if (vflag) {
if (NotTape)
"K\n", K(blocks));
else
FMT_blkcnt_t " tape blocks\n"),
blocks);
}
goto filedone;
"Can't create special %s\n"), namep);
continue;
}
/* BLOCK SPECIAL */
}
linkp++;
"tar: %s: cannot link\n"), namep);
continue;
}
if (vflag)
"x %s linked to %s\n"), namep,
linkp);
xcnt++; /* increment # files extracted */
continue;
}
continue;
}
if (vflag) {
if (NotTape)
"K\n", K(blocks));
else
FMT_blkcnt_t " tape blocks\n"),
blocks);
}
goto filedone;
continue;
}
else
linkp++;
}
namep);
continue;
}
if (vflag)
"x %s symbolic link to %s\n"),
goto filedone;
}
linkp++;
}
#if defined(O_XATTR)
if (xattrp && xattr_linkp) {
"Cannot fchdir to attribute "
"directory %s"),
exit(1);
}
} else {
}
#else
#endif
if (error < 0) {
"tar: %s%s%s: cannot link\n"),
(xattr_linkp != NULL) ?
xattrapath : "");
continue;
}
if (vflag)
"x %s%s%s linked to %s%s%s\n"), namep,
(xattr_linkp != NULL) ?
(xattr_linkp != NULL) ?
xattr_linkaname : "",
(xattr_linkp != NULL) ?
xcnt++; /* increment # files extracted */
#if defined(O_XATTR)
xattr_linkp = NULL;
}
#endif
continue;
}
/* REGULAR FILES */
convflag = 1;
if (errflag) {
"tar: %s: typeflag '%c' not recognized\n"),
done(1);
} else {
"tar: %s: typeflag '%c' not recognized, "
"converting to regular file\n"), namep,
Errflg = 1;
}
}
linkp++;
"tar: %s: cannot link\n"), namep);
continue;
}
if (vflag)
"x %s linked to %s\n"), comp,
linkp);
xcnt++; /* increment # files extracted */
#if defined(O_XATTR)
xattr_linkp = NULL;
}
#endif
continue;
}
#if defined(O_XATTR)
if (ofile < 0) {
}
}
#endif
if (ofile < 0) {
"tar: %s%s%s%s - cannot create\n"),
gettext("system attribute ") :
gettext("attribute ")),
if (errflag)
done(1);
else
Errflg = 1;
#if defined(O_XATTR)
xattr_linkp = NULL;
}
#endif
passtape();
continue;
}
if (errflag)
done(1);
else
Errflg = 1;
passtape();
continue;
}
if (extno != 0) { /* file is in pieces */
"tar: ignoring bad extent info for "
"%s%s%s%s\n"),
gettext("system attribute ") :
gettext("attribute ")),
else {
/* extract it */
}
}
extno = 0; /* let everyone know file is not split */
if (vflag) {
gettext(" system attribute ") :
gettext(" attribute ")),
gettext("bytes"));
if (NotTape)
K(blocks));
else
}
#if defined(O_XATTR)
xattr_linkp = NULL;
}
#endif
continue;
}
if (dir)
else
#if defined(O_XATTR)
/*
* Set the time on the attribute unless
* the attribute is a system attribute
* (can't successfully do this) or the
* hidden attribute directory, "." (the
* time on the hidden attribute
* directory will be updated when
* attributes are restored, otherwise
* it's transient).
*/
if (!rw_sysattr && (Hiddendir == 0)) {
}
} else
#else
#endif
}
/* moved this code from above */
else
}
/*
* Because ancillary file preceeds the normal file,
* acl info may have been retrieved (in aclp).
* All file types are directed here (go filedone).
* Always restore ACLs if there are ACLs.
*/
int ret;
#if defined(O_XATTR)
if (Hiddendir)
else
} else {
}
#else
#endif
if (ret < 0) {
if (pflag) {
"%s%s%s%s: failed to set acl "
"entries\n"), namep,
(rw_sysattr ? gettext(
" system attribute ") :
gettext(" attribute ")),
}
/* else: silent and continue */
}
}
if (!oflag)
/* set file ownership */
"tar: cannot stat extracted file "
"%s%s%s%s\n"),
gettext("system attribute ") :
gettext("attribute ")),
"tar: warning - file permissions have "
"changed for %s%s%s%s (are 0%o, should be "
"0%o)\n"),
gettext("system attribute ") :
gettext("attribute ")),
}
}
#if defined(O_XATTR)
xattr_linkp = NULL;
}
#endif
if (ofile != -1) {
dirfd = -1;
ofile = -1;
}
xcnt++; /* increment # files extracted */
}
/*
* Process ancillary file.
*
*/
char *secp;
char *tp;
int attrsize;
int cnt;
/* reset Trusted Extensions flags */
dir_flag = 0;
mld_flag = 0;
lk_rpath_flag = 0;
rpath_flag = 0;
if (pflag) {
"Insufficient memory for acl\n"));
passtape();
continue;
}
/*
* Display a line for each ancillary file.
*/
FMT_blkcnt_t " %s, %"
FMT_blkcnt_t " %s\n",
while (blocks-- > 0) {
break;
} else {
TBLOCK);
}
}
/* got all attributes in secp */
do {
case UFSD_ACL:
case ACE_ACL:
"%7o",
(uint_t *)
&cnt);
/* header is 8 */
error =
if (error != 0) {
"aclfromtext "
"failed: %s\n"),
error));
break;
}
"aclcnt error\n"));
break;
}
break;
/* Trusted Extensions */
case DIR_TYPE:
case LBL_TYPE:
case APRIV_TYPE:
case FPRIV_TYPE:
case COMP_TYPE:
case LK_COMP_TYPE:
case ATTR_FLAG_TYPE:
attrsize =
sizeof (struct sec_attr) +
if (Tflag)
attr);
break;
default:
"unrecognized attr"
" type\n"));
break;
}
/* next attributes */
} while (bytes != 0);
} else {
passtape();
}
} /* acl */
} /* for */
/*
* Ensure that all the directories still on the directory stack
* get their modification times set correctly by flushing the
* stack.
*/
#if defined(O_XATTR)
xattr_linkp = NULL;
}
#endif
/*
* Check if the number of files extracted is different from the
* number of files listed on the command line
*/
gettext("tar: %d file(s) not extracted\n"),
Errflg = 1;
}
}
/*
*
* xblocks(issysattr, bytes, ofile);
*
* issysattr flag set if the files being extracted
* is an extended system attribute file.
* unsigned long long bytes size of extent or file to be extracted
* ofile output file
*
* called by doxtract() and xsfile()
*/
static int
{
char *buf;
/* Don't need to do anything if this is a zero size file */
if (bytes <= 0) {
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 smallest of the following two
* things:
* 1) The size of the archived file.
* 2) The preferred I/O size of the file.
*/
/*
* Writes to system attribute files must be
* performed in one operation.
*/
} else {
/*
* fstat() the file to get the preferred I/O size.
* If it fails, then resort back to just writing
* one block at a time.
*/
} else {
}
}
/*
* The buffer used to accumulate the data for the write operation
* needs to be the maximum number of bytes to be written rounded up
* to the nearest TBLOCK since readtape reads one block at a time.
*/
}
while (bytes > 0) {
/*
* readtape() obtains one block (TBLOCK) of data at a time.
* Accumulate as many blocks of data in buf as we can write
* in one operation.
*/
}
sizeof (tempname));
else
/*
* If the extended system attribute being extracted
* contains attributes that the user needs privileges
* for, then just display a warning message, skip
* the extraction of this file, and return.
*/
"tar: unable to extract system attribute "
"%s: insufficient privileges\n"), tempname);
Errflg = 1;
return (1);
} else {
"tar: %s: HELP - extract write error\n"),
tempname);
done(2);
}
}
/*
* If we've reached this point and there is still data
* to be written, maxwrite had to have been determined
* by the preferred I/O size. 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 maxwrite to the number of bytes left to write.
*/
}
}
return (0);
}
/*
* xsfile extract split file
*
* xsfile(ofd); ofd = output file descriptor
*
* file extracted and put in ofd via xblocks()
*
* NOTE: only called by doxtract() to extract one large file
*/
static int
{
int i, c;
int sysattrerr = 0;
else
totalext = 0; /* these keep count */
/* make sure we do extractions in order */
"tar: first extent read is not #1\n"
"OK to read file beginning with extent #%d (%s/%s) ? "),
if (yes() == 0) {
passtape();
if (sysattrerr) {
return (1);
} else {
return (0);
}
}
}
i = extno;
/*CONSTCOND*/
while (1) {
} else {
}
if (vflag)
FMT_off_t " %s, %ldK\n",
sysattrerr = 1;
goto canit;
}
totalbytes += bytes;
totalext++;
if (++i > extents)
break;
/* get next volume and verify it's the right one */
newvol();
xhdr_flgs = 0;
getdir();
if (Xhdrflag > 0)
(void) get_xdata(); /* Get x-header & regular hdr */
}
if (endtape()) { /* seemingly empty volume */
"tar: first record is null\n"));
"tar: need volume with extent #%d of %s\n"),
i, name);
goto tryagain;
}
if (notsame()) {
"tar: first file on that volume is not "
"the same file\n"));
goto asknicely;
}
if (i != extno) {
"tar: extent #%d received out of order\ntar: "
"should be #%d\n"), extno, i);
"Ignore error, Abort this file, or "
"load New volume (i/a/n) ? "));
c = response();
if (c == 'a')
goto canit;
if (c != 'i') /* default to new volume */
goto asknicely;
i = extno; /* okay, start from there */
}
}
if (vflag)
return (0);
}
/*
* notsame() check if extract file extent is invalid
*
* returns true if anything differs between savedblock and dblock
* except extno (extent number), checksum, or size (extent size).
* Determines if this header belongs to the same file as the one we're
* extracting.
*
* NOTE: though rather bulky, it is only called once per file
* extension, and it can withstand changes in the definition
* of the header structure.
*
* WARNING: this routine is local to xsfile() above
*/
static int
notsame(void)
{
return (
}
static void
{
int want;
dumping = 0;
/* if not on magtape, maximize seek speed */
#else
nblock = 1;
#endif
}
for (;;) {
/* namep is set by wantit to point to the full name */
continue;
if (want == -1)
break;
++tcnt;
if (Fflag) {
passtape();
continue;
}
}
/*
* ACL support:
* aclchar is introduced to indicate if there are
* acl entries. longt() now takes one extra argument.
*/
if (vflag) {
aclchar = '+';
passtape();
continue;
}
aclchar = ' ';
}
#if defined(O_XATTR)
int issysattr;
/*
* We could use sysattr_type() to test whether or not
* the attribute we are processing is really an
* extended system attribute, which as of this writing
* just does a strcmp(), however, sysattr_type() may
* be changed to issue a pathconf() call instead, which
* would require being changed into the parent attribute
* directory. So instead, just do simple string
* comparisons to see if we are processing an extended
* system attribute.
*/
} else {
}
#else
#endif
if (extno != 0) {
if (vflag) {
/* keep the '\n' for backwards compatibility */
} else {
}
}
if (xhdr_flgs & _X_LINKPATH) {
} else {
#if defined(O_XATTR)
} else {
}
#else
#endif
}
/*
* TRANSLATION_NOTE
* Subject is omitted here.
* Translate this as if
* <subject> linked to %s
*/
#if defined(O_XATTR)
(void) printf(
gettext(" linked to attribute %s"),
} else {
(void) printf(
}
#else
(void) printf(
#endif
}
/*
* TRANSLATION_NOTE
* Subject is omitted here.
* Translate this as if
* <subject> symbolic link to %s
*/
" symbolic link to %s"), templink);
(void) printf("\n");
#if defined(O_XATTR)
}
#endif
passtape();
}
/*
* Check if the number of files tabled is different from the
* number of files listed on the command line
*/
Errflg = 1;
}
}
static void
{
char *cp;
*cp++ = '\0';
while (n-- > 0)
}
static void
{
int i, j, temp;
for (i = 0; i < 11; i++)
modestr[i] = '-';
modestr[i] = '\0';
/* a '+' sign is printed if there is ACL */
for (i = 0; i < 3; i++) {
j = (i * 3) + 1;
modestr[j] = 'r';
}
switch (temp) {
case (S_IFIFO):
modestr[0] = 'p';
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:
/* This field may be zero in old archives. */
/*
* For POSIX compliant archives, the mode field
* consists of 12 bits, ie: the file type bits
* are not stored in dblock.dbuf.mode.
* For files other than hard links, getdir() sets
* the file type bits in the st_mode field of the
* stat structure based upon dblock.dbuf.typeflag.
*/
"tar: impossible file type"));
}
}
}
static void
{
if (xhdr_flgs & _X_LINKPATH)
else
'\0', NAMSIZ) ?
}
}
/*
* checkdir - Attempt to ensure that the path represented in name
* exists, and return 1 if this is true and name itself is a
* directory.
* Return 0 if this path cannot be created or if name is not
* a directory.
*/
static int
{
/*
* Scan through the name, and locate first and last slashes.
*/
if (*cp == '/') {
if (! firstSlash) {
firstSlash = cp;
}
}
}
/*
* Determine what you can from the proceeds of the scan.
*/
/*
* The named file does not have any subdrectory
* structure; just bail out.
*/
return (0);
}
/*
* Make sure that name doesn`t end with slash for the loop.
* This ensures that the makeDir attempt after the loop is
* meaningful.
*/
if (trailingSlash) {
}
/*
* Make the path one component at a time.
*/
cp;
*cp = '\0';
*cp = '/';
if (!success) {
return (0);
}
}
/*
* This makes the last component of the name, if it is a
* directory.
*/
if (markedDir) {
return (0);
}
}
return (markedDir);
}
/*
* resugname - Restore the user name and group name. Search the NIS
* before using the uid and gid.
* (It is presumed that an archive entry cannot be
* simultaneously a symlink and some other type.)
*/
static void
char *name, /* name of the file to be modified */
int symflag) /* true if file is a symbolic link */
{
char *u_g_name;
/*
* Try and extract the intended uid and gid from the name
* service before believing the uid and gid in the header.
*
* In the case where we archived a setuid or setgid file
* owned by someone with a large uid, then it will
* have made it into the archive with a uid of nobody. If
* the corresponding username doesn't appear to exist, then we
* want to make sure it *doesn't* end up as setuid nobody!
*
* Our caller will print an error message about the fact
* that the restore didn't work out quite right ..
*/
else
}
/* (Ditto for gids) */
else
}
}
}
/*ARGSUSED*/
static void
{
term++;
}
/*ARGSUSED*/
static void
{
term++;
}
/*ARGSUSED*/
static void
{
term++;
}
static void
{
/*
* If the uid or gid is too large, we can't put it into
* the archive. We could fail to put anything in the
* archive at all .. but most of the time the name service
* will save the day when we do a lookup at restore time.
*
* Instead we choose a "safe" uid and gid, and fix up whether
* or not the setuid and setgid bits are left set to extraction
* time.
*/
if (Eflag) {
}
}
(off_t)0);
} else
} else {
}
uid = UID_NOBODY;
gid = GID_NOBODY;
}
static int
#ifdef EUC
/*
* Warning: the result of this function depends whether 'char' is a
* signed or unsigned data type. This a source of potential
* non-portability among heterogeneous systems. It is retained here
* for backward compatibility.
*/
#else
#endif /* EUC */
{
int i;
char *cp;
*cp = ' ';
i = 0;
i += *cp;
return (i);
}
#ifdef EUC
/*
* Generate unsigned checksum, regardless of what C compiler is
* used. Survives in the face of arbitrary 8-bit clean filenames,
* e.g., internationalized filenames.
*/
static int
{
unsigned i;
unsigned char *cp;
cp < (unsigned char *)
*cp = ' ';
i = 0;
i += *cp;
return (i);
}
#endif /* EUC */
/*
* If the w flag is set, output the action to be taken and the name of the
* file. Perform the action if the user response is affirmative.
*/
static int
{
if (wflag) {
if (vflag)
if (yes() == 1) {
return (1);
}
return (0);
}
return (1);
}
/*
* When the F flag is set, exclude RCS and SCCS directories (and any files
* or directories under them). If F is set twice, also exclude .o files,
* and files names errs, core, and a.out.
*
* Return 0 if file should be excluded, 1 otherwise.
*/
static int
{
#if defined(O_XATTR)
/*
* If there is an xattr_buf structure associated with this file,
* always return 1.
*/
if (xattrp) {
return (1);
}
#endif
/*
* First check to see if the base name is an RCS or SCCS directory.
*/
return (1);
if (is_dir) {
return (0);
}
/*
* If two -F command line options were given then exclude .o files,
* and files named errs, core, and a.out.
*/
return (0);
return (0);
}
/*
* At this point, check to see if this file has a parent directory
* named RCS or SCCS. If so, then this file should be excluded too.
* The strcpy() operation is done again, because basename(3C) may
* modify the path string passed to it.
*/
return (1);
return (0);
}
return (1);
}
static int
response(void)
{
int c;
c = getchar();
if (c != '\n')
while (getchar() != '\n')
;
else c = 'n';
return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
}
/* Has file been modified since being put into archive? If so, return > 0. */
static int
{
long nsecs;
return (1);
/*
* Unless nanoseconds were stored in the file, only use seconds for
* comparison of time. Nanoseconds are stored when -E is specified.
*/
if (Eflag == 0)
return (0);
return (1);
}
/*
* newvol get new floppy (or tape) volume
*
* newvol(); resets tapepos and first to TRUE, prompts for
* for new volume, and waits.
* if dumping, end-of-file is written onto the tape.
*/
static void
newvol(void)
{
int c;
if (dumping) {
dlog("newvol called with 'dumping' set\n");
closevol();
flushtape();
sync();
tapepos = 0;
} else
mt = 0;
"tar: \007please insert new volume, then press RETURN."));
if (c == EOF)
if (term)
errno = 0;
} else {
}
if (mt < 0) {
"tar: cannot reopen %s (%s)\n"),
done(2);
}
}
/*
* Write a trailer portion to close out the current output volume.
*/
static void
closevol(void)
{
if (mulvol) {
/*
* blocklim does not count the 2 EOT marks;
* tapepos does count the 2 EOT marks;
* therefore we need the +2 below.
*/
}
}
static void
done(int n)
{
/*
* If we were terminated in some way, and we would otherwise have
* exited with a value of 0, adjust to 1, so that external callers
* can determine this by looking at the exit status.
*/
if (term && n == 0)
n = 1;
if (compress_opt != NULL)
(void) free(compress_opt);
if (mt > 0) {
exit(2);
}
}
/*
* If we have a compression child, we should have a child process that
* we're waiting for to finish compressing or uncompressing the tar
* stream.
*/
if (comp_pid != 0)
exit(n);
}
/*
* Determine if s1 is a prefix portion of s2 (or the same as s2).
*/
static int
{
while (*s1)
return (0);
if (*s2)
return (*s2 == '/');
return (1);
}
/*
* lookup and bsrch look through tfile entries to find a match for a name.
* The name can be up to PATH_MAX bytes. bsrch compares what it sees between
* a pair of newline chars, so the buffer it uses must be long enough for
* two lines: name and modification time as well as period, newline and space.
*
* A kludge was added to bsrch to take care of matching on the first entry
* in the file--there is no leading newline. So, if we are reading from the
* start of the file, read into byte two and set the first byte to a newline.
* Otherwise, the first entry cannot be matched.
*
*/
static off_t
lookup(char *s)
{
int i;
off_t a;
for (i = 0; s[i]; i++)
if (s[i] == ' ')
break;
return (a);
}
static off_t
{
int i, j;
char b[N];
loop:
if (l >= h)
return ((off_t)-1);
m = l + (h-l)/2 - N/2;
if (m < l)
m = l;
if (m == 0) {
b[0] = '\n';
m--;
} else
for (i = 0; i < N; i++) {
if (b[i] == '\n')
break;
m++;
}
if (m >= h)
return ((off_t)-1);
m1 = m;
j = i;
for (i++; i < N; i++) {
m1++;
if (b[i] == '\n')
break;
}
i = cmp(b+j, s, n);
if (i < 0) {
h = m;
goto loop;
}
if (i > 0) {
l = m1;
goto loop;
}
if (m < 0)
m = 0;
return (m);
}
static int
cmp(char *b, char *s, int n)
{
int i;
assert(b[0] == '\n');
for (i = 0; i < n; i++) {
if (b[i+1] > s[i])
return (-1);
if (b[i+1] < s[i])
return (1);
}
return (b[i+1] == ' '? 0 : -1);
}
/*
* seekdisk seek to next file on archive
*
* called by passtape() only
*
* WARNING: expects "nblock" to be set, that is, readtape() to have
* already been called. Since passtape() is only called
* after a file header block has been read (why else would
* we skip to next file?), this is currently safe.
*
* changed to guarantee SYS_BLOCK boundary
*/
static void
{
/* handle non-multiple of SYS_BLOCK */
#endif
return;
}
goto noseek;
#endif
"tar: device seek error\n"));
done(3);
}
/* read those extra blocks */
if (nxb) {
dlog("reading extra blocks\n");
"tar: read error while skipping file\n"));
done(8);
}
}
#endif
}
static void
{
int i, j;
++tapepos;
if (first) {
/*
* set the number of blocks to read initially, based on
* the defined defaults for the device, or on the
* explicit block factor given.
*/
j = nblock;
else
j = NBLOCK;
} else
j = nblock;
"tar: tape read error\n"));
done(3);
/*
* i == 0 and !rflag means that EOF is reached and we are
* trying to update or replace an empty tar file, so exit
* with an error.
*
* If i == 0 and !first and NotTape, it means the pointer
* has gone past the EOF. It could happen if two processes
* try to update the same tar file simultaneously. So exit
* with an error.
*/
} else if (i == 0) {
"tar: blocksize = %d\n"), i);
}
/*
* Short read - try to get the remaining bytes.
*/
char *b = (char *)tbuf + i;
int r;
do {
gettext("tar: tape read error\n"));
done(3);
}
b += r;
remaining -= r;
i += r;
} while (remaining > 0 && r != 0);
}
if (first) {
if ((i % TBLOCK) != 0) {
"tar: tape blocksize error\n"));
done(3);
}
i /= TBLOCK;
if (!NotTape)
"tar: blocksize = %d\n"), i);
}
/*
* If we are reading a tape, then a short read is
* understood to signify that the amount read is
* the tape's actual blocking factor. We adapt
* nblock accordingly. There is no reason to do
* this when the device is not blocked.
*/
if (!NotTape)
nblock = i;
}
recno = 0;
}
}
/*
* replacement for writetape.
*/
static int
{
int i;
tapepos += n; /* output block count */
recno = 0;
}
/*
* Special case: We have an empty tape buffer, and the
* users data size is >= the tape block size: Avoid
* the bcopy and dma direct to tape. BIG WIN. Add the
* residual to the tape buffer.
*/
n -= nblock;
}
while (n-- > 0) {
recno = 0;
}
}
/* Tell the user how much to write to get in sync */
}
/*
* backtape - reposition tape after reading soft "EOF" record
*
* Backtape tries to reposition the tape back over the EOF
* record. This is for the 'u' and 'r' function letters so that the
* tape can be extended. This code is not well designed, but
* I'm confident that the only callers who care about the
* backspace-over-EOF feature are those involved in 'u' and 'r'.
*
* The proper way to backup the tape is through the use of mtio.
* Earlier spins used lseek combined with reads in a confusing
* maneuver that only worked on 4.x, but shouldn't have, even
* there. Lseeks are explicitly not supported for tape devices.
*/
static void
backtape(void)
{
nblock);
/*
* Backup to the position in the archive where the record
* currently sitting in the tbuf buffer is situated.
*/
if (NotTape) {
/*
* For non-tape devices, this means lseeking to the
* correct position. The absolute location tapepos-recno
* should be the beginning of the current record.
*/
(off_t)-1) {
gettext("tar: lseek to end of archive failed\n"));
done(4);
}
} else {
/*
* For tape devices, we backup over the most recently
* read record.
*/
gettext("tar: backspace over record failed\n"));
done(4);
}
}
/*
* Decrement the tape and tbuf buffer indices to prepare for the
* coming write to overwrite the soft EOF record.
*/
recno--;
tapepos--;
}
/*
* flushtape write buffered block(s) onto tape
*
* recno points to next free block in tbuf. If nonzero, a write is done.
* Care is taken to write in multiples of SYS_BLOCK when device is
* non-magtape in case raw i/o is used.
*
* NOTE: this is called by writetape() to do the actual writing
*/
static void
flushtape(void)
{
if (recno > 0) { /* anything buffered? */
if (NotTape) {
int i;
/*
* an odd-block write can only happen when
* we are at the end of a volume that is not a tape.
* Here we round recno up to an even SYS_BLOCK
* boundary.
*/
dlog("flushtape() %d rounding blocks\n", i);
recno += i; /* round up to even SYS_BLOCK */
}
#endif
}
"tar: tape write error\n"));
done(2);
}
recno = 0;
}
}
static void
{
}
/*
* kcheck()
* - checks the validity of size values for non-tape devices
* - if size is zero, mulvol tar is disabled and size is
* assumed to be infinite.
* - returns volume size in TBLOCKS
*/
static blkcnt_t
{
mulvol = 0; /* definitely not mulvol, but we must */
return (0); /* took out setting of NotTape */
}
"tar: sizes below %luK not supported (%" FMT_blkcnt_t
"bad size entry for %s in %s.\n"),
done(1);
}
mulvol++;
NotTape++; /* implies non-tape */
}
/*
* bcheck()
* - checks the validity of blocking factors
* - returns blocking factor
*/
static int
{
"tar: invalid blocksize \"%s\".\n"), bstr);
if (!bflag)
"bad blocksize entry for '%s' in %s.\n"),
done(1);
}
return ((int)bval);
}
/*
* defset()
* - reads DEF_FILE for the set of default values specified.
* - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
* - 'usefile' points to static data, so will be overwritten
* if this routine is called a second time.
* - the pattern specified by 'arch' must be followed by four
* blank-separated fields (1) device (2) blocking,
* (3) size(K), and (4) tape
*/
static int
{
char *bp;
return (FALSE);
"tar: error setting parameters for %s.\n"), DEF_FILE);
return (FALSE); /* & following ones too */
}
"tar: missing or invalid '%s' entry in %s.\n"),
return (FALSE);
}
return (FALSE);
}
"tar: block component missing in '%s' entry in %s.\n"),
return (FALSE);
}
"tar: size component missing in '%s' entry in %s.\n"),
return (FALSE);
}
else
return (TRUE);
}
/*
* Following code handles excluded and included files.
* A hash table of file names to be {in,ex}cluded is built.
* For excluded files, before writing or extracting a file
* check to see if it is in the exclude_tbl.
* For included files, the wantit() procedure will check to
* see if the named file is in the include_tbl.
*/
static void
{
/* Only add to table if line has something in it */
}
}
/*
* Add a file name to the the specified table, if the file name has any
* trailing '/'s then delete them before inserting into the table
*/
static void
{
unsigned int h;
}
sizeof (char))) == NULL) {
exit(1);
}
exit(1);
}
}
/*
* See if a file name or any of the file's parent directories is in the
* specified table, if the file name has any trailing '/'s then delete
* them before searching the table
*/
static int
{
unsigned int h;
char *ptr;
}
/*
* check for the file name in the passed list
*/
return (1);
}
}
/*
* check for any parent directories in the file list
*/
return (1);
}
}
}
return (0);
}
/*
* Compute a hash from a string.
*/
static unsigned int
{
char *cp;
unsigned int h;
h = 0;
h += *cp;
}
return (h % TABLE_SIZE);
}
static void *
{
"tar: out of memory, link and directory modtime "
"info lost\n"));
freemem = 0;
if (errflag)
done(1);
else
Errflg = 1;
}
return (p);
}
/*
* vperror() --variable argument perror.
* Takes 3 args: exit_status, formats, args. If exit_status is 0, then
* the errflag (exit on error) is checked -- if it is non-zero, tar exits
* with the value of whatever "errno" is set to. If exit_status is not
* zero, then tar exits with that error status. If errflag and exit_status
* are both zero, the routine returns to where it was called and sets Errflg
* to errno.
*/
static void
{
if (exit_status)
else
if (errflag)
else
}
static void
{
done(1);
}
/*
* Check to make sure that argument is a char * ptr.
* Actually, we just check to see that it is non-null.
* If it is null, print out the message and call usage(), bailing out.
*/
static void
{
if (s == NULL) {
usage();
}
}
static void
{
"tar: %s error: "), operation);
if (i < 0)
perror("");
else
}
static int
{
char **cp;
int ret;
top:
xhdr_flgs = 0;
}
getdir();
if (Xhdrflag > 0) {
if (ret != 0) { /* Xhdr items and regular header */
passtape();
return (0); /* Error--don't want to extract */
}
}
/*
* If typeflag is not 'A' and xhdr_flgs is set, then processing
* of ancillary file is either over or ancillary file
* processing is not required, load info from Xtarhdr and set
* _X_XHDR bit in xhdr_flgs.
*/
}
#if defined(O_XATTR)
/*
* Always needs to read the extended header. If atflag, saflag,
* or tflag isn't set, then we'll have the correct info for
* passtape() later.
*/
(void) read_xattr_hdr(attrinfo);
goto top;
}
/*
* Now that we've read the extended header, call passtape()
* if we don't want to restore attributes or system 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 is 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.
*/
if (!tflag &&
ainfo->attr_rw_sysattr)) ||
!ainfo->attr_rw_sysattr)))) {
passtape();
return (0);
}
}
#endif
/* sets *namep to point at the proper name */
passtape();
return (0);
}
if (endtape()) {
if (Bflag) {
/*
* Logically at EOT - consume any extra blocks
* so that write to our stdin won't fail and
* emit an error message; otherwise something
* like "dd if=foo.tar | (cd bar; tar xvf -)"
* will produce a bogus error message from "dd".
*/
extra_blocks += sz;
}
dlog("wantit(): %d bytes of extra blocks\n",
}
dlog("wantit(): at end of tape.\n");
return (-1);
}
gotit = 0;
gotit = 1;
} else {
gotit = 1;
break;
}
}
}
if (! gotit) {
passtape();
return (0);
}
if (vflag) {
*namep);
}
passtape();
return (0);
}
return (1);
}
static void
{
/*
* In a scenario where a typeflag 'X' was followed by
* a typeflag 'A' and typeflag 'O', then the number of
* bytes to skip should be the size of ancillary file,
* plus the dblock for regular file, and the size
* from Xtarhdr. However, if the typeflag was just 'X'
* followed by typeflag 'O', then the number of bytes
* to skip should be the size from Xtarhdr.
*/
}
}
static int
{
char *tpath;
char *tparent;
/* parent info */
if (attrparent != NULL) {
"unable to allocate memory for attribute parent "
"name for %sattribute %s/%s of %s"),
return (1);
}
} else {
}
/* path info */
if (attrparent != NULL) {
}
"unable to allocate memory for full "
"attribute path name for %sattribute %s%s%s of %s"),
}
return (1);
}
attr);
/* fill in the attribute info */
"unable to allocate memory for attribute "
"information for %sattribute %s%s%s of %s"),
}
return (1);
}
} else {
}
}
/*
* The parent file descriptor is passed in, so don't
* close it here as it should be closed by the function
* that opened it.
*/
}
return (0);
}
/*
* Test to see if name is a directory.
*
* Return 1 if true, 0 otherwise.
*/
static int
{
#if defined(O_XATTR)
/*
* If there is an xattr_buf structure associated with this file,
* then the directory test is based on whether the name has a
* trailing slash.
*/
if (xattrp)
#endif
if (is_posix)
else
}
/*
* Version of chdir that handles directory pathnames of greater than PATH_MAX
* length, by changing the working directory to manageable portions of the
* complete directory pathname. If any of these attempts fail, then it exits
* non-zero.
*
* If a segment (i.e. a portion of "path" between two "/"'s) of the overall
* pathname is greater than PATH_MAX, then this still won't work, and this
* routine will return -1 with errno set to ENAMETOOLONG.
*
* NOTE: this routine is semantically different to the system chdir in
* that it is remotely possible for the currently working directory to be
* changed to a different directory, if a chdir call fails when processing
* one of the segments of a path that is greater than PATH_MAX. This isn't
* a problem as this is tar's own specific version of chdir.
*/
static int
{
/* The trivial case. */
return (0);
}
if (errno == ENAMETOOLONG) {
return (-1);
/* strtok(3C) modifies the string, so make a copy. */
return (-1);
}
/* chdir(2) for every path element. */
return (-1);
}
}
return (0);
}
/* If chdir fails for any reason except ENAMETOOLONG. */
return (-1);
}
/*
* Test if name has a '..' sequence in it.
*
* Return 1 if found, 0 otherwise.
*/
static int
{
char *s;
if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
return (1);
while (! (*s == '/')) {
if (! *s++)
return (0);
}
}
return (0);
}
/*
* Test if name is an absolute path name.
*
* Return 1 if true, 0 otherwise.
*/
static int
{
#if defined(O_XATTR)
/*
* If this is an extended attribute (whose name will begin with
* the name intact, to allow other tar archiving programs that
* don't understand extended attributes, to correctly throw them away.
*/
if (xattrp)
return (0);
#endif
return (name[0] == '/');
}
/*
* Adjust the pathname to make it a relative one. Strip off any leading
* '/' characters and if the pathname contains any '..' sequences, strip
* upto and including the last occurance of '../' (or '..' if found at
* the very end of the pathname).
*
* Return the relative pathname. stripped_prefix will also return the
* portion of name that was stripped off and should be freed by the
* calling routine when no longer needed.
*/
static char *
{
char *s;
if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
do {
char c = *s++;
if (c == '/')
break;
} while (*s);
}
continue;
prefix_len = s - name;
/* Create the portion of the name that was stripped off. */
s[prefix_len] = 0;
*stripped_prefix = s;
s = &name[prefix_len];
return (s);
}
/*
* Return through *namep a pointer to the proper fullname (i.e "<name> |
* <prefix>/<name>"), as represented in the header entry dblock.dbuf.
*
* Returns 0 if successful, otherwise returns 1.
*/
static int
{
char *s;
} else {
else
}
/*
* If we are printing a table of contents or extracting an archive,
* make absolute pathnames relative and prohibit the unpacking of
* files contain ".." in their name (unless the user has supplied
* the -P option).
*/
char *stripped_prefix;
gettext("tar: Removing leading '%s' from '%s'\n"),
}
}
/*
* Set dir and component names
*/
#if defined(O_XATTR)
#endif
/*
* Save of real name since were going to chop off the
* trailing slashes.
*/
/*
* first strip of trailing slashes.
*/
s = get_component(savename);
#if defined(O_XATTR)
} else {
}
#endif
return (0);
}
/*
* Return true if the object indicated by the file descriptor and type
* is a tape device, false otherwise
*/
static int
{
int result = 0;
result = 1;
}
}
return (result);
}
#include <utmpx.h>
} cachenode_t;
static int
{
int i, c, h = 0;
for (i = 0; i < NMAX; i++) {
c = name[i];
if (c == '\0')
break;
h = (h << 4) + h + c;
}
return (h);
}
static cachenode_t *
{
int h = val;
cachenode_t *c;
return (c);
}
return (NULL);
}
static cachenode_t *
{
int h = hash_byname(name);
cachenode_t *c;
return (c);
}
return (NULL);
}
static cachenode_t *
{
cachenode_t *c;
int signature;
if (c == NULL) {
perror("malloc");
exit(1);
}
}
else
return (c);
}
static char *
{
cachenode_t *c;
}
return (c->name);
}
static char *
{
cachenode_t *c;
}
return (c->name);
}
static uid_t
{
cachenode_t *c;
}
}
static gid_t
{
cachenode_t *c;
}
}
/*
* Build the header.
* Determine whether or not an extended header is also needed. If needed,
* create and write the extended header and its data.
* Writing of the extended header assumes that "tomodes" has been called and
* the relevant information has been placed in the header block.
*/
static int
const char *name,
const char *linkname,
const char typeflag,
const int filetype,
const char *prefix)
{
int nblks;
const char *filename;
const char *lastslash;
if (filetype == XATTR_FILE)
else
else
if (Eflag) {
xhdr_flgs |= _X_DEVMAJOR;
} else {
"Device major too large for %s. Use -E flag."),
filename);
if (errflag)
done(1);
else
Errflg = 1;
}
dev = 0;
}
if (Eflag) {
xhdr_flgs |= _X_DEVMINOR;
} else {
"Device minor too large for %s. Use -E flag."),
filename);
if (errflag)
done(1);
else
Errflg = 1;
}
dev = 0;
}
if (Eflag) {
else
lastslash++;
xhdr_count++;
xrec_offset = 0;
if (gen_utf8_names(filename) != 0)
return (1);
#ifdef XHDR_DEBUG
#endif
if (xhdr_flgs) {
if (xhdr_flgs & _X_DEVMAJOR)
if (xhdr_flgs & _X_DEVMINOR)
if (xhdr_flgs & _X_LINKPATH)
}
}
return (0);
}
/*
* makeDir - ensure that a directory with the pathname denoted by name
* exists, and return 1 on success, and 0 on failure (e.g.,
* read-only file system, exists but not-a-directory).
*/
static int
{
return (0);
}
} else { /* name exists */
return (0);
}
}
return (1);
}
/*
* Save this directory and its mtime on the stack, popping and setting
* the mtimes of any stacked dirs which aren't parents of this one.
* A null name causes the entire stack to be unwound and set.
*
* Since all the elements of the directory "stack" share a common
* prefix, we can make do with one string. We keep only the current
* directory path, with an associated array of mtime's. A negative
* mtime means no mtime.
*
* This stack algorithm is not guaranteed to work for tapes created
* with the 'r' function letter, but the vast majority of tapes with
* directories are not. This avoids saving every directory record on
* the tape and setting all the times at the end.
*
* (This was borrowed from the 4.1.3 source, and adapted to the 5.x
* environment)
*/
static void
{
/* Add spaces for the last slash and last NULL */
char *p = dirstack;
char *q = name;
char *savp;
if (q) {
/*
* Find common prefix
*/
while (*p == *q && *p) {
p++; q++;
}
}
savp = p;
while (*p) {
/*
* Not a child: unwind the stack, setting the times.
* The order we do this doesn't matter, so we go "forward."
*/
if (*p == '/')
*p = '\0'; /* zap the slash */
*p = '/';
}
++p;
}
p = savp;
/*
* Push this one on the "stack"
*/
if (q) {
/*
* Since the name parameter points the dir pathname
* which is limited only to contain PATH_MAX chars
* at maximum, we can ignore the overflow case of p.
*/
while ((*p = *q++)) { /* append the rest of the new dir */
p++;
}
/*
* If the tar file had used 'P' or 'E' function modifier,
* append the last slash.
*/
if (*(p - 1) != '/') {
*p++ = '/';
*p = '\0';
}
/* overwrite the last one */
}
}
/*
* setPathTimes - set the modification time for given path. Return 1 if
* successful and 0 if not successful.
*/
static void
{
/*
* futimesat takes an array of two timeval structs.
* The first entry contains access time.
* The second entry contains modification time.
* Unlike a timestruc_t, which uses nanoseconds, timeval uses
* microseconds.
*/
/* Extended header: use microseconds */
}
/*
* If hflag is set then delete the symbolic link's target.
* If !hflag then delete the target.
*/
static void
{
int n;
PATH_MAX)) != -1) {
} else {
}
} else {
}
}
}
}
/*
* ACL changes:
* putfile():
* Get acl info after stat. Write out ancillary file
* before the normal file, i.e. directory, regular, FIFO,
* link, special. If acl count is less than 4, no need to
* create ancillary file. (i.e. standard permission is in
* use.
* doxtract():
* Process ancillary file. Read it in and set acl info.
* watch out for 'o' function modifier.
* 't' function letter to display table
*/
/*
* New functions for ACLs and other security attributes
*/
/*
* The function appends the new security attribute info to the end of
* existing secinfo.
*/
int
char **secinfo, /* existing security info */
int *secinfo_len, /* length of existing security info */
int size, /* new attribute size: unit depends on type */
char *attrtext, /* new attribute text */
char attr_type) /* new attribute type */
{
char *new_secinfo;
int newattrsize;
int oldsize;
/* no need to add */
return (0);
}
switch (attr_type) {
case UFSD_ACL:
case ACE_ACL:
return (-1);
}
/* header: type + size = 8 */
gettext("can't allocate memory\n"));
return (-1);
}
break;
/* Trusted Extensions */
case DIR_TYPE:
case LBL_TYPE:
gettext("can't allocate memory\n"));
return (-1);
}
break;
default:
gettext("unrecognized attribute type\n"));
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);
}
/*
* write_ancillary(): write out an ancillary file.
* The file has the same header as normal file except the type and size
* fields. The type is 'A' and size is the sum of all attributes
* in bytes.
* The body contains a list of attribute type, size and info. Currently,
* there is only ACL info. This file is put before the normal file.
*/
void
{
long blocks;
int savflag;
int savsize;
/* Just tranditional permissions or no security attribute info */
return;
/* save flag and size */
/* special flag for ancillary file */
if (hdrtype == _XATTR_HDRTYPE)
else
/* for pre-2.5 versions of tar, need to make sure */
/* the ACL file is readable */
/* write out the header */
/* write out security info */
/* restore mode, flag and size */
}
/*
* Read the data record for extended headers and then the regular header.
* The data are read into the buffer and then null-terminated. Entries
* for typeflag 'X' extended headers are of the format:
* "%d %s=%s\n"
*
* When an extended header record is found, the extended header must
* be processed and its values used to override the values in the
* normal header. The way this is done is to process the extended
* header data record and set the data values, then call getdir
* to process the regular header, then then to reconcile the two
* sets of data.
*/
static int
get_xdata(void)
{
struct keylist_pair {
int keynum;
char *keylist;
_X_DEVMINOR, "SUN.devminor",
_X_GID, "gid",
_X_GNAME, "gname",
_X_LINKPATH, "linkpath",
_X_PATH, "path",
_X_SIZE, "size",
_X_UID, "uid",
_X_UNAME, "uname",
_X_MTIME, "mtime",
_X_LAST, "NULL" };
char *lineloc;
int length, i;
int bufneeded;
int errors;
xhdr_count++;
errors = 0;
}
while (nblocks-- > 0) {
}
keyword = "path";
} else {
}
i = 0;
break;
i++;
}
errno = 0;
switch (keylist_pair[i].keynum) {
case _X_DEVMAJOR:
if (errno) {
"tar: Extended header major value error "
"for file # %llu.\n"), xhdr_count);
errors++;
} else
xhdr_flgs |= _X_DEVMAJOR;
break;
case _X_DEVMINOR:
if (errno) {
"tar: Extended header minor value error "
"for file # %llu.\n"), xhdr_count);
errors++;
} else
xhdr_flgs |= _X_DEVMINOR;
break;
case _X_GID:
"tar: Extended header gid value error "
"for file # %llu.\n"), xhdr_count);
}
break;
case _X_GNAME:
break;
case _X_LINKPATH:
xhdr_flgs |= _X_LINKPATH;
else
errors++;
break;
case _X_PATH:
else
errors++;
break;
case _X_SIZE:
if (errno) {
"tar: Extended header invalid filesize "
"for file # %llu.\n"), xhdr_count);
errors++;
} else
break;
case _X_UID:
"tar: Extended header uid value error "
"for file # %llu.\n"), xhdr_count);
}
break;
case _X_UNAME:
break;
case _X_MTIME:
if (errno)
"tar: Extended header modification time "
"value error for file # %llu.\n"),
else
break;
default:
gettext("tar: unrecognized extended"
" header keyword '%s'. Ignored.\n"), keyword);
break;
}
}
getdir(); /* get regular header */
done(1);
else
if (errors)
Errflg = 1;
return (errors);
}
/*
* load_info_from_xtarhdr - sets Gen and stbuf variables from
* extended header
* load_info_from_xtarhdr(flag, xhdrp);
* u_longlong_t flag; xhdr_flgs
* struct xtar_hdr *xhdrp; pointer to extended header
* NOTE: called when typeflag is not 'A' and xhdr_flgs
* is set.
*/
static void
{
if (flag & _X_DEVMAJOR) {
}
if (flag & _X_DEVMINOR) {
}
}
}
}
}
}
/*
* gen_num creates a string from a keyword and an usigned long long in the
* format: %d %s=%s\n
* This is part of the extended header data record.
*/
void
{
int len;
char *curr_ptr;
/*
* len = length of entire line, including itself. len will be
* two digits. So, add the string lengths plus the length of len,
* plus a blank, an equal sign, and a newline.
*/
"cannot allocate extended header buffer"));
xrec_size *= 2;
}
xrec_offset += len;
}
/*
* gen_date creates a string from a keyword and a timestruc_t in the
* format: %d %s=%s\n
* This is part of the extended header data record.
* Currently, granularity is only microseconds, so the low-order three digits
* will be truncated.
*/
void
{
/* Allow for <seconds>.<nanoseconds>\n */
int len;
char *curr_ptr;
/*
* len = length of entire line, including itself. len will be
* two digits. So, add the string lengths plus the length of len,
* plus a blank, an equal sign, and a newline.
*/
"cannot allocate extended header buffer"));
xrec_size *= 2;
}
xrec_offset += len;
}
/*
* gen_string creates a string from a keyword and a char * in the
* format: %d %s=%s\n
* This is part of the extended header data record.
*/
void
{
int len;
char *curr_ptr;
/*
* len = length of entire line, including itself. The character length
* of len must be 1-4 characters, because the maximum size of the path
* or the name is PATH_MAX, which is 1024. So, assume 1 character
* for len, one for the space, one for the "=", and one for the newline.
* Then adjust as needed.
*/
/* LINTED constant expression */
if (len > 997)
len += 3;
else if (len > 98)
len += 2;
else if (len > 9)
len += 1;
"cannot allocate extended header buffer"));
xrec_size *= 2;
}
#ifdef XHDR_DEBUG
#endif
#ifdef XHDR_DEBUG
else {
len += 11;
}
#endif
xrec_offset += len;
}
/*
* Convert time found in the extended header data to seconds and nanoseconds.
*/
void
{
char *period;
int i;
period[0] = '\0';
else {
}
}
/*
* Check linkpath for length.
* Emit an error message and return 1 if too long.
*/
int
char *name,
char *longname,
char *linkname,
char *prefix,
char type,
int filetype)
{
if (Eflag > 0) {
xhdr_flgs |= _X_LINKPATH;
} else {
"tar: %s: linked name too long\n"), linkname);
if (errflag)
done(1);
else
Errflg = 1;
return (1);
}
}
if (xhdr_flgs & _X_LINKPATH)
prefix));
else
}
/*
* Convert from UTF-8 to local character set.
*/
static int
char *option,
char **Xhdr_ptrptr,
char *target,
const char *source,
int max_val)
{
char *nl_target;
const char *iconv_src;
char *iconv_trg;
"tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
xhdr_count, source);
return (1);
} else if (charset_type == 0) { /* iconv_open has not yet been done */
nl_target = "646";
charset_type = 1;
charset_type = 3;
else {
nl_target += 3;
charset_type = 2;
errno = 0;
(iconv_t)-1) {
"tar: conversion routines not "
"available for current locale. "));
"file # %llu: (%s) UTF-8 conversion"
charset_type = -1;
return (1);
}
}
}
/* locale using 7-bit codeset or UTF-8 locale */
"tar: file # %llu: Extended header %s too long.\n"),
xhdr_count, option);
return (1);
}
if (charset_type == 3)
"tar: file # %llu: (%s) UTF-8 conversion"
return (1);
}
*Xhdr_ptrptr = target;
return (0);
}
"tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
xhdr_count, source);
/* Get remaining output; reinitialize conversion descriptor */
inlen = 0;
return (1);
}
/* Get remaining output; reinitialize conversion descriptor */
inlen = 0;
"tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
xhdr_count, source);
return (1);
}
"tar: file # %llu: Extended header %s too long.\n"),
xhdr_count, option);
return (1);
}
*Xhdr_ptrptr = target;
return (0);
}
/*
* Check gname, uname, path, and linkpath to see if they need to go in an
* extended header. If they are already slated to be in an extended header,
* or if they are not ascii, then they need to be in the extended header.
* Then, convert all extended names to UTF-8.
*/
int
{
char *nl_target;
int nbytes;
int errors;
"tar: file # %llu: UTF-8 conversion failed.\n"),
return (1);
}
if (charset_type == 0) { /* Need to get conversion descriptor */
nl_target = "646";
charset_type = 1;
charset_type = 3;
else {
nl_target += 3;
charset_type = 2;
errno = 0;
#ifdef ICONV_DEBUG
gettext("Opening iconv_cd with target %s\n"),
#endif
(iconv_t)-1) {
"tar: conversion routines not "
"available for current locale. "));
"file (%s): UTF-8 conversion failed.\n"),
filename);
charset_type = -1;
return (1);
}
}
}
errors = 0;
}
if (nbytes > 0) {
}
}
if (errors > 0)
"tar: file (%s): UTF-8 conversion failed.\n"), filename);
done(1);
else
if (errors)
Errflg = 1;
return (errors);
}
static int
char **Xhdr_ptrptr,
char *target,
const char *source,
int xhdrflg,
int max_val)
{
const char *iconv_src;
const char *starting_src;
char *iconv_trg;
#ifdef ICONV_DEBUG
unsigned char c_to_hex;
#endif
/*
* If the item is already slated for extended format, get the string
* to convert from the extended header record. Otherwise, get it from
* the regular (dblock) area.
*/
*Xhdr_ptrptr = target;
return (0);
} else
iconv_src = (const char *) *Xhdr_ptrptr;
} else {
return (0); /* Don't create xhdr record */
}
return (0);
gettext("tar: invalid character in"
" UTF-8 conversion of '%s'\n"), starting_src);
return (1);
}
return (0);
}
errno = 0;
(size_t)-1) {
/* An error occurred, or not all characters were converted */
gettext("tar: invalid character in"
" UTF-8 conversion of '%s'\n"), starting_src);
else
"tar: conversion to UTF-8 aborted for '%s'.\n"),
/* Get remaining output; reinitialize conversion descriptor */
inlen = 0;
return (1);
}
/* Get remaining output; reinitialize conversion descriptor */
inlen = 0;
gettext("tar: invalid character in"
" UTF-8 conversion of '%s'\n"), starting_src);
else
"tar: conversion to UTF-8 aborted for '%s'.\n"),
return (1);
}
*Xhdr_ptrptr = target;
#ifdef ICONV_DEBUG
}
}
#endif
}
return (0);
}
/*
* Function to test each byte of the source string to make sure it is
* in within bounds (value between 0 and 127).
* If valid, copy source to target.
*/
int
{
const char *thischar;
while (len-- > 0) {
return (1);
}
return (0);
}
#if defined(O_XATTR)
static void
char **attrbuf,
char *filename,
char *attrpath,
char typeflag,
int *rlen)
{
char *aptr;
/*
* length of filename + attr
* in link section
*/
int linkstringlen;
/*
* Release previous buffer
*/
}
/*
* 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(
}
}
#else
static void
char **attrbuf,
char *filename,
char *attrname,
char typeflag,
int *rlen)
{
*rlen = 0;
}
#endif
int
{
int i, j;
int printerr;
int slnkerr;
if (!hflag)
else
if (i < 0) {
/* Initialize flag to print error mesg. */
printerr = 1;
/*
* If stat is done, then need to do lstat
* to determine whether it's a sym link
*/
if (hflag) {
/* Save returned error */
/*
* Suppress error message when file is a symbolic link
* and function modifier 'l' is off. Exception: when
* a symlink points to a symlink points to a
* symlink ... and we get past MAXSYMLINKS. That
* error will cause a file not to be archived, and
* needs to be printed.
*/
printerr = 0;
/*
* Restore errno in case the lstat
* on symbolic link change
*/
}
if (printerr) {
"tar: %s%s%s%s: %s\n"),
Errflg = 1;
}
return (1);
}
return (0);
}
/*
* of the base file, longname. Note: extended system attribute files will be
* archived only if the extended system attributes are not transient (i.e. the
* extended system attributes are other than the default values).
*
* If -@ was specified and the underlying file system supports it, archive the
* extended attributes, and if there is a system attribute associated with the
* extended attribute, then recursively call xattrs_put() to archive the
* hidden attribute directory and the extended system attribute. If -/ was
* specified and the underlying file system supports it, archive the extended
* system attributes. Read-only extended system attributes are never archived.
*
* Currently, there cannot be attributes on attributes; only system
* attributes on attributes. In addition, there cannot be attributes on
* system attributes. A file and it's attribute directory hierarchy looks as
* follows:
* longname ----> . ("." is the hidden attribute directory)
* |
* ----------------------------
* | |
* <sys_attr_name> <attr_name> ----> .
* |
* <sys_attr_name>
*
*/
#if defined(O_XATTR)
static void
{
int arc_rwsysattr = 0;
int dirfd;
int rw_sysattr = 0;
int ext_attr = 0;
int rc;
/*
* If the underlying file system supports it, then archive the extended
* attributes if -@ was specified, and the extended system attributes
* if -/ was specified.
*/
return;
}
/*
* Only want to archive a read-write extended system attribute file
* if it contains extended system attribute settings that are not the
* default values.
*/
#if defined(_PC_SATTR_ENABLED)
if (saflag) {
int filefd;
/* Determine if there are non-transient system attributes */
errno = 0;
if (attrparent == NULL) {
"unable to open file %s"), longname);
}
return;
}
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 */
/* open the parent attribute directory */
if (fd < 0) {
"unable to open attribute directory for %s%s%sfile %s"),
longname);
return;
}
/*
* We need to change into the parent's attribute directory to determine
* if each of the attributes should be archived.
*/
"cannot change to attribute directory of %s%s%sfile %s"),
longname);
return;
}
"tar: unable to open dir pointer for %s%s%sfile %s\n"),
longname);
if (fd > 0) {
}
return;
}
continue;
Hiddendir = 1;
} else {
Hiddendir = 0;
}
/* Determine if this attribute should be archived */
&rw_sysattr) != ATTR_OK) {
continue;
}
/* gather the attribute's information to pass to putfile() */
continue;
}
/* add the attribute to the archive */
if (exitflag) {
break;
}
#if defined(_PC_SATTR_ENABLED)
/*
* If both -/ and -@ were specified, then archive the
* attribute's extended system attributes and hidden directory
* by making a recursive call to xattrs_put().
*/
(Hiddendir == 0)) {
/*
* Change back to the parent's attribute directory
* to process any further attributes.
*/
"cannot change back to attribute directory "
"of file %s"), longname);
break;
}
}
#endif /* _PC_SATTR_ENABLED */
}
}
}
if (fd != -1) {
}
/* Change back to the parent directory of the base file */
if (attrparent == NULL) {
}
Hiddendir = 0;
}
#else
static void
{
}
#endif /* O_XATTR */
static int
{
int found = 0;
found++;
break;
}
if (found) {
#if defined(O_XATTR)
if (filetype == XATTR_FILE)
goto out;
}
#endif
if (filetype != XATTR_FILE) {
goto out;
}
}
newvol();
/*
* write_ancillary() is not needed here.
* The first link is handled in the following
* else statement. No need to process ACLs
* for other hard links since they are the
* same file.
*/
if (vflag) {
if (NotTape)
"K\n", K(tapepos));
if (filetype == XATTR_FILE) {
"a %s attribute %s link to "
"%s attribute %s\n"),
} else {
"a %s link to %s\n"),
}
}
return (0);
} else {
if (filetype == XATTR_FILE) {
} else {
}
}
}
}
out:
return (1);
}
static int
{
int error;
}
#if defined(O_XATTR)
return (1);
}
}
#endif
/* ACL support */
if (pflag) {
int len = 0;
/* ACL support */
/*
* Get ACL info: dont bother allocating space if
* there is only a trivial ACL.
*/
&aclp)) != 0) {
"%s: failed to retrieve acl : %s\n"),
return (1);
}
}
/* append security attributes if any */
}
if (Tflag) {
/* append Trusted Extensions extended attributes */
}
}
return (0);
}
#if defined(O_XATTR)
static int
{
int error = 0;
int attrlen;
}
}
"Buffer overflow writing extended attribute file name"));
}
/*
* dump extended attr lookup info
*/
/*
* Set up filename for attribute
*/
return (error);
}
#endif
#if defined(O_XATTR)
static int
{
char *tp;
int namelen;
int attrparentlen;
int parentfilelen;
return (1);
"Insufficient memory for extended attribute\n"));
return (1);
}
while (blocks-- > 0) {
break;
} else {
}
}
/*
* Validate that we can handle header format
*/
gettext("Unknown extended attribute format encountered\n"));
gettext("Disabling extended attribute parsing\n"));
xattrbadhead = 1;
return (0);
}
sizeof (struct xattr_hdr));
if (link_len > 0)
xattr_linkp = (struct xattr_buf *)
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 (1);
}
/* Gather link info */
if (xattr_linkp) {
} else {
}
return (0);
}
#else
static int
{
return (0);
}
#endif
/*
* skip over extra slashes in string.
*
* For example:
*
* would return pointer at
* ^
*/
static char *
{
string--;
}
return (string);
}
/*
* 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 char *
{
char *ptr;
return (path);
} else {
/*
* Handle trailing slash
*/
return (ptr);
else
return (ptr + 1);
}
}
#else
static char *
{
return (path);
}
#endif
#if defined(O_XATTR)
static int
{
int dirfd;
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);
}
"tar: cannot stat %sfile %s: %s\n"),
return (-1);
}
"tar: failed to retrieve ACL on %sfile %s: %s\n"),
return (-1);
}
"tar: cannot fchmod %sfile %s to %o: %s\n"),
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
*/
gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
}
if (aclp) {
if (error) {
gettext("tar: failed to set acl entries on "
"%sfile %s\n"),
}
}
/*
* Put back time stamps
*/
return (ofilefd);
}
#endif
#if !defined(O_XATTR)
static int
{
}
static int
{
}
static int
{
if (flag == AT_SYMLINK_NOFOLLOW)
else
}
static int
{
}
static int
{
}
static int
{
if (flag == AT_REMOVEDIR)
else
}
static int
{
if (flag == AT_SYMLINK_NOFOLLOW)
else
}
static int
{
return (-1);
}
#endif
static void
{
/*
* Chop of slashes, but not if all we have is slashes
* for example: ////
* should make no changes, otherwise it will screw up
* checkdir
*/
*ptr = '\0';
}
}
}
/* Trusted Extensions */
/*
* append_ext_attr():
*
* Append extended attributes and other information into the buffer
* that gets written to the ancillary file.
*
* With option 'T', we create a tarfile which
* has an ancillary file each corresponding archived file.
* Each ancillary file contains 1 or more of the
* following attributes:
*
* attribute type attribute process procedure
* ---------------- ---------------- --------------------------
* DIR_TYPE = 'D' directory flag append if a directory
* LBL_TYPE = 'L' SL[IL] or SL append ascii label
*
*
*/
static void
{
/*
* For each attribute type, append it if it is
* relevant to the file type.
*/
/*
* For attribute type DIR_TYPE,
* append it to the following file type:
*
* S_IFDIR: directories
*/
/*
* For attribute type LBL_TYPE,
* append it to the following file type:
*
* S_IFDIR: directories (including mld, sld)
* S_IFLNK: symbolic link
* S_IFREG: regular file but not hard link
* S_IFIFO: FIFO file but not hard link
* S_IFCHR: char special file but not hard link
* S_IFBLK: block special file but not hard link
*/
case S_IFDIR:
/*
* append DIR_TYPE
*/
"\0", DIR_TYPE);
/*
* Get and append attribute types LBL_TYPE.
* For directories, LBL_TYPE contains SL.
*/
/* get binary sensitivity label */
gettext("tar: can't get sensitvity label for "
" %s, getlabel() error: %s\n"),
} else {
/* get ascii SL */
0, 0) <= 0) {
gettext("tar: can't get ascii SL for"
" %s\n"), shortname);
} else {
/* append LBL_TYPE */
LBL_TYPE);
/* free storage */
ascii = (char *)0;
}
}
}
break;
case S_IFLNK:
case S_IFREG:
case S_IFIFO:
case S_IFCHR:
case S_IFBLK:
/* get binary sensitivity label */
gettext("tar: can't get sensitivty label for %s, "
"getlabel() error: %s\n"),
} else {
/* get ascii IL[SL] */
gettext("tar: can't translate sensitivity "
" label for %s\n"), shortname);
} else {
char *cmw_label;
"Insufficient memory for label\n"));
exit(1);
}
/* append LBL_TYPE */
"ADMIN_LOW [%s]", ascii);
LBL_TYPE);
/* free storage */
ascii = (char *)0;
}
}
}
break;
default:
break;
} /* end switch for LBL_TYPE */
/* DONE !! */
return;
} /* end of append_ext_attr */
/*
* Name: extract_attr()
*
* Description:
* Process attributes from the ancillary file due to
* the T option.
*
* Call by doxtract() as part of the switch case structure.
* Making this a separate routine because the nesting are too
* deep in doxtract, thus, leaving very little space
* on each line for instructions.
*
* With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
*
* For option 'T', following are possible attributes in
* a TS 8 ancillary file: (NOTE: No IL support)
*
* attribute type attribute process procedure
* ---------------- ---------------- -------------------------
* # LBL_TYPE = 'L' SL construct binary label
* # APRIV_TYPE = 'P' allowed priv construct privileges
* # FPRIV_TYPE = 'p' forced priv construct privileges
* # COMP_TYPE = 'C' path component construct real path
* # DIR_TYPE = 'D' directory flag note it is a directory
* $ UFSD_ACL = '1' ACL data construct ACL entries
* ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
* LK_COMP_TYPE = 'K' linked path comp construct linked real path
*
* note: # = attribute names common between TS 8 & TS 2.5 ancillary
* files.
* $ = ACL attribute is processed for the option 'p', it doesn't
* need option 'T'.
*
* Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
*
*/
static void
{
case DIR_TYPE:
dir_flag++;
break;
case LBL_TYPE:
/*
* LBL_TYPE is used to indicate SL for directory, and
* CMW label for other file types.
*/
if (!dir_flag) { /* not directory */
/* Skip over IL portion */
err = 0;
else
} else { /* directory */
}
if (err == 0) {
"can't convert %s to binary label\n"),
char *buf;
if (*orig_namep != '/') {
/* got relative linked to path */
} else
*tempbuf = '\0';
if (from_label != NULL) {
gettext("tar: "
"can't get zone root path for "
"%s\n"), tempbuf);
} else
rpath_flag = 1;
}
}
}
break;
case COMP_TYPE:
break;
case LK_COMP_TYPE:
== 0) {
lk_rpath_flag = 1;
} else {
"target pathname might be invalid.\n"));
lk_rpath_flag = 0;
}
break;
case APRIV_TYPE:
break;
case FPRIV_TYPE:
break;
case ATTR_FLAG_TYPE:
break;
default:
break;
}
/* done */
return;
} /* end extract_attr */
/*
* Name: rebuild_comp_path()
*
* Description:
* Take the string of components passed down by the calling
* routine and parse the values and rebuild the path.
* This routine no longer needs to produce a new real_path
* string because it is produced when the 'L' LABEL_TYPE is
* interpreted. So the only thing done here is to distinguish
* between an SLD and an MLD entry. We only want one, so we
* ignore the MLD entry by setting the mld_flag.
*
* return value:
* none
*/
static void
{
char *cp;
while (*str != '\0') {
switch (*str) {
case MLD_TYPE:
str++;
*cp = '\0';
*cp = ';';
}
mld_flag = 1;
break;
case SLD_TYPE:
str++;
*cp = '\0';
*cp = ';';
}
mld_flag = 0;
break;
case PATH_TYPE:
str++;
*cp = '\0';
*cp = ';';
}
break;
}
}
if (rpath_flag)
return;
} /* end rebuild_comp_path() */
/*
* Name: rebuild_lk_comp_path()
*
* Description:
* Take the string of components passed down by the calling
* routine and parse the values and rebuild the path.
*
* return value:
* 0 = succeeded
* -1 = failed
*/
static int
{
char *cp;
int reterr;
char *buf;
int plen;
int use_pbuf;
int mismatch;
/* init stuff */
use_pbuf = 0;
mismatch = 0;
/*
* For linked to pathname (LK_COMP_TYPE):
* - If the linked to pathname is absolute (start with /), we
* will use it as is.
* - If it is a relative pathname then it is relative to 1 of 2
* directories. For a hardlink, it is relative to the current
* directory. For a symbolic link, it is relative to the
* directory the symbolic link is in. For the symbolic link
* case, set a flag to indicate we need to use the prefix of
* the restored file's pathname with the linked to pathname.
*
* NOTE: At this point, we have no way to determine if we have
* a hardlink or a symbolic link. We will compare the 1st
* component in the prefix portion of the restore file's
* pathname to the 1st component in the attribute data
* (the linked pathname). If they are the same, we will assume
* the link pathname to reconstruct is relative to the current
* directory. Otherwise, we will set a flag indicate we need
* to use a prefix with the reconstructed name. Need to compare
* both the adorned and unadorned version before deciding a
* mismatch.
*/
buf = lk_real_path;
ptr1 = orig_namep;
if (plen > 0) {
pbuf[0] = '\0';
plen++; /* include '/' */
mismatch = 1;
}
if (mismatch == 1)
use_pbuf = 1;
}
buf[0] = '\0';
while (*str != '\0') {
switch (*str) {
case MLD_TYPE:
str++;
*cp = '\0';
/*
* Ignore attempts to backup over .MLD.
*/
*cp = ';';
}
break;
case SLD_TYPE:
str++;
*cp = '\0';
/*
* Use the path name in the header if
* error occurs when processing the
* SLD type.
*/
NO_CORRECTION, &reterr)) {
"tar: can't translate to binary"
"SL for SLD, stobsl() error:"
return (-1);
}
*cp = ';';
if (use_pbuf == 1) {
if (*pbuf != '/') {
/* relative linked to path */
(sizeof (tempbuf)));
}
else
} else if (*buf != '/') {
/* got relative linked to path */
(sizeof (tempbuf)));
} else
*tempbuf = '\0';
*buf = '\0';
}
/*
* Check for cross-zone symbolic links
*/
if ((zoneid =
gettext("tar: can't get "
"zone ID for %s\n"),
tempbuf);
return (-1);
}
/* Badly configured zone info */
gettext("tar: can't get "
"zonename for %s\n"),
tempbuf);
return (-1);
}
}
if (from_label != NULL)
break;
}
mld_flag = 0;
break;
case PATH_TYPE:
str++;
*cp = '\0';
*cp = ';';
}
break;
default:
"tar: error rebuilding path %s\n"),
*namep);
*buf = '\0';
str++;
return (-1);
}
}
/*
* Done for LK_COMP_TYPE
*/
return (0); /* component path is rebuilt successfully */
} /* end rebuild_lk_comp_path() */
/*
* Name: check_ext_attr()
*
* Description:
* Check the extended attributes for a file being extracted.
* The attributes being checked here are CMW labels.
* ACLs are not set here because they are set by the
* pflag in doxtract().
*
* If the label doesn't match, return 0
* else return 1
*/
static int
{
/* No label check possible */
return (0);
}
gettext("tar: can't get label for "
" %s, getlabel() error: %s\n"),
return (0);
/* get current src SL */
gettext("tar: can't interpret requested label for"
" %s\n"), filename);
} else {
gettext("tar: can't apply label %s to %s\n"),
}
return (0);
}
return (1);
} /* end check_ext_attr */
/* Compressing a tar file using compression method provided in 'opt' */
static void
{
if (vflag) {
gettext("Compressing '%s' with '%s'...\n"),
}
} else if (pid == -1) {
}
if (suffix == 0) {
}
}
void
check_compression(void)
{
}
}
}
}
}
}
}
char *
{
return (gsuffix[0]);
}
return (gsuffix[6]);
}
return (bsuffix[0]);
}
return (xsuffix[0]);
}
}
return (NULL);
}
/* Decompressing a tar file using compression method from the file type */
void
decompress_file(void)
{
char *added_suffix;
added_suffix = add_suffix();
if (added_suffix != NULL) {
}
if (vflag) {
gettext("Decompressing '%s' with "
}
} else if (pid == -1) {
}
/* restore the file name - original file was without suffix */
}
}
/* Set the archive for writing and then compress the archive */
compress_file(void)
{
if (vflag) {
}
}
return (pid);
}
/* child */
return (0); /*NOTREACHED*/
}
uncompress_file(void)
{
if (vflag) {
}
}
return (pid);
}
/* child */
return (0); /*NOTREACHED*/
}
/* Checking suffix validity */
char *
{
int i;
int slen;
for (i = 0; i < size; i++) {
return (NULL);
return (suf[i]);
}
return (NULL);
}
/* Checking valid 'bzip2' suffix */
char *
bz_suffix(void)
{
}
/* Checking valid 'gzip' suffix */
char *
gz_suffix(void)
{
}
/* Checking valid 'xz' suffix */
char *
xz_suffix(void)
{
}
void *
{
void *opt;
gettext("Could not allocate compress buffer\n"));
}
return (opt);
}
void
{
int status;
;
}
static void
verify_compress_opt(const char *t)
{
}
static void
detect_compress(void)
{
Zflag = 1;
jflag = 1;
zflag = 1;
Jflag = 1;
} else {
}
}