/*****************************************************************************/
/* File name: ActionExtract.java                                             */
/* Purpose: to keep an option and a corresponding flag for Jtar              */
/* Last modified: 13.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*                                                                           */
/* This program is distributed in the hope that it will be useful, but       */
/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
/* Public License for more details.                                          */
/*                                                                           */
/* This software is distributed under the terms                              */
/* of the GNU General Public License as published                            */
/* by the Free Software Foundation; either version 2, or (at your option)    */
/* any later version.                                                        */
/* See file COPYING for your rights (GNU GPL)                                */
/*****************************************************************************/

package jtar;


import java.io.*;
import java.util.*;
import general.Constants;
import io.*;


class

ActionExtract

                   extends ActionRead

     implements jtar.Constants,
                general.Constants,
                Serializable

{

  private final static String RCSID =
"$Header: /d/NFS/jtar/RCS/ActionExtract.java,v 1.5 1999/08/13 20:04:35 vklimov Exp $";

  private final static String HEADER_DIALOG_TITLE   = "Extract";
  private final static int    HEADER_DIALOG_ROWS    = 23;
  private final static int    HEADER_DIALOG_COLUMNS = 77;

  private static final String OUTPUT_RANDOM_ACCESS_FILE_MODE = "rw";

  private static boolean warnedOnceStrippingLeadingSlash = false;
  private static boolean conttypeDiagnosed = false;
  private final static String EXTRACT_COMPLETED_MSG = "\nExtract completed";


  ActionExtract( char    option,
                 boolean flag   )
/*****************************************************************************/
/* Function name: ActionExtract                                              */
/* File name: ActionExtract.java                                             */
/* Purpose: constructor for the ActionExtract object                         */
/* Parameters: option - 't', 'x', 'c' etc                                    */
/*             flag - corresponding flag                                     */
/* Returns:                                                                  */
/* Last modified: 11.12.98                                                   */
/* Author: Victor Klimov, 1998                                               */
/*****************************************************************************/
    {
                                                    /* ActionExtract */
/*---------------------------------------------------------------------------*/

      super( option, flag );

    }
/*end of ActionExtract*/



  int
  extractSparseFile( RandomAccessFile outputRandomAccessFile,
                     int totalSize, String name,
                     BufferRead readBuffer,
                     Vector sparseVector,
                     AllActions allActions                    )
/*****************************************************************************/
/* Function name: extractSparseFile                                          */
/* File name: ActionExtract.java                                             */
/* Purpose: to extract a sparse file                                         */
/* Parameters: outputRandomAccessFile - file to write to                     */
/*             totalSize - the total number of bytes to write                */
/*             name - name of the file to write to                           */
/*             readBuffer - an object to read in tar blocks                  */
/*             sparseVector - vector, containing info on a sparse file       */
/*             allActions                                                    */
/* Returns: sizeLeft                                                         */
/* Last modified: 26.07.99                                                   */
/* Author of the Java translation: Victor Klimov, 1999                       */
/*****************************************************************************/
    {
      Block dataBlock = null;
      SpArray previousSpArrayElement;
      SpArray currentSpArrayElement;

      int sizeLeft;
      int sparseInd = 0;
      int written = 0;
                                                  /* extractSparseFile */
/*---------------------------------------------------------------------------*/

      sizeLeft = totalSize;             /* sizeLeft is initially totalSize */

      while( sizeLeft > 0 )
        {
          dataBlock = readBuffer.
            getCurrentDataBlock( allActions );

          if (dataBlock == null)
            {
              return sizeLeft;                              /* return ! */
            }
          else
            ;
        /*end of if on null*/

          try
            {
              previousSpArrayElement = (SpArray)
                sparseVector.elementAt( sparseInd );
              outputRandomAccessFile.
                seek( previousSpArrayElement.offset );

              sparseInd++;
              currentSpArrayElement = (SpArray)
                sparseVector.elementAt( sparseInd );

              written = currentSpArrayElement.numbytes;

              while( written > BLOCKSIZE )
                {
                  outputRandomAccessFile.
                    write( dataBlock.buffer, 0,
                           BLOCKSIZE            );
                  written -= BLOCKSIZE;
                  sizeLeft -= BLOCKSIZE;
                  readBuffer.
                    permitToFillUpNewCurrentBlock();
                  dataBlock = readBuffer.
                    getCurrentDataBlock( allActions );

                  if (dataBlock == null)
                    {
                      return sizeLeft;                          /* return ! */
                    }
                  else
                    ;
                /*end of if on null*/
                }
            /*end of while-loop on written*/

              outputRandomAccessFile.
                write( dataBlock.buffer, 0,
                       written              );
            }
          catch( ArrayIndexOutOfBoundsException e )
            {
              System.out.println(
                "\nShould not happen:\n" +
                e.getMessage()             );
            }
          catch( IOException e )
            {
              System.out.println( name +
                  ": Could not write to file" +
                  e.getMessage()             );
            }
        /*end of try-catch on writing*/

          sizeLeft -= written;
          readBuffer.
            permitToFillUpNewCurrentBlock();

        }
    /*end of while-loop on sizeLeft*/

      readBuffer.
        permitToFillUpNewCurrentBlock();

      return sizeLeft;

    }
/*end of extractSparseFile*/


  int

  extractRegularFile( RandomAccessFile outputRandomAccessFile,
                      NamesFilesInputOutput namesInputOutput,
                      BufferRead readBuffer,
                      AllActions allActions                       )
/*****************************************************************************/
/* Function name: extractRegularFile                                         */
/* File name: ActionExtract.java                                             */
/* Purpose: to extract a regular file                                        */
/* Parameters: outputRandomAccessFile - file to write to                     */
/*             namesInputOutput - this object contains information           */
/*                                on what to extract and to where            */
/*             readBuffer - an object to read in tar blocks                  */
/*             allActions                                                    */
/* Returns: totalWritten                                                     */
/* Last modified: 13.08.99                                                   */
/* Author of the Java translation: Victor Klimov, 1998, 1999                 */
/*****************************************************************************/
    {
      Block dataBlock = null;
      int size;
      int written = 0;
      int totalWritten = 0;
                                                  /* extractRegularFile */
/*---------------------------------------------------------------------------*/

      for (size = allActions.currentStat.size;
           size > 0;
           size -= written)
        {
          if (allActions.multiVolume)
            {
              readBuffer.saveName = new
                String( namesInputOutput.getInputFileName() );
              readBuffer.saveTotsize =
                allActions.currentStat.size;
            }
          else
            ;
        /*end of if on multiVolume*/


          written = readBuffer.
            availableSpaceAfter();

          dataBlock = readBuffer.
            getCurrentDataBlock( allActions );

          if (dataBlock == null)
            {
              System.out.println(
                  "ActionExtract.extractRegularFile: " +
                  "unexpected EOF on archive file" );
              break;                                  /* break ! */
            }
          else
            ;
        /*end of if on null*/

          if (written == 0)
            written =
              dataBlock.buffer.length;
          else
            ;
        /*end of if on written*/

          if (written > size)
            written = size;
          else
            ;
        /*end of if on written*/

          if (written > dataBlock.buffer.length)
            written =
              dataBlock.buffer.length;
          else
            ;
        /*end of if on written*/

          try
            {
              outputRandomAccessFile.
                write(
                  dataBlock.buffer, 0,
                  written              );
              totalWritten += written;
            }
          catch( IOException e )
            {
              System.out.println(
                    namesInputOutput.getOutputFileName() +
                  ": Error writing to file"   );

              readBuffer.
                skipFile( (size - written),
                          allActions         );
              break;                                   /* break ! */
            }
        /*end of try-catch*/

          readBuffer.
            permitToFillUpNewCurrentBlock();
        }
    /*end of for-loop on size*/

      return totalWritten;

    }
/*end of extractRegularFile*/


  void

  extractFile( NamesFilesInputOutput namesInputOutput,
               RandomAccessFile outputRandomAccessFile,
               Header tarHeader,
               BufferRead readBuffer,
               Vector sparseVector,
               AllActions allActions                    )
/*****************************************************************************/
/* Function name: extractFile                                                */
/* File name: ActionExtract.java                                             */
/* Purpose: to extract a file                                                */
/* Parameters: namesInputOutput - this object contains information           */
/*                                on what to extract and to where            */
/*             outputRandomAccessFile - file to write to                     */
/*             tarHeader - an object to handle tar headers                   */
/*             readBuffer - an object to read in tar blocks                  */
/*             sparseVector - vector, containing info on a sparse file       */
/*             allActions                                                    */
/* Returns:                                                                  */
/* Last modified: 13.08.99                                                   */
/* Author: Victor Klimov, 1998, 1999                                         */
/*****************************************************************************/
    {
      String name;
      int size;
                                                     /* extractFile */
/*---------------------------------------------------------------------------*/

      if (tarHeader.currentHeader.typeflag == GNUTYPE_SPARSE)
        {
          name = new String( namesInputOutput.getInputFileName() );
          size = extractSparseFile(
                   outputRandomAccessFile, 
                   allActions.currentStat.size,
                   name,
                   readBuffer,
                   sparseVector,
                   allActions                    );
        }
      else /* something other, Not GNUTYPE_SPARSE */
        {
          size = 
            extractRegularFile(
              outputRandomAccessFile,
              namesInputOutput,
              readBuffer,
              allActions                   );
        }
    /*end of if on GNUTYPE_SPARSE*/

      if (allActions.multiVolume)
        readBuffer.saveName = null;
      else
        ;
    /*end of if on multiVolume*/

    }
/*end of extractFile*/


  void

  processOutputFileCreationError(
    Header tarHeader,
    BufferRead readBuffer,
    AllActions allActions                     )
/*****************************************************************************/
/* Function name: processOut                                                 */
/* File name: ActionExtract.java                                             */
/* Purpose: to process an error in output file creation                      */
/* Parameters: tarHeader - an object to handle tar headers                   */
/*             readBuffer - an object to read in tar blocks                  */
/*             allActions                                                    */
/* Returns:                                                                  */
/* Last modified: 13.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      NamesFilesInputOutput resultAgainFile = null;
      boolean neededCreateIntermediateDirs;

                                       /* processOutputFileCreationError */
/*---------------------------------------------------------------------------*/

      if (tarHeader.currentHeader.isextended != 0)
        readBuffer.skipExtendedHeaders( allActions );
      else
        ;
    /*end of if on isextended*/

      readBuffer.skipFile(
        allActions.currentStat.size,
        allActions                    );

      if (allActions.backup)
        io.Backup.undoLastBackup();
      else
        ;
    /*end of if on backup*/

    }
