*
* Based in part on the tar implementation from busybox-0.28
* Copyright (C) 1995 Bruce Perens
- * This is free software under the GNU General Public License.
*
- * Licensed under GPL v2 (or later), see file LICENSE in this tarball.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <fcntl.h>
-#include <getopt.h>
-#include <search.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fnmatch.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/sysmacros.h> /* major() and minor() */
-#include "unarchive.h"
#include "busybox.h"
+#include "unarchive.h"
+#include <fnmatch.h>
+#include <getopt.h>
#ifdef CONFIG_FEATURE_TAR_CREATE
/* Tar file constants */
-# define TAR_MAGIC "ustar" /* ustar and a null */
-# define TAR_VERSION " " /* Be compatable with GNU tar format */
#define TAR_BLOCK_SIZE 512
-#define TAR_MAGIC_LEN 6
-#define TAR_VERSION_LEN 2
/* POSIX tar Header Block, from POSIX 1003.1-1990 */
#define NAME_SIZE 100
/* Some info to be carried along when creating a new tarball */
struct TarBallInfo {
- char *fileName; /* File name of the tarball */
int tarFd; /* Open-for-write file descriptor
for the tarball */
struct stat statBuf; /* Stat info for the tarball, letting
typedef enum TarFileType TarFileType;
/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
-static inline void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr,
+static void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr,
struct stat *statbuf,
- const char *name)
+ const char *fileName)
{
/* Note: hlInfoHeadPtr can never be NULL! */
HardLinkInfo *hlInfo;
- hlInfo = (HardLinkInfo *) xmalloc(sizeof(HardLinkInfo) + strlen(name));
+ hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
hlInfo->next = *hlInfoHeadPtr;
*hlInfoHeadPtr = hlInfo;
hlInfo->dev = statbuf->st_dev;
hlInfo->ino = statbuf->st_ino;
hlInfo->linkCount = statbuf->st_nlink;
- strcpy(hlInfo->name, name);
+ strcpy(hlInfo->name, fileName);
}
static void freeHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr)
}
/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
-static inline HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbuf)
+static HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbuf)
{
while (hlInfo) {
if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev))
break;
hlInfo = hlInfo->next;
}
- return (hlInfo);
+ return hlInfo;
}
/* Put an octal string into the specified buffer.
}
/* Write out a tar header for the specified file/directory/whatever */
-static inline int writeTarHeader(struct TarBallInfo *tbInfo,
- const char *header_name, const char *real_name, struct stat *statbuf)
+static int writeTarHeader(struct TarBallInfo *tbInfo,
+ const char *header_name, const char *fileName, struct stat *statbuf)
{
long chksum = 0;
struct TarHeader header;
const unsigned char *cp = (const unsigned char *) &header;
ssize_t size = sizeof(struct TarHeader);
- memset(&header, 0, size);
+ bzero(&header, size);
- strncpy(header.name, header_name, sizeof(header.name));
+ safe_strncpy(header.name, header_name, sizeof(header.name));
putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */
putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
- strncpy(header.magic, TAR_MAGIC TAR_VERSION,
- TAR_MAGIC_LEN + TAR_VERSION_LEN);
+ strcpy(header.magic, "ustar ");
/* Enter the user and group names (default to root if it fails) */
if (bb_getpwuid(header.uname, statbuf->st_uid, sizeof(header.uname)) == NULL)
strncpy(header.linkname, tbInfo->hlInfo->name,
sizeof(header.linkname));
} else if (S_ISLNK(statbuf->st_mode)) {
- char *lpath = xreadlink(real_name);
+ char *lpath = xreadlink(fileName);
if (!lpath) /* Already printed err msg inside xreadlink() */
- return (FALSE);
+ return FALSE;
header.typeflag = SYMTYPE;
strncpy(header.linkname, lpath, sizeof(header.linkname));
free(lpath);
header.typeflag = REGTYPE;
putOctal(header.size, sizeof(header.size), statbuf->st_size);
} else {
- bb_error_msg("%s: Unknown file type", real_name);
- return (FALSE);
+ bb_error_msg("%s: unknown file type", fileName);
+ return FALSE;
}
/* Calculate and store the checksum (i.e., the sum of all of the bytes of
putOctal(header.chksum, 7, chksum);
/* Now write the header out to disk */
- if ((size =
- bb_full_write(tbInfo->tarFd, (char *) &header,
- sizeof(struct TarHeader))) < 0) {
- bb_error_msg(bb_msg_io_error, real_name);
- return (FALSE);
- }
- /* Pad the header up to the tar block size */
- for (; size < TAR_BLOCK_SIZE; size++) {
- write(tbInfo->tarFd, "\0", 1);
- }
+ xwrite(tbInfo->tarFd, &header, sizeof(struct TarHeader));
+
/* Now do the verbose thing (or not) */
if (tbInfo->verboseFlag) {
fprintf(vbFd, "%s\n", header.name);
}
- return (TRUE);
+ return TRUE;
}
# ifdef CONFIG_FEATURE_TAR_FROM
-static inline int exclude_file(const llist_t *excluded_files, const char *file)
+static int exclude_file(const llist_t *excluded_files, const char *file)
{
while (excluded_files) {
if (excluded_files->data[0] == '/') {
int inputFileFd = -1;
/*
- ** Check to see if we are dealing with a hard link.
- ** If so -
- ** Treat the first occurance of a given dev/inode as a file while
- ** treating any additional occurances as hard links. This is done
- ** by adding the file information to the HardLinkInfo linked list.
+ * Check to see if we are dealing with a hard link.
+ * If so -
+ * Treat the first occurance of a given dev/inode as a file while
+ * treating any additional occurances as hard links. This is done
+ * by adding the file information to the HardLinkInfo linked list.
*/
tbInfo->hlInfo = NULL;
if (statbuf->st_nlink > 1) {
/* It is against the rules to archive a socket */
if (S_ISSOCK(statbuf->st_mode)) {
bb_error_msg("%s: socket ignored", fileName);
- return (TRUE);
+ return TRUE;
}
/* It is a bad idea to store the archive we are in the process of creating,
if (tbInfo->statBuf.st_dev == statbuf->st_dev &&
tbInfo->statBuf.st_ino == statbuf->st_ino) {
bb_error_msg("%s: file is the archive; skipping", fileName);
- return (TRUE);
+ return TRUE;
}
header_name = fileName;
static int alreadyWarned = FALSE;
if (alreadyWarned == FALSE) {
- bb_error_msg("Removing leading '/' from member names");
+ bb_error_msg("removing leading '/' from member names");
alreadyWarned = TRUE;
}
header_name++;
if (strlen(fileName) >= NAME_SIZE) {
bb_error_msg(bb_msg_name_longer_than_foo, NAME_SIZE);
- return (TRUE);
+ return TRUE;
}
if (header_name[0] == '\0')
/* Is this a regular file? */
if ((tbInfo->hlInfo == NULL) && (S_ISREG(statbuf->st_mode))) {
-
/* open the file we want to archive, and make sure all is well */
if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
- bb_perror_msg("%s: Cannot open", fileName);
- return (FALSE);
+ bb_perror_msg("%s: cannot open", fileName);
+ return FALSE;
}
}
/* Add an entry to the tarball */
if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
- return (FALSE);
+ return FALSE;
}
/* If it was a regular file, write out the body */
- if (inputFileFd >= 0 ) {
+ if (inputFileFd >= 0) {
ssize_t readSize = 0;
/* write the file to the archive */
close(inputFileFd);
/* Pad the file up to the tar block size */
- for (; (readSize % TAR_BLOCK_SIZE) != 0; readSize++)
- write(tbInfo->tarFd, "\0", 1);
+ readSize = (TAR_BLOCK_SIZE - readSize) & (TAR_BLOCK_SIZE-1);
+ bzero(bb_common_bufsiz1, readSize);
+ xwrite(tbInfo->tarFd, bb_common_bufsiz1, readSize);
}
- return (TRUE);
+ return TRUE;
}
-static inline int writeTarFile(const int tar_fd, const int verboseFlag,
+static int writeTarFile(const int tar_fd, const int verboseFlag,
const unsigned long dereferenceFlag, const llist_t *include,
const llist_t *exclude, const int gzip)
{
pid_t gzipPid = 0;
-
int errorFlag = FALSE;
- ssize_t size;
struct TarBallInfo tbInfo;
tbInfo.hlInfoHead = NULL;
/* Store the stat info for the tarball's file, so
* can avoid including the tarball into itself.... */
if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
- bb_perror_msg_and_die("Couldnt stat tar file");
+ bb_perror_msg_and_die("cannot stat tar file");
if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) {
int gzipDataPipe[2] = { -1, -1 };
if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0)
- bb_perror_msg_and_die("create pipe");
+ bb_perror_msg_and_die("pipe");
signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
while (1) {
char buf;
- int n = bb_full_read(gzipStatusPipe[0], &buf, 1);
+ int n = full_read(gzipStatusPipe[0], &buf, 1);
if (n == 0 && vfork_exec_errno != 0) {
errno = vfork_exec_errno;
include = include->link;
}
/* Write two empty blocks to the end of the archive */
- for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++)
- write(tbInfo.tarFd, "\0", 1);
+ bzero(bb_common_bufsiz1, 2*TAR_BLOCK_SIZE);
+ xwrite(tbInfo.tarFd, bb_common_bufsiz1, 2*TAR_BLOCK_SIZE);
/* To be pedantically correct, we would check if the tarball
* is smaller than 20 tar blocks, and pad it if it was smaller,
llist_t *newlist = NULL;
while (cur) {
- src_stream = bb_xfopen(cur->data, "r");
+ src_stream = xfopen(cur->data, "r");
tmp = cur;
cur = cur->link;
free(tmp);
- while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL)
- newlist = llist_add_to(newlist, line);
+ while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL) {
+ char *filename_ptr = last_char_is(line, '/');
+ if (filename_ptr > line)
+ *filename_ptr = '\0';
+ llist_add_to(&newlist, line);
+ }
fclose(src_stream);
}
return newlist;
archive_handle->seek = seek_by_char;
/* do the decompression, and cleanup */
- if (bb_xread_char(archive_handle->src_fd) != 0x1f ||
- bb_xread_char(archive_handle->src_fd) != 0x9d)
+ if (xread_char(archive_handle->src_fd) != 0x1f ||
+ xread_char(archive_handle->src_fd) != 0x9d)
{
- bb_error_msg_and_die("Invalid magic");
+ bb_error_msg_and_die("invalid magic");
}
archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress);
archive_handle->offset = 0;
- while (get_header_tar(archive_handle) == EXIT_SUCCESS);
+ while (get_header_tar(archive_handle) == EXIT_SUCCESS)
+ /* nothing */;
/* Can only do one file at a time */
return(EXIT_FAILURE);
#define TAR_OPT_AFTER_START 8
#define CTX_CREATE (1 << (TAR_OPT_AFTER_START))
-#define TAR_OPT_DEREFERNCE (1 << (TAR_OPT_AFTER_START + 1))
+#define TAR_OPT_DEREFERENCE (1 << (TAR_OPT_AFTER_START + 1))
#ifdef CONFIG_FEATURE_TAR_CREATE
# define TAR_OPT_STR_CREATE "ch"
# define TAR_OPT_AFTER_CREATE TAR_OPT_AFTER_START + 2
if (filename_ptr > argv[optind])
*filename_ptr = '\0';
- tar_handle->accept = llist_add_to(tar_handle->accept, argv[optind]);
+ llist_add_to(&(tar_handle->accept), argv[optind]);
optind++;
}
tar_handle->src_fd = fileno(tar_stream);
tar_handle->seek = seek_by_char;
} else {
- tar_handle->src_fd = bb_xopen(tar_filename, flags);
+ tar_handle->src_fd = xopen3(tar_filename, flags, 0666);
}
}
- if ((base_dir) && (chdir(base_dir)))
- bb_perror_msg_and_die("Couldnt chdir to %s", base_dir);
+ if (base_dir)
+ xchdir(base_dir);
/* create an archive */
if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) {
{
verboseFlag = TRUE;
}
- writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERNCE, tar_handle->accept,
+ writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERENCE,
+ tar_handle->accept,
tar_handle->reject, zipMode);
} else {
- while (get_header_ptr(tar_handle) == EXIT_SUCCESS);
+ while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
+ /* nothing */;
/* Check that every file that should have been extracted was */
while (tar_handle->accept) {
if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
&& !find_list_entry(tar_handle->passed, tar_handle->accept->data))
{
- bb_error_msg_and_die("%s: Not found in archive", tar_handle->accept->data);
+ bb_error_msg_and_die("%s: not found in archive", tar_handle->accept->data);
}
tar_handle->accept = tar_handle->accept->link;
}