Browse Source

Move over to new tar package

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271947 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Donald 23 years ago
parent
commit
ae05bf36b0
9 changed files with 4 additions and 2227 deletions
  1. BIN
      proposal/myrmidon/lib/excalibur-tar-1.0.jar
  2. +0
    -488
      proposal/myrmidon/src/java/org/apache/aut/tar/TarBuffer.java
  3. +0
    -133
      proposal/myrmidon/src/java/org/apache/aut/tar/TarConstants.java
  4. +0
    -627
      proposal/myrmidon/src/java/org/apache/aut/tar/TarEntry.java
  5. +0
    -419
      proposal/myrmidon/src/java/org/apache/aut/tar/TarInputStream.java
  6. +0
    -329
      proposal/myrmidon/src/java/org/apache/aut/tar/TarOutputStream.java
  7. +0
    -224
      proposal/myrmidon/src/java/org/apache/aut/tar/TarUtils.java
  8. +2
    -4
      proposal/myrmidon/src/todo/org/apache/tools/todo/taskdefs/archive/Tar.java
  9. +2
    -3
      proposal/myrmidon/src/todo/org/apache/tools/todo/taskdefs/archive/Untar.java

BIN
proposal/myrmidon/lib/excalibur-tar-1.0.jar View File


+ 0
- 488
proposal/myrmidon/src/java/org/apache/aut/tar/TarBuffer.java View File

@@ -1,488 +0,0 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.aut.tar;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* The TarBuffer class implements the tar archive concept of a buffered input
* stream. This concept goes back to the days of blocked tape drives and special
* io devices. In the Java universe, the only real function that this class
* performs is to ensure that files have the correct "block" size, or other tars
* will complain. <p>
*
* You should never have a need to access this class directly. TarBuffers are
* created by Tar IO Streams.
*
* @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
class TarBuffer
{
public final static int DEFAULT_RCDSIZE = ( 512 );
public final static int DEFAULT_BLKSIZE = ( DEFAULT_RCDSIZE * 20 );

private byte[] m_blockBuffer;
private int m_blockSize;
private int m_currBlkIdx;
private int m_currRecIdx;
private boolean m_debug;

private InputStream m_input;
private OutputStream m_output;
private int m_recordSize;
private int m_recsPerBlock;

public TarBuffer( final InputStream input )
{
this( input, TarBuffer.DEFAULT_BLKSIZE );
}

public TarBuffer( final InputStream input, final int blockSize )
{
this( input, blockSize, TarBuffer.DEFAULT_RCDSIZE );
}

public TarBuffer( final InputStream input,
final int blockSize,
final int recordSize )
{
m_input = input;
initialize( blockSize, recordSize );
}

public TarBuffer( final OutputStream output )
{
this( output, TarBuffer.DEFAULT_BLKSIZE );
}

public TarBuffer( final OutputStream output, final int blockSize )
{
this( output, blockSize, TarBuffer.DEFAULT_RCDSIZE );
}

public TarBuffer( final OutputStream output,
final int blockSize,
final int recordSize )
{
m_output = output;
initialize( blockSize, recordSize );
}

/**
* Set the debugging flag for the buffer.
*
* @param debug If true, print debugging output.
*/
public void setDebug( final boolean debug )
{
m_debug = debug;
}

/**
* Get the TAR Buffer's block size. Blocks consist of multiple records.
*
* @return The BlockSize value
*/
public int getBlockSize()
{
return m_blockSize;
}

/**
* Get the current block number, zero based.
*
* @return The current zero based block number.
*/
public int getCurrentBlockNum()
{
return m_currBlkIdx;
}

/**
* Get the current record number, within the current block, zero based.
* Thus, current offset = (currentBlockNum * recsPerBlk) + currentRecNum.
*
* @return The current zero based record number.
*/
public int getCurrentRecordNum()
{
return m_currRecIdx - 1;
}

/**
* Get the TAR Buffer's record size.
*
* @return The RecordSize value
*/
public int getRecordSize()
{
return m_recordSize;
}

/**
* Determine if an archive record indicate End of Archive. End of archive is
* indicated by a record that consists entirely of null bytes.
*
* @param record The record data to check.
* @return The EOFRecord value
*/
public boolean isEOFRecord( final byte[] record )
{
final int size = getRecordSize();
for( int i = 0; i < size; ++i )
{
if( record[ i ] != 0 )
{
return false;
}
}

return true;
}

/**
* Close the TarBuffer. If this is an output buffer, also flush the current
* block before closing.
*/
public void close()
throws IOException
{
if( m_debug )
{
debug( "TarBuffer.closeBuffer()." );
}

if( null != m_output )
{
flushBlock();

if( m_output != System.out && m_output != System.err )
{
m_output.close();
m_output = null;
}
}
else if( m_input != null )
{
if( m_input != System.in )
{
m_input.close();
m_input = null;
}
}
}

/**
* Read a record from the input stream and return the data.
*
* @return The record data.
* @exception IOException Description of Exception
*/
public byte[] readRecord()
throws IOException
{
if( m_debug )
{
final String message = "ReadRecord: recIdx = " + m_currRecIdx +
" blkIdx = " + m_currBlkIdx;
debug( message );
}

if( null == m_input )
{
final String message = "reading from an output buffer";
throw new IOException( message );
}

if( m_currRecIdx >= m_recsPerBlock )
{
if( !readBlock() )
{
return null;
}
}

final byte[] result = new byte[ m_recordSize ];
System.arraycopy( m_blockBuffer,
( m_currRecIdx * m_recordSize ),
result,
0,
m_recordSize );

m_currRecIdx++;

return result;
}

/**
* Skip over a record on the input stream.
*/
public void skipRecord()
throws IOException
{
if( m_debug )
{
final String message = "SkipRecord: recIdx = " + m_currRecIdx +
" blkIdx = " + m_currBlkIdx;
debug( message );
}

if( null == m_input )
{
final String message = "reading (via skip) from an output buffer";
throw new IOException( message );
}

if( m_currRecIdx >= m_recsPerBlock )
{
if( !readBlock() )
{
return;// UNDONE
}
}

m_currRecIdx++;
}

/**
* Write an archive record to the archive.
*
* @param record The record data to write to the archive.
*/
public void writeRecord( final byte[] record )
throws IOException
{
if( m_debug )
{
final String message = "WriteRecord: recIdx = " + m_currRecIdx +
" blkIdx = " + m_currBlkIdx;
debug( message );
}

if( null == m_output )
{
final String message = "writing to an input buffer";
throw new IOException( message );
}

if( record.length != m_recordSize )
{
final String message = "record to write has length '" +
record.length + "' which is not the record size of '" +
m_recordSize + "'";
throw new IOException( message );
}

if( m_currRecIdx >= m_recsPerBlock )
{
writeBlock();
}

System.arraycopy( record,
0,
m_blockBuffer,
( m_currRecIdx * m_recordSize ),
m_recordSize );

m_currRecIdx++;
}

/**
* Write an archive record to the archive, where the record may be inside of
* a larger array buffer. The buffer must be "offset plus record size" long.
*
* @param buffer The buffer containing the record data to write.
* @param offset The offset of the record data within buf.
*/
public void writeRecord( final byte[] buffer, final int offset )
throws IOException
{
if( m_debug )
{
final String message = "WriteRecord: recIdx = " + m_currRecIdx +
" blkIdx = " + m_currBlkIdx;
debug( message );
}

if( null == m_output )
{
final String message = "writing to an input buffer";
throw new IOException( message );
}

if( ( offset + m_recordSize ) > buffer.length )
{
final String message = "record has length '" + buffer.length +
"' with offset '" + offset + "' which is less than the record size of '" +
m_recordSize + "'";
throw new IOException( message );
}

if( m_currRecIdx >= m_recsPerBlock )
{
writeBlock();
}

System.arraycopy( buffer,
offset,
m_blockBuffer,
( m_currRecIdx * m_recordSize ),
m_recordSize );

m_currRecIdx++;
}

/**
* Flush the current data block if it has any data in it.
*/
private void flushBlock()
throws IOException
{
if( m_debug )
{
final String message = "TarBuffer.flushBlock() called.";
debug( message );
}

if( m_output == null )
{
final String message = "writing to an input buffer";
throw new IOException( message );
}

if( m_currRecIdx > 0 )
{
writeBlock();
}
}

/**
* Initialization common to all constructors.
*/
private void initialize( final int blockSize, final int recordSize )
{
m_debug = false;
m_blockSize = blockSize;
m_recordSize = recordSize;
m_recsPerBlock = ( m_blockSize / m_recordSize );
m_blockBuffer = new byte[ m_blockSize ];

if( null != m_input )
{
m_currBlkIdx = -1;
m_currRecIdx = m_recsPerBlock;
}
else
{
m_currBlkIdx = 0;
m_currRecIdx = 0;
}
}

/**
* @return false if End-Of-File, else true
*/
private boolean readBlock()
throws IOException
{
if( m_debug )
{
final String message = "ReadBlock: blkIdx = " + m_currBlkIdx;
debug( message );
}

if( null == m_input )
{
final String message = "reading from an output buffer";
throw new IOException( message );
}

m_currRecIdx = 0;

int offset = 0;
int bytesNeeded = m_blockSize;

while( bytesNeeded > 0 )
{
final long numBytes = m_input.read( m_blockBuffer, offset, bytesNeeded );

//
// NOTE
// We have fit EOF, and the block is not full!
//
// This is a broken archive. It does not follow the standard
// blocking algorithm. However, because we are generous, and
// it requires little effort, we will simply ignore the error
// and continue as if the entire block were read. This does
// not appear to break anything upstream. We used to return
// false in this case.
//
// Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
//
if( numBytes == -1 )
{
break;
}

offset += numBytes;
bytesNeeded -= numBytes;

if( numBytes != m_blockSize )
{
if( m_debug )
{
System.err.println( "ReadBlock: INCOMPLETE READ "
+ numBytes + " of " + m_blockSize
+ " bytes read." );
}
}
}

m_currBlkIdx++;

return true;
}

/**
* Write a TarBuffer block to the archive.
*
* @exception IOException Description of Exception
*/
private void writeBlock()
throws IOException
{
if( m_debug )
{
final String message = "WriteBlock: blkIdx = " + m_currBlkIdx;
debug( message );
}

if( null == m_output )
{
final String message = "writing to an input buffer";
throw new IOException( message );
}

m_output.write( m_blockBuffer, 0, m_blockSize );
m_output.flush();

m_currRecIdx = 0;
m_currBlkIdx++;
}

protected void debug( final String message )
{
if( m_debug )
{
System.err.println( message );
}
}
}