/*end of processOutputFileCreationError*/


  NamesFilesInputOutput

  againFile( NamesFilesInputOutput namesInputOutput,
             Header tarHeader,
             BufferRead readBuffer,
             Vector sparseVector,
             AllActions allActions                     )
/*****************************************************************************/
/* Function name: againFile                                                  */
/* File name: ActionExtract.java                                             */
/* Purpose: to process additionaly a directory                               */
/* Parameters: namesInputOutput - this object contains information           */
/*                                on what to extract and to where            */
/*             tarHeader - an object to handle tar headers                   */
/*             readBuffer - an object to read in tar blocks                  */
/*             sparseVector - vector, containing info on a sparse file       */
/*             allActions                                                    */
/* Returns: a NamesFilesInputOutput object if everything is all right,       */
/*          null - otherwise                                                 */
/* Last modified: 13.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      File outputFile;
      RandomAccessFile outputRandomAccessFile;
                                                          /* againFile */
/*---------------------------------------------------------------------------*/

      if (tarHeader.currentHeader.typeflag == CONTTYPE)
        {

          if (!conttypeDiagnosed)
            {
              conttypeDiagnosed = true;
            }
          else
            ;
        /*end of if on conttypeDiagnosed*/
        }
      else /* Not CONTTYPE */
        ;
    /*end of if on CONTTYPE*/

      try
        {
          outputFile = new
            File( namesInputOutput.getOutputFileName() );

          outputRandomAccessFile = new
            RandomAccessFile( outputFile,
                              OUTPUT_RANDOM_ACCESS_FILE_MODE );
        }
      catch( NullPointerException e)
        {
          return null;                                      /* return ! */
        }
      catch( IllegalArgumentException e)
        {
          return null;                                      /* return ! */
        }
      catch( SecurityException e)
        {
          processOutputFileCreationError(
            tarHeader,
            readBuffer,
            allActions                   );

          return null;                                      /* return ! */
        }
      catch( IOException e)
        {
          processOutputFileCreationError(
            tarHeader,
            readBuffer,
            allActions                   );

          return null;                                      /* return ! */
        }
    /*end of try-catch*/

      extractFile( namesInputOutput,
                   outputRandomAccessFile,
                   tarHeader,  
                   readBuffer,
                   sparseVector,
                   allActions                    );

      try
        {
          outputRandomAccessFile.close();
        }
      catch( IOException e)
        {
          System.out.println(
                namesInputOutput.
                  getOutputFileName() +
              ": Error while closing"       );
          if (allActions.backup)
            io.Backup.undoLastBackup();
          else
            ;
        /*end of if on backup*/
          return null;                                      /* return ! */
        }
    /*end of try-catch*/

      return new NamesFilesInputOutput(null,null);

    }
