/*******************************************************************************
* Copyright (c) 2012-2017 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 org.eclipse.che.api.vfs;
import com.google.common.io.ByteStreams;
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 org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.vfs.util.NotClosableInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class TarArchiver extends Archiver {
public TarArchiver(VirtualFile folder) {
super(folder);
}
@Override
public void compress(OutputStream tarOutput) throws IOException, ServerException {
compress(tarOutput, VirtualFileFilter.ACCEPT_ALL);
}
@Override
public void compress(OutputStream tarOutput, VirtualFileFilter filter) throws IOException, ServerException {
try (TarArchiveOutputStream tarOutputStream = new TarArchiveOutputStream(tarOutput)) {
tarOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
folder.accept(new VirtualFileVisitor() {
@Override
public void visit(VirtualFile visitedVirtualFile) throws ServerException {
if (filter.accept(visitedVirtualFile)) {
if (!visitedVirtualFile.equals(folder)) {
addTarEntry(visitedVirtualFile, tarOutputStream);
}
if (visitedVirtualFile.isFolder()) {
for (VirtualFile child : visitedVirtualFile.getChildren()) {
child.accept(this);
}
}
}
}
});
}
}
private String getTarEntryName(VirtualFile virtualFile) {
Path tarPath = virtualFile.getPath().subPath(folder.getPath());
if (virtualFile.isFolder()) {
return tarPath.toString() + '/';
}
return tarPath.toString();
}
private void addTarEntry(VirtualFile virtualFile, TarArchiveOutputStream tarOutputStream) throws ServerException {
try {
TarArchiveEntry tarEntry = new TarArchiveEntry(getTarEntryName(virtualFile));
if (virtualFile.isFolder()) {
tarEntry.setModTime(0);
tarOutputStream.putArchiveEntry(tarEntry);
} else {
tarEntry.setSize(virtualFile.getLength());
tarEntry.setModTime(virtualFile.getLastModificationDate());
tarOutputStream.putArchiveEntry(tarEntry);
try (InputStream content = virtualFile.getContent()) {
ByteStreams.copy(content, tarOutputStream);
}
}
tarOutputStream.closeArchiveEntry();
} catch (ForbiddenException e) {
throw new ServerException(e.getServiceError());
} catch (IOException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
public void extract(InputStream tarInput, boolean overwrite, int stripNumber)
throws IOException, ForbiddenException, ConflictException, ServerException {
try (TarArchiveInputStream tarInputStream = new TarArchiveInputStream(tarInput)) {
InputStream notClosableInputStream = new NotClosableInputStream(tarInputStream);
TarArchiveEntry tarEntry;
while ((tarEntry = tarInputStream.getNextTarEntry()) != null) {
VirtualFile extractFolder = folder;
Path relativePath = Path.of(tarEntry.getName());
if (stripNumber > 0) {
if (relativePath.length() <= stripNumber) {
continue;
}
relativePath = relativePath.subPath(stripNumber);
}
if (tarEntry.isDirectory()) {
if (!extractFolder.hasChild(relativePath)) {
extractFolder.createFolder(relativePath.toString());
}
continue;
}
if (relativePath.length() > 1) {
Path neededParentPath = relativePath.getParent();
VirtualFile neededParent = extractFolder.getChild(neededParentPath);
if (neededParent == null) {
neededParent = extractFolder.createFolder(neededParentPath.toString());
}
extractFolder = neededParent;
}
String fileName = relativePath.getName();
VirtualFile file = extractFolder.getChild(Path.of(fileName));
if (file == null) {
extractFolder.createFile(fileName, notClosableInputStream);
} else {
if (overwrite) {
file.updateContent(notClosableInputStream);
} else {
throw new ConflictException(String.format("File '%s' already exists", file.getPath()));
}
}
}
}
}
}