+ 0
- 133
proposal/myrmidon/src/java/org/apache/aut/tar/TarConstants.java View File

@@ -1,133 +0,0 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.aut.tar;

/**
* This interface contains all the definitions used in the package.
*
* @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
*/
interface TarConstants
{
/**
* The length of the mode field in a header buffer.
*/
int MODELEN = 8;

/**
* The length of the user id field in a header buffer.
*/
int UIDLEN = 8;

/**
* The length of the group id field in a header buffer.
*/
int GIDLEN = 8;

/**
* The length of the checksum field in a header buffer.
*/
int CHKSUMLEN = 8;

/**
* The length of the size field in a header buffer.
*/
int SIZELEN = 12;

/**
* The length of the magic field in a header buffer.
*/
int MAGICLEN = 8;

/**
* The length of the modification time field in a header buffer.
*/
int MODTIMELEN = 12;

/**
* The length of the user name field in a header buffer.
*/
int UNAMELEN = 32;

/**
* The length of the group name field in a header buffer.
*/
int GNAMELEN = 32;

/**
* The length of the devices field in a header buffer.
*/
int DEVLEN = 8;

/**
* LF_ constants represent the "link flag" of an entry, or more commonly,
* the "entry type". This is the "old way" of indicating a normal file.
*/
byte LF_OLDNORM = 0;

/**
* Normal file type.
*/
byte LF_NORMAL = (byte)'0';

/**
* Link file type.
*/
byte LF_LINK = (byte)'1';

/**
* Symbolic link file type.
*/
byte LF_SYMLINK = (byte)'2';

/**
* Character device file type.
*/
byte LF_CHR = (byte)'3';

/**
* Block device file type.
*/
byte LF_BLK = (byte)'4';

/**
* Directory file type.
*/
byte LF_DIR = (byte)'5';

/**
* FIFO (pipe) file type.
*/
byte LF_FIFO = (byte)'6';

/**
* Contiguous file type.
*/
byte LF_CONTIG = (byte)'7';

/**
* The magic tag representing a POSIX tar archive.
*/
String TMAGIC = "ustar";

/**
* The magic tag representing a GNU tar archive.
*/
String GNU_TMAGIC = "ustar ";

/**
* The namr of the GNU tar entry which contains a long name.
*/
String GNU_LONGLINK = "././@LongLink";

/**
* Identifies the *next* file on the tape as having a long name.
*/
byte LF_GNUTYPE_LONGNAME = (byte)'L';
}