/*end of againFile*/


  boolean
  againDir( StringBuffer currentFileNameStringBuffer,
            BufferRead readBuffer,
            AllActions allActions                     )
/*****************************************************************************/
/* Function name: againDir                                                   */
/* File name: ActionExtract.java                                             */
/* Purpose: to process additionaly a directory                               */
/* Parameters: currentFileNameStringBuffer                                   */
/*             readBuffer - an object to read in tar blocks                  */
/*             allActions                                                    */
/* Returns: true - if everything is all right, false - otherwise             */
/* Last modified: 26.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      boolean removedOK;
      boolean resultAgainDir;

      int nameLength;
      int pathSeparatorIndexLast;

      boolean created;

      File currentFile = null;
                                                   /* againDir */
/*---------------------------------------------------------------------------*/

      try
        {
          currentFile = new
            File( currentFileNameStringBuffer.toString() );

          created = currentFile.mkdirs();
          if (!created)
            {
              if (allActions.backup)
                io.Backup.undoLastBackup();
              else
                ;
            /*end of if on backup*/

              return false;                                /* return ! */

            }
          else
            ;
        /*end of if on created*/
        }
      catch( NullPointerException e )
        {
          readBuffer.close();
          return false;                                /* return ! */
        }
      catch( SecurityException e )
        {
          if ( (currentFile != null ) &&
              (currentFile.exists())
             )
            {
              if ( ! allActions.
                    keepOldFiles )
                {
                  removedOK =
                    io.Remove.
                      removeAnyFile(
                        currentFileNameStringBuffer.toString(),
                        false /* not recursive */               );
                  if (removedOK)
                    resultAgainDir =
                      againDir(
                        currentFileNameStringBuffer,
                        readBuffer,
                        allActions                   );
                  else
                    return false;                       /* return ! */
                /*end of if on removedOK*/
                }
              else
                ;
            /*end of if on keepOldFiles*/
            }
          else
            ;
        /*end of if on exists*/

          if (allActions.backup)
            io.Backup.undoLastBackup();
          else
            ;
        /*end of if on backup*/

          return false;                             /* return ! */

        }
    /*end of try-catch on mkdir*/

      return true;

    }
