@@ -861,52 +861,9 @@ public static long secureRandomLong() {
861
861
* @param jarFile the .jar file to unpack
862
862
* @param toDir the destination directory into which to unpack the jar
863
863
*/
864
- public static void unJar (File jarFile , File toDir )
865
- throws IOException {
866
- JarFile jar = new JarFile (jarFile );
867
- try {
868
- Enumeration <JarEntry > entries = jar .entries ();
869
- while (entries .hasMoreElements ()) {
870
- final JarEntry entry = entries .nextElement ();
871
- if (!entry .isDirectory ()) {
872
- InputStream in = jar .getInputStream (entry );
873
- try {
874
- File file = new File (toDir , entry .getName ());
875
- ensureDirectory (file .getParentFile ());
876
- OutputStream out = new FileOutputStream (file );
877
- try {
878
- copyBytes (in , out , 8192 );
879
- } finally {
880
- out .close ();
881
- }
882
- } finally {
883
- in .close ();
884
- }
885
- }
886
- }
887
- } finally {
888
- jar .close ();
889
- }
890
- }
891
-
892
- /**
893
- * Copies from one stream to another.
894
- *
895
- * @param in InputStream to read from
896
- * @param out OutputStream to write to
897
- * @param buffSize the size of the buffer
898
- */
899
- public static void copyBytes (InputStream in , OutputStream out , int buffSize )
900
- throws IOException {
901
- PrintStream ps = out instanceof PrintStream ? (PrintStream )out : null ;
902
- byte buf [] = new byte [buffSize ];
903
- int bytesRead = in .read (buf );
904
- while (bytesRead >= 0 ) {
905
- out .write (buf , 0 , bytesRead );
906
- if ((ps != null ) && ps .checkError ()) {
907
- throw new IOException ("Unable to write to output stream." );
908
- }
909
- bytesRead = in .read (buf );
864
+ public static void unJar (File jarFile , File toDir ) throws IOException {
865
+ try (JarFile jar = new JarFile (jarFile )) {
866
+ extractZipFile (jar , toDir , null );
910
867
}
911
868
}
912
869
@@ -930,20 +887,17 @@ private static void ensureDirectory(File dir) throws IOException {
930
887
*
931
888
* @param inFile The tar file as input.
932
889
* @param untarDir The untar directory where to untar the tar file.
890
+ * @param symlinksDisabled true if symlinks should be disabled, else false.
933
891
* @throws IOException
934
892
*/
935
- public static void unTar (File inFile , File untarDir ) throws IOException {
936
- if (!untarDir .mkdirs ()) {
937
- if (!untarDir .isDirectory ()) {
938
- throw new IOException ("Mkdirs failed to create " + untarDir );
939
- }
940
- }
893
+ public static void unTar (File inFile , File untarDir , boolean symlinksDisabled ) throws IOException {
894
+ ensureDirectory (untarDir );
941
895
942
896
boolean gzipped = inFile .toString ().endsWith ("gz" );
943
- if (isOnWindows ()) {
897
+ if (Utils . isOnWindows () || symlinksDisabled ) {
944
898
// Tar is not native to Windows. Use simple Java based implementation for
945
899
// tests and simple tar archives
946
- unTarUsingJava (inFile , untarDir , gzipped );
900
+ unTarUsingJava (inFile , untarDir , gzipped , symlinksDisabled );
947
901
} else {
948
902
// spawn tar utility to untar archive for full fledged unix behavior such
949
903
// as resolving symlinks in tar archives
@@ -980,7 +934,9 @@ private static void unTarUsingTar(File inFile, File untarDir,
980
934
}
981
935
982
936
private static void unTarUsingJava (File inFile , File untarDir ,
983
- boolean gzipped ) throws IOException {
937
+ boolean gzipped , boolean symlinksDisabled ) throws IOException {
938
+ final String base = untarDir .getCanonicalPath ();
939
+ LOG .trace ("java untar {} to {}" , inFile , base );
984
940
InputStream inputStream = null ;
985
941
try {
986
942
if (gzipped ) {
@@ -991,7 +947,7 @@ private static void unTarUsingJava(File inFile, File untarDir,
991
947
}
992
948
try (TarArchiveInputStream tis = new TarArchiveInputStream (inputStream )) {
993
949
for (TarArchiveEntry entry = tis .getNextTarEntry (); entry != null ; ) {
994
- unpackEntries (tis , entry , untarDir );
950
+ unpackEntries (tis , entry , untarDir , base , symlinksDisabled );
995
951
entry = tis .getNextTarEntry ();
996
952
}
997
953
}
@@ -1003,35 +959,82 @@ private static void unTarUsingJava(File inFile, File untarDir,
1003
959
}
1004
960
1005
961
private static void unpackEntries (TarArchiveInputStream tis ,
1006
- TarArchiveEntry entry , File outputDir ) throws IOException {
962
+ TarArchiveEntry entry , File outputDir , final String base ,
963
+ boolean symlinksDisabled ) throws IOException {
964
+ File target = new File (outputDir , entry .getName ());
965
+ String found = target .getCanonicalPath ();
966
+ if (!found .startsWith (base )) {
967
+ LOG .error ("Invalid location {} is outside of {}" , found , base );
968
+ return ;
969
+ }
1007
970
if (entry .isDirectory ()) {
1008
- File subDir = new File (outputDir , entry .getName ());
1009
- if (!subDir .mkdirs () && !subDir .isDirectory ()) {
1010
- throw new IOException ("Mkdirs failed to create tar internal dir "
1011
- + outputDir );
1012
- }
971
+ LOG .trace ("Extracting dir {}" , target );
972
+ ensureDirectory (target );
1013
973
for (TarArchiveEntry e : entry .getDirectoryEntries ()) {
1014
- unpackEntries (tis , e , subDir );
974
+ unpackEntries (tis , e , target , base , symlinksDisabled );
1015
975
}
1016
- return ;
976
+ } else if (entry .isSymbolicLink ()) {
977
+ if (symlinksDisabled ) {
978
+ LOG .info ("Symlinks disabled skipping {}" , target );
979
+ } else {
980
+ Path src = target .toPath ();
981
+ Path dest = Paths .get (entry .getLinkName ());
982
+ LOG .trace ("Extracting sym link {} to {}" , target , dest );
983
+ // Create symbolic link relative to tar parent dir
984
+ Files .createSymbolicLink (src , dest );
985
+ }
986
+ } else if (entry .isFile ()) {
987
+ LOG .trace ("Extracting file {}" , target );
988
+ ensureDirectory (target .getParentFile ());
989
+ try (BufferedOutputStream outputStream = new BufferedOutputStream (new FileOutputStream (target ))) {
990
+ IOUtils .copy (tis , outputStream );
991
+ }
992
+ } else {
993
+ LOG .error ("{} is not a currently supported tar entry type." , entry );
1017
994
}
1018
- File outputFile = new File (outputDir , entry .getName ());
1019
- if (!outputFile .getParentFile ().exists ()) {
1020
- if (!outputFile .getParentFile ().mkdirs ()) {
1021
- throw new IOException ("Mkdirs failed to create tar internal dir "
1022
- + outputDir );
995
+
996
+ Path p = target .toPath ();
997
+ if (Files .exists (p )) {
998
+ try {
999
+ //We created it so lets chmod it properly
1000
+ int mode = entry .getMode ();
1001
+ Files .setPosixFilePermissions (p , parsePerms (mode ));
1002
+ } catch (UnsupportedOperationException e ) {
1003
+ //Ignored the file system we are on does not support this, so don't do it.
1023
1004
}
1024
1005
}
1025
- int count ;
1026
- byte data [] = new byte [2048 ];
1027
- BufferedOutputStream outputStream = new BufferedOutputStream (
1028
- new FileOutputStream (outputFile ));
1006
+ }
1029
1007
1030
- while ((count = tis .read (data )) != -1 ) {
1031
- outputStream .write (data , 0 , count );
1008
+ private static Set <PosixFilePermission > parsePerms (int mode ) {
1009
+ Set <PosixFilePermission > ret = new HashSet <>();
1010
+ if ((mode & 0001 ) > 0 ) {
1011
+ ret .add (PosixFilePermission .OTHERS_EXECUTE );
1012
+ }
1013
+ if ((mode & 0002 ) > 0 ) {
1014
+ ret .add (PosixFilePermission .OTHERS_WRITE );
1015
+ }
1016
+ if ((mode & 0004 ) > 0 ) {
1017
+ ret .add (PosixFilePermission .OTHERS_READ );
1018
+ }
1019
+ if ((mode & 0010 ) > 0 ) {
1020
+ ret .add (PosixFilePermission .GROUP_EXECUTE );
1032
1021
}
1033
- outputStream .flush ();
1034
- outputStream .close ();
1022
+ if ((mode & 0020 ) > 0 ) {
1023
+ ret .add (PosixFilePermission .GROUP_WRITE );
1024
+ }
1025
+ if ((mode & 0040 ) > 0 ) {
1026
+ ret .add (PosixFilePermission .GROUP_READ );
1027
+ }
1028
+ if ((mode & 0100 ) > 0 ) {
1029
+ ret .add (PosixFilePermission .OWNER_EXECUTE );
1030
+ }
1031
+ if ((mode & 0200 ) > 0 ) {
1032
+ ret .add (PosixFilePermission .OWNER_WRITE );
1033
+ }
1034
+ if ((mode & 0400 ) > 0 ) {
1035
+ ret .add (PosixFilePermission .OWNER_READ );
1036
+ }
1037
+ return ret ;
1035
1038
}
1036
1039
1037
1040
public static boolean isOnWindows () {
@@ -1045,16 +1048,21 @@ public static boolean isAbsolutePath(String path) {
1045
1048
return Paths .get (path ).isAbsolute ();
1046
1049
}
1047
1050
1048
- public static void unpack (File localrsrc , File dst ) throws IOException {
1051
+ public static void unpack (File localrsrc , File dst , boolean symLinksDisabled ) throws IOException {
1049
1052
String lowerDst = localrsrc .getName ().toLowerCase ();
1050
- if (lowerDst .endsWith (".jar" )) {
1053
+ if (lowerDst .endsWith (".jar" ) ||
1054
+ lowerDst .endsWith ("_jar" )) {
1051
1055
unJar (localrsrc , dst );
1052
- } else if (lowerDst .endsWith (".zip" )) {
1056
+ } else if (lowerDst .endsWith (".zip" ) ||
1057
+ lowerDst .endsWith ("_zip" )) {
1053
1058
unZip (localrsrc , dst );
1054
1059
} else if (lowerDst .endsWith (".tar.gz" ) ||
1055
- lowerDst .endsWith (".tgz" ) ||
1056
- lowerDst .endsWith (".tar" )) {
1057
- unTar (localrsrc , dst );
1060
+ lowerDst .endsWith ("_tar_gz" ) ||
1061
+ lowerDst .endsWith (".tgz" ) ||
1062
+ lowerDst .endsWith ("_tgz" ) ||
1063
+ lowerDst .endsWith (".tar" ) ||
1064
+ lowerDst .endsWith ("_tar" )) {
1065
+ unTar (localrsrc , dst , symLinksDisabled );
1058
1066
} else {
1059
1067
LOG .warn ("Cannot unpack " + localrsrc );
1060
1068
if (!localrsrc .renameTo (dst )) {
@@ -1067,6 +1075,35 @@ public static void unpack(File localrsrc, File dst) throws IOException {
1067
1075
}
1068
1076
}
1069
1077
1078
+ private static void extractZipFile (ZipFile zipFile , File toDir , String prefix ) throws IOException {
1079
+ ensureDirectory (toDir );
1080
+ final String base = toDir .getCanonicalPath ();
1081
+
1082
+ Enumeration <? extends ZipEntry > entries = zipFile .entries ();
1083
+ while (entries .hasMoreElements ()) {
1084
+ ZipEntry entry = entries .nextElement ();
1085
+ if (!entry .isDirectory ()) {
1086
+ if (prefix != null && !entry .getName ().startsWith (prefix )) {
1087
+ //No need to extract it, it is not what we are looking for.
1088
+ continue ;
1089
+ }
1090
+ File file = new File (toDir , entry .getName ());
1091
+ String found = file .getCanonicalPath ();
1092
+ if (!found .startsWith (base )) {
1093
+ LOG .error ("Invalid location {} is outside of {}" , found , base );
1094
+ continue ;
1095
+ }
1096
+
1097
+ try (InputStream in = zipFile .getInputStream (entry )) {
1098
+ ensureDirectory (file .getParentFile ());
1099
+ try (OutputStream out = new FileOutputStream (file )) {
1100
+ IOUtils .copy (in , out );
1101
+ }
1102
+ }
1103
+ }
1104
+ }
1105
+ }
1106
+
1070
1107
public static boolean canUserReadBlob (ReadableBlobMeta meta , String user ) {
1071
1108
SettableBlobMeta settable = meta .get_settable ();
1072
1109
for (AccessControl acl : settable .get_acl ()) {
@@ -1397,45 +1434,12 @@ public static void validateTopologyBlobStoreMap(Map<String, ?> stormConf, Set<St
1397
1434
* Given a File input it will unzip the file in a the unzip directory
1398
1435
* passed as the second parameter
1399
1436
* @param inFile The zip file as input
1400
- * @param unzipDir The unzip directory where to unzip the zip file.
1437
+ * @param toDir The unzip directory where to unzip the zip file.
1401
1438
* @throws IOException
1402
1439
*/
1403
- public static void unZip (File inFile , File unzipDir ) throws IOException {
1404
- Enumeration <? extends ZipEntry > entries ;
1405
- ZipFile zipFile = new ZipFile (inFile );
1406
-
1407
- try {
1408
- entries = zipFile .entries ();
1409
- while (entries .hasMoreElements ()) {
1410
- ZipEntry entry = entries .nextElement ();
1411
- if (!entry .isDirectory ()) {
1412
- InputStream in = zipFile .getInputStream (entry );
1413
- try {
1414
- File file = new File (unzipDir , entry .getName ());
1415
- if (!file .getParentFile ().mkdirs ()) {
1416
- if (!file .getParentFile ().isDirectory ()) {
1417
- throw new IOException ("Mkdirs failed to create " +
1418
- file .getParentFile ().toString ());
1419
- }
1420
- }
1421
- OutputStream out = new FileOutputStream (file );
1422
- try {
1423
- byte [] buffer = new byte [8192 ];
1424
- int i ;
1425
- while ((i = in .read (buffer )) != -1 ) {
1426
- out .write (buffer , 0 , i );
1427
- }
1428
- } finally {
1429
- out .close ();
1430
- }
1431
- } finally {
1432
- in .close ();
1433
- }
1434
- }
1435
- }
1436
- } finally {
1437
- zipFile .close ();
1438
- }
1440
+ public static void unZip (File inFile , File toDir ) throws IOException {
1441
+ try (ZipFile zipFile = new ZipFile (inFile )) {
1442
+ extractZipFile (zipFile , toDir , null ); }
1439
1443
}
1440
1444
1441
1445
/**
@@ -1905,21 +1909,10 @@ public static int execCommand(String... command) throws ExecuteException, IOExce
1905
1909
public static void extractDirFromJar (String jarpath , String dir , File destdir ) {
1906
1910
_instance .extractDirFromJarImpl (jarpath , dir , destdir );
1907
1911
}
1908
-
1912
+
1909
1913
public void extractDirFromJarImpl (String jarpath , String dir , File destdir ) {
1910
1914
try (JarFile jarFile = new JarFile (jarpath )) {
1911
- Enumeration <JarEntry > jarEnums = jarFile .entries ();
1912
- while (jarEnums .hasMoreElements ()) {
1913
- JarEntry entry = jarEnums .nextElement ();
1914
- if (!entry .isDirectory () && entry .getName ().startsWith (dir )) {
1915
- File aFile = new File (destdir , entry .getName ());
1916
- aFile .getParentFile ().mkdirs ();
1917
- try (FileOutputStream out = new FileOutputStream (aFile );
1918
- InputStream in = jarFile .getInputStream (entry )) {
1919
- IOUtils .copy (in , out );
1920
- }
1921
- }
1922
- }
1915
+ extractZipFile (jarFile , destdir , dir );
1923
1916
} catch (IOException e ) {
1924
1917
LOG .info ("Could not extract {} from {}" , dir , jarpath );
1925
1918
}
0 commit comments