+ 0
- 627
proposal/myrmidon/src/java/org/apache/aut/tar/TarEntry.java View File

@@ -1,627 +0,0 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.aut.tar;

import java.io.File;
import java.util.Date;
import java.util.Locale;

/**
* This class represents an entry in a Tar archive. It consists of the entry's
* header, as well as the entry's File. Entries can be instantiated in one of
* three ways, depending on how they are to be used. <p>
*
* TarEntries that are created from the header bytes read from an archive are
* instantiated with the TarEntry( byte[] ) constructor. These entries will be
* used when extracting from or listing the contents of an archive. These
* entries have their header filled in using the header bytes. They also set the
* File to null, since they reference an archive entry not a file. <p>
*
* TarEntries that are created from Files that are to be written into an archive
* are instantiated with the TarEntry( File ) constructor. These entries have
* their header filled in using the File's information. They also keep a
* reference to the File for convenience when writing entries. <p>
*
* Finally, TarEntries can be constructed from nothing but a name. This allows
* the programmer to construct the entry by hand, for instance when only an
* InputStream is available for writing to the archive, and the header
* information is constructed from other information. In this case the header
* fields are set to defaults and the File is set to null. <p>
*
* The C structure for a Tar Entry's header is: <pre>
* struct header {
* char name[NAMSIZ];
* char mode[8];
* char uid[8];
* char gid[8];
* char size[12];
* char mtime[12];
* char chksum[8];
* char linkflag;
* char linkname[NAMSIZ];
* char magic[8];
* char uname[TUNMLEN];
* char gname[TGNMLEN];
* char devmajor[8];
* char devminor[8];
* } header;
* </pre>
*
* @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class TarEntry
{
/**
* The length of the name field in a header buffer.
*/
public final static int NAMELEN = 100;

/**
* The entry's modification time.
*/
private int m_checkSum;

/**
* The entry's group name.
*/
private int m_devMajor;

/**
* The entry's major device number.
*/
private int m_devMinor;

/**
* The entry's minor device number.
*/
private File m_file;

/**
* The entry's user id.
*/
private int m_groupId;

/**
* The entry's user name.
*/
private StringBuffer m_groupName;

/**
* The entry's checksum.
*/
private byte m_linkFlag;

/**
* The entry's link flag.
*/
private StringBuffer m_linkName;

/**
* The entry's link name.
*/
private StringBuffer m_magic;

/**
* The entry's size.
*/
private long m_modTime;

/**
* The entry's name.
*/
private int m_mode;

private StringBuffer m_name;

/**
* The entry's group id.
*/
private long m_size;

/**
* The entry's permission mode.
*/
private int m_userID;

/**
* The entry's magic tag.
*/
private StringBuffer m_userName;

/**
* Construct an entry with only a name. This allows the programmer to
* construct the entry's header "by hand". File is set to null.
*/
public TarEntry( final String name )
{
this();

final boolean isDir = name.endsWith( "/" );

m_name = new StringBuffer( name );
m_mode = isDir ? 040755 : 0100644;
m_linkFlag = isDir ? TarConstants.LF_DIR : TarConstants.LF_NORMAL;
m_modTime = ( new Date() ).getTime() / 1000;
m_linkName = new StringBuffer( "" );
m_userName = new StringBuffer( "" );
m_groupName = new StringBuffer( "" );
}

/**
* Construct an entry with a name an a link flag.
*
* @param name Description of Parameter
* @param linkFlag Description of Parameter
*/
public TarEntry( final String name, final byte linkFlag )
{
this( name );
m_linkFlag = linkFlag;
}

/**
* Construct an entry for a file. File is set to file, and the header is
* constructed from information from the file.
*
* @param file The file that the entry represents.
*/
public TarEntry( final File file )
{
this();

m_file = file;

String name = file.getPath();

// Strip off drive letters!
final String osName =
System.getProperty( "os.name" ).toLowerCase( Locale.US );
if( -1 != osName.indexOf( "netware" ) )
{
if( name.length() > 2 )
{
final char ch1 = name.charAt( 0 );
final char ch2 = name.charAt( 1 );

if( ch2 == ':' &&
( ( ch1 >= 'a' && ch1 <= 'z' ) ||
( ch1 >= 'A' && ch1 <= 'Z' ) ) )
{
name = name.substring( 2 );
}
}
}
else if( -1 != osName.indexOf( "netware" ) )
{
final int colon = name.indexOf( ':' );
if( colon != -1 )
{
name = name.substring( colon + 1 );
}
}

name = name.replace( File.separatorChar, '/' );

// No absolute pathnames
// Windows (and Posix?) paths can start with "\\NetworkDrive\",
// so we loop on starting /'s.
while( name.startsWith( "/" ) )
{
name = name.substring( 1 );
}

m_linkName = new StringBuffer( "" );
m_name = new StringBuffer( name );

if( file.isDirectory() )
{
m_mode = 040755;
m_linkFlag = TarConstants.LF_DIR;

if( m_name.charAt( m_name.length() - 1 ) != '/' )
{
m_name.append( "/" );
}
}
else
{
m_mode = 0100644;
m_linkFlag = TarConstants.LF_NORMAL;
}

m_size = file.length();
m_modTime = file.lastModified() / 1000;
m_checkSum = 0;
m_devMajor = 0;
m_devMinor = 0;
}

/**
* Construct an entry from an archive's header bytes. File is set to null.
*
* @param header The header bytes from a tar archive entry.
*/
public TarEntry( final byte[] header )
{
this();
parseTarHeader( header );
}

/**
* Construct an empty entry and prepares the header values.
*/
private TarEntry()
{
m_magic = new StringBuffer( TarConstants.TMAGIC );
m_name = new StringBuffer();
m_linkName = new StringBuffer();

String user = System.getProperty( "user.name", "" );
if( user.length() > 31 )
{
user = user.substring( 0, 31 );
}

m_userName = new StringBuffer( user );
m_groupName = new StringBuffer( "" );
}