/*end of againDir*/


  void
  extractDirectory( StringBuffer currentFileNameStringBuffer,
                    Header tarHeader,
                    BufferRead readBuffer,
                    AllActions allActions                      )
/*****************************************************************************/
/* Function name: extractDirectory                                           */
/* File name: ActionExtract.java                                             */
/* Purpose: to extract a directory                                           */
/* Parameters: currentFileNameStringBuffer                                   */
/*             tarHeader - an object to handle tar headers                   */
/*             readBuffer - an object to read in tar blocks                  */
/*             allActions                                                    */
/* Returns:                                                                  */
/* Last modified: 26.07.99                                                   */
/* Author: Victor Klimov, 1998, 1999                                         */
/*****************************************************************************/
    {
      boolean resultAgainDir;
                                                   /* extractDirectory */
/*---------------------------------------------------------------------------*/

                                                    /* Check for trailing /, */
                                                    /* and zap as many       */
                                                    /* as we find            */
      currentFileNameStringBuffer =
        new StringBuffer(
          util.String.removeTrailingPathSeparator(
            currentFileNameStringBuffer.toString() ) );

                                      /* Read the entry and delete files   */
                                      /* that aren't listed in the archive */
      if (allActions.incremental.flag)
        {
          /* gnuRestore(skipcrud); */

            readBuffer.
              skipFile(
                allActions.currentStat.size,
                allActions                    );
        }
      else /* regular, not incremental */
        {
          if (tarHeader.currentHeader.typeflag ==
              GNUTYPE_DUMPDIR)
            {
            readBuffer.
              skipFile(
                allActions.currentStat.size,
                allActions                   );
            }
          else
            ;
        /*end of if on GNUTYPE_DUMPDIR*/
        }
    /*end of if on incremental*/

      resultAgainDir =
        againDir( currentFileNameStringBuffer,
                  readBuffer,
                  allActions                   );

    }
/*end of extractDirectory*/


  Vector
  doFirstThingsForSparse( Header tarHeader,
                          BufferRead readBuffer,
                          AllActions allActions  )
