aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn L McGrath <bug1@ihug.co.nz>2001-06-22 09:22:06 +0000
committerGlenn L McGrath <bug1@ihug.co.nz>2001-06-22 09:22:06 +0000
commit8f5b63edea12501b998400789da5646140bb9911 (patch)
tree5a1924092009892cc80f0b0947ec1bae17ca3b1c
parent52a97ca00cf5d290c9beb65ba7c217a5ed69ee42 (diff)
downloadbusybox-8f5b63edea12501b998400789da5646140bb9911.tar.gz
cpio applet, and changes to associated code
-rw-r--r--Config.h1
-rw-r--r--applets.h3
-rw-r--r--applets/usage.h12
-rw-r--r--ar.c2
-rw-r--r--archival/ar.c2
-rw-r--r--archival/cpio.c93
-rw-r--r--archival/dpkg_deb.c3
-rw-r--r--cpio.c93
-rw-r--r--dpkg_deb.c3
-rw-r--r--include/applets.h3
-rw-r--r--include/usage.h12
-rw-r--r--libbb/unarchive.c85
-rw-r--r--usage.h12
13 files changed, 305 insertions, 19 deletions
diff --git a/Config.h b/Config.h
index a86f20a3d..b92540b3b 100644
--- a/Config.h
+++ b/Config.h
@@ -19,6 +19,7 @@
#define BB_CLEAR
//#define BB_CMP
#define BB_CP
+//#define BB_CPIO
#define BB_CUT
#define BB_DATE
//#define BB_DC
diff --git a/applets.h b/applets.h
index 0fd89c71a..88aec8ad1 100644
--- a/applets.h
+++ b/applets.h
@@ -83,6 +83,9 @@
#ifdef BB_CP
APPLET(cp, cp_main, _BB_DIR_BIN)
#endif
+#ifdef BB_CPIO
+ APPLET(cpio, cpio_main, _BB_DIR_BIN)
+#endif
#ifdef BB_CUT
APPLET(cut, cut_main, _BB_DIR_USR_BIN)
#endif
diff --git a/applets/usage.h b/applets/usage.h
index 9fd3a2e1c..51a06b977 100644
--- a/applets/usage.h
+++ b/applets/usage.h
@@ -129,6 +129,18 @@
"\t-f\tforce (implied; ignored) - always set\n" \
"\t-R\tCopies directories recursively"
+#define cpio_trivial_usage \
+ "-[dimtuv][F cpiofile]"
+#define cpio_full_usage \
+ "Extract or list files from a cpio archive\n" \
+ "Main operation mode:\n" \
+ "\td\t\tmake directories (assumed)\n" \
+ "\ti\t\textract\n" \
+ "\tm\t\tpreserve time\n" \
+ "\tt\t\tlist\n" \
+ "\tu\t\tunconditional (assumed)\t" \
+ "\tF\t\tinput from file\t"
+
#define cut_trivial_usage \
"[OPTION]... [FILE]..."
#define cut_full_usage \
diff --git a/ar.c b/ar.c
index fd98d86f5..09a4a8894 100644
--- a/ar.c
+++ b/ar.c
@@ -34,7 +34,7 @@ extern int ar_main(int argc, char **argv)
FILE *src_stream = NULL;
char **extract_names = NULL;
char ar_magic[8];
- int extract_function = 0;
+ int extract_function = extract_unconditional;
int opt;
int num_of_entries = 0;
extern off_t archive_offset;
diff --git a/archival/ar.c b/archival/ar.c
index fd98d86f5..09a4a8894 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -34,7 +34,7 @@ extern int ar_main(int argc, char **argv)
FILE *src_stream = NULL;
char **extract_names = NULL;
char ar_magic[8];
- int extract_function = 0;
+ int extract_function = extract_unconditional;
int opt;
int num_of_entries = 0;
extern off_t archive_offset;
diff --git a/archival/cpio.c b/archival/cpio.c
new file mode 100644
index 000000000..ecd6f534a
--- /dev/null
+++ b/archival/cpio.c
@@ -0,0 +1,93 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cpio implementation for busybox
+ *
+ * Copyright (C) 2001 by Glenn McGrath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Limitations:
+ * Doesn't check CRC's
+ * Only supports new ASCII and CRC formats
+ * Doesnt support hard links
+ *
+ */
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int cpio_main(int argc, char **argv)
+{
+ FILE *src_stream = stdin;
+ char **extract_names = NULL;
+ int extract_function = 0;
+ int num_of_entries = 0;
+ int opt = 0;
+ mode_t oldmask = 0;
+
+ while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) {
+ switch (opt) {
+ case 'i': // extract
+ extract_function |= extract_all_to_fs;
+ break;
+ case 'd': // create directories
+ extract_function |= extract_create_dirs;
+ oldmask = umask(077); /* Make create_path act like GNU cpio */
+ break;
+ case 'm': // preserve modification time
+ extract_function |= extract_preserve_date;
+ break;
+ case 'v': // verbosly list files
+ extract_function |= extract_verbose_list;
+ break;
+ case 'u': // unconditional
+ extract_function |= extract_unconditional;
+ break;
+ case 't': // list files
+ extract_function |= extract_list;
+ break;
+ case 'F':
+ src_stream = xfopen(optarg, "r");
+ break;
+ default:
+ show_usage();
+ }
+ }
+
+ if (extract_function & extract_all_to_fs && extract_function & extract_list) {
+ extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/
+ }
+
+ if (extract_function & extract_all_to_fs && extract_function & extract_verbose_list) { /* The meaning of v changes on extract */
+ extract_function ^= extract_verbose_list;
+ extract_function |= extract_list;
+ }
+
+ extract_names = malloc(4);
+ while (optind < argc) {
+ num_of_entries++;
+ *extract_names = realloc(*extract_names, num_of_entries);
+ extract_names[num_of_entries - 1] = xstrdup(argv[optind]);
+ optind++;
+ }
+
+ unarchive(src_stream, &get_header_cpio, extract_function, "./", extract_names);
+ if (oldmask) umask(oldmask); /* Restore umask if we changed it */
+ return EXIT_SUCCESS;
+}
+
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c
index 77172b0f6..b1cbb1bbc 100644
--- a/archival/dpkg_deb.c
+++ b/archival/dpkg_deb.c
@@ -26,7 +26,7 @@ extern int dpkg_deb_main(int argc, char **argv)
char *output_buffer = NULL;
int opt = 0;
int arg_type = 0;
- int deb_extract_funct = extract_create_dirs;
+ int deb_extract_funct = extract_create_dirs | extract_unconditional;
const int arg_type_prefix = 1;
const int arg_type_field = 2;
@@ -92,6 +92,7 @@ extern int dpkg_deb_main(int argc, char **argv)
strcat(prefix, "/");
}
}
+ mkdir(prefix, 0777);
}
if (arg_type == arg_type_filename) {
diff --git a/cpio.c b/cpio.c
new file mode 100644
index 000000000..ecd6f534a
--- /dev/null
+++ b/cpio.c
@@ -0,0 +1,93 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cpio implementation for busybox
+ *
+ * Copyright (C) 2001 by Glenn McGrath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Limitations:
+ * Doesn't check CRC's
+ * Only supports new ASCII and CRC formats
+ * Doesnt support hard links
+ *
+ */
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int cpio_main(int argc, char **argv)
+{
+ FILE *src_stream = stdin;
+ char **extract_names = NULL;
+ int extract_function = 0;
+ int num_of_entries = 0;
+ int opt = 0;
+ mode_t oldmask = 0;
+
+ while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) {
+ switch (opt) {
+ case 'i': // extract
+ extract_function |= extract_all_to_fs;
+ break;
+ case 'd': // create directories
+ extract_function |= extract_create_dirs;
+ oldmask = umask(077); /* Make create_path act like GNU cpio */
+ break;
+ case 'm': // preserve modification time
+ extract_function |= extract_preserve_date;
+ break;
+ case 'v': // verbosly list files
+ extract_function |= extract_verbose_list;
+ break;
+ case 'u': // unconditional
+ extract_function |= extract_unconditional;
+ break;
+ case 't': // list files
+ extract_function |= extract_list;
+ break;
+ case 'F':
+ src_stream = xfopen(optarg, "r");
+ break;
+ default:
+ show_usage();
+ }
+ }
+
+ if (extract_function & extract_all_to_fs && extract_function & extract_list) {
+ extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/
+ }
+
+ if (extract_function & extract_all_to_fs && extract_function & extract_verbose_list) { /* The meaning of v changes on extract */
+ extract_function ^= extract_verbose_list;
+ extract_function |= extract_list;
+ }
+
+ extract_names = malloc(4);
+ while (optind < argc) {
+ num_of_entries++;
+ *extract_names = realloc(*extract_names, num_of_entries);
+ extract_names[num_of_entries - 1] = xstrdup(argv[optind]);
+ optind++;
+ }
+
+ unarchive(src_stream, &get_header_cpio, extract_function, "./", extract_names);
+ if (oldmask) umask(oldmask); /* Restore umask if we changed it */
+ return EXIT_SUCCESS;
+}
+
diff --git a/dpkg_deb.c b/dpkg_deb.c
index 77172b0f6..b1cbb1bbc 100644
--- a/dpkg_deb.c
+++ b/dpkg_deb.c
@@ -26,7 +26,7 @@ extern int dpkg_deb_main(int argc, char **argv)
char *output_buffer = NULL;
int opt = 0;
int arg_type = 0;
- int deb_extract_funct = extract_create_dirs;
+ int deb_extract_funct = extract_create_dirs | extract_unconditional;
const int arg_type_prefix = 1;
const int arg_type_field = 2;
@@ -92,6 +92,7 @@ extern int dpkg_deb_main(int argc, char **argv)
strcat(prefix, "/");
}
}
+ mkdir(prefix, 0777);
}
if (arg_type == arg_type_filename) {
diff --git a/include/applets.h b/include/applets.h
index 0fd89c71a..88aec8ad1 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -83,6 +83,9 @@
#ifdef BB_CP
APPLET(cp, cp_main, _BB_DIR_BIN)
#endif
+#ifdef BB_CPIO
+ APPLET(cpio, cpio_main, _BB_DIR_BIN)
+#endif
#ifdef BB_CUT
APPLET(cut, cut_main, _BB_DIR_USR_BIN)
#endif
diff --git a/include/usage.h b/include/usage.h
index 9fd3a2e1c..51a06b977 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -129,6 +129,18 @@
"\t-f\tforce (implied; ignored) - always set\n" \
"\t-R\tCopies directories recursively"
+#define cpio_trivial_usage \
+ "-[dimtuv][F cpiofile]"
+#define cpio_full_usage \
+ "Extract or list files from a cpio archive\n" \
+ "Main operation mode:\n" \
+ "\td\t\tmake directories (assumed)\n" \
+ "\ti\t\textract\n" \
+ "\tm\t\tpreserve time\n" \
+ "\tt\t\tlist\n" \
+ "\tu\t\tunconditional (assumed)\t" \
+ "\tF\t\tinput from file\t"
+
#define cut_trivial_usage \
"[OPTION]... [FILE]..."
#define cut_full_usage \
diff --git a/libbb/unarchive.c b/libbb/unarchive.c
index 635dcae35..20609ded7 100644
--- a/libbb/unarchive.c
+++ b/libbb/unarchive.c
@@ -119,10 +119,11 @@ char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *f
}
}
else if (function & extract_all_to_fs) {
-#if 0
struct stat oldfile;
- if ( (S_ISLNK(file_entry->mode) ? lstat (full_name, &oldfile) : stat (full_name, &oldfile)) == 0) { /* The file already exists */
- if (function & extract_unconditional || oldfile.st_mtime < file_entry->mtime) {
+ int stat_res;
+ stat_res = lstat (full_name, &oldfile);
+ if (stat_res == 0) { /* The file already exists */
+ if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) {
if (!S_ISDIR(oldfile.st_mode)) {
unlink(full_name); /* Directories might not be empty etc */
}
@@ -134,7 +135,6 @@ char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *f
return (NULL);
}
}
-#endif
switch(file_entry->mode & S_IFMT) {
case S_IFREG:
if (file_entry->link_name) { /* Found a cpio hard link */
@@ -153,10 +153,11 @@ char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *f
}
break;
case S_IFDIR:
- /* Use make_directory instead of mkdir in case prefix path hasn't been created */
- if (function & extract_create_dirs) {
- if (make_directory(full_name, file_entry->mode, FILEUTILS_RECUR) < 0) {
- return NULL;
+ if ((function & extract_create_dirs) && (stat_res != 0)) {
+ /* Make sure the prefix component of full_name was create
+ * in applet before getting here*/
+ if (mkdir(full_name, file_entry->mode) < 0) {
+ perror_msg("extract_archive: ");
}
}
break;
@@ -335,14 +336,38 @@ void *get_header_ar(FILE *src_stream)
#endif
#ifdef L_get_header_cpio
+struct hardlinks {
+ file_header_t *entry;
+ int inode;
+ struct hardlinks *next;
+};
+
void *get_header_cpio(FILE *src_stream)
{
file_header_t *cpio_entry = NULL;
char cpio_header[110];
- char dummy[14];
int namesize;
- int major, minor, nlink;
-
+ char dummy[16];
+ int major, minor, nlink, inode;
+ static struct hardlinks *saved_hardlinks = NULL;
+ static int pending_hardlinks = 0;
+
+ if (pending_hardlinks) { /* Deal with any pending hardlinks */
+ struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL;
+ while (tmp) {
+ if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
+ cpio_entry = tmp->entry;
+ if (oldtmp) oldtmp->next = tmp->next; /* Remove item from linked list */
+ else saved_hardlinks = tmp->next;
+ free(tmp);
+ return (cpio_entry);
+ }
+ oldtmp = tmp;
+ tmp = tmp->next;
+ }
+ pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
+ }
+
/* There can be padding before archive header */
seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4);
if (fread(cpio_header, 1, 110, src_stream) == 110) {
@@ -356,8 +381,8 @@ void *get_header_cpio(FILE *src_stream)
/* Doesnt do the crc check yet */
case '1': /* "newc" header format */
cpio_entry = (file_header_t *) xcalloc(1, sizeof(file_header_t));
- sscanf(cpio_header, "%14c%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
- dummy, &cpio_entry->mode, &cpio_entry->uid, &cpio_entry->gid,
+ sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
+ dummy, &inode, &cpio_entry->mode, &cpio_entry->uid, &cpio_entry->gid,
&nlink, &cpio_entry->mtime, &cpio_entry->size,
dummy, &major, &minor, &namesize, dummy);
@@ -368,6 +393,19 @@ void *get_header_cpio(FILE *src_stream)
seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4);
if (strcmp(cpio_entry->name, "TRAILER!!!") == 0) {
printf("%d blocks\n", (int) (archive_offset % 512 ? (archive_offset / 512) + 1 : archive_offset / 512)); /* Always round up */
+ if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
+ struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL;
+ while (tmp) {
+ error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
+ oldtmp = tmp;
+ tmp = tmp->next;
+ free (oldtmp->entry->name);
+ free (oldtmp->entry);
+ free (oldtmp);
+ }
+ saved_hardlinks = NULL;
+ pending_hardlinks = 0;
+ }
return(NULL);
}
@@ -376,9 +414,26 @@ void *get_header_cpio(FILE *src_stream)
fread(cpio_entry->link_name, 1, cpio_entry->size, src_stream);
archive_offset += cpio_entry->size;
}
- if (nlink > 1 && !S_ISDIR(cpio_entry->mode) && cpio_entry->size == 0) {
- error_msg("%s not extracted: Cannot handle hard links yet", cpio_entry->name);
+ if (nlink > 1 && !S_ISDIR(cpio_entry->mode)) {
+ if (cpio_entry->size == 0) { /* Put file on a linked list for later */
+ struct hardlinks *new = xmalloc(sizeof(struct hardlinks));
+ new->next = saved_hardlinks;
+ new->inode = inode;
+ new->entry = cpio_entry;
+ saved_hardlinks = new;
return(get_header_cpio(src_stream)); /* Recurse to next file */
+ } else { /* Found the file with data in */
+ struct hardlinks *tmp = saved_hardlinks;
+ pending_hardlinks = 1;
+ while (tmp) {
+ if (tmp->inode == inode) {
+ tmp->entry->link_name = xstrdup(cpio_entry->name);
+ nlink--;
+ }
+ tmp = tmp->next;
+ }
+ if (nlink > 1) error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
+ }
}
cpio_entry->device = (major << 8) | minor;
break;
diff --git a/usage.h b/usage.h
index 9fd3a2e1c..51a06b977 100644
--- a/usage.h
+++ b/usage.h
@@ -129,6 +129,18 @@
"\t-f\tforce (implied; ignored) - always set\n" \
"\t-R\tCopies directories recursively"
+#define cpio_trivial_usage \
+ "-[dimtuv][F cpiofile]"
+#define cpio_full_usage \
+ "Extract or list files from a cpio archive\n" \
+ "Main operation mode:\n" \
+ "\td\t\tmake directories (assumed)\n" \
+ "\ti\t\textract\n" \
+ "\tm\t\tpreserve time\n" \
+ "\tt\t\tlist\n" \
+ "\tu\t\tunconditional (assumed)\t" \
+ "\tF\t\tinput from file\t"
+
#define cut_trivial_usage \
"[OPTION]... [FILE]..."
#define cut_full_usage \