/**
* Set this entry's group id.
*
* @param groupId This entry's new group id.
*/
public void setGroupId( final int groupId )
{
m_groupId = groupId;
}

/**
* Set this entry's group name.
*
* @param groupName This entry's new group name.
*/
public void setGroupName( final String groupName )
{
m_groupName = new StringBuffer( groupName );
}

/**
* Set this entry's modification time. The parameter passed to this method
* is in "Java time".
*
* @param time This entry's new modification time.
*/
public void setModTime( final long time )
{
m_modTime = time / 1000;
}

/**
* Set this entry's modification time.
*
* @param time This entry's new modification time.
*/
public void setModTime( final Date time )
{
m_modTime = time.getTime() / 1000;
}

/**
* Set the mode for this entry
*
* @param mode The new Mode value
*/
public void setMode( final int mode )
{
m_mode = mode;
}

/**
* Set this entry's name.
*
* @param name This entry's new name.
*/
public void setName( final String name )
{
m_name = new StringBuffer( name );
}

/**
* Set this entry's file size.
*
* @param size This entry's new file size.
*/
public void setSize( final long size )
{
m_size = size;
}

/**
* Set this entry's user id.
*
* @param userId This entry's new user id.
*/
public void setUserId( final int userId )
{
m_userID = userId;
}

/**
* Set this entry's user name.
*
* @param userName This entry's new user name.
*/
public void setUserName( final String userName )
{
m_userName = new StringBuffer( userName );
}

/**
* If this entry represents a file, and the file is a directory, return an
* array of TarEntries for this entry's children.
*
* @return An array of TarEntry's for this entry's children.
*/
public TarEntry[] getDirectoryEntries()
{
if( null == m_file || !m_file.isDirectory() )
{
return new TarEntry[ 0 ];
}

final String[] list = m_file.list();
final TarEntry[] result = new TarEntry[ list.length ];

for( int i = 0; i < list.length; ++i )
{
result[ i ] = new TarEntry( new File( m_file, list[ i ] ) );
}

return result;
}

/**
* Get this entry's file.
*
* @return This entry's file.
*/
public File getFile()
{
return m_file;
}

/**
* Get this entry's group id.
*
* @return This entry's group id.
*/
public int getGroupId()
{
return m_groupId;
}

/**
* Get this entry's group name.
*
* @return This entry's group name.
*/
public String getGroupName()
{
return m_groupName.toString();
}

/**
* Set this entry's modification time.
*
* @return The ModTime value
*/
public Date getModTime()
{
return new Date( m_modTime * 1000 );
}

/**
* Get this entry's mode.
*
* @return This entry's mode.
*/
public int getMode()
{
return m_mode;
}

/**
* Get this entry's name.
*
* @return This entry's name.
*/
public String getName()
{
return m_name.toString();
}

/**
* Get this entry's file size.
*
* @return This entry's file size.
*/
public long getSize()
{
return m_size;
}

/**
* Get this entry's checksum.
*
* @return This entry's checksum.
*/
public int getCheckSum()
{
return m_checkSum;
}

/**
* Get this entry's user id.
*
* @return This entry's user id.
*/
public int getUserId()
{
return m_userID;
}

/**
* Get this entry's user name.
*
* @return This entry's user name.
*/
public String getUserName()
{
return m_userName.toString();
}

/**
* Determine if the given entry is a descendant of this entry. Descendancy
* is determined by the name of the descendant starting with this entry's
* name.
*
* @param desc Entry to be checked as a descendent of
* @return True if entry is a descendant of
*/
public boolean isDescendent( final TarEntry desc )
{
return desc.getName().startsWith( getName() );
}

/**
* Return whether or not this entry represents a directory.
*
* @return True if this entry is a directory.
*/
public boolean isDirectory()
{
if( m_file != null )
{
return m_file.isDirectory();
}

if( m_linkFlag == TarConstants.LF_DIR )
{
return true;
}

if( getName().endsWith( "/" ) )
{
return true;
}

return false;
}

/**
* Indicate if this entry is a GNU long name block
*
* @return true if this is a long name extension provided by GNU tar
*/
public boolean isGNULongNameEntry()
{
return m_linkFlag == TarConstants.LF_GNUTYPE_LONGNAME &&
m_name.toString().equals( TarConstants.GNU_LONGLINK );
}

/**
* Determine if the two entries are equal. Equality is determined by the
* header names being equal.
*
* @param other Entry to be checked for equality.
* @return True if the entries are equal.
*/
public boolean equals( final TarEntry other )
{
return getName().equals( other.getName() );
}

/**
* Parse an entry's header information from a header buffer.
*
* @param header The tar entry header buffer to get information from.
*/
private void parseTarHeader( final byte[] header )
{
int offset = 0;

m_name = TarUtils.parseName( header, offset, NAMELEN );
offset += NAMELEN;
m_mode = (int)TarUtils.parseOctal( header, offset, TarConstants.MODELEN );
offset += TarConstants.MODELEN;
m_userID = (int)TarUtils.parseOctal( header, offset, TarConstants.UIDLEN );
offset += TarConstants.UIDLEN;
m_groupId = (int)TarUtils.parseOctal( header, offset, TarConstants.GIDLEN );
offset += TarConstants.GIDLEN;
m_size = TarUtils.parseOctal( header, offset, TarConstants.SIZELEN );
offset += TarConstants.SIZELEN;
m_modTime = TarUtils.parseOctal( header, offset, TarConstants.MODTIMELEN );
offset += TarConstants.MODTIMELEN;
m_checkSum = (int)TarUtils.parseOctal( header, offset, TarConstants.CHKSUMLEN );
offset += TarConstants.CHKSUMLEN;
m_linkFlag = header[ offset++ ];
m_linkName = TarUtils.parseName( header, offset, NAMELEN );
offset += NAMELEN;
m_magic = TarUtils.parseName( header, offset, TarConstants.MAGICLEN );
offset += TarConstants.MAGICLEN;
m_userName = TarUtils.parseName( header, offset, TarConstants.UNAMELEN );
offset += TarConstants.UNAMELEN;
m_groupName = TarUtils.parseName( header, offset, TarConstants.GNAMELEN );
offset += TarConstants.GNAMELEN;
m_devMajor = (int)TarUtils.parseOctal( header, offset, TarConstants.DEVLEN );
offset += TarConstants.DEVLEN;
m_devMinor = (int)TarUtils.parseOctal( header, offset, TarConstants.DEVLEN );
}

