[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