HADOOP-15170. Add symlink support to FileUtil#unTarUsingJava. Contributed by Ajay Kumar

This commit is contained in:
Jason Lowe 2018-02-02 11:31:39 -06:00
parent 4aef8bd2ef
commit 460d77bd64
2 changed files with 97 additions and 1 deletions

View File

@ -34,6 +34,8 @@ import java.net.URI;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.file.AccessDeniedException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
@ -894,7 +896,7 @@ public class FileUtil {
}
}
private static void unTarUsingJava(File inFile, File untarDir,
static void unTarUsingJava(File inFile, File untarDir,
boolean gzipped) throws IOException {
InputStream inputStream = null;
TarArchiveInputStream tis = null;
@ -956,6 +958,14 @@ public class FileUtil {
return;
}
if (entry.isSymbolicLink()) {
// Create symbolic link relative to tar parent dir
Files.createSymbolicLink(FileSystems.getDefault()
.getPath(outputDir.getPath(), entry.getName()),
FileSystems.getDefault().getPath(entry.getLinkName()));
return;
}
File outputFile = new File(outputDir, entry.getName());
if (!outputFile.getParentFile().exists()) {
if (!outputFile.getParentFile().mkdirs()) {

View File

@ -26,6 +26,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -37,6 +38,8 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -47,6 +50,9 @@ import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.test.GenericTestUtils;
import org.apache.hadoop.util.StringUtils;
@ -1173,4 +1179,84 @@ public class TestFileUtil {
assertEquals(FileUtil.compareFs(fs3,fs4),true);
assertEquals(FileUtil.compareFs(fs1,fs6),false);
}
@Test(timeout = 8000)
public void testCreateSymbolicLinkUsingJava() throws IOException {
setupDirs();
final File simpleTar = new File(del, FILE);
OutputStream os = new FileOutputStream(simpleTar);
TarArchiveOutputStream tos = new TarArchiveOutputStream(os);
File untarFile = null;
try {
// Files to tar
final String tmpDir = "tmp/test";
File tmpDir1 = new File(tmpDir, "dir1/");
File tmpDir2 = new File(tmpDir, "dir2/");
// Delete the directories if they already exist
tmpDir1.mkdirs();
tmpDir2.mkdirs();
java.nio.file.Path symLink = FileSystems
.getDefault().getPath(tmpDir1.getPath() + "/sl");
// Create Symbolic Link
Files.createSymbolicLink(symLink,
FileSystems.getDefault().getPath(tmpDir2.getPath())).toString();
assertTrue(Files.isSymbolicLink(symLink.toAbsolutePath()));
// put entries in tar file
putEntriesInTar(tos, tmpDir1.getParentFile());
tos.close();
untarFile = new File(tmpDir, "2");
// Untar using java
FileUtil.unTarUsingJava(simpleTar, untarFile, false);
// Check symbolic link and other directories are there in untar file
assertTrue(Files.exists(untarFile.toPath()));
assertTrue(Files.exists(FileSystems.getDefault().getPath(untarFile
.getPath(), tmpDir)));
assertTrue(Files.isSymbolicLink(FileSystems.getDefault().getPath(untarFile
.getPath().toString(), symLink.toString())));
} finally {
FileUtils.deleteDirectory(new File("tmp"));
tos.close();
}
}
private void putEntriesInTar(TarArchiveOutputStream tos, File f)
throws IOException {
if (Files.isSymbolicLink(f.toPath())) {
TarArchiveEntry tarEntry = new TarArchiveEntry(f.getPath(),
TarArchiveEntry.LF_SYMLINK);
tarEntry.setLinkName(Files.readSymbolicLink(f.toPath()).toString());
tos.putArchiveEntry(tarEntry);
tos.closeArchiveEntry();
return;
}
if (f.isDirectory()) {
tos.putArchiveEntry(new TarArchiveEntry(f));
tos.closeArchiveEntry();
for (File child : f.listFiles()) {
putEntriesInTar(tos, child);
}
}
if (f.isFile()) {
tos.putArchiveEntry(new TarArchiveEntry(f));
BufferedInputStream origin = new BufferedInputStream(
new FileInputStream(f));
int count;
byte[] data = new byte[2048];
while ((count = origin.read(data)) != -1) {
tos.write(data, 0, count);
}
tos.flush();
tos.closeArchiveEntry();
origin.close();
}
}
}