/*****************************************************************************/
/* Function name: doFirstThingsForSparse                                     */
/* File name: ActionExtract.java                                             */
/* Purpose: to do some preliminary things for the sparse case                */
/*                                                                           */
/*          JK - What we want to do if the file is sparse is loop through    */
/*          the array of sparse structures in the header and read in and     */
/*          translate the character strings representing 1) the offset at    */
/*          which to write and 2) how many bytes to write into numbers,      */
/*          which we store into the scratch array, "sparseVector".  This     */
/*          array makes our life easier the same way it did in creating      */
/*          the tar file that had to deal with a sparse file.                */
/*                                                                           */
/*          After we read in the first five (at most) sparse structures,     */
/*          we check to see if the file has an extended header, i.e.,        */
/*          if more sparse structures are needed to describe the contents    */
/*          of the new file.  If so, we read in the extended headers and     */
/*          continue to store their contents into the sparseVector.          */
/*                                                                           */
/* Parameters: tarHeader - an object to handle tar headers                   */
/*             readBuffer - an object to read in tar blocks                  */
/*             allActions                                                    */
/* Returns: sparseVector - if everything is all right, null - otherwise      */
/* Last modified: 26.07.99                                                   */
/* Author of the Java translation: Victor Klimov, 1998, 1999                 */
/*****************************************************************************/
    {
      int ind;
      int counter;
      int spArraySize;
      int numbytes;
      Vector sparseVector;
      SpArray tempSpArray;
      Block exhdr = null;
                                               /* doFirstThingsForSparse */
/*---------------------------------------------------------------------------*/

      spArraySize = SP_VECTOR_INIT_SIZE;
      sparseVector = new Vector( spArraySize );

      for (counter = 0;
           counter < SPARSES_IN_OLDGNU_HEADER;
           counter++
          )
        {
          tempSpArray = new SpArray();
          tempSpArray.offset = Octal.fromOct(
              SPARSE_DESCRIPTOR_FIELD_LENGTH_OFFSET,
              tarHeader.currentHeader.sp[counter].offset);
          tempSpArray.numbytes = Octal.fromOct(
              SPARSE_DESCRIPTOR_FIELD_LENGTH_NUMBYTES,
              tarHeader.currentHeader.sp[counter].numbytes);

          sparseVector.addElement(
            (Object) tempSpArray   );

          if (tempSpArray.numbytes == 0 )
            break;                             /* break ! */
          else
            ;
        /*end of if on numbytes*/
        }
    /*end of for-loop on sparses*/

      if (tarHeader.currentHeader.isextended != 0)
        {
                                             /* read in the list     */
                                             /* of extended headers  */
                                             /* and translate them   */
                                             /* into the sparseVector*/
                                             /* as before            */

          ind = SPARSES_IN_OLDGNU_HEADER;

          while( true )
            {
              exhdr = readBuffer.
                getCurrentDataBlock( allActions );

              if (exhdr == null) /* end of file */
                {
                  readBuffer.close();
                  return null;                          /* return ! */
                }
              else
                ;
            /*end of if on null*/

              for (counter = 0;
                   counter < SPARSES_IN_SPARSE_HEADER;
                   counter++
                  )
                {
                  numbytes = Octal.fromOct(
                    SPARSE_DESCRIPTOR_FIELD_LENGTH_NUMBYTES,
                    exhdr.sp[counter].numbytes               );
                  if (numbytes == 0)
                    break;                             /* break ! */
                  else
                    ;
                /*end of if on 0*/

                  tempSpArray = new SpArray();
                  tempSpArray.offset = Octal.fromOct(
                    SPARSE_DESCRIPTOR_FIELD_LENGTH_OFFSET,
                    exhdr.sp[counter].offset                 );
                  tempSpArray.numbytes = Octal.fromOct(
                    SPARSE_DESCRIPTOR_FIELD_LENGTH_NUMBYTES,
                    exhdr.sp[counter].numbytes               );

                  sparseVector.addElement(
                    (Object) tempSpArray   );
                }
            /*end of for-loop on counter*/

              if ( exhdr.isextended != 0 )
                break; /* regular header */            /* break ! */
              else /* extended header */
                {
                  ind += SPARSES_IN_SPARSE_HEADER;
                  readBuffer.
                    permitToFillUpNewCurrentBlock();
                }
            /*end of if on isextended*/
            }
        /*end of while-loop*/

          readBuffer.
            permitToFillUpNewCurrentBlock();

        }
      else /* no extended headers */
        ;
    /*end of isextended*/

      return sparseVector;

    }
/*end of doFirstThingsForSparse*/


  NamesFilesInputOutput

  scanCommandLineOptionsVector(
    Vector commandLineOptionsVector,
    String currentFileNameString        )
