cpio applet, and changes to associated code
authorGlenn L McGrath <bug1@ihug.co.nz>
Fri, 22 Jun 2001 09:22:06 +0000 (09:22 -0000)
committerGlenn L McGrath <bug1@ihug.co.nz>
Fri, 22 Jun 2001 09:22:06 +0000 (09:22 -0000)
13 files changed:
Config.h
applets.h
applets/usage.h
ar.c
archival/ar.c
archival/cpio.c [new file with mode: 0644]
archival/dpkg_deb.c
cpio.c [new file with mode: 0644]
dpkg_deb.c
include/applets.h
include/usage.h
libbb/unarchive.c
usage.h

index a86f20a3d2e152949a443492a5f21ad29ee3a11a..b92540b3b5ccefe72750880ff0fbdecacf17380f 100644 (file)
--- 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
index 0fd89c71aa832de3bfa84216c697f9b9d6e1d4ab..88aec8ad1938b6816a437690aa6821901c49fc80 100644 (file)
--- 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
index 9fd3a2e1c6a7992b50c6400a8c3aea66390501cd..51a06b9774381563d53df798b5df1aedb7559120 100644 (file)
        "\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 fd98d86f547906d382d69dd66f2bd9c098ce8bcc..09a4a88948bfeb011fffaff85fcde4dc81d040f7 100644 (file)
--- 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;
index fd98d86f547906d382d69dd66f2bd9c098ce8bcc..09a4a88948bfeb011fffaff85fcde4dc81d040f7 100644 (file)
@@ -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 (file)
index 0000000..ecd6f53
--- /dev/null
@@ -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;
+}
+
index 77172b0f6d0df85d8880d39bfa4934ed5ec363fb..b1cbb1bbcb264bf3a38c61f87c77df19e3df91c9 100644 (file)
@@ -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 (file)
index 0000000..ecd6f53
--- /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;
+}
+
index 77172b0f6d0df85d8880d39bfa4934ed5ec363fb..b1cbb1bbcb264bf3a38c61f87c77df19e3df91c9 100644 (file)
@@ -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) {
index 0fd89c71aa832de3bfa84216c697f9b9d6e1d4ab..88aec8ad1938b6816a437690aa6821901c49fc80 100644 (file)
@@ -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
index 9fd3a2e1c6a7992b50c6400a8c3aea66390501cd..51a06b9774381563d53df798b5df1aedb7559120 100644 (file)
        "\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 \
index 635dcae350ce3001b5277a20cce1466a6d324e06..20609ded7ff75173ab2ce2f5e5a8e5a85bcb8a3d 100644 (file)
@@ -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 9fd3a2e1c6a7992b50c6400a8c3aea66390501cd..51a06b9774381563d53df798b5df1aedb7559120 100644 (file)
--- a/usage.h
+++ b/usage.h
        "\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 \