Logo Search packages:      
Sourcecode: jedit version File versions  Download package

TarEntry.java

/*
** Authored by Timothy Gerard Endres
** <mailto:time@gjt.org>  <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
00075 class       TarEntry
extends           Object
      {
      /**
       * If this entry represents a File, this references it.
       */
00081       protected File                      file;

      /**
       * This is the entry's header information.
       */
00086       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
00093       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
00106       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
00120       TarEntry( byte[] headerBuf )
            throws InvalidHeaderException
            {
            this.initialize();
            this.parseTarHeader( this.header, headerBuf );
            }

      /**
       * Initialization code common to all constructors.
       */
      private void
00131       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
00145       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
00161       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
00174       getHeader()
            {
            return this.header;
            }

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

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

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

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

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

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

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

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

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

      /**
       * Set this entry's group name.
       *
       * @param groupName This entry's new group name.
       */
      public void
00286       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
00299       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
00312       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
00325       setModTime( long time )
            {
            this.header.modTime = time / 1000;
            }

      /**
       * Set this entry's modification time.
       *
       * @param time This entry's new modification time.
       */
      public void
00336       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
00347       getModTime()
            {
            return new Date( this.header.modTime * 1000 );
            }

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

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

      /**
       * Set this entry's file size.
       *
       * @param size This entry's new file size.
       */
      public void
00380       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
00393       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
00407       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
00431       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[]
00509       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
00539       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
00557       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
00621       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
00699       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;
            }

      }


Generated by  Doxygen 1.6.0   Back to index