/*****************************************************************************/
/* Function name: scanCommandLineOptionsVector                               */
/* File name: ActionExtract.java                                             */
/* Purpose: to scan the list of remaining options (that should be only       */
/*          file names) and check whether the current file name is in there  */
/* Parameters: commandLineOptionsVector - list of the file names             */
/*             currentFileNameString                                         */
/* Returns: a NamesFilesInputOutput object that contains input and output    */
/*          file names or                                                    */
/*          null if not found                                                */
/* Last modified: 11.08.99                                                   */
/* Author of the Java translation: Victor Klimov, 1999                       */
/*****************************************************************************/
    {
      NamesFilesInputOutput namesInputOutput = null;
      boolean continueToLoop = true;
      int i;
      int nFileNames;
      String aFileName;
                                       /* scanCommandLineOptionsVector */
/*---------------------------------------------------------------------------*/

      if (commandLineOptionsVector == null)
        {                              /* no file names - extract everything */
          namesInputOutput = new
            NamesFilesInputOutput(
              currentFileNameString,
              currentFileNameString );
          return namesInputOutput;                            /* return ! */
        }
      else
        {
          nFileNames =
            commandLineOptionsVector.size();
          if (nFileNames == 0) /* no file names - extract everything */
            {
              namesInputOutput = new
                NamesFilesInputOutput(
                  currentFileNameString,
                  currentFileNameString );
              return namesInputOutput;                      /* return ! */
            }
          else
            ;
        /*end of if on nFileNames*/
        }
    /*end of if on null*/

      currentFileNameString =
        util.String.
          removeTrailingPathSeparator(
            currentFileNameString      );
      
      for ( i = 0;
            continueToLoop &&
            (i < nFileNames);   i++ )
        {
          namesInputOutput = (NamesFilesInputOutput)
                   commandLineOptionsVector.elementAt( i );

          aFileName = namesInputOutput.getInputFileName();

          aFileName =
            util.String.
              removeTrailingPathSeparator(
                aFileName                  );
          if ( ( aFileName.equals(
                 currentFileNameString ) )        ||
               currentFileNameString.startsWith(
                 aFileName + File.separator    )
             )
            continueToLoop = false;
          else
            ;
        /*end of if*/
        }
    /*end of for-loop*/

      if (continueToLoop)
        return null;
      else
        return namesInputOutput;
    /*end of if*/

    }
/*end of scanCommandLineOptionsVector*/


  NamesFilesInputOutput

  prepareToExtractArchiveEntry(
    Header tarHeader,
    BufferRead readBuffer,
    StringBuffer currentFileNameStringBuffer,
    Vector commandLineOptionsVector,
    AllActions allActions                      )
/*****************************************************************************/
/* Function name: prepareToExtractArchiveEntry                               */
/* File name: ActionExtract.java                                             */
/* Purpose: to prepare to extract an element from a tar archive              */
/* Parameters: tarHeader - an object to handle tar headers                   */
/*             readBuffer - an object to read in tar blocks                  */
/*             currentFileNameStringBuffer                                   */
/*             commandLineOptionsVector                                      */
/*             allActions                                                    */
/* Returns: a NamesFilesInputOutput object or                                */
/*          null - the current entry must be skipped                         */
/* Last modified: 11.08.99                                                   */
/* Author of the Java translation: Victor Klimov, 1999                       */
/*****************************************************************************/
    {
      NamesFilesInputOutput namesInputOutput = null;
      boolean backupMadeOrUnneeded = false;
      int pathSeparatorLength = File.separator.length();
      String currentFileNameStringNew;

                                          /* prepareToExtractArchiveEntry */
/*---------------------------------------------------------------------------*/

      readBuffer.
        permitToFillUpNewCurrentBlock();
      tarHeader.decodeHeader( false,           /* no user group yet */
                              allActions );

      namesInputOutput =
        scanCommandLineOptionsVector(
          commandLineOptionsVector,
          currentFileNameStringBuffer.toString() );

      if ( (namesInputOutput==null) ||
           ( allActions.interactive &&
             ! io.Interaction.confirm(
                 MESSAGE_ACTION_STRING_EXTRACT,
                 currentFileNameStringBuffer.toString() )
           )
         )
        {
          if ( tarHeader.currentHeader.isextended != 0 )
            readBuffer.skipExtendedHeaders( allActions );
          else
            ;
        /*end of if*/

          readBuffer.skipFile(
            allActions.
              currentStat.size,
            allActions          );

          return null;                                  /* return ! */

        }
      else
        ;
    /*end of if on interactive*/
                                                 /* print the block     */
                                                 /* from currentHeader */
                                                 /* and currentStat    */
      tarHeader.printHeader( (Buffer) readBuffer,
                             false, null,
                             allActions            );

                                 /* Check for fully specified file names */
                                 /* and other atrocities                 */

      currentFileNameStringNew =
        util.String.
          removeLeadingPathSeparator(
            currentFileNameStringBuffer.
              toString()                  );

      if ( ! currentFileNameStringNew.equals(
               currentFileNameStringBuffer.
                 toString()                 )  &&
           ! warnedOnceStrippingLeadingSlash )
        {
          warnedOnceStrippingLeadingSlash = true;
        }
      else
        ;
    /*end of if on warnedOnceStrippingLeadingSlash*/

      currentFileNameStringBuffer =
        new StringBuffer(
          currentFileNameStringNew );

                                        /* Take a safety backup          */
                                        /* of a previously existing file */
      if ( allActions.backup &&
           ! allActions.toStdout )
        {
          backupMadeOrUnneeded =
            io.Backup.checkPathMakeBackup(
              currentFileNameStringBuffer.toString(),
              false ); /* not an archive file */

          if ( ! backupMadeOrUnneeded )
            {
              if (tarHeader.currentHeader.isextended != 0 )
                readBuffer.skipExtendedHeaders( allActions );
              else
                ;
            /*end of if on isextended*/

              readBuffer.skipFile(
                allActions.currentStat.size,
                allActions                   );

              return null;                                 /* return ! */

            }
          else /* backup made OK */
            ;
        /*end of if on backupMadeOrUnneeded*/

        }
      else /* no need to backup */
        ;
    /*end of if*/

      return namesInputOutput;

    }
