com.codenvy.commons.lang.TarUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.codenvy.commons.lang.TarUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2012-2015 Codenvy, S.A.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Codenvy, S.A. - initial API and implementation
 *******************************************************************************/
package com.codenvy.commons.lang;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;

/**
 * @author andrew00x
 */
public class TarUtils {
    private static final int BUF_SIZE = 4096;

    /**
     * Add content of directory {@code dir} to tar archive {@code tar}.
     *
     * @param parentPath
     *         parent path of tar archive. Typically if need add only content of {@code dir} this path should be absolute path to {@code
     *         dir} but if need to have in archive some parents this parameter may be used. For example if need add to archive content of
     *         directory '/a/b/c' but need to save directory 'c' in path:
     *         <pre>
     *                         {@code File dir = new File("a/b/c");
     *                      File tar = new File("archive.tar");
     *                      TarUtils.tarDir(dir.getParentFile().getAbsolutePath(), dir, tar, -1, IoUtil.ANY_FILTER);
     *                         }
     *                         </pre>
     *         In this case directory 'c' is added in tar archive.
     * @param dir
     *         dir to add
     * @param tar
     *         tar archive
     * @param modTime
     *         modification time that applied to all entries in archive instead modification time provided by method {@link
     *         File#lastModified()}. This parameter should be {@code -1} if don't need to set any specified time
     * @param filter
     *         optional filter for files to add in archive
     * @throws IOException
     *         if i/o error occurs
     * @throws IllegalArgumentException
     *         if {@code dir} is not directory or if {@code parentPath} is invalid, e.g. is neither parent nor equals to path of {@code
     *         dir}
     */
    public static void tarDir(String parentPath, File dir, File tar, long modTime, FilenameFilter filter)
            throws IOException {
        if (!dir.isDirectory()) {
            throw new IllegalArgumentException("Not a directory.");
        }
        if (!dir.getAbsolutePath().startsWith(parentPath)) {
            throw new IllegalArgumentException("Invalid parent directory path " + parentPath);
        }
        if (filter == null) {
            filter = IoUtil.ANY_FILTER;
        }
        try (TarArchiveOutputStream tarOut = new TarArchiveOutputStream(
                new BufferedOutputStream(new FileOutputStream(tar)))) {
            tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
            addDirectoryRecursively(tarOut, parentPath, dir, modTime, filter);
        }
    }

    public static void tarDir(String parentPath, File dir, File tar, FilenameFilter filter) throws IOException {
        tarDir(parentPath, dir, tar, -1, filter);
    }

    public static void tarFiles(File tar, long modTime, File... files) throws IOException {
        try (TarArchiveOutputStream tarOut = new TarArchiveOutputStream(
                new BufferedOutputStream(new FileOutputStream(tar)))) {
            tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
            for (File f : files) {
                if (f.isDirectory()) {
                    addDirectoryEntry(tarOut, f.getName(), f, modTime);
                    final String parentPath = f.getParentFile().getAbsolutePath();
                    addDirectoryRecursively(tarOut, parentPath, f, modTime, IoUtil.ANY_FILTER);
                } else if (f.isFile()) {
                    addFileEntry(tarOut, f.getName(), f, modTime);
                }
            }
        }
    }

    public static void tarFiles(File tar, File... files) throws IOException {
        tarFiles(tar, -1, files);
    }

    private static void addDirectoryRecursively(TarArchiveOutputStream tarOut, String parentPath, File dir,
            long modTime, FilenameFilter filter) throws IOException {
        final int parentPathLength = parentPath.length() + 1;
        final LinkedList<File> q = new LinkedList<>();
        q.add(dir);
        while (!q.isEmpty()) {
            final File current = q.pop();
            final File[] list = current.listFiles();
            if (list != null) {
                for (File f : list) {
                    if (filter.accept(current, f.getName())) {
                        final String entryName = f.getAbsolutePath().substring(parentPathLength).replace('\\', '/');
                        if (f.isDirectory()) {
                            addDirectoryEntry(tarOut, entryName, f, modTime);
                            q.push(f);
                        } else if (f.isFile()) {
                            addFileEntry(tarOut, entryName, f, modTime);
                        }
                    }
                }
            }
        }
    }

    private static void addDirectoryEntry(TarArchiveOutputStream tarOut, String entryName, File directory,
            long modTime) throws IOException {
        final TarArchiveEntry tarEntry = new TarArchiveEntry(directory, entryName);
        if (modTime >= 0) {
            tarEntry.setModTime(modTime);
        }
        tarOut.putArchiveEntry(tarEntry);
        tarOut.closeArchiveEntry();
    }

    private static void addFileEntry(TarArchiveOutputStream tarOut, String entryName, File file, long modTime)
            throws IOException {
        final TarArchiveEntry tarEntry = new TarArchiveEntry(file, entryName);
        if (modTime >= 0) {
            tarEntry.setModTime(modTime);
        }
        tarOut.putArchiveEntry(tarEntry);
        try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
            final byte[] buf = new byte[BUF_SIZE];
            int r;
            while ((r = in.read(buf)) != -1) {
                tarOut.write(buf, 0, r);
            }
        }
        tarOut.closeArchiveEntry();
    }

    public static void untar(File tar, File targetDir) throws IOException {
        try (InputStream in = new FileInputStream(tar)) {
            untar(in, targetDir);
        }
    }

    public static void untar(InputStream in, File targetDir) throws IOException {
        final TarArchiveInputStream tarIn = new TarArchiveInputStream(in);
        byte[] b = new byte[BUF_SIZE];
        TarArchiveEntry tarEntry;
        while ((tarEntry = tarIn.getNextTarEntry()) != null) {
            final File file = new File(targetDir, tarEntry.getName());
            if (tarEntry.isDirectory()) {
                file.mkdirs();
            } else {
                final File parent = file.getParentFile();
                if (!parent.exists()) {
                    parent.mkdirs();
                }
                try (FileOutputStream fos = new FileOutputStream(file)) {
                    int r;
                    while ((r = tarIn.read(b)) != -1) {
                        fos.write(b, 0, r);
                    }
                }
            }
        }
    }

    public static boolean isTarFile(File file) throws IOException {
        if (file.isDirectory()) {
            return false;
        }
        // http://en.wikipedia.org/wiki/Tar_(computing)#File_header
        final byte[] header = new byte[512];
        try (FileInputStream fIn = new FileInputStream(file)) {
            if (fIn.read(header) != header.length) {
                return false;
            }
        }
        return TarArchiveInputStream.matches(header, header.length);
    }

    private TarUtils() {
    }
}