+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).
#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.
*/
virtual int GetArchiveEntry();
virtual int ProcessEntityData( int );
+ virtual char *EntityDataAsString();
/* ...those for which each specialisation is expected to
* furnish its own task specific implementation...
*/
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)...
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;
+}
/*******************
*