/**
* Write an entry's header information to a header buffer.
*
* @param buffer The tar entry header buffer to fill in.
*/
public void writeEntryHeader( final byte[] buffer )
{
int offset = 0;

offset = TarUtils.getNameBytes( m_name, buffer, offset, NAMELEN );
offset = TarUtils.getOctalBytes( m_mode, buffer, offset, TarConstants.MODELEN );
offset = TarUtils.getOctalBytes( m_userID, buffer, offset, TarConstants.UIDLEN );
offset = TarUtils.getOctalBytes( m_groupId, buffer, offset, TarConstants.GIDLEN );
offset = TarUtils.getLongOctalBytes( m_size, buffer, offset, TarConstants.SIZELEN );
offset = TarUtils.getLongOctalBytes( m_modTime, buffer, offset, TarConstants.MODTIMELEN );

final int checkSumOffset = offset;
for( int i = 0; i < TarConstants.CHKSUMLEN; ++i )
{
buffer[ offset++ ] = (byte)' ';
}

buffer[ offset++ ] = m_linkFlag;
offset = TarUtils.getNameBytes( m_linkName, buffer, offset, NAMELEN );
offset = TarUtils.getNameBytes( m_magic, buffer, offset, TarConstants.MAGICLEN );
offset = TarUtils.getNameBytes( m_userName, buffer, offset, TarConstants.UNAMELEN );
offset = TarUtils.getNameBytes( m_groupName, buffer, offset, TarConstants.GNAMELEN );
offset = TarUtils.getOctalBytes( m_devMajor, buffer, offset, TarConstants.DEVLEN );
offset = TarUtils.getOctalBytes( m_devMinor, buffer, offset, TarConstants.DEVLEN );

while( offset < buffer.length )
{
buffer[ offset++ ] = 0;
}

final long checkSum = TarUtils.computeCheckSum( buffer );
TarUtils.getCheckSumOctalBytes( checkSum, buffer, checkSumOffset, TarConstants.CHKSUMLEN );
}
}

+ 0
- 419
proposal/myrmidon/src/java/org/apache/aut/tar/TarInputStream.java View File

