/*
** Authored by Timothy Gerard Endres
** <mailto:[email protected]> <http://www.trustice.com>
**
** This work has been placed into the public domain.
** You may use this work in any way and for any purpose you wish.
**
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
** REDISTRIBUTION OF THIS SOFTWARE.
**
*/
package installer;
import java.io.*;
import java.util.Date;
/**
*
* 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>
*
* @see TarHeader
*
*/
public
class TarEntry
extends Object
{
/**
* If this entry represents a File, this references it.
*/
protected File file;
/**
* This is the entry's header information.
*/
protected TarHeader header;
/**
* 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( String name )
{
this.initialize();
this.nameTarHeader( this.header, name );
}
/**
* 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( File file )
throws InvalidHeaderException
{
this.initialize();
this.getFileTarHeader( this.header, file );
}
/**
* Construct an entry from an archive's header bytes. File is set
* to null.
*
* @param headerBuf The header bytes from a tar archive entry.
*/
public
TarEntry( byte[] headerBuf )
throws InvalidHeaderException
{
this.initialize();
this.parseTarHeader( this.header, headerBuf );
}
/**
* Initialization code common to all constructors.
*/
private void
initialize()
{
this.file = null;
this.header = new TarHeader();
}
/**
* Determine if the two entries are equal. Equality is determined
* by the header names being equal.
*
* @return it Entry to be checked for equality.
* @return True if the entries are equal.
*/
public boolean
equals( TarEntry it )
{
return
this.header.name.toString().equals
( it.header.name.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 this.
* @return True if entry is a descendant of this.
*/
public boolean
isDescendent( TarEntry desc )
{
return
desc.header.name.toString().startsWith
( this.header.name.toString() );
}
/**
* Get this entry's header.
*
* @return This entry's TarHeader.
*/
public TarHeader
getHeader()
{
return this.header;
}
/**
* Get this entry's name.
*
* @return This entry's name.
*/
public String
getName()
{
return this.header.name.toString();
}
/**
* Set this entry's name.
*
* @param name This entry's new name.
*/
public void
setName( String name )
{
this.header.name =
new StringBuffer( name );
}
/**
* Get this entry's user id.
*
* @return This entry's user id.
*/
public int
getUserId()
{
return this.header.userId;
}
/**
* Set this entry's user id.
*
* @param userId This entry's new user id.
*/
public void
setUserId( int userId )
{
this.header.userId = userId;
}
/**
* Get this entry's group id.
*
* @return This entry's group id.
*/
public int
getGroupId()
{
return this.header.groupId;
}
/**
* Set this entry's group id.
*
* @param groupId This entry's new group id.
*/
public void
setGroupId( int groupId )
{
this.header.groupId = groupId;
}
/**
* Get this entry's user name.
*
* @return This entry's user name.
*/
public String
getUserName()
{
return this.header.userName.toString();
}
/**
* Set this entry's user name.
*
* @param userName This entry's new user name.
*/
public void
setUserName( String userName )
{
this.header.userName =
new StringBuffer( userName );
}
/**
* Get this entry's group name.
*
* @return This entry's group name.
*/
public String
getGroupName()
{
return this.header.groupName.toString();
}
/**
* Set this entry's group name.
*
* @param groupName This entry's new group name.
*/
public void
setGroupName( String groupName )
{
this.header.groupName =
new StringBuffer( groupName );
}
/**
* Convenience method to set this entry's group and user ids.
*
* @param userId This entry's new user id.
* @param groupId This entry's new group id.
*/
public void
setIds( int userId, int groupId )
{
this.setUserId( userId );
this.setGroupId( groupId );
}
/**
* Convenience method to set this entry's group and user names.
*
* @param userName This entry's new user name.
* @param groupName This entry's new group name.
*/
public void
setNames( String userName, String groupName )
{
this.setUserName( userName );
this.setGroupName( 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( long time )
{
this.header.modTime = time / 1000;
}
/**
* Set this entry's modification time.
*
* @param time This entry's new modification time.
*/
public void
setModTime( Date time )
{
this.header.modTime = time.getTime() / 1000;
}
/**
* Set this entry's modification time.
*
* @param time This entry's new modification time.
*/
public Date
getModTime()
{
return new Date( this.header.modTime * 1000 );
}
/**
* Get this entry's file.
*
* @return This entry's file.
*/
public File
getFile()
{
return this.file;
}
/**
* Get this entry's file size.
*
* @return This entry's file size.
*/
public long
getSize()
{
return this.header.size;
}
/**
* Set this entry's file size.
*
* @param size This entry's new file size.
*/
public void
setSize( long size )
{
this.header.size = size;
}
/**
* Convenience method that will modify an entry's name directly
* in place in an entry header buffer byte array.
*
* @param outbuf The buffer containing the entry header to modify.
* @param newName The new name to place into the header buffer.
*/
public void
adjustEntryName( byte[] outbuf, String newName )
{
int offset = 0;
offset = TarHeader.getNameBytes
( new StringBuffer( newName ),
outbuf, offset, TarHeader.NAMELEN );
}
/**
* Return whether or not this entry represents a directory.
*
* @return True if this entry is a directory.
*/
public boolean
isDirectory()
{
if ( this.file != null )
return this.file.isDirectory();
if ( this.header != null )
{
if ( this.header.linkFlag == TarHeader.LF_DIR )
return true;
if ( this.header.name.toString().endsWith( "/" ) )
return true;
}
return false;
}
/**
* Fill in a TarHeader with information from a File.
*
* @param hdr The TarHeader to fill in.
* @param file The file from which to get the header information.
*/
public void
getFileTarHeader( TarHeader hdr, File file )
throws InvalidHeaderException
{
this.file = file;
String name = file.getPath();
String osname = System.getProperty( "os.name" );
if ( osname != null )
{
// Strip off drive letters!
// REVIEW Would a better check be "(File.separator == '\')"?
// String Win32Prefix = "Windows";
// String prefix = osname.substring( 0, Win32Prefix.length() );
// if ( prefix.equalsIgnoreCase( Win32Prefix ) )
// if ( File.separatorChar == '\\' )
// Per Patrick Beard:
String Win32Prefix = "windows";
if ( osname.toLowerCase().startsWith( Win32Prefix ) )
{
if ( name.length() > 2 )
{
char ch1 = name.charAt(0);
char ch2 = name.charAt(1);
if ( ch2 == ':'
&& ( (ch1 >= 'a' && ch1 <= 'z')
|| (ch1 >= 'A' && ch1 <= 'Z') ) )
{
name = name.substring( 2 );
}
}
}
}
name = name.replace( File.separatorChar, '/' );
// No absolute pathnames
// Windows (and Posix?) paths can start with "\\NetworkDrive\",
// so we loop on starting /'s.
for ( ; name.startsWith( "/" ) ; )
name = name.substring( 1 );
hdr.linkName = new StringBuffer( "" );
hdr.name = new StringBuffer( name );
if ( file.isDirectory() )
{
hdr.mode = 040755;
hdr.linkFlag = TarHeader.LF_DIR;
if ( hdr.name.charAt( hdr.name.length() - 1 ) != '/' )
hdr.name.append( "/" );
}
else
{
hdr.mode = 0100644;
hdr.linkFlag = TarHeader.LF_NORMAL;
}
// UNDONE When File lets us get the userName, use it!
hdr.size = file.length();
hdr.modTime = file.lastModified() / 1000;
hdr.checkSum = 0;
hdr.devMajor = 0;
hdr.devMinor = 0;
}
/**
* 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()
throws InvalidHeaderException
{
if ( this.file == null
|| ! this.file.isDirectory() )
{
return new TarEntry[0];
}
String[] list = this.file.list();
TarEntry[] result = new TarEntry[ list.length ];
for ( int i = 0 ; i < list.length ; ++i )
{
result[i] =
new TarEntry
( new File( this.file, list[i] ) );
}
return result;
}
/**
* Compute the checksum of a tar entry header.
*
* @param buf The tar entry's header buffer.
* @return The computed checksum.
*/
public long
computeCheckSum( byte[] buf )
{
long sum = 0;
for ( int i = 0 ; i < buf.length ; ++i )
{
sum += 255 & buf[ i ];
}
return sum;
}
/**
* Write an entry's header information to a header buffer.
*
* @param outbuf The tar entry header buffer to fill in.
*/
public void
writeEntryHeader( byte[] outbuf )
{
int offset = 0;
offset = TarHeader.getNameBytes
( this.header.name, outbuf, offset, TarHeader.NAMELEN );
offset = TarHeader.getOctalBytes
( this.header.mode, outbuf, offset, TarHeader.MODELEN );
offset = TarHeader.getOctalBytes
( this.header.userId, outbuf, offset, TarHeader.UIDLEN );
offset = TarHeader.getOctalBytes
( this.header.groupId, outbuf, offset, TarHeader.GIDLEN );
long size = this.header.size;
offset = TarHeader.getLongOctalBytes
( size, outbuf, offset, TarHeader.SIZELEN );
offset = TarHeader.getLongOctalBytes
( this.header.modTime, outbuf, offset, TarHeader.MODTIMELEN );
int csOffset = offset;
for ( int c = 0 ; c < TarHeader.CHKSUMLEN ; ++c )
outbuf[ offset++ ] = (byte) ' ';
outbuf[ offset++ ] = this.header.linkFlag;
offset = TarHeader.getNameBytes
( this.header.linkName, outbuf, offset, TarHeader.NAMELEN );
offset = TarHeader.getNameBytes
( this.header.magic, outbuf, offset, TarHeader.MAGICLEN );
offset = TarHeader.getNameBytes
( this.header.userName, outbuf, offset, TarHeader.UNAMELEN );
offset = TarHeader.getNameBytes
( this.header.groupName, outbuf, offset, TarHeader.GNAMELEN );
offset = TarHeader.getOctalBytes
( this.header.devMajor, outbuf, offset, TarHeader.DEVLEN );
offset = TarHeader.getOctalBytes
( this.header.devMinor, outbuf, offset, TarHeader.DEVLEN );
for ( ; offset < outbuf.length ; )
outbuf[ offset++ ] = 0;
long checkSum = this.computeCheckSum( outbuf );
TarHeader.getCheckSumOctalBytes
( checkSum, outbuf, csOffset, TarHeader.CHKSUMLEN );
}
/**
* Parse an entry's TarHeader information from a header buffer.
*
* @param hdr The TarHeader to fill in from the buffer information.
* @param header The tar entry header buffer to get information from.
*/
public void
parseTarHeader( TarHeader hdr, byte[] header )
throws InvalidHeaderException
{
int offset = 0;
hdr.name =
TarHeader.parseName( header, offset, TarHeader.NAMELEN );
offset += TarHeader.NAMELEN;
hdr.mode = (int)
TarHeader.parseOctal( header, offset, TarHeader.MODELEN );
offset += TarHeader.MODELEN;
hdr.userId = (int)
TarHeader.parseOctal( header, offset, TarHeader.UIDLEN );
offset += TarHeader.UIDLEN;
hdr.groupId = (int)
TarHeader.parseOctal( header, offset, TarHeader.GIDLEN );
offset += TarHeader.GIDLEN;
hdr.size =
TarHeader.parseOctal( header, offset, TarHeader.SIZELEN );
offset += TarHeader.SIZELEN;
hdr.modTime =
TarHeader.parseOctal( header, offset, TarHeader.MODTIMELEN );
offset += TarHeader.MODTIMELEN;
hdr.checkSum = (int)
TarHeader.parseOctal( header, offset, TarHeader.CHKSUMLEN );
offset += TarHeader.CHKSUMLEN;
hdr.linkFlag = header[ offset++ ];
hdr.linkName =
TarHeader.parseName( header, offset, TarHeader.NAMELEN );
offset += TarHeader.NAMELEN;
hdr.magic =
TarHeader.parseName( header, offset, TarHeader.MAGICLEN );
offset += TarHeader.MAGICLEN;
hdr.userName =
TarHeader.parseName( header, offset, TarHeader.UNAMELEN );
offset += TarHeader.UNAMELEN;
hdr.groupName =
TarHeader.parseName( header, offset, TarHeader.GNAMELEN );
offset += TarHeader.GNAMELEN;
hdr.devMajor = (int)
TarHeader.parseOctal( header, offset, TarHeader.DEVLEN );
offset += TarHeader.DEVLEN;
hdr.devMinor = (int)
TarHeader.parseOctal( header, offset, TarHeader.DEVLEN );
}
/**
* Fill in a TarHeader given only the entry's name.
*
* @param hdr The TarHeader to fill in.
* @param name The tar entry name.
*/
public void
nameTarHeader( TarHeader hdr, String name )
{
boolean isDir = name.endsWith( "/" );
hdr.checkSum = 0;
hdr.devMajor = 0;
hdr.devMinor = 0;
hdr.name = new StringBuffer( name );
hdr.mode = isDir ? 040755 : 0100644;
hdr.userId = 0;
hdr.groupId = 0;
hdr.size = 0;
hdr.checkSum = 0;
hdr.modTime =
(new java.util.Date()).getTime() / 1000;
hdr.linkFlag =
isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;
hdr.linkName = new StringBuffer( "" );
hdr.userName = new StringBuffer( "" );
hdr.groupName = new StringBuffer( "" );
hdr.devMajor = 0;
hdr.devMinor = 0;
}
}
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet)
¤
|
Haftungshinweis
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.
|