[prev in list] [next in list] [prev in thread] [next in thread]
List: busybox
Subject: Re: cpio: need to fix this
From: "Charles C. Bennett, Jr." <ccb () acm ! org>
Date: 2005-08-30 4:35:23
Message-ID: 1125376523.314.1.camel () bbox ! memecycle ! com
[Download RAW message or body]
Here you go... see attachment.
Comments gratefully accepted.
ccb
On Mon, 2005-08-29 at 19:56 -0500, Rob Landley wrote:
> On Monday 29 August 2005 11:28, Charles C. Bennett, Jr. wrote:
> > Hi All -
> >
> > Has anyone fixes in their back pocket for the fact that the cpio applet
> > doesn't handle hard links gracefully? If not, does anyone mind if I
> > generate a patch to archival/libunarchive/get_header_cpio.c using GNU
> > cpio to crib the algorithm?
>
> Go for it.
>
> On an unrelated note, do we have any plans for a cpio create that's compatible
> with initramfs in the 2.6 kernel? (Keeping in mind that the kernel _has_
> a .c program that creates one of these suckers already as part of the build,
> so it's not exactly a pressing need...)
>
> > Thanks in Advance,
> > ccb
>
> Rob
--
Charles C. Bennett, Jr. <ccb@acm.org>
["busybox-hardlink.patch" (busybox-hardlink.patch)]
--- ./archival/libunarchive/get_header_cpio.c.hardlink 2005-08-29 17:02:29.000000000 -0400
+++ ./archival/libunarchive/get_header_cpio.c 2005-08-29 19:14:21.000000000 -0400
@@ -23,21 +23,104 @@
#include "libbb.h"
typedef struct hardlinks_s {
- file_header_t *entry;
- int inode;
+ file_header_t *entry; /* file header info */
+ int major; /* dev major */
+ int minor; /* dev minor */
+ int inode; /* inode, unique only within a device */
+ int count; /* the list is a priority queue */
struct hardlinks_s *next;
} hardlinks_t;
+static hardlinks_t *
+findLink( hardlinks_t *list, int major, int minor, int inode ) {
+
+ while( list ) {
+ if( list->major == major
+ && list->minor == minor
+ && list->inode == inode ) {
+ return list;
+ }
+ list = list->next;
+ }
+ return NULL;
+}
+
+static hardlinks_t *
+putLink( hardlinks_t *list, hardlinks_t *alink ) {
+
+ hardlinks_t *last = NULL, *here;
+
+ alink->next = NULL;
+ if( list == NULL ) {
+ return alink;
+ }
+ here = list;
+ while( here ) {
+ if( here->major == alink->major
+ && here->minor == alink->minor
+ && here->inode == alink->inode ) {
+ /* keep track of how many of these we've seen */
+ alink->count = here->count + 1;
+ alink->next = here;
+ if( here == list ) {
+ return alink;
+ }
+ else {
+ return list;
+ }
+ }
+ last = here;
+ here = here->next;
+ }
+ last->next = alink;
+ return list;
+}
+
+
+static hardlinks_t
+*flushLinks( hardlinks_t *list, int major, int minor, int inode ) {
+ hardlinks_t *here = list, *last;
+ if( list == NULL ) return list;
+
+ while( here ) {
+ if( here->major == major
+ && here->minor == minor
+ && here->inode == inode ) {
+ int count = here->count;
+
+ while( count-- ) {
+ last = here;
+ here = here->next;
+ if( last == list ) {
+ list = here;
+ }
+ free(last->entry->name);
+ free(last->entry->link_name);
+ free(last->entry);
+ free(last);
+ }
+ return list;
+ }
+ else {
+ last = here;
+ here = here->next;
+ }
+ }
+ return list;
+}
+
extern char get_header_cpio(archive_handle_t *archive_handle)
{
static hardlinks_t *saved_hardlinks = NULL;
- static unsigned short pending_hardlinks = 0;
+ unsigned short linklast = 0;
file_header_t *file_header = archive_handle->file_header;
char cpio_header[110];
int namesize;
char dummy[16];
int major, minor, nlink, inode;
+#if 0
+ /* this is broken */
if (pending_hardlinks) { /* Deal with any pending hardlinks */
hardlinks_t *tmp;
hardlinks_t *oldtmp;
@@ -62,6 +145,7 @@
}
pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
}
+#endif
/* There can be padding before archive header */
data_align(archive_handle, 4);
@@ -103,11 +187,11 @@
oldtmp = tmp;
tmp = tmp->next;
free (oldtmp->entry->name);
+ free( oldtmp->entry->link_name );
free (oldtmp->entry);
free (oldtmp);
}
saved_hardlinks = NULL;
- pending_hardlinks = 0;
}
return(EXIT_FAILURE);
}
@@ -122,26 +206,30 @@
file_header->link_name = NULL;
}
if (nlink > 1 && !S_ISDIR(file_header->mode)) {
- if (file_header->size == 0) { /* Put file on a linked list for later */
- hardlinks_t *new = xmalloc(sizeof(hardlinks_t));
- new->next = saved_hardlinks;
- new->inode = inode;
- new->entry = file_header;
- saved_hardlinks = new;
- return(EXIT_SUCCESS); // Skip this one
- } else { /* Found the file with data in */
- hardlinks_t *tmp = saved_hardlinks;
- pending_hardlinks = 1;
- while (tmp) {
- if (tmp->inode == inode) {
- tmp->entry->link_name = bb_xstrdup(file_header->name);
- nlink--;
- }
- tmp = tmp->next;
+ hardlinks_t *p = findLink( saved_hardlinks, major, minor, inode );
+ if( p != NULL && p->count + 1 == nlink ) {
+ linklast = 1;
+ }
+ else {
+ p = xmalloc( sizeof(hardlinks_t) );
+ if( p == NULL ) {
+ printf( "No Memory!\n" );
+ exit(1);
}
- if (nlink > 1) {
- bb_error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
+ p->count = 1;
+ p->major = major;
+ p->minor = minor;
+ p->inode = inode;
+ p->entry = xmalloc( sizeof(file_header_t) );
+ if( p->entry == NULL ) {
+ printf( "No Memory!\n" );
+ exit(1);
}
+ memcpy( p->entry, file_header, sizeof(file_header_t) );
+ p->entry->name = bb_xstrdup( file_header->name );
+ /* printf( "pushing %s\n", p->entry->name ); */
+ saved_hardlinks = putLink( saved_hardlinks, p );
+ return(EXIT_SUCCESS);
}
}
file_header->device = makedev(major, minor);
@@ -149,7 +237,29 @@
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
archive_handle->action_data(archive_handle);
archive_handle->action_header(archive_handle->file_header);
- } else {
+ if( linklast ) {
+ /* we just dropped in a file that has pending links */
+ hardlinks_t *p = findLink( saved_hardlinks, major, minor, inode );
+ int count = p->count;
+ while( count-- ) {
+ p->entry->link_name = bb_xstrdup(file_header->name);
+ archive_handle->file_header = p->entry;
+ if( archive_handle->filter(archive_handle) == EXIT_SUCCESS ) {
+ archive_handle->action_data(archive_handle);
+ archive_handle->action_header(p->entry);
+ }
+ p = p->next;
+ }
+ /* restore the real current file_header
+ * not sure any body really cares...
+ */
+ archive_handle->file_header = file_header;
+
+ /* flush this batch of saved_hardlinks */
+ saved_hardlinks = flushLinks( saved_hardlinks, major, minor, inode );
+ }
+ }
+ else {
data_skip(archive_handle);
}
_______________________________________________
busybox mailing list
busybox@busybox.net
http://busybox.net/cgi-bin/mailman/listinfo/busybox
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic