3

I need to add a config file to an existing tar file. I am using apache.commons.compress library. The following code snippet adds the entry correctly but overwrites the existing entries of the tar file.

public static void injectFileToTar () throws IOException, ArchiveException {
        String agentSourceFilePath = "C:\\Work\\tar.gz\\";
        String fileToBeAdded = "activeSensor.cfg";
        String unzippedFileName = "sample.tar";

    File f2 = new File(agentSourceFilePath+unzippedFileName); // Refers to the .tar file
    File f3 = new File(agentSourceFilePath+fileToBeAdded);    // The new entry to be added to the .tar file

    // Injecting an entry in the tar
    OutputStream tarOut = new FileOutputStream(f2);
    TarArchiveOutputStream aos = (TarArchiveOutputStream) new  ArchiveStreamFactory().createArchiveOutputStream("tar", tarOut);
    TarArchiveEntry entry = new TarArchiveEntry(fileToBeAdded);
    entry.setMode(0100000);
    entry.setSize(f3.length());
    aos.putArchiveEntry(entry);
    FileInputStream fis = new FileInputStream(f3);
    IOUtils.copy(fis, aos);
    fis.close();
    aos.closeArchiveEntry();
    aos.finish();
    aos.close();
    tarOut.close(); 

}

On checking the tar, only "activeSensor.cfg" file is found and the initial content of the tar is found missing. Is the "mode" not set correctly ?

Ankit Sharma
  • 61
  • 1
  • 2
  • 6

2 Answers2

3

The problem is that the TarArchiveOutputStream does not automatically read in the existing archive, which is something that you'd need to do. Something along the lines of:

CompressorStreamFactory csf = new CompressorStreamFactory();
ArchiveStreamFactory asf = new ArchiveStreamFactory();

String tarFilename = "test.tgz";
String toAddFilename = "activeSensor.cfg";
File toAddFile = new File(toAddFilename);
File tempFile = File.createTempFile("updateTar", "tgz");
File tarFile = new File(tarFilename);

FileInputStream fis = new FileInputStream(tarFile);
CompressorInputStream cis = csf.createCompressorInputStream(CompressorStreamFactory.GZIP, fis);
ArchiveInputStream ais = asf.createArchiveInputStream(ArchiveStreamFactory.TAR, cis);

FileOutputStream fos = new FileOutputStream(tempFile);
CompressorOutputStream cos = csf.createCompressorOutputStream(CompressorStreamFactory.GZIP, fos);
ArchiveOutputStream aos = asf.createArchiveOutputStream(ArchiveStreamFactory.TAR, cos);

// copy the existing entries    
ArchiveEntry nextEntry;
while ((nextEntry = ais.getNextEntry()) != null) {
    aos.putArchiveEntry(nextEntry);
    IOUtils.copy(ais, aos, (int)nextEntry.getSize());
    aos.closeArchiveEntry();
}

// create the new entry
TarArchiveEntry entry = new TarArchiveEntry(toAddFilename);
entry.setSize(toAddFile.length());
aos.putArchiveEntry(entry);
IOUtils.copy(new FileInputStream(toAddFile), aos, (int)toAddFile.length());
aos.closeArchiveEntry();

aos.finish();

ais.close();
aos.close();

// copies the new file over the old
tarFile.delete();
tempFile.renameTo(tarFile);

A couple of notes:

  • This code does not include any exception handling (please add the appropriate try-catch-finally blocks)
  • This code does not handle files with a size over 2147483647 (Integer.MAX_VALUE) as it only reads file sizes to integer precision bytes (see the cast to int). However, that's not a problem as Apache Compress does not handle files over 2 GB anyway.
beny23
  • 32,077
  • 3
  • 78
  • 83
  • Thanks, it worked. I had to tweak the code slightly in the sense that I was not able to execute the entire code that you shared, directly on .tar.gz file format. So I had to unzip the file first to arrive at .tar format. After injecting the required entry in the tar file as per the suggested manner, I had to re-zip it again. For unzipping and re-zipping, I used java.util.zip.GZIPInputStream and java.util.zip.GZIPOutputStream utilities. – Ankit Sharma Apr 04 '12 at 12:38
1

Try changing

OutputStream tarOut = new FileOutputStream(f2);

to

OutputStream tarOut = new FileOutputStream(f2, true); //Set append to true

biggusjimmus
  • 2,568
  • 3
  • 25
  • 31
  • Thanks. I made the above change. The tar contents are retained but the new entry (activeSensor.cfg) does not get added to the tar. Am I messing something up with the path or the argument passed to the TarArchiveEntry constructor ? – Ankit Sharma Apr 04 '12 at 08:44
  • I was using this approach before I went searching here. Seems that causes the entry to be put beyond the end of the tar archive, so I would get an error to that effect, but my new file wouldn't be there. – froggythefrog May 11 '17 at 02:09