@@ -1,419 +0,0 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.aut.tar;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* The TarInputStream reads a UNIX tar archive as an InputStream. methods are
* provided to position at each successive entry in the archive, and the read
* each entry as a normal input stream using read().
*
* @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class TarInputStream
extends FilterInputStream
{
private TarBuffer m_buffer;
private TarEntry m_currEntry;
private boolean m_debug;
private int m_entryOffset;
private int m_entrySize;
private boolean m_hasHitEOF;
private byte[] m_oneBuf;
private byte[] m_readBuf;

public TarInputStream( final InputStream input )
{
this( input, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE );
}

public TarInputStream( final InputStream input, final int blockSize )
{
this( input, blockSize, TarBuffer.DEFAULT_RCDSIZE );
}

public TarInputStream( final InputStream input,
final int blockSize,
final int recordSize )
{
super( input );

m_buffer = new TarBuffer( input, blockSize, recordSize );
m_oneBuf = new byte[ 1 ];
}

/**
* Sets the debugging flag.
*
* @param debug The new Debug value
*/
public void setDebug( final boolean debug )
{
m_debug = debug;
m_buffer.setDebug( debug );
}

/**
* Get the next entry in this tar archive. This will skip over any remaining
* data in the current entry, if there is one, and place the input stream at
* the header of the next entry, and read the header and instantiate a new
* TarEntry from the header bytes and return that entry. If there are no
* more entries in the archive, null will be returned to indicate that the
* end of the archive has been reached.
*
* @return The next TarEntry in the archive, or null.
* @exception IOException Description of Exception
*/
public TarEntry getNextEntry()
throws IOException
{
if( m_hasHitEOF )
{
return null;
}

if( m_currEntry != null )
{
final int numToSkip = m_entrySize - m_entryOffset;

if( m_debug )
{
final String message = "TarInputStream: SKIP currENTRY '" +
m_currEntry.getName() + "' SZ " + m_entrySize +
" OFF " + m_entryOffset + " skipping " + numToSkip + " bytes";
debug( message );
}

if( numToSkip > 0 )
{
skip( numToSkip );
}

m_readBuf = null;
}

final byte[] headerBuf = m_buffer.readRecord();
if( headerBuf == null )
{
if( m_debug )
{
debug( "READ NULL RECORD" );
}
m_hasHitEOF = true;
}
else if( m_buffer.isEOFRecord( headerBuf ) )
{
if( m_debug )
{
debug( "READ EOF RECORD" );
}
m_hasHitEOF = true;
}

if( m_hasHitEOF )
{
m_currEntry = null;
}
else
{
m_currEntry = new TarEntry( headerBuf );

if( !( headerBuf[ 257 ] == 'u' && headerBuf[ 258 ] == 's' &&
headerBuf[ 259 ] == 't' && headerBuf[ 260 ] == 'a' &&
headerBuf[ 261 ] == 'r' ) )
{
//Must be v7Format
}

if( m_debug )
{
final String message = "TarInputStream: SET CURRENTRY '" +
m_currEntry.getName() + "' size = " + m_currEntry.getSize();
debug( message );
}

m_entryOffset = 0;

// REVIEW How do we resolve this discrepancy?!
m_entrySize = (int)m_currEntry.getSize();
}

if( null != m_currEntry && m_currEntry.isGNULongNameEntry() )
{
// read in the name
final StringBuffer longName = new StringBuffer();
final byte[] buffer = new byte[ 256 ];
int length = 0;
while( ( length = read( buffer ) ) >= 0 )
{
final String str = new String( buffer, 0, length );
longName.append( str );
}
getNextEntry();
m_currEntry.setName( longName.toString() );
}

return m_currEntry;
}

/**
* Get the record size being used by this stream's TarBuffer.
*
* @return The TarBuffer record size.
*/
public int getRecordSize()
{
return m_buffer.getRecordSize();
}

/**
* Get the available data that can be read from the current entry in the
* archive. This does not indicate how much data is left in the entire
* archive, only in the current entry. This value is determined from the
* entry's size header field and the amount of data already read from the
* current entry.
*
* @return The number of available bytes for the current entry.
* @exception IOException Description of Exception
*/
public int available()
throws IOException
{
return m_entrySize - m_entryOffset;
}

/**
* Closes this stream. Calls the TarBuffer's close() method.
*/
public void close()
throws IOException
{
m_buffer.close();
}

/**
* Copies the contents of the current tar archive entry directly into an
* output stream.
*
* @param output The OutputStream into which to write the entry's data.
* @exception IOException Description of Exception
*/
public void copyEntryContents( final OutputStream output )
throws IOException
{
final byte[] buffer = new byte[ 32 * 1024 ];
while( true )
{
final int numRead = read( buffer, 0, buffer.length );
if( numRead == -1 )
{
break;
}

output.write( buffer, 0, numRead );
}
}

/**
* Since we do not support marking just yet, we do nothing.
*
* @param markLimit The limit to mark.
*/
public void mark( int markLimit )
{
}

/**
* Since we do not support marking just yet, we return false.
*
* @return False.
*/
public boolean markSupported()
{
return false;
}

/**
* Reads a byte from the current tar archive entry. This method simply calls
* read( byte[], int, int ).
*
* @return The byte read, or -1 at EOF.
* @exception IOException Description of Exception
*/
public int read()
throws IOException
{
final int num = read( m_oneBuf, 0, 1 );
if( num == -1 )
{
return num;
}
else
{
return (int)m_oneBuf[ 0 ];
}
}

/**
* Reads bytes from the current tar archive entry. This method simply calls
* read( byte[], int, int ).
*
* @param buffer The buffer into which to place bytes read.
* @return The number of bytes read, or -1 at EOF.
* @exception IOException Description of Exception
*/
public int read( final byte[] buffer )
throws IOException
{
return read( buffer, 0, buffer.length );
}

/**
* Reads bytes from the current tar archive entry. This method is aware of
* the boundaries of the current entry in the archive and will deal with
* them as if they were this stream's start and EOF.
*
* @param buffer The buffer into which to place bytes read.
* @param offset The offset at which to place bytes read.
* @param count The number of bytes to read.
* @return The number of bytes read, or -1 at EOF.
*/
public int read( final byte[] buffer,
final int offset,
final int count )
throws IOException
{
int position = offset;
int numToRead = count;
int totalRead = 0;

if( m_entryOffset >= m_entrySize )
{
return -1;
}

if( ( numToRead + m_entryOffset ) > m_entrySize )
{
numToRead = ( m_entrySize - m_entryOffset );
}

if( null != m_readBuf )
{
final int size =
( numToRead > m_readBuf.length ) ? m_readBuf.length : numToRead;

System.arraycopy( m_readBuf, 0, buffer, position, size );

if( size >= m_readBuf.length )
{
m_readBuf = null;
}
else
{
final int newLength = m_readBuf.length - size;
final byte[] newBuffer = new byte[ newLength ];

System.arraycopy( m_readBuf, size, newBuffer, 0, newLength );

m_readBuf = newBuffer;
}

totalRead += size;
numToRead -= size;
position += size;
}

while( numToRead > 0 )
{
final byte[] rec = m_buffer.readRecord();
if( null == rec )
{
// Unexpected EOF!
final String message =
"unexpected EOF with " + numToRead + " bytes unread";
throw new IOException( message );
}

int size = numToRead;
final int recordLength = rec.length;

if( recordLength > size )
{
System.arraycopy( rec, 0, buffer, position, size );

m_readBuf = new byte[ recordLength - size ];

System.arraycopy( rec, size, m_readBuf, 0, recordLength - size );
}
else
{
size = recordLength;

System.arraycopy( rec, 0, buffer, position, recordLength );
}

totalRead += size;
numToRead -= size;
position += size;
}

m_entryOffset += totalRead;

return totalRead;
}

/**
* Since we do not support marking just yet, we do nothing.
*/
public void reset()
{
}

/**
* Skip bytes in the input buffer. This skips bytes in the current entry's
* data, not the entire archive, and will stop at the end of the current
* entry's data if the number to skip extends beyond that point.
*
* @param numToSkip The number of bytes to skip.
*/
public void skip( final int numToSkip )
throws IOException
{
// REVIEW
// This is horribly inefficient, but it ensures that we
// properly skip over bytes via the TarBuffer...
//
final byte[] skipBuf = new byte[ 8 * 1024 ];
int num = numToSkip;
while( num > 0 )
{
final int count = ( num > skipBuf.length ) ? skipBuf.length : num;
final int numRead = read( skipBuf, 0, count );
if( numRead == -1 )
{
break;
}

num -= numRead;
}
}

protected void debug( final String message )
{
if( m_debug )
{
System.err.println( message );
}
}
}

+ 0
- 329
proposal/myrmidon/src/java/org/apache/aut/tar/TarOutputStream.java View File

