OSDN Git Service

Handle the GNU long name tar header format.
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Fri, 6 Aug 2010 22:34:39 +0000 (22:34 +0000)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Fri, 6 Aug 2010 22:34:39 +0000 (22:34 +0000)
ChangeLog
src/pkgproc.h
src/tarproc.cpp

index 04b828c..0c2fb85 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2010-07-27  Cesar Strauss  <cestrauss@gmail.com>
+
+       Handle the GNU long name tar header format.
+
+       * src/pkgproc.h (TAR_ENTITY_TYPE_GNU_LONGNAME): New manifest constant;
+       define it.
+       (pkgTarArchiveProcessor::EntityDataAsString): New protected method;
+       declare and...
+       * src/tarproc.cpp: ...implement it.
+       (pkgTarArchiveProcessor::Process): Before building the entry pathname,
+       check for a GNU long name type header; when found, read pathname from
+       the entry data area, before fetching the following header, from which
+       to retrieve the associated entity data.
+
 2010-06-24  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
        Work around an autoconf bug (reported by Stefano Sabatini).
index ce23736..03db49a 100644 (file)
@@ -125,6 +125,7 @@ union tar_archive_header
 #define TAR_ENTITY_TYPE_CHRDEV         '3'
 #define TAR_ENTITY_TYPE_BLKDEV         '4'
 #define TAR_ENTITY_TYPE_DIRECTORY      '5'
+#define TAR_ENTITY_TYPE_GNU_LONGNAME   'L'
 
 /* Some older style tar archives may use '\0' as an alternative to '0',
  * to identify an archive entry representing a regular file.
@@ -159,6 +160,7 @@ class pkgTarArchiveProcessor : public pkgArchiveProcessor
      */
     virtual int GetArchiveEntry();
     virtual int ProcessEntityData( int );
+    virtual char *EntityDataAsString();
 
     /* ...those for which each specialisation is expected to
      * furnish its own task specific implementation...
index 6112f08..0131e14 100644 (file)
@@ -231,12 +231,41 @@ int pkgTarArchiveProcessor::Process()
    */
   while( GetArchiveEntry() > 0 )
   {
+    char *prefix = *header.field.prefix ? header.field.prefix : NULL;
+    char *name = header.field.name;
+
+    /* Handle the GNU long name header format. 
+     * If the pathname overflows the name field, GNU tar creates a special
+     * entry type, where the data contains the full pathname for the
+     * following entry.
+     */
+    char *longname = NULL;
+    if( *header.field.typeflag == TAR_ENTITY_TYPE_GNU_LONGNAME )
+    {
+      /* Extract the full pathname from the data of this entry.
+       */
+      longname = EntityDataAsString();
+      if( !longname )
+        dmh_notify( DMH_ERROR, "Unable to read a long name entry\n" );
+
+      /* Read the entry for which this long name is intended.
+       */
+      if( GetArchiveEntry() <= 0 )
+        dmh_notify( DMH_ERROR, "Expected a new entry after a long name entry\n" );
+
+      /* Use the previously determined long name as the pathname for this entry.
+       */
+      prefix = NULL;
+      name = longname;
+    }
+
     /* Found an archive entry; map it to an equivalent file system
      * path name, within the designated sysroot hierarchy.
      */
-    char *prefix = *header.field.prefix ? header.field.prefix : NULL;
-    char pathname[mkpath( NULL, sysroot_path, header.field.name, prefix )];
-    mkpath( pathname, sysroot_path, header.field.name, prefix );
+    char pathname[mkpath( NULL, sysroot_path, name, prefix )];
+    mkpath( pathname, sysroot_path, name, prefix );
+
+    free( longname );
 
     /* Direct further processing to the appropriate handler; (this
      * is specific to the archive entry classification)...
@@ -388,6 +417,45 @@ int pkgTarArchiveProcessor::ProcessEntityData( int fd )
   return status;
 }
 
+char *pkgTarArchiveProcessor::EntityDataAsString()
+{
+  /* Read the data associated with a specific header within a tar archive
+   * and return it as a string.  The return value is stored in memory which
+   * is allocated by malloc; it should be freed when no longer required.
+   *
+   * It is assumed that the return data can be accommodated within available
+   * heap memory.  Since the length isn't returned, we assume that the string
+   * is NUL-terminated, and that it contains no embedded NULs.
+   *
+   * In the event of any error, NULL is returned.
+   */
+  char *data;
+  uint64_t bytes_to_copy = octval( header.field.size );
+  
+  /* Round the buffer size to the smallest multiple of the record size.
+   */
+  bytes_to_copy += sizeof( header ) - 1;
+  bytes_to_copy -= bytes_to_copy % sizeof( header );
+
+  /* Allocate the data buffer.
+   */
+  data = (char*)(malloc( bytes_to_copy ));
+  if( !data )
+    return NULL;
+  
+  /* Read the data into the buffer.
+   */
+  size_t count = stream->Read( data, bytes_to_copy );
+  if( count < bytes_to_copy )
+  {
+    /* Failure to fully populate the transfer buffer, (i.e. a short
+     * read), indicates a corrupt archive.
+     */
+    free( data );
+    return NULL;
+  }
+  return data;
+}
 
 /*******************
  *