cpio.c revision 4bc0a2ef2b7ba50a7a717e7ddbf31472ad28e358
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License, Version 1.0 only 2N/A * (the "License"). You may not use this file except in compliance 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 2N/A/* All Rights Reserved */ 2N/A * Portions of this source code were derived from Berkeley 4.3 BSD 2N/A * under license from the Regents of the University of California. 2N/A#
pragma ident "%Z%%M% %I% %E% SMI" * Special kludge for off_t being a signed quantity. * These limits reflect the maximum size regular file that * can be archived, depending on the archive type. For archives * with character-format headers (odc, tar, ustar) we use * CHAR_OFFSET_MAX. For archives with SVR4 ASCII headers (-c, -H crc) * we store filesize in an 8-char hexadecimal string and use * ASC_OFFSET_MAX. Otherwise, we are limited to the size that will * fit in a signed long value. static long mklong(
short v[]);
static int g_read(
int,
int,
char *,
unsigned);
static int g_write(
int,
int,
char *,
unsigned);
struct passwd *
Curpw_p,
/* Current password entry for -t option */ *
Rpw_p,
/* Password entry for -R option */struct group *
Curgr_p,
/* Current group entry for -t option */ /* Data structure for buffered I/O. */ char *
b_base_p,
/* Pointer to base of buffer */ *
b_out_p,
/* Position to take bytes from buffer at */ *
b_in_p,
/* Position to put bytes into buffer at */ *
b_end_p;
/* Pointer to end of buffer */ long b_cnt,
/* Count of unprocessed bytes */ b_size;
/* Size of buffer in bytes */ /* Generic header format */ g_ino,
/* Inode number of file */ int g_dirfd;
/* directory file descriptor */ /* Data structure for handling multiply-linked files */ short L_cnt,
/* Number of links encountered */ L_data;
/* Data has been encountered if 1 */ struct gen_hdr L_gen;
/* gen_hdr information for this file */ *
L_bck_p,
/* Previous file in list */ *
L_lnk_p;
/* Next link for this file */ * ------------------------------------------------------------------------- * Stuff needed to pre-view the name stream * issymlink is used to remember that the current file is a symlink between * getname() and file_pass(); the former trashes this information immediately struct sl_info *
llink;
/* Left subtree ptr (tree depth in *sl_head) */ int bal;
/* Subtree balance factor */ * The following structure maintains a hash entry for the * balancing trees which are allocated for each device nodes. * For remapping dev,inode for -Hodc archives. /* forward declarations */ * ------------------------------------------------------------------------- struct stat ArchSt,
/* stat(2) information of the archive */ SrcSt,
/* stat(2) information of source file */ DesSt,
/* stat(2) of destination file */ *
OldSt =
NULL;
/* stat info converted to svr32 format */ * bin_mag: Used to validate a binary magic number, * by combining to bytes into an unsigned short. * swpbuf: Used in swap() to swap bytes within a halfword, * halfwords within a word, or to reverse the order of the * bytes within a word. Also used in mklong() and mkshort(). char Adir,
/* Flags object as a directory */ Hiddendir,
/* Processing hidden attribute directory */ Aspec,
/* Flags object as a special file */ Do_rename,
/* Indicates rename() is to be used */ Time[
50],
/* Array to hold date and time */ *
Buf_p,
/* Buffer for file system I/O */ *
Empty,
/* Empty block for TARTYP headers */ *
Full_p,
/* Pointer to full pathname */ *
Efil_p,
/* -E pattern file string */ *
Eom_p =
"Change to part %d and press RETURN key. [q] ",
*
Hdr_p,
/* -H header type string */ *
Lnkend_p,
/* Pointer to end of Lnknam_p */ *
Lnknam_p,
/* Buffer for linking files with -p option */ *
Nam_p,
/* Array to hold filename */ *
Savenam_p,
/* copy of filename xattr belongs to */ *
Own_p,
/* New owner login id string */ *
Renam_p,
/* Buffer for renaming files */ *
Symlnk_p,
/* Buffer for holding symbolic link name */ *
Over_p,
/* Holds temporary filename when overwriting */ **
Pat_pp = 0,
/* Pattern strings */int Append = 0,
/* Flag set while searching to end of archive */ Archive,
/* File descriptor of the archive */ Buf_error = 0,
/* I/O error occured during buffer fill */ Device,
/* Device type being accessed (used with libgenIO) */ Error_cnt = 0,
/* Cumulative count of I/O errors */ Finished =
1,
/* Indicates that a file transfer has completed */ Hdrsz =
ASCSZ,
/* Fixed length portion of the header */ Hdr_type,
/* Flag to indicate type of header selected */ Ifile,
/* File des. of file being archived */ Ofile,
/* File des. of file being extracted from archive */ Use_old_stat = 0,
/* Create an old style -Hodc hdr (small dev's) */ Onecopy = 0,
/* Flags old vs. new link handling */ Pad_val = 0,
/* Indicates the number of bytes to pad (if any) */ PageSize = 0,
/* The native page size, used for figuring block size */ Volcnt =
1,
/* Number of archive volumes processed */ Verbcnt = 0,
/* Count of number of dots '.' output */ Compressed,
/* Flag to indicate if the bar archive is compressed */ Bar_vol_num = 0;
/* Volume number count for bar archive */ gid_t Lastgid = -
1;
/* Used with -t & -v to record current gid */ uid_t Lastuid = -
1;
/* Used with -t & -v to record current uid */ long Args,
/* Mask of selected options */ FILE *
Ef_p,
/* File pointer of pattern input file */ *
Err_p =
stderr,
/* File pointer for error reporting */ *
Out_p =
stdout,
/* File pointer for non-archive output */ *
Rtty_p,
/* Input file pointer for interactive rename */ *
Wtty_p;
/* Output file ptr for interactive rename */static int Pflag = 0;
/* flag indicates that acl is preserved */ static int acl_is_set = 0;
/* True if an acl was set on the file */ * cpio has been changed to support extended attributes. * As part of this change cpio has been changed to use the new *at() syscalls * such as openat, fchownat(), unlinkat()... * This was done so that attributes can be handled with as few code changes * What this means is that cpio now opens the directory that a file or directory * resides in and then performs *at() functions to manipulate the entry. * For example a new file is now created like this: * dfd = open(<some dir path>) * fd = openat(dfd, <name>,....); * or in the case of an extended attribute * dfd = attropen(<pathname>, ".", ....) * Once we have a directory file descriptor all of the *at() functions can * unlinkat(dfd, <component name>,...) * fchownat(dfd, <component name>,..) * This works for both normal namespace files and extended attribute file * Extended attribute layout * Extended attributes are stored in two pieces. * 1. An attribute header which has information about * what file the attribute is for and what the attribute * 2. The attribute record itself. Stored as a normal file type * The names of the header in the archive look like: * The name of the attribute looks like: * This is done so that an archiver that doesn't understand these formats * can just dispose of the attribute records unless the user chooses to * rename them via cpio -r or pax -i * The format is composed of a fixed size header followed * by a variable sized xattr_buf. If the attribute is a hard link * to another attribute, then another xattr_buf section is included * 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 * The basic layout looks like this. * -------------------------------- * -------------------------------- * -------------------------------- * -------------------------------- * -------------------------------- * | (optional link info) | * -------------------------------- * -------------------------------- * | stored as normal tar | * -------------------------------- * Extended attributes structures * xattrhead is the complete extended attribute header, as read of off * disk/tape. It includes the variable xattr_buf portion. * xattrp is basically an offset into xattrhead that points to the * "pathing" section which defines how to get to the attribute. * xattr_linkp is identical to xattrp except that it is used for linked * attributes. It provides the pathing steps to get to the linked * These structures are updated when an extended attribute header is read off static int xattrbadhead;
/* is extended attribute header bad? */ * Note regarding cpio and changes to ensure cpio doesn't try to second * guess whether it runs with sufficient privileges or not: * cpio has been changed so that it doesn't carry a second implementation of * the kernel's policy with respect to privileges. Instead of attempting * to restore uid and gid from an archive only if cpio is run as uid 0, * cpio now *always* tries to restore the uid and gid from the archive. * If the restoration of the uid and gid are unsuccessful, then an error * message will only be received if cpio is being run with root privileges, * i.e., effective uid (euid) is 0, or if -R was specified. * Note regarding debugging mechanism for cpio: * The following mechanism is provided to allow us to debug cpio in complicated * situations, like when it is part of a pipe. The idea is that you compile * with -DWAITAROUND defined, and then add the "-z" command line option to the * target cpio invocation. If stderr is available, it will tell you to which * pid to attach the debugger; otherwise, use ps to find it. Attach to the * process from the debugger, and, *PRESTO*, you are there! * Simply assign "waitaround = 0" once you attach to the process, and then * proceed from there as usual. int waitaround = 0;
/* wait for rendezvous with the debugger */ * Allocation wrappers and their flags #
define E_NORMAL 0x0 /* Return NULL if allocation fails */#
define E_EXIT 0x1 /* Exit if allocation fails */ * main: Call setup() to process options and perform initializations, * and then select either copy in (-i), copy out (-o), or pass (-p) action. #
if !
defined(
TEXT_DOMAIN)
/* Should be defined by cc -D */#
define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ * Any ACL info for this file would or should * have been used after file_in(); clear out * aclp so it is is not erroneously used on /* Do not count "extra" "read-ahead" buffered data */ * If file is a fully qualified path then * file_pass will strip off the leading '/' * and we need to save off the unstripped * name for attribute traversal. msg(
EXT,
"Impossible action.");
* add_lnk: Add a linked file's header to the linked file data structure, by * either adding it to the end of an existing sub-list or starting * a new sub-list. Each sub-list saves the links to a given file. * Directly returns a pointer to the new entry; returns a pointer to the head * of the sub-list in which that entry is located through the argument. /* add to existing sub-list */ * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer, * moving them to rd_buf_p. When there are no bytes left in the I/O buffer, * Fillbuf is set and the I/O buffer is filled. The variable dist is the * distance to lseek if an I/O error is encountered with the -k option set * (converted to a multiple of Bufsize). }
/* (rv = g_read(Device, Archive ... */ eof = 0;
/* reset the eof after chgreel */ * if spans multiple volume, skip the volume header of * the next volume so that the file currently being * extracted can continue to be extracted. }
/* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */ }
/* (rv = g_read(Device, Archive ... */ * bflush: Move wr_cnt bytes from data_p into the I/O buffer. When the * I/O buffer is full, Flushbuf is set and the buffer is written out. * chgreel: Determine if end-of-medium has been reached. If it has, * close the current medium and prompt the user for the next medium. msg(
EXTN,
"Error during stat() of archive");
"Can't read input: end of file encountered ",
"prior to expected end of archive.");
msg(
EPOST,
"\007End of medium on \"%s\".",
dir ?
"output" :
"input");
msg(
EXT,
"Cannot change media types in mid-stream.");
else {
/* dir == OUTPUT */ "Unable to write this medium, try " * ckname: Check filenames against user specified patterns, * and/or ask the user for new name when -r is used. /* Re-visit tar size issues later */ msg(
ERR,
"Name exceeds maximum length - skipped.");
if ((
Args &
OCr) && !
Adir) {
/* rename interactively */ /* remove trailing '\n' */ * ckopts: Check the validity of all command line options. msg(
ERR,
"One of -i, -o or -p must be specified.");
/* if non-zero, invalid options were specified */ msg(
ERR,
"-a and -m are mutually exclusive.");
msg(
ERR,
"-c and -H are mutually exclusive.");
msg(
ERR,
"-v and -V are mutually exclusive.");
msg(
ERR,
"-t and -V are mutually exclusive.");
msg(
ERR,
"-B and -C are mutually exclusive.");
msg(
ERR,
"-H and -6 are mutually exclusive.");
msg(
ERR,
"-M not meaningful without -O or -I.");
msg(
ERR,
"-A requires the -O option.");
msg(
ERR,
"Illegal size given for -C option.");
"Header type bar can only be used with -i");
"Can't preserve using bar header");
"Cannot open \"%s\" for append",
"Cannot open \"%s\" for output",
* We are in pass mode with no block size specified. Use the * larger of the native page size and 8192. * cksum: Calculate the simple checksum of a file (CRC) or header * (TARTYP (TAR and USTAR)). For -o and the CRC header, the file is opened and * the checksum is calculated. For -i and the CRC header, the checksum * is calculated as each block is transferred from the archive I/O buffer * to the file system I/O buffer. The TARTYP (TAR and USTAR) headers calculate * the simple checksum of the header (with the checksum field of the * header initialized to all spaces (\040). if (
Args &
OCi) {
/* do running checksum */ /* OCo - do checksum of file */ msg(
ERR,
"Error computing checksum.");
msg(
ERRN,
"Cannot reset file after checksum");
case TARTYP:
/* TAR and USTAR */ * tar uses unsigned checksum, so we must use unsigned * here in order to be able to read tar archives. msg(
EXT,
"Impossible header type.");
* creat_hdr: Fill in the generic header structure with the specific * header information based on the value of Hdr_type. * return (1) if this process was successful, and (0) otherwise. * If the length of the full name is greater than 256, * print out a message and return. * The length of the full name is greater than * 100, so we must split the filename from the * If the filename is greater than 100 we can't "%s: filename is greater than %d",
* If the prefix is greater than 155 we can't "%s: prefix is greater than %d",
"cpio: could not get passwd information " /* make name null string */ "cpio: could not get group information " /* make name null string */ msg(
EXT,
"Impossible header type.");
msg(
ERR,
"%s%s%s: cannot be archived - inode too big " * creat_lnk: Create a link from the existing name1_p to name2_p. * Check to see if we are trying to link this * file to itself. If so, count the effort as * successful. If the two files are different, * or if either lstat is unsuccessful, proceed * as we would have otherwise; the appropriate * error will be reported subsequently. msg(
ERR,
"Cannot lstat source file %s",
"Existing \"%s\" same age or newer",
msg(
ERRN,
"Error cannot unlink \"%s\"",
"Unable to create directory for \"%s\"",
name2_p);
* Create one of the following: Do_rename = 0;
/* creat_tmp() may reset this */ * Is this the extraction of the hidden attribute directory? * If so then just set the mode/times correctly, and return. "Cannot chown() \"attribute directory of " "Cannot chmod() \"attribute directory of " "failed to set acl on attribute" * The archive file is a directory. /* A file by the same name exists. */ "\"%s\": failed to set acl",
* We are creating directories. Keep the /* The archive file is not a directory. */ * A file by the same name exists. Move it to a * We weren't able to create the temp file. * This pile tries to create the file directly, and, if there is a * problem, creates missing directories, and then tries to create the * file again. Two strikes and you're out. /* The archive file is a directory. */ * The archive file is block special, * char special or a fifo. * The file creation succeeded. Take care of the ACLs. "\"%s\": failed to set acl",
nam_p);
"Cannot create directory for \"%s\"",
nam_p);
msg(
ERR,
"Attempt to pass a file to itself.");
/* Make the temporary file name. */ * Save our current directory, so we can go into * the attribute directory to make the temp file /* Return to the current directory. */ /* mktemp reports a failure. */ msg(
ERR,
"Cannot get temporary file name.");
* If it's a regular file, write to the temporary file, and then rename * in order to accomodate potential executables. * Note: g_typeflag is only defined (set) for USTAR archive types. It * defaults to 0 in the cpio-format-regular file case, so this test * The archive file and the filesystem file are both regular * files. We write to the temporary file in this case. * Either the archive file or the filesystem file is not a * The filesystem file is a directory. * Save the current working directory because we will * want to restore it back just in case remove_dir() * fails or get confused about where we should be. "Cannot remove the directory \"%s\"",
* Restore working directory back to the one * Restore working directory back to the one * The file is not a directory. Will use the original * namefs, link would fail with EXDEV. Therefore, we * use rename() first to back up the file. * If rename failed, try old construction "Cannot create temporary file");
"Cannot unlink() current \"%s\"",
* data_in: If proc_mode == P_PROC, bread() the file's data from the archive * and write(2) it to the open fdes gotten from openout(). If proc_mode == * P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data * and ignore it. If the user specified any of the "swap" options (b, s or S), * and the length of the file is not appropriate for that action, do not * perform the "swap", otherwise perform the action on a buffer by buffer basis. * If the CRC header was selected, calculate a running checksum as each buffer FILE *
pipef;
/* pipe for bar to do de-compression */ if (
Args & (
OCb |
OCs |
OCS)) {
/* verfify that swapping is possible */ "Cannot swap bytes of \"%s\", odd number of bytes",
"Cannot swap halfwords of \"%s\", odd number " /* This writes out the file from the archive */ * if the bar archive is compressed, set up a pipe and * do the de-compression while reading in the file * data_out: open(2) the file to be archived, compute the checksum * of it's data if the CRC header was specified and write the header. * read(2) each block of data and bwrite() it to the archive. For TARTYP (TAR * and USTAR) archives, pad the data with NULLs to the next 512 byte boundary. /* append security attributes */ "can create security information");
/* call append_secattr() if more than one */ /* write ancillary only if there is sec info */ /* Note that "size" and G_p->g_filesz are the same number */ * Note that it is OK not to add the NUL after the name read by * readlink, because it is not being used subsequently. * G_p->g_filesz is the length of the right-hand side of * The tar link field is only NAMSIZ long. "Symbolic link too long \"%s\"",
nam_p);
"Cannot read symbolic link \"%s\"",
nam_p);
* Dump extended attribute header. * ACL has been retrieved in getname(). /* append security attributes */ msg(
ERR,
"can create security information");
/* call append_secattr() if more than one */ /* write ancillary only if there is sec info */ msg(
EXTN,
"Cannot read \"%s%s%s\"",
/* the file has shrunk */ /* the file is the same size */ msg(
ERR,
"File size of \"%s%s%s\" has increased by %lld",
msg(
ERR,
"File size of \"%s%s%s\" has decreased by %lld",
* data_pass: If not a special file (Aspec), open(2) the file to be * transferred, read(2) each block of data and write(2) it to the output file * Ofile, which was opened in file_pass(). msg(
ERRN,
"Cannot open \"%s%s%s\", skipped",
msg(
ERRN,
"Cannot read \"%s%s%s\"",
msg(
ERRN,
"Cannot write \"%s%s%s\"",
* Allocation wrappers. Used to centralize error handling for * Note: unlike the other e_*lloc functions, e_realloc does not zero out the * additional memory it returns. Ensure that you do not trust its contents * file_in: Process an object from the archive. If a TARTYP (TAR or USTAR) * archive and g_nlink == 1, link this file to the file name in t_linkname * and return. Handle linked files in one of two ways. If Onecopy == 0, this * is an old style (binary or -c) archive, create and extract the data for the * first link found, link all subsequent links to this file and skip their data. * If Oncecopy == 1, save links until all have been processed, and then * process the links first to last checking their names against the patterns * and/or asking the user to rename them. The first link that is accepted * for xtraction is created and the data is read from the archive. * All subsequent links that are accepted are linked to this file. * Open target directory if this isn't a skipped file * Links are handled further down in this function. * Normally ckname() prints out the file as a side * effect except for table of contents listing * when its parameter is zero and Onecopy isn't * Zero. Due to this we need to force the name * For archives in USTAR format, the files are extracted according * Are we linking an attribute? return;
/* don't do anything yet */ * ckname will clear aclchar. We need to keep aclchar for }
/* (proc_file = ckname(1)) != F_SKIP */ }
/* tl_p->L_lnk_p != (struct Lnk *)NULL */ * file_out: If the current file is not a special file (!Aspec) and it * is identical to the archive, skip it (do not archive the archive if it * is a regular file). If creating a TARTYP (TAR or USTAR) archive, the first * time a link to a file is encountered, write the header and file out normally. * Subsequent links to this file put this file name in their t_linkname field. * Otherwise, links are handled in one of two ways, for the old headers * (i.e. binary and -c), linked files are written out as they are encountered. * For the new headers (ASC and CRC), links are saved up until all the links * to each file are found. For a file with n links, write n - 1 headers with * g_filesz set to 0, write the final (nth) header with the correct g_filesz * value and write the data for the file to the archive. return (
1);
/* do not archive the archive if it's a reg file */ msg(
ERR,
"cpio: %s%s%s: too large to archive in current mode",
return (
1);
/* do not archive if it's too big */ if (
tl_p ==
l_p) {
/* first link to this file encountered */ * check if linkname is greater than 100 characters msg(
EPOST,
"cpio: %s: linkname %s is greater than %d",
/* find the lnk entry in sublist, unlink it, and free it */ * ACL has been retrieved in getname(). /* append security attributes */ msg(
ERR,
"can create security information");
/* call append_secattr() if more than one */ return (0);
/* don't process data yet */ /* one link with the acl is sufficient */ /* old style: has acl and data for every link */ * file_pass: If the -l option is set (link files when possible), and the * source and destination file systems are the same, link the source file * (G_p->g_nam_p) to the destination file (Fullnam) and return. If not a * linked file, transfer the data. Otherwise, the first link to a file * encountered is transferred normally and subsequent links are linked to it. "Cannot open attribute directory of" /* We are linking back to the source directory. */ /* We are chasing symlinks. */ "Cannot read symbolic link \"%s\"",
/* The archive file is a symlink. */ "Cannot read symbolic link \"%s\"",
save_name);
"Error during chown() of \"%s\"",
/* The archive file has hard links. */ /* The archive file was not found. */ /* The archive file was found. */ /* We are linking an attribute */ /* We are not linking an attribute */ * The archive file is a directory, block special, char * flush_lnks: With new linked file handling, linked files are not archived * until all links have been collected. When the end of the list of filenames * to archive has been reached, all files that did not encounter all their links * are written out with actual (encountered) link counts. A file with n links * (that are archived) will be represented by n headers (one for each link (the * first n - 1 have g_filesz set to 0)) followed by the data for the file. (
off_t)0);
/* header only */ }
else /* stat(Gen.g_nam_p, &SrcSt) == 0 */ msg(
ERR,
"\"%s%s%s\" has disappeared",
* gethdr: Get a header from the archive, validate it and check for the trailer. * Any user specified Hdr_type is ignored (set to NONE in main). Hdr_type is * set appropriately after a valid header is found. Unless the -k option is * set a corrupted header causes an exit with an error. I/O errors during * examination of any part of the header cause gethdr to throw away any current * data and start over. Other errors during examination of any part of the * header cause gethdr to advance one byte and continue the examination. do {
/* hit == NONE && (Args & OCk) && Buffr.b_cnt > 0 */ msg(
EXT,
"Impossible header type.");
}
else if (
hit !=
BAR) {
/* binary, -c, ASC and CRC */ "Corrupt header, file(s) may be lost.");
msg(
EXT,
"Not a cpio file, bad header.");
msg(
EXT,
"Impossible header type.");
* initialize the buffer so that the prefix will not * applied to the next entry in the archive /* extended attribute support */ /* acl support: grab acl info */ /* this is an ancillary file */ /* got all attributes in secp */ "aclfromtext failed: %s",
/* SunFed case goes here */ msg(
EXT,
"unrecognized attr type");
* We already got the file content, dont call file_in() * when return. The new return code(2) is used to * Skip any trailing slashes * getname: Get file names for inclusion in the archive. When end of file * on the input stream of file names is reached, flush the link buffer out. * For each filename, remove leading "./"s and multiple "/"s, and remove * any trailing newline "\n". Finally, verify the existance of the file, * and call creat_hdr() to fill in the gen_hdr structure. * Skip any trailing slashes * Figure out parent directory "Cannot open attribute directory" "Cannot open directory %s",
dir);
* g_dirpath is the pathname cache maintaining * the dirname which is currently opened. * We first check the g_dirpath to see if the * given dirname matches. If so, we don't need * to open the dir, but we can use the g_dirfd * as is if it is still available. * It's the first time or it has /* different directory */ * We need to open the new directory. * discard the pathname and dirfd * for the previous directory. /* creat_hdr checks for USTAR filename length */ msg(
ERR,
"%s%s%s name too long.",
"Error with fstatat() of \"%s%s%s\"",
* Get ACL info: dont bother allocating space if there are only * standard permissions, i.e. ACL count < 4 /* else: only traditional permissions, so proceed as usual */ *(
Nam_p +
len -
1) =
'\0';
/* remove the \n */ msg(
EXTN,
"Error during stat() of archive");
msg(
EXT,
"ulimit reached for output file.");
msg(
EXT,
"No space left for output file.");
msg(
EXTN,
"I/O error - cannot continue");
msg(
EXT,
"Unexpected end-of-file encountered.");
msg(
EXTN,
"\007I/O error on \"%s\"",
dir ?
"output" :
"input");
* matched: Determine if a filename matches the specified pattern(s). If the * pattern is matched (the second return), return 0 if -f was specified, else * return != 0. If the pattern is not matched (the first and third * returns), return 0 if -f was not specified, else return != 0. msg(
POST,
"error matching file %s with pattern" return (
Args &
OCf);
/* not matched */ * missdir: Create missing directories for files. * (Possible future performance enhancement, if missdir is called, we know * that at least the very last directory of the path does not exist, therefore, * scan the path from the end if (*(
c_p =
nam_p) ==
'/')
/* skip over 'root slash' */ msg(
ERR,
"Missing -d option.");
if (
cnt ==
2)
/* the file already exists */ * mklong: Convert two shorts into one long. For VAX, Interdata ... * mkshort: Convert a long into 2 shorts, for VAX, Interdata ... * msg: Print either a message (no error) (POST), an error message with or * without the errno (ERRN or ERR), or print an error message with or without * the errno and exit (EXTN or EXT). /* gettext replaces version of string */ * openout: Open files for output and set all necessary information. * If the u option is set (unconditionally overwrite existing files), * and the current file exists, get a temporary file name from mktemp(3C), * link the temporary file to the existing file, and remove the existing file. * Finally either creat(2), mkdir(2) or mknod(2) as appropriate. Do_rename = 0;
/* creat_tmp() may reset this */ /* ... divided by 512 ... */ msg(
ERR,
"Skipping \"%s%s%s\": exceeds ulimit by %lld bytes",
* A file by the same name exists. Move it to a temporary * We weren't able to create the temp file. Report /* nam_p was changed by creat_tmp() above. */ * This pile tries to create the file directly, and, if there is a * problem, creates missing directories, and then tries to create the * file again. Two strikes and you're out. * On XATTR system, the directory has already been created by * open_dirfd(), so error shouldn't happen in the loop. However, * on non-XATTR system, symlink/open may fail with ENOENT. In such * case, we go to create missing directories. /* The archive file is a TAR symlink. */ /* The attempt to symlink failed. */ "Cannot create symbolic link \"%s\" -> " /* The attempt to symlink failed. */ "Cannot create symbolic link \"%s\" -> " /* The attempt to symlink failed. */ "Cannot create symbolic link \"%s\" -> " "\"%s\": failed to set acl",
/* The attempt to open failed. */ "Error during chown() of " "Error during chown() of \"%s%s%s\"",
msg(
ERRN,
"Cannot create directory for \"%s%s%s\"",
msg(
ERRN,
"Cannot create directory for \"%s%s%s\"",
msg(
ERRN,
"Cannot create \"%s%s%s\"",
msg(
ERRN,
"Cannot create \"%s%s%s\"",
* read_hdr: Transfer headers from the selected format * in the archive I/O buffer to the generic structure. "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6o%11llo",
#
define cpioMAJOR(x) (
int)(((
unsigned)x >>
8) &
0x7F)
/* needs error checking */ "%6lx%8lx%8lx%8lx%8lx%8lx%8lx%8llx%8x%8x%8x%8x%8x%8lx",
case USTAR:
/* TAR and USTAR */ msg(
EXT,
"Impossible header type.");
* reclaim: Reclaim linked file structure storage. * rstbuf: Reset the I/O buffer, move incomplete potential headers to * the front of the buffer and force bread() to refill the buffer. The * return value from bread() is returned (to identify I/O errors). On the * 3B2, reads must begin on a word boundary, therefore, with the -i option, * any remaining bytes in the buffer must be moved to the base of the buffer * in such a way that the destination locations of subsequent reads are msg(
EXT,
"Unexpected end-of-archive encountered.");
msg(
EPOST,
"cpio: problem reading passwd entry");
msg(
EPOST,
"cpio: problem reading group entry");
* rstfiles: Perform final changes to the file. If the -u option is set, * and overwrite == U_OVER, remove the temporary file, else if overwrite * == U_KEEP, unlink the current file, and restore the existing version * of the file. In addition, where appropriate, set the access or modification * times, change the owner and change the modes of the file. * Note that if Do_rename is set, then the roles of original and temporary * file are reversed. If all went well, we will rename() the temporary file * over the original in order to accomodate potentially executing files. msg(
POST,
"Restoring existing \"%s%s%s\"",
msg(
POST,
"Restoring existing \"%s%s%s\"",
/* delete what we just built */ /* If the old file needs restoring, do the necessary links */ Do_rename = 0;
/* names now have original values */ "Cannot recover original version" "Cannot remove temp file " * Over_p is pointing at g_attrnam_p * which must be preserved. * We don't want the tmp_ptr and so * on to throw away our only copy of Do_rename = 0;
/* names now have original values */ "Cannot unlink() temp file \"%s%s%s\"",
}
else /* OCi only uses onam_p, OCo only uses inam_p */ * change the modes back to the ones originally created in the /* Acl was not set, so we must chmod */ * use fchmod for attributes, since * we known they are always regular * files, whereas when it isn't an * attribute it could be for a fifo * or something other that we don't * open and don't have a valid Ofile "Cannot chmod() \"%s%s%s\"",
msg(
ERRN,
"Cannot chown() \"%s%s%s\"",
* Use dirfd since we are updating original file * and not just created file msg(
ERRN,
"Cannot chown() \"%s%s%s\"",
/* OCi only uses onam_p, OCo only uses inam_p */ msg(
ERRN,
"Cannot chown() \"%s%s%s\"",
* scan4trail: Scan the archive looking for the trailer. * When found, back the archive up over the trailer and overwrite * the trailer with the files to be added to the archive. msg(
EXTN,
"Unable to append to this archive");
msg(
EXTN,
"Cannot append to this archive");
msg(
EXTN,
"Unable to append to this archive");
* setup: Perform setup and initialization functions. Parse the options * using getopt(3C), call ckopts to check the options and initialize various * structures and pointers. Specifically, for the -i option, save any * patterns, for the -o option, check (via stat(2)) the archive, and for * the -p option, validate the destination directory. char *
opts_p =
"zabcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6@";
char *
opts_p =
"abcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6@";
char *
opts_p =
"zabcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6";
char *
opts_p =
"abcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6";
char *
dupl_p =
"Only one occurrence of -%c allowed";
/* Remember the native page size. */ * This sysconf call will almost certainly never fail. The * symbol PAGESIZE itself resolves to the above sysconf call, * so we should go ahead and define our own constant. /* rendezvous with the debugger */ case 'a':
/* reset access time */ case 'b':
/* swap bytes and halfwords */ case 'c':
/* select character header */ case 'd':
/* create directories as needed */ case 'f':
/* select files not in patterns */ case 'i':
/* "copy in" */ case 'k':
/* retry after I/O errors */ case 'l':
/* link files when possible */ case 'm':
/* retain modification time */ case 'o':
/* "copy out" */ case 'r':
/* rename files interactively */ case 's':
/* swap bytes */ case 't':
/* table of contents */ case 'u':
/* copy unconditionally */ case 'v':
/* verbose - print file names */ case 'A':
/* append to existing archive */ case 'B':
/* set block size to 5120 bytes */ case 'C':
/* set arbitrary block size */ case 'E':
/* alternate file for pattern input */ case 'H':
/* select header type */ case 'I':
/* alternate file for archive input */ case 'L':
/* follow symbolic links */ case 'M':
/* specify new end-of-media message */ case 'O':
/* alternate file for archive output */ case 'P':
/* preserve acls */ case 'S':
/* swap halfwords */ case 'V':
/* print a dot '.' for each file */ case '6':
/* for old, sixth-edition files */ }
/* (option = getopt(largc, largv, opts_p)) != EOF */ msg(
EXT,
"Unable to determine current directory.");
if (
largc > 0)
/* save patterns for -i option, if any */ if (
largc != 0)
/* error if arguments left with -o */ msg(
ERRN,
"Error during stat() of archive");
case USTAR:
/* TAR and USTAR */ msg(
EXT,
"Impossible header type.");
}
else {
/* directory must be specified */ "Error during access() of \"%s\"", *
largv);
"Error during initialization");
"Error during initialization");
* Now that Bufsize has stabilized, we can allocate our i/o buffer if (
Args &
OCp) {
/* get destination directory */ * set_tym: Set the access and/or modification times for a file. "Unable to reset access time for \"%s%s%s\"",
"Unable to reset modification time for \"%s%s%s\"",
* sigint: Catch interrupts. If an interrupt occurs during the extraction * of a file from the archive with the -u option set, and the filename did * exist, remove the current file and restore the original file. Then exit. if (*
Over_p !=
'\0') {
/* There is a temp file */ "Cannot remove incomplete \"%s\"",
nam_p);
"Cannot recover original \"%s\"",
"Cannot remove temp file \"%s\"",
"Cannot remove incomplete \"%s\"",
nam_p);
* swap: Swap bytes (-s), halfwords (-S) or or both halfwords and bytes (-b). * usage: Print the usage message on stderr and exit. "\tcpio -i[bcdfkmrstuv@BSV6] [-C size] " "[-E file] [-H hdr] [-I file [-M msg]] " "\tcpio -o[acv@ABLV] [-C size] " "[-H hdr] [-O file [-M msg]]\n" "\tcpio -p[adlmuv@LV] [-R id] directory\n"));
"\tcpio -i[bcdfkmrstuvBSV6] [-C size] " "[-E file] [-H hdr] [-I file [-M msg]] " "\tcpio -o[acvABLV] [-C size] " "[-H hdr] [-O file [-M msg]]\n" "\tcpio -p[adlmuvLV] [-R id] directory\n"));
* verbose: For each file, print either the filename (-v) or a dot (-V). * If the -t option (table of contents) is set, print either the filename, * or if the -v option is also set, print an "ls -l"-like listing. * The printf format and associated arguments to print the current * filename. Normally, just nam_p. If we're processing an extended * attribute, these are overridden. /* dont print ancillary file */ for (i = 0; i <
3; i++) {
case (
S_IFREG):
/* was initialized to '-' */ msg(
ERR,
"Impossible file type");
if (
Verbcnt++ >=
49) {
/* start a new line of dots */ * write_hdr: Transfer header information for the generic structure * into the format for the selected header and bwrite() the header. * ACL support: add two new argumnets. secflag indicates that it's an * ancillary file. len is the size of the file (incl. all security * attributes). We only have acls now. const char warnfmt[] =
"%s%s%s : %s";
* If attribute is being archived in cpio format then * zap off the file type bits since those are truly a * mask and reset them with _XATTR_CPIO_MODE * len is the value of g_filesz for normal files * and the length of the special header buffer in * the case of acl and xattr headers. * Handle EFT uids and gids. If they get too big * to be represented in a particular format, force 'em to 'nobody'. case BIN:
/* 16-bits of u_short */ case CHR:
/* %.6lo => 262143 base 10 */ case ASC:
/* %.8lx => full 32 bits */ case TAR:
/* %.7lo => 2097151 base 10 */ msg(
EXT,
"Impossible header type.");
* Since cpio formats -don't- encode the symbolic names, print * a warning message when we map the uid or gid this way. * Also, if the ownership just changed, clear set[ug]id bits * (Except for USTAR format of course, where we have a string * representation of the username embedded in the header) gettext(
"uid too large for archive format"));
gettext(
"gid too large for archive format"));
case USTAR:
/* TAR and USTAR */ msg(
EXT,
"Impossible header type.");
"%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11lo%.6lo%." "%.6lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%." msg(
EXT,
"Impossible header type.");
* write_trail: Create the appropriate trailer for the selected header type * and bwrite the trailer. Pad the buffer with nulls out to the next Bufsize * boundary, and force a write. If the write completes, or if the trailer is * completely written (but not all of the padding nulls (as can happen on end * of medium)) return. Otherwise, the trailer was not completely written out, * so re-pad the buffer with nulls and try again. case USTAR:
/* TAR and USTAR */ msg(
EXT,
"Impossible header type.");
* if archives in USTAR format, check if typeflag == '5' for directories * if archives in USTAR format, check if typeflag == '3' || '4' || '6' * for character, block, fifo special files * The return value is a pointer to a converted copy of the information in * FromStat if the file is representable in -Hodc format, and NULL otherwise. * Encountered a problem representing the rdev information. msg(
ERR,
"Error -Hodc format can't support expanded" * Having trouble representing the device/inode pair. We can't * track links in this case; break them all into separate "Warning: file %s%s%s has large " "device number - linked " "files will be restored as " /* Start converting values */ /* -actual- not truncated uid */ /* -actual- not truncated gid */ * In the beginning of each bar archive, there is a header which describes the * current volume being created, followed by a header which describes the * current file being created, followed by the file itself. If there is * more than one file to be created, a separate header will be created for * each additional file. This structure may be repeated if the bar archive * contains multiple volumes. If a file spans across volumes, its header * will not be repeated in the next volume. * | file header i | i = 0 * read in the header that describes the current volume of the bar archive "bar error: cannot read volume header\n"));
/* set the compress flag */ * not the first volume; exit gettext(
"error: This is not volume 1. "));
* read in the header that describes the current file to be extracted * if the bar archive is compressed, set up a pipe and do the de-compression * as the compressed file is read in. "chmod +w '%s'; uncompress -c > '%s'; " * if the bar archive spans multiple volumes, read in the header that * describes the next volume. "error in skip_bar_volhdr\n"));
gettext(
"cpio error: cannot read bar volume " * Now put the rest of the bytes read in into the data buffer. * check the linkflag which indicates the type of the file to be extracted, * invoke the corresponding routine to extract the file. * the file is a directory /* character device or FIFO */ * XXX And it is very broken. #
define G_TM_TAPE 1 /* Tapemaster controller */#
define G_NS 12 /* noswap pseudo-dev */#
define G_RAM 13 /* ram pseudo-dev */#
define G_FT 14 /* tftp */#
define G_HD 15 /* 386 network disk */#
define G_FD 16 /* 386 AT disk */#
define G_FILE 28 /* file, not a device */#
define G_NO_DEV 29 /* device does not require special treatment */#
define G_DEV_MAX 30 /* last valid device type */ * g_init: Determine the device being accessed, set the buffer size, * and perform any device specific initialization. Since at this point * Sun has no system call to read the configuration, the major numbers * are assumed to be static and types are figured out as such. However, * as a rough estimate, the buffer size for all types is set to 512 /* find block size for this file system */ * We'll have to add a remote attribute to stat but this * g_read: Read nbytes of data from fdes (of type devtype) and place * data in location pointed to by buf. In case of end of medium, * translate (where necessary) device specific EOM indications into * the generic EOM indication of rv = -1, errno = ENOSPC. /* st devices return 0 when no space left */ * g_write: Write nbytes of data to fdes (of type devtype) from * the location pointed to by buf. In case of end of medium, * translate (where necessary) device specific EOM indications into * the generic EOM indication of rv = -1, errno = ENOSPC. /* st devices return 0 when no more space left */ * try to do a generic tape ioctl, just to see if * the thing is in fact a tape drive(er). /* the ioctl succeeded, must have been a tape */ * try to get the floppy drive characteristics, just to see if * the thing is in fact a floppy drive(er). /* the ioctl succeeded, must have been a floppy */ * New functions for ACLs and other security attributes * The function appends the new security attribute info to the end of char **
secinfo,
/* existing security info */ int *
secinfo_len,
/* length of existing security info */ acl_t *
aclp)
/* new attribute data pointer */ /* header: type + size = 8 */ /* SunFed's case goes here */ /* old security info + new attr header(8) + new attr */ /* Just tranditional permissions or no security attribute info */ /* write out security info */ #
define MSG1 "remove_dir() failed to stat(\"%s\") "#
define MSG2 "remove_dir() failed to remove_dir(\"%s\") "#
define MSG3 "remove_dir() failed to unlink(\"%s\") " * Open the directory for reading. msg(
ERRN,
"remove_dir() failed to opendir(\"%s\") ",
path);
msg(
ERRN,
"remove_dir() failed to chdir(\"%s\") ",
path);
* Read every directory entry. * Ignore "." and ".." entries. * Close the directory we just finished reading. * Change directory to the parent directory... msg(
ERRN,
"remove_dir() failed to chdir(\"..\") ");
* ...and finally remove the directory; note we have to * make a copy since basename is free to modify its input. msg(
ERRN,
"cannot strdup() the directory pathname ");
msg(
ERRN,
"remove_dir() failed to rmdir(\"%s\") ",
path);
* If aclp still exists then free it since it is was set when base msg(
ERRN,
"Cannot open attribute directory of file \"%s\"",
msg(
ERRN,
"Cannot dup(2) attribute directory descriptor");
msg(
ERRN,
"Cannot fdopendir(2) directory file descriptor");
"Could not fstatat(2) attribute \"%s\" of" "Could not convert to old stat format");
* Set up dummy header name * One piece is written with .hdr, which * contains the actual xattr hdr or pathing information * then the name is updated to drop the .hdr off * and the actual file itself is archived. msg(
ERRN,
"Could not calloc memory for attribute name");
* Get attribute's ACL info: don't bother allocating space * if there are only standard permissions, i.e. ACL count < 4 "Could not open attribute \"%s\" of" "Error with acl() on %s",
* Return the parent directory of a given path. * dir is assumed to be at least as big as path. msg(
EXT,
"pathname is too long");
char *
bufhead;
/* ptr to full buffer */ int totalen;
/* total buffer length */ int len;
/* length returned to user */ int stringlen;
/* length of filename + attr */ int complen;
/* length of pathing section */ int linklen;
/* length of link section */ * Release previous buffer if any. * First add in fixed size stuff * Add space for two nulls * Now add on space for link info if any * Again add space for two nulls * 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 * Now fill in the optional link section if we have one * Include any padding in the read. We need to be positioned * at beginning of next header. "Insufficient memory for extended attribute\n"));
* Validate that we can handle header format gettext(
"Unknown extended attribute format encountered\n"));
gettext(
"Disabling extended attribute header parsing\n"));
* open directory; creating missing directories along the way. * namep was allocated in xattrs_out. It is big enough to hold * either the name + .hdr on the end or just the attr name * 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-- * won't let us create an attribute dir * if it doesn't already exist. msg(
ERRN,
"Cannot open attribute directory of file %s",
name);
* Put mode back to original msg(
ERRN,
"Cannot restore permissions of file %s to %o",
msg(
ERRN,
"Cannot reset timestamps on file %s");
* skip over extra slashes in string. * would return pointer at * If a match for the key values was found in the tree, return a pointer to it. * If a match was not found, insert it and return a pointer to it. This is * based on Knuth's Algorithm A in Vol 3, section 6.2.3. sl_info_t *s;
/* pt where rebalancing may be needed */ int a;
/* used to hold balance factors */ int done;
/* loop control */ int cmpflg;
/* used to hold the result of a comparison */ /* adjust balance factors */ }
else if (s->
bal == -a) {
}
else if (r->
bal == -a) {
}
else if (p->
bal == -a) {
}
else if (p->
bal == a) {
* sl_numlinks: return the number of links that we saw during our preview. * sl_preview_synonyms: Read the file list from the input stream, remembering * each reference to each file. /* /var/tmp is read-only in the mini-root environment */ /* pre-process the name */ while (s[0] ==
'.' && s[
1] ==
'/') {
* sl_remember_tgt: Add the device/inode for lstat or stat info to the list of * those we've seen before. * This tree (rooted under head) is keyed by the device/inode of the file * being pointed to. A count is kept of the number of references encountered /* Determine whether we've seen this one before */ * We have seen this file before. * Note that if we are not chasing symlinks, and this one is a * symlink, it is identically the one we saw before (you cannot * have hard links to symlinks); in this case, we leave the * count alone, so that we don't wind up archiving a symlink to /* We have not seen this file before */ /* -Hodc: remap inode (-1 on overflow) */ ((
1 << (
sizeof (
o_ino_t) *
8)) -
1)) {
* A faster search, which does not insert the key values into the tree. * If the a match was found in the tree, return a pointer to it. If it was not int c;
/* comparison value */