@@ -1,329 +0,0 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.aut.tar;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
* The TarOutputStream writes a UNIX tar archive as an OutputStream. Methods are
* provided to put entries, and then write their contents by writing to this
* stream using write().
*
* @author Timothy Gerard Endres <a href="mailto:time@ice.com">time@ice.com</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class TarOutputStream
extends FilterOutputStream
{
public final static int LONGFILE_ERROR = 0;
public final static int LONGFILE_TRUNCATE = 1;
public final static int LONGFILE_GNU = 2;

private int m_longFileMode = LONGFILE_ERROR;
private byte[] m_assemBuf;
private int m_assemLen;
private TarBuffer m_buffer;
private int m_currBytes;
private int m_currSize;

private byte[] m_oneBuf;
private byte[] m_recordBuf;

public TarOutputStream( final OutputStream output )
{
this( output, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE );
}

public TarOutputStream( final OutputStream output, final int blockSize )
{
this( output, blockSize, TarBuffer.DEFAULT_RCDSIZE );
}

public TarOutputStream( final OutputStream output,
final int blockSize,
final int recordSize )
{
super( output );

m_buffer = new TarBuffer( output, blockSize, recordSize );
m_assemLen = 0;
m_assemBuf = new byte[ recordSize ];
m_recordBuf = new byte[ recordSize ];
m_oneBuf = new byte[ 1 ];
}

/**
* Sets the debugging flag in this stream's TarBuffer.
*
* @param debug The new BufferDebug value
*/
public void setBufferDebug( boolean debug )
{
m_buffer.setDebug( debug );
}

public void setLongFileMode( final int longFileMode )
{
m_longFileMode = longFileMode;
}

/**
* Get the record size being used by this stream's TarBuffer.
*
* @return The TarBuffer record size.
*/
public int getRecordSize()
{
return m_buffer.getRecordSize();
}

/**
* Ends the TAR archive and closes the underlying OutputStream. This means
* that finish() is called followed by calling the TarBuffer's close().
*
* @exception IOException Description of Exception
*/
public void close()
throws IOException
{
finish();
m_buffer.close();
}

/**
* Close an entry. This method MUST be called for all file entries that
* contain data. The reason is that we must buffer data written to the
* stream in order to satisfy the buffer's record based writes. Thus, there
* may be data fragments still being assembled that must be written to the
* output stream before this entry is closed and the next entry written.
*
* @exception IOException Description of Exception
*/
public void closeEntry()
throws IOException
{
if( m_assemLen > 0 )
{
for( int i = m_assemLen; i < m_assemBuf.length; ++i )
{
m_assemBuf[ i ] = 0;
}

m_buffer.writeRecord( m_assemBuf );

m_currBytes += m_assemLen;
m_assemLen = 0;
}

if( m_currBytes < m_currSize )
{
final String message = "entry closed at '" + m_currBytes +
"' before the '" + m_currSize +
"' bytes specified in the header were written";
throw new IOException( message );
}
}

/**
* Ends the TAR archive without closing the underlying OutputStream. The
* result is that the EOF record of nulls is written.
*
* @exception IOException Description of Exception
*/
public void finish()
throws IOException
{
writeEOFRecord();
}

/**
* Put an entry on the output stream. This writes the entry's header record
* and positions the output stream for writing the contents of the entry.
* Once this method is called, the stream is ready for calls to write() to
* write the entry's contents. Once the contents are written, closeEntry()
* <B>MUST</B> be called to ensure that all buffered data is completely
* written to the output stream.
*
* @param entry The TarEntry to be written to the archive.
* @exception IOException Description of Exception
*/
public void putNextEntry( final TarEntry entry )
throws IOException
{
if( entry.getName().length() >= TarEntry.NAMELEN )
{

if( m_longFileMode == LONGFILE_GNU )
{
// create a TarEntry for the LongLink, the contents
// of which are the entry's name
final TarEntry longLinkEntry =
new TarEntry( TarConstants.GNU_LONGLINK,
TarConstants.LF_GNUTYPE_LONGNAME );

longLinkEntry.setSize( entry.getName().length() + 1 );
putNextEntry( longLinkEntry );
write( entry.getName().getBytes() );
write( 0 );
closeEntry();
}
else if( m_longFileMode != LONGFILE_TRUNCATE )
{
final String message = "file name '" + entry.getName() +
"' is too long ( > " + TarEntry.NAMELEN + " bytes)";
throw new IOException( message );
}
}

entry.writeEntryHeader( m_recordBuf );
m_buffer.writeRecord( m_recordBuf );

m_currBytes = 0;

if( entry.isDirectory() )
{
m_currSize = 0;
}
else
{
m_currSize = (int)entry.getSize();
}
}

/**
* Writes a byte to the current tar archive entry. This method simply calls
* read( byte[], int, int ).
*
* @param data The byte written.
* @exception IOException Description of Exception
*/
public void write( final int data )
throws IOException
{
m_oneBuf[ 0 ] = (byte)data;

write( m_oneBuf, 0, 1 );
}

/**
* Writes bytes to the current tar archive entry. This method simply calls
* write( byte[], int, int ).
*
* @param buffer The buffer to write to the archive.
*/
public void write( final byte[] buffer )
throws IOException
{
write( buffer, 0, buffer.length );
}

/**
* Writes bytes to the current tar archive entry. This method is aware of
* the current entry and will throw an exception if you attempt to write
* bytes past the length specified for the current entry. The method is also
* (painfully) aware of the record buffering required by TarBuffer, and
* manages buffers that are not a multiple of recordsize in length,
* including assembling records from small buffers.
*
* @param buffer The buffer to write to the archive.
* @param offset The offset in the buffer from which to get bytes.
* @param count The number of bytes to write.
*/
public void write( final byte[] buffer,
final int offset,
final int count )
throws IOException
{
int position = offset;
int numToWrite = count;
if( ( m_currBytes + numToWrite ) > m_currSize )
{
final String message = "request to write '" + numToWrite +
"' bytes exceeds size in header of '" + m_currSize + "' bytes";
throw new IOException( message );
//
// We have to deal with assembly!!!
// The programmer can be writing little 32 byte chunks for all
// we know, and we must assemble complete records for writing.
// REVIEW Maybe this should be in TarBuffer? Could that help to
// eliminate some of the buffer copying.
//
}

if( m_assemLen > 0 )
{
if( ( m_assemLen + numToWrite ) >= m_recordBuf.length )
{
final int length = m_recordBuf.length - m_assemLen;

System.arraycopy( m_assemBuf, 0, m_recordBuf, 0,
m_assemLen );
System.arraycopy( buffer, position, m_recordBuf,
m_assemLen, length );
m_buffer.writeRecord( m_recordBuf );

m_currBytes += m_recordBuf.length;
position += length;
numToWrite -= length;
m_assemLen = 0;
}
else
{
System.arraycopy( buffer, position, m_assemBuf, m_assemLen,
numToWrite );

position += numToWrite;
m_assemLen += numToWrite;
numToWrite -= numToWrite;
}
}

//
// When we get here we have EITHER:
// o An empty "assemble" buffer.
// o No bytes to write (numToWrite == 0)
//
while( numToWrite > 0 )
{
if( numToWrite < m_recordBuf.length )
{
System.arraycopy( buffer, position, m_assemBuf, m_assemLen,
numToWrite );

m_assemLen += numToWrite;

break;
}

m_buffer.writeRecord( buffer, position );

int num = m_recordBuf.length;

m_currBytes += num;
numToWrite -= num;
position += num;
}
}

/**
* Write an EOF (end of archive) record to the tar archive. An EOF record
* consists of a record of all zeros.
*/
private void writeEOFRecord()
throws IOException
{
for( int i = 0; i < m_recordBuf.length; ++i )
{
m_recordBuf[ i ] = 0;
}

m_buffer.writeRecord( m_recordBuf );
}
}

+ 0
- 224
proposal/myrmidon/src/java/org/apache/aut/tar/TarUtils.java View File