/*end of prepareToExtractArchiveEntry*/


  public
  boolean

  action( Vector commandLineOptionsVector,
          Header dummyTarHeader,
          BufferRead dummyReadBuffer,
          AllActions allActions            )
/*****************************************************************************/
/* Function name: action to extract archive members                          */
/* File name: ActionExtract.java                                             */
/* Purpose: to extract elements from a tar archive                           */
/* Parameters: commandLineOptionsVector - vector, containig strings          */
/*                                 of command line arguments to Jtar         */
/*             dummyTarHeader                                                */
/*             dummyReadBuffer                                               */
/*             allActions                                                    */
/* Returns: true - if everything is all right, false - otherwise             */
/* Last modified: 13.08.99                                                   */
/* Author of the Java translation: Victor Klimov, 1999                       */
/*****************************************************************************/
    {
      boolean continueToLoop = true;
      NamesFilesInputOutput namesInputOutput = null;

      int written;
      int nameLength;
      int pathSeparatorLength = File.separator.length();
      int pathSeparatorIndexLast;

      boolean readOK = true;

      Vector sparseVector = null;

      BufferRead readBuffer = new BufferRead( allActions );
      Header tarHeader = new Header();
      StringBuffer currentFileNameStringBuffer;

      boolean resultSuperAction = true;
                                                          /* action */
/*---------------------------------------------------------------------------*/

      readOK =
        readBuffer.open( allActions );

      if (!readOK)
        return false;                                  /* return ! */
      else
        ;
    /*end of if on readOK*/

      while( continueToLoop )
        {
          resultSuperAction =
            super.action( commandLineOptionsVector,
                          tarHeader,
                          readBuffer,
                          allActions                );

          if ( (tarHeader.status == HEADER_ZERO_BLOCK) ||
               (tarHeader.status == HEADER_END_OF_FILE) ||
               (tarHeader.status == HEADER_FAILURE)
             )
            {

            break;                                          /* break ! */

            }
          else
            ;
        /*end of if on status*/

          currentFileNameStringBuffer = new
            StringBuffer(
              c.String.truncateNull(
                allActions.currentFileName ) );

          namesInputOutput =
            prepareToExtractArchiveEntry(
              tarHeader,
              readBuffer,
              currentFileNameStringBuffer,
              commandLineOptionsVector,
              allActions                   );

          if (namesInputOutput==null)
            {
              continue;                                  /* continue ! */
            }
          else
            {
            }
        /*end of if on namesInputOutput*/
                                               /* extract the archive entry */
                                               /* according to its type     */

          switch( tarHeader.currentHeader.typeflag)
            {

            case GNUTYPE_SPARSE: /* ------------ case ------------- */

              sparseVector =
                doFirstThingsForSparse(
                  tarHeader,
                  readBuffer,
                  allActions           );

              if ( sparseVector == null )
                {
                  continueToLoop = false;
                  break;                                 /* break ! */
                }
              else
                ;
            /*end of if on resultDoFirstThingsForSparse*/

            /* Fall through.  */

            case AREGTYPE: /* ------------ case ------------- */
            case REGTYPE:
            case CONTTYPE:
                                                   /* Appears to be a file */
                                                   /* But BSD tar uses     */
                                                   /* the convention that  */
                                                   /* a slash suffix means */
                                                   /* a directory          */

              nameLength = currentFileNameStringBuffer.length();

              pathSeparatorIndexLast =
                currentFileNameStringBuffer.toString().
                  lastIndexOf( File.separator,
                               nameLength -
                                 pathSeparatorLength );

              if ( ( pathSeparatorIndexLast +
                     pathSeparatorLength      ==
                     nameLength               )   &&
                   ( pathSeparatorIndexLast !=
                     JAVA_ERROR_CODE           )
                 )
                extractDirectory(
                  currentFileNameStringBuffer,
                  tarHeader,
                  readBuffer,
                  allActions                   );
              else
                namesInputOutput =
                  againFile( namesInputOutput,
                             tarHeader,
                             readBuffer,
                             sparseVector,
                             allActions                   );
            /*end of if on trailing slash*/

              break;

            case SYMTYPE: /* ------------ case ------------- */

              System.out.println(
                    currentFileNameStringBuffer.
                     toString()                  +
                  ": the current version does " +
                  "not know how to create symlinks" );

              if (allActions.backup)
                io.Backup.undoLastBackup();
              else
                ;
            /*end of if on backup*/

              break;

            case LNKTYPE: /* ------------ case ------------- */

                System.out.println(
                    currentFileNameStringBuffer.
                     toString()                  +
                  ": the current version does " +
                  "not know how to create links"  );

              if (allActions.backup)
                io.Backup.undoLastBackup();
              else
                ;
            /*end of if on backup*/

              break;

            case CHRTYPE: /* ------------ case ------------- */
            case BLKTYPE: /* ------------ case ------------- */

              System.out.println(
                    currentFileNameStringBuffer.
                     toString()                  +
                  ": the current version does " +
                  "not know how to make os nodes"       );

              if (allActions.backup)
                io.Backup.undoLastBackup();
              else
                ;
             /*end of if on backup*/

              break;

            case FIFOTYPE: /* ------------ case ------------- */

              System.out.println(
                    currentFileNameStringBuffer.
                     toString()                  +
                  ": the current version does " +
                  "not know how to make fifo pipe files" );

              if (allActions.backup)
                io.Backup.undoLastBackup();
              else
                ;
            /*end of if on backup*/

              break;

            case DIRTYPE: /* ------------ case ------------- */
            case GNUTYPE_DUMPDIR:

              nameLength =
                currentFileNameStringBuffer.length();

              extractDirectory(
                  currentFileNameStringBuffer,
                  tarHeader,
                  readBuffer,
                  allActions                    );

              break;

            case GNUTYPE_VOLHDR: /* ------------ case ------------- */

              if (allActions.verbose.flag)
                {
                }
              else
                ;
            /*end of if on verbose*/

              break;

            case GNUTYPE_NAMES: /* ------------ case ------------- */

              System.out.println(
                  "The current version can " +
                  "not handle GNUTYPE_NAMES records: " +
                    currentFileNameStringBuffer.
                     toString()                            );

              readBuffer.skipFile(
                allActions.currentStat.size,
                allActions                   );

              if (allActions.backup)
                io.Backup.undoLastBackup();
              else
                ;
            /*end of if on backup*/
              break;

            case GNUTYPE_MULTIVOL: /* ------------ case ------------- */

              System.out.println(
                  "The current version can " +
                  "not extract " +
                    currentFileNameStringBuffer.
                     toString()                  +
                  " -- file is continued from another volume" );

              readBuffer.skipFile(
                allActions.currentStat.size,
                allActions                   );

              if (allActions.backup)
                io.Backup.undoLastBackup();
              else
                ;
            /*end of if on backup*/
              break;

            case GNUTYPE_LONGNAME: /* ------------ case ------------- */
            case GNUTYPE_LONGLINK:

              readBuffer.skipFile(
                allActions.currentStat.size,
                allActions                    );

              if (allActions.backup)
                io.Backup.undoLastBackup();
              else
                ;
            /*end of if on backup*/
              break;

            default:

              System.out.println(
                "Unknown file type " +
                tarHeader.currentHeader.typeflag +
                " for " + currentFileNameStringBuffer +
                " extracted as normal file"            );

              againFile( namesInputOutput,
                         tarHeader,
                         readBuffer,
                         sparseVector,
                         allActions                    );
            }
        /*end of switch on typeflag*/

        }
    /*end of while-loop*/

      readBuffer.close();
      Names.namesNotFound();            /* print names not found */

      return resultSuperAction;

    }
/*end of action*/


} /*end of class ActionExtract */

/*****************************************************************************/
/* End of file: ActionExtract.java                                           */
/*****************************************************************************/
