@@ -861,52 +861,9 @@ public static long secureRandomLong() {
861861 * @param jarFile the .jar file to unpack
862862 * @param toDir the destination directory into which to unpack the jar
863863 */
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 );
910867 }
911868 }
912869
@@ -930,20 +887,17 @@ private static void ensureDirectory(File dir) throws IOException {
930887 *
931888 * @param inFile The tar file as input.
932889 * @param untarDir The untar directory where to untar the tar file.
890+ * @param symlinksDisabled true if symlinks should be disabled, else false.
933891 * @throws IOException
934892 */
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 );
941895
942896 boolean gzipped = inFile .toString ().endsWith ("gz" );
943- if (isOnWindows ()) {
897+ if (Utils . isOnWindows () || symlinksDisabled ) {
944898 // Tar is not native to Windows. Use simple Java based implementation for
945899 // tests and simple tar archives
946- unTarUsingJava (inFile , untarDir , gzipped );
900+ unTarUsingJava (inFile , untarDir , gzipped , symlinksDisabled );
947901 } else {
948902 // spawn tar utility to untar archive for full fledged unix behavior such
949903 // as resolving symlinks in tar archives
@@ -980,7 +934,9 @@ private static void unTarUsingTar(File inFile, File untarDir,
980934 }
981935
982936 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 );
984940 InputStream inputStream = null ;
985941 try {
986942 if (gzipped ) {
@@ -991,7 +947,7 @@ private static void unTarUsingJava(File inFile, File untarDir,
991947 }
992948 try (TarArchiveInputStream tis = new TarArchiveInputStream (inputStream )) {
993949 for (TarArchiveEntry entry = tis .getNextTarEntry (); entry != null ; ) {
994- unpackEntries (tis , entry , untarDir );
950+ unpackEntries (tis , entry , untarDir , base , symlinksDisabled );
995951 entry = tis .getNextTarEntry ();
996952 }
997953 }
@@ -1003,35 +959,82 @@ private static void unTarUsingJava(File inFile, File untarDir,
1003959 }
1004960
1005961 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+ }
1007970 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 );
1013973 for (TarArchiveEntry e : entry .getDirectoryEntries ()) {
1014- unpackEntries (tis , e , subDir );
974+ unpackEntries (tis , e , target , base , symlinksDisabled );
1015975 }
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 );
1017994 }
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.
10231004 }
10241005 }
1025- int count ;
1026- byte data [] = new byte [2048 ];
1027- BufferedOutputStream outputStream = new BufferedOutputStream (
1028- new FileOutputStream (outputFile ));
1006+ }
10291007
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 );
1021+ }
1022+ if ((mode & 0020 ) > 0 ) {
1023+ ret .add (PosixFilePermission .GROUP_WRITE );
10321024 }
1033- outputStream .flush ();
1034- outputStream .close ();
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 ;
10351038 }
10361039
10371040 public static boolean isOnWindows () {
@@ -1045,16 +1048,21 @@ public static boolean isAbsolutePath(String path) {
10451048 return Paths .get (path ).isAbsolute ();
10461049 }
10471050
1048- public static void unpack (File localrsrc , File dst ) throws IOException {
1051+ public static void unpack (File localrsrc , File dst , boolean symLinksDisabled ) throws IOException {
10491052 String lowerDst = localrsrc .getName ().toLowerCase ();
1050- if (lowerDst .endsWith (".jar" )) {
1053+ if (lowerDst .endsWith (".jar" ) ||
1054+ lowerDst .endsWith ("_jar" )) {
10511055 unJar (localrsrc , dst );
1052- } else if (lowerDst .endsWith (".zip" )) {
1056+ } else if (lowerDst .endsWith (".zip" ) ||
1057+ lowerDst .endsWith ("_zip" )) {
10531058 unZip (localrsrc , dst );
10541059 } 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 );
10581066 } else {
10591067 LOG .warn ("Cannot unpack " + localrsrc );
10601068 if (!localrsrc .renameTo (dst )) {
@@ -1067,6 +1075,35 @@ public static void unpack(File localrsrc, File dst) throws IOException {
10671075 }
10681076 }
10691077
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+
10701107 public static boolean canUserReadBlob (ReadableBlobMeta meta , String user ) {
10711108 SettableBlobMeta settable = meta .get_settable ();
10721109 for (AccessControl acl : settable .get_acl ()) {
@@ -1398,45 +1435,12 @@ public static void validateTopologyBlobStoreMap(Map<String, ?> stormConf, Set<St
13981435 * Given a File input it will unzip the file in a the unzip directory
13991436 * passed as the second parameter
14001437 * @param inFile The zip file as input
1401- * @param unzipDir The unzip directory where to unzip the zip file.
1438+ * @param toDir The unzip directory where to unzip the zip file.
14021439 * @throws IOException
14031440 */
1404- public static void unZip (File inFile , File unzipDir ) throws IOException {
1405- Enumeration <? extends ZipEntry > entries ;
1406- ZipFile zipFile = new ZipFile (inFile );
1407-
1408- try {
1409- entries = zipFile .entries ();
1410- while (entries .hasMoreElements ()) {
1411- ZipEntry entry = entries .nextElement ();
1412- if (!entry .isDirectory ()) {
1413- InputStream in = zipFile .getInputStream (entry );
1414- try {
1415- File file = new File (unzipDir , entry .getName ());
1416- if (!file .getParentFile ().mkdirs ()) {
1417- if (!file .getParentFile ().isDirectory ()) {
1418- throw new IOException ("Mkdirs failed to create " +
1419- file .getParentFile ().toString ());
1420- }
1421- }
1422- OutputStream out = new FileOutputStream (file );
1423- try {
1424- byte [] buffer = new byte [8192 ];
1425- int i ;
1426- while ((i = in .read (buffer )) != -1 ) {
1427- out .write (buffer , 0 , i );
1428- }
1429- } finally {
1430- out .close ();
1431- }
1432- } finally {
1433- in .close ();
1434- }
1435- }
1436- }
1437- } finally {
1438- zipFile .close ();
1439- }
1441+ public static void unZip (File inFile , File toDir ) throws IOException {
1442+ try (ZipFile zipFile = new ZipFile (inFile )) {
1443+ extractZipFile (zipFile , toDir , null ); }
14401444 }
14411445
14421446 /**
@@ -1910,21 +1914,10 @@ public static int execCommand(String... command) throws ExecuteException, IOExce
19101914 public static void extractDirFromJar (String jarpath , String dir , File destdir ) {
19111915 _instance .extractDirFromJarImpl (jarpath , dir , destdir );
19121916 }
1913-
1917+
19141918 public void extractDirFromJarImpl (String jarpath , String dir , File destdir ) {
19151919 try (JarFile jarFile = new JarFile (jarpath )) {
1916- Enumeration <JarEntry > jarEnums = jarFile .entries ();
1917- while (jarEnums .hasMoreElements ()) {
1918- JarEntry entry = jarEnums .nextElement ();
1919- if (!entry .isDirectory () && entry .getName ().startsWith (dir )) {
1920- File aFile = new File (destdir , entry .getName ());
1921- aFile .getParentFile ().mkdirs ();
1922- try (FileOutputStream out = new FileOutputStream (aFile );
1923- InputStream in = jarFile .getInputStream (entry )) {
1924- IOUtils .copy (in , out );
1925- }
1926- }
1927- }
1920+ extractZipFile (jarFile , destdir , dir );
19281921 } catch (IOException e ) {
19291922 LOG .info ("Could not extract {} from {}" , dir , jarpath );
19301923 }
0 commit comments