@@ -1,224 +0,0 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.aut.tar;

/**
* This class provides static utility methods to work with byte streams.
*
* @author <a href="mailto:time@ice.com">Timothy Gerard Endres</a>
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
*/
class TarUtils
{
/**
* Parse the checksum octal integer from a header buffer.
*
* @param offset The offset into the buffer from which to parse.
* @param length The number of header bytes to parse.
* @param value Description of Parameter
* @param buf Description of Parameter
* @return The integer value of the entry's checksum.
*/
public static int getCheckSumOctalBytes( final long value,
final byte[] buf,
final int offset,
final int length )
{
getOctalBytes( value, buf, offset, length );

buf[ offset + length - 1 ] = (byte)' ';
buf[ offset + length - 2 ] = 0;

return offset + length;
}

/**
* Parse an octal long integer from a header buffer.
*
* @param offset The offset into the buffer from which to parse.
* @param length The number of header bytes to parse.
* @param value Description of Parameter
* @param buf Description of Parameter
* @return The long value of the octal bytes.
*/
public static int getLongOctalBytes( final long value,
final byte[] buf,
final int offset,
final int length )
{
byte[] temp = new byte[ length + 1 ];

getOctalBytes( value, temp, 0, length + 1 );
System.arraycopy( temp, 0, buf, offset, length );

return offset + length;
}

/**
* Determine the number of bytes in an entry name.
*
* @param offset The offset into the buffer from which to parse.
* @param length The number of header bytes to parse.
* @param name Description of Parameter
* @param buf Description of Parameter
* @return The number of bytes in a header's entry name.
*/
public static int getNameBytes( final StringBuffer name,
final byte[] buffer,
final int offset,
final int length )
{
int i;

for( i = 0; i < length && i < name.length(); ++i )
{
buffer[ offset + i ] = (byte)name.charAt( i );
}

for( ; i < length; ++i )
{
buffer[ offset + i ] = 0;
}

return offset + length;
}

/**
* Parse an octal integer from a header buffer.
*
* @param offset The offset into the buffer from which to parse.
* @param length The number of header bytes to parse.
* @return The integer value of the octal bytes.
*/
public static int getOctalBytes( final long value,
final byte[] buffer,
final int offset,
final int length )
{
int idx = length - 1;

buffer[ offset + idx ] = 0;
--idx;
buffer[ offset + idx ] = (byte)' ';
--idx;

if( value == 0 )
{
buffer[ offset + idx ] = (byte)'0';
--idx;
}
else
{
long val = value;
while( idx >= 0 && val > 0 )
{
buffer[ offset + idx ] = (byte)( (byte)'0' + (byte)( val & 7 ) );
val = val >> 3;
idx--;
}
}

while( idx >= 0 )
{
buffer[ offset + idx ] = (byte)' ';
idx--;
}

return offset + length;
}

/**
* Compute the checksum of a tar entry header.
*
* @param buf The tar entry's header buffer.
* @return The computed checksum.
*/
public static long computeCheckSum( final byte[] buffer )
{
long sum = 0;

for( int i = 0; i < buffer.length; ++i )
{
sum += 255 & buffer[ i ];
}

return sum;
}

/**
* Parse an entry name from a header buffer.
*
* @param header The header buffer from which to parse.
* @param offset The offset into the buffer from which to parse.
* @param length The number of header bytes to parse.
* @return The header's entry name.
*/
public static StringBuffer parseName( final byte[] header,
final int offset,
final int length )
{
StringBuffer result = new StringBuffer( length );
int end = offset + length;

for( int i = offset; i < end; ++i )
{
if( header[ i ] == 0 )
{
break;
}

result.append( (char)header[ i ] );
}

return result;
}

/**
* Parse an octal string from a header buffer. This is used for the file
* permission mode value.
*
* @param header The header buffer from which to parse.
* @param offset The offset into the buffer from which to parse.
* @param length The number of header bytes to parse.
* @return The long value of the octal string.
*/
public static long parseOctal( final byte[] header,
final int offset,
final int length )
{
long result = 0;
boolean stillPadding = true;
int end = offset + length;

for( int i = offset; i < end; ++i )
{
if( header[ i ] == 0 )
{
break;
}

if( header[ i ] == (byte)' ' || header[ i ] == '0' )
{
if( stillPadding )
{
continue;
}

if( header[ i ] == (byte)' ' )
{
break;
}
}

stillPadding = false;
result = ( result << 3 ) + ( header[ i ] - '0' );
}

return result;
}
}

+ 2
- 4
proposal/myrmidon/src/todo/org/apache/tools/todo/taskdefs/archive/Tar.java View File

@@ -13,12 +13,10 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import org.apache.aut.tar.TarEntry;
import org.apache.aut.tar.TarOutputStream;
import org.apache.avalon.excalibur.io.IOUtil; import org.apache.avalon.excalibur.io.IOUtil;
import org.apache.avalon.excalibur.tar.TarEntry;
import org.apache.avalon.excalibur.tar.TarOutputStream;
import org.apache.myrmidon.api.TaskException; import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.api.AbstractTask;
import org.apache.myrmidon.api.TaskContext;
import org.apache.tools.todo.taskdefs.MatchingTask; import org.apache.tools.todo.taskdefs.MatchingTask;
import org.apache.tools.todo.types.ScannerUtil; import org.apache.tools.todo.types.ScannerUtil;
import org.apache.tools.todo.types.SourceFileScanner; import org.apache.tools.todo.types.SourceFileScanner;


+ 2
- 3
proposal/myrmidon/src/todo/org/apache/tools/todo/taskdefs/archive/Untar.java View File

@@ -10,11 +10,10 @@ package org.apache.tools.todo.taskdefs.archive;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import org.apache.aut.tar.TarEntry;
import org.apache.aut.tar.TarInputStream;
import org.apache.avalon.excalibur.io.IOUtil; import org.apache.avalon.excalibur.io.IOUtil;
import org.apache.avalon.excalibur.tar.TarEntry;
import org.apache.avalon.excalibur.tar.TarInputStream;
import org.apache.myrmidon.api.TaskException; import org.apache.myrmidon.api.TaskException;
import org.apache.tools.todo.taskdefs.archive.Expand;


/** /**
* Untar a file. Heavily based on the Expand task. * Untar a file. Heavily based on the Expand task.


Loading…
Cancel
Save