/*
   * Decode a tar file header. The stream is assumed to be at the beginning of the header.
   */
  private TarFile decodeNextFile() throws IOException {
    byte[] buffer = new byte[TAR_FILE_GRANULARITY];

    // A header must be present for an OVA component file to be available..
    this.inputStream.readFully(buffer);

    // If last two empty sections of the TAR file were reached, exit.
    String signature = SIGNATURE_FIELD.getFirstFieldValue(buffer);
    if (!TAR_SIGNATURE.equals(signature)) {
      logger.error("Invalid file signature: '{}'", signature);
      logger.error("Input stream buffer content: [{}]", buffer);
      return null;
    }

    // Get embedded file name.
    TarFile fileInfo = new TarFile();
    fileInfo.name = NAME_FIELD.getFirstFieldValue(buffer);

    // Get embedded file length.
    String octalByteLength = OCTAL_BYTE_LENGTH_FIELD.getFirstFieldValue(buffer);
    long fileByteLength = Long.parseLong(octalByteLength.trim(), 8 /* octal base */);

    // Get embedded file content.
    fileInfo.content = getFileContentStream(fileByteLength);

    return fileInfo;
  }
  /**
   * Attempts to close the passed tar file, and answers a boolean indicating success.
   *
   * @param file The tar file to attempt to close
   * @param shell The shell to display error dialogs in
   * @return Returns true if the operation was successful
   * @since 3.4
   */
  public static boolean closeTarFile(Messages messages, TarFile file, Shell shell) {
    try {
      file.close();
    } catch (IOException e) {
      displayErrorDialog(NLS.bind(messages.ZipImport_couldNotClose(), file.getName()), shell);
      return false;
    }

    return true;
  }
  /**
   * Determine whether the file with the given filename is in .tar.gz or .tar format.
   *
   * @param fileName file to test
   * @return true if the file is in tar format
   */
  public static boolean isTarFile(String fileName, Messages messages) {
    if (fileName.length() == 0) {
      return false;
    }

    TarFile tarFile = null;
    try {
      tarFile = new TarFile(fileName, messages);
    } catch (TarException tarException) {
      return false;
    } catch (IOException ioException) {
      return false;
    } finally {
      if (tarFile != null) {
        try {
          tarFile.close();
        } catch (IOException e) {
          // ignore
        }
      }
    }

    return true;
  }
 @Override
 public void run(IProgressMonitor monitor)
     throws InvocationTargetException, OperationCanceledException {
   monitor.beginTask(
       NLS.bind(
           DataTransferMessages.SmartImportWizardPage_expandingArchive,
           archive.getName(),
           destination.getName()),
       1);
   TarFile tarFile = null;
   ZipFile zipFile = null;
   ILeveledImportStructureProvider importStructureProvider = null;
   try {
     if (ArchiveFileManipulations.isTarFile(archive.getAbsolutePath())) {
       tarFile = new TarFile(archive);
       importStructureProvider = new TarLeveledStructureProvider(tarFile);
     } else if (ArchiveFileManipulations.isZipFile(archive.getAbsolutePath())) {
       zipFile = new ZipFile(archive);
       importStructureProvider = new ZipLeveledStructureProvider(zipFile);
     }
     LinkedList<Object> toProcess = new LinkedList<>();
     toProcess.add(importStructureProvider.getRoot());
     while (!toProcess.isEmpty()) {
       if (monitor.isCanceled()) {
         throw new OperationCanceledException();
       }
       Object current = toProcess.pop();
       String path = importStructureProvider.getFullPath(current);
       File toCreate = null;
       if (path.equals("/")) { // $NON-NLS-1$
         toCreate = destination;
       } else {
         toCreate = new File(destination, path);
       }
       if (importStructureProvider.isFolder(current)) {
         toCreate.mkdirs();
       } else {
         try (InputStream content = importStructureProvider.getContents(current)) {
           // known IImportStructureProviders already log an
           // exception before returning null
           if (content != null) {
             Files.copy(content, toCreate.toPath());
           }
         }
       }
       List<?> children = importStructureProvider.getChildren(current);
       if (children != null) {
         toProcess.addAll(children);
       }
     }
     monitor.worked(1);
     monitor.done();
   } catch (Exception ex) {
     throw new InvocationTargetException(ex);
   } finally {
     if (importStructureProvider != null) {
       importStructureProvider.closeArchive();
     }
     if (tarFile != null)
       try {
         tarFile.close();
       } catch (IOException ex) {
       }
     if (zipFile != null)
       try {
         zipFile.close();
       } catch (IOException ex) {
       }
   }
 }