@@ -859,52 +859,9 @@ public static long secureRandomLong() {
859859 * @param jarFile the .jar file to unpack
860860 * @param toDir the destination directory into which to unpack the jar
861861 */
862- public static void unJar (File jarFile , File toDir )
863- throws IOException {
864- JarFile jar = new JarFile (jarFile );
865- try {
866- Enumeration <JarEntry > entries = jar .entries ();
867- while (entries .hasMoreElements ()) {
868- final JarEntry entry = entries .nextElement ();
869- if (!entry .isDirectory ()) {
870- InputStream in = jar .getInputStream (entry );
871- try {
872- File file = new File (toDir , entry .getName ());
873- ensureDirectory (file .getParentFile ());
874- OutputStream out = new FileOutputStream (file );
875- try {
876- copyBytes (in , out , 8192 );
877- } finally {
878- out .close ();
879- }
880- } finally {
881- in .close ();
882- }
883- }
884- }
885- } finally {
886- jar .close ();
887- }
888- }
889-
890- /**
891- * Copies from one stream to another.
892- *
893- * @param in InputStream to read from
894- * @param out OutputStream to write to
895- * @param buffSize the size of the buffer
896- */
897- public static void copyBytes (InputStream in , OutputStream out , int buffSize )
898- throws IOException {
899- PrintStream ps = out instanceof PrintStream ? (PrintStream )out : null ;
900- byte buf [] = new byte [buffSize ];
901- int bytesRead = in .read (buf );
902- while (bytesRead >= 0 ) {
903- out .write (buf , 0 , bytesRead );
904- if ((ps != null ) && ps .checkError ()) {
905- throw new IOException ("Unable to write to output stream." );
906- }
907- bytesRead = in .read (buf );
862+ public static void unJar (File jarFile , File toDir ) throws IOException {
863+ try (JarFile jar = new JarFile (jarFile )) {
864+ extractZipFile (jar , toDir , null );
908865 }
909866 }
910867
@@ -928,20 +885,17 @@ private static void ensureDirectory(File dir) throws IOException {
928885 *
929886 * @param inFile The tar file as input.
930887 * @param untarDir The untar directory where to untar the tar file.
888+ * @param symlinksDisabled true if symlinks should be disabled, else false.
931889 * @throws IOException
932890 */
933- public static void unTar (File inFile , File untarDir ) throws IOException {
934- if (!untarDir .mkdirs ()) {
935- if (!untarDir .isDirectory ()) {
936- throw new IOException ("Mkdirs failed to create " + untarDir );
937- }
938- }
891+ public static void unTar (File inFile , File untarDir , boolean symlinksDisabled ) throws IOException {
892+ ensureDirectory (untarDir );
939893
940894 boolean gzipped = inFile .toString ().endsWith ("gz" );
941- if (isOnWindows ()) {
895+ if (Utils . isOnWindows () || symlinksDisabled ) {
942896 // Tar is not native to Windows. Use simple Java based implementation for
943897 // tests and simple tar archives
944- unTarUsingJava (inFile , untarDir , gzipped );
898+ unTarUsingJava (inFile , untarDir , gzipped , symlinksDisabled );
945899 } else {
946900 // spawn tar utility to untar archive for full fledged unix behavior such
947901 // as resolving symlinks in tar archives
@@ -978,7 +932,9 @@ private static void unTarUsingTar(File inFile, File untarDir,
978932 }
979933
980934 private static void unTarUsingJava (File inFile , File untarDir ,
981- boolean gzipped ) throws IOException {
935+ boolean gzipped , boolean symlinksDisabled ) throws IOException {
936+ final String base = untarDir .getCanonicalPath ();
937+ LOG .trace ("java untar {} to {}" , inFile , base );
982938 InputStream inputStream = null ;
983939 try {
984940 if (gzipped ) {
@@ -989,7 +945,7 @@ private static void unTarUsingJava(File inFile, File untarDir,
989945 }
990946 try (TarArchiveInputStream tis = new TarArchiveInputStream (inputStream )) {
991947 for (TarArchiveEntry entry = tis .getNextTarEntry (); entry != null ; ) {
992- unpackEntries (tis , entry , untarDir );
948+ unpackEntries (tis , entry , untarDir , base , symlinksDisabled );
993949 entry = tis .getNextTarEntry ();
994950 }
995951 }
@@ -1001,35 +957,82 @@ private static void unTarUsingJava(File inFile, File untarDir,
1001957 }
1002958
1003959 private static void unpackEntries (TarArchiveInputStream tis ,
1004- TarArchiveEntry entry , File outputDir ) throws IOException {
960+ TarArchiveEntry entry , File outputDir , final String base ,
961+ boolean symlinksDisabled ) throws IOException {
962+ File target = new File (outputDir , entry .getName ());
963+ String found = target .getCanonicalPath ();
964+ if (!found .startsWith (base )) {
965+ LOG .error ("Invalid location {} is outside of {}" , found , base );
966+ return ;
967+ }
1005968 if (entry .isDirectory ()) {
1006- File subDir = new File (outputDir , entry .getName ());
1007- if (!subDir .mkdirs () && !subDir .isDirectory ()) {
1008- throw new IOException ("Mkdirs failed to create tar internal dir "
1009- + outputDir );
1010- }
969+ LOG .trace ("Extracting dir {}" , target );
970+ ensureDirectory (target );
1011971 for (TarArchiveEntry e : entry .getDirectoryEntries ()) {
1012- unpackEntries (tis , e , subDir );
972+ unpackEntries (tis , e , target , base , symlinksDisabled );
1013973 }
1014- return ;
974+ } else if (entry .isSymbolicLink ()) {
975+ if (symlinksDisabled ) {
976+ LOG .info ("Symlinks disabled skipping {}" , target );
977+ } else {
978+ Path src = target .toPath ();
979+ Path dest = Paths .get (entry .getLinkName ());
980+ LOG .trace ("Extracting sym link {} to {}" , target , dest );
981+ // Create symbolic link relative to tar parent dir
982+ Files .createSymbolicLink (src , dest );
983+ }
984+ } else if (entry .isFile ()) {
985+ LOG .trace ("Extracting file {}" , target );
986+ ensureDirectory (target .getParentFile ());
987+ try (BufferedOutputStream outputStream = new BufferedOutputStream (new FileOutputStream (target ))) {
988+ IOUtils .copy (tis , outputStream );
989+ }
990+ } else {
991+ LOG .error ("{} is not a currently supported tar entry type." , entry );
1015992 }
1016- File outputFile = new File (outputDir , entry .getName ());
1017- if (!outputFile .getParentFile ().exists ()) {
1018- if (!outputFile .getParentFile ().mkdirs ()) {
1019- throw new IOException ("Mkdirs failed to create tar internal dir "
1020- + outputDir );
993+
994+ Path p = target .toPath ();
995+ if (Files .exists (p )) {
996+ try {
997+ //We created it so lets chmod it properly
998+ int mode = entry .getMode ();
999+ Files .setPosixFilePermissions (p , parsePerms (mode ));
1000+ } catch (UnsupportedOperationException e ) {
1001+ //Ignored the file system we are on does not support this, so don't do it.
10211002 }
10221003 }
1023- int count ;
1024- byte data [] = new byte [2048 ];
1025- BufferedOutputStream outputStream = new BufferedOutputStream (
1026- new FileOutputStream (outputFile ));
1004+ }
10271005
1028- while ((count = tis .read (data )) != -1 ) {
1029- outputStream .write (data , 0 , count );
1006+ private static Set <PosixFilePermission > parsePerms (int mode ) {
1007+ Set <PosixFilePermission > ret = new HashSet <>();
1008+ if ((mode & 0001 ) > 0 ) {
1009+ ret .add (PosixFilePermission .OTHERS_EXECUTE );
1010+ }
1011+ if ((mode & 0002 ) > 0 ) {
1012+ ret .add (PosixFilePermission .OTHERS_WRITE );
1013+ }
1014+ if ((mode & 0004 ) > 0 ) {
1015+ ret .add (PosixFilePermission .OTHERS_READ );
1016+ }
1017+ if ((mode & 0010 ) > 0 ) {
1018+ ret .add (PosixFilePermission .GROUP_EXECUTE );
10301019 }
1031- outputStream .flush ();
1032- outputStream .close ();
1020+ if ((mode & 0020 ) > 0 ) {
1021+ ret .add (PosixFilePermission .GROUP_WRITE );
1022+ }
1023+ if ((mode & 0040 ) > 0 ) {
1024+ ret .add (PosixFilePermission .GROUP_READ );
1025+ }
1026+ if ((mode & 0100 ) > 0 ) {
1027+ ret .add (PosixFilePermission .OWNER_EXECUTE );
1028+ }
1029+ if ((mode & 0200 ) > 0 ) {
1030+ ret .add (PosixFilePermission .OWNER_WRITE );
1031+ }
1032+ if ((mode & 0400 ) > 0 ) {
1033+ ret .add (PosixFilePermission .OWNER_READ );
1034+ }
1035+ return ret ;
10331036 }
10341037
10351038 public static boolean isOnWindows () {
@@ -1043,16 +1046,21 @@ public static boolean isAbsolutePath(String path) {
10431046 return Paths .get (path ).isAbsolute ();
10441047 }
10451048
1046- public static void unpack (File localrsrc , File dst ) throws IOException {
1049+ public static void unpack (File localrsrc , File dst , boolean symLinksDisabled ) throws IOException {
10471050 String lowerDst = localrsrc .getName ().toLowerCase ();
1048- if (lowerDst .endsWith (".jar" )) {
1051+ if (lowerDst .endsWith (".jar" ) ||
1052+ lowerDst .endsWith ("_jar" )) {
10491053 unJar (localrsrc , dst );
1050- } else if (lowerDst .endsWith (".zip" )) {
1054+ } else if (lowerDst .endsWith (".zip" ) ||
1055+ lowerDst .endsWith ("_zip" )) {
10511056 unZip (localrsrc , dst );
10521057 } else if (lowerDst .endsWith (".tar.gz" ) ||
1053- lowerDst .endsWith (".tgz" ) ||
1054- lowerDst .endsWith (".tar" )) {
1055- unTar (localrsrc , dst );
1058+ lowerDst .endsWith ("_tar_gz" ) ||
1059+ lowerDst .endsWith (".tgz" ) ||
1060+ lowerDst .endsWith ("_tgz" ) ||
1061+ lowerDst .endsWith (".tar" ) ||
1062+ lowerDst .endsWith ("_tar" )) {
1063+ unTar (localrsrc , dst , symLinksDisabled );
10561064 } else {
10571065 LOG .warn ("Cannot unpack " + localrsrc );
10581066 if (!localrsrc .renameTo (dst )) {
@@ -1065,6 +1073,35 @@ public static void unpack(File localrsrc, File dst) throws IOException {
10651073 }
10661074 }
10671075
1076+ private static void extractZipFile (ZipFile zipFile , File toDir , String prefix ) throws IOException {
1077+ ensureDirectory (toDir );
1078+ final String base = toDir .getCanonicalPath ();
1079+
1080+ Enumeration <? extends ZipEntry > entries = zipFile .entries ();
1081+ while (entries .hasMoreElements ()) {
1082+ ZipEntry entry = entries .nextElement ();
1083+ if (!entry .isDirectory ()) {
1084+ if (prefix != null && !entry .getName ().startsWith (prefix )) {
1085+ //No need to extract it, it is not what we are looking for.
1086+ continue ;
1087+ }
1088+ File file = new File (toDir , entry .getName ());
1089+ String found = file .getCanonicalPath ();
1090+ if (!found .startsWith (base )) {
1091+ LOG .error ("Invalid location {} is outside of {}" , found , base );
1092+ continue ;
1093+ }
1094+
1095+ try (InputStream in = zipFile .getInputStream (entry )) {
1096+ ensureDirectory (file .getParentFile ());
1097+ try (OutputStream out = new FileOutputStream (file )) {
1098+ IOUtils .copy (in , out );
1099+ }
1100+ }
1101+ }
1102+ }
1103+ }
1104+
10681105 public static boolean canUserReadBlob (ReadableBlobMeta meta , String user ) {
10691106 SettableBlobMeta settable = meta .get_settable ();
10701107 for (AccessControl acl : settable .get_acl ()) {
@@ -1374,45 +1411,12 @@ public static void handleUncaughtException(Throwable t) {
13741411 * Given a File input it will unzip the file in a the unzip directory
13751412 * passed as the second parameter
13761413 * @param inFile The zip file as input
1377- * @param unzipDir The unzip directory where to unzip the zip file.
1414+ * @param toDir The unzip directory where to unzip the zip file.
13781415 * @throws IOException
13791416 */
1380- public static void unZip (File inFile , File unzipDir ) throws IOException {
1381- Enumeration <? extends ZipEntry > entries ;
1382- ZipFile zipFile = new ZipFile (inFile );
1383-
1384- try {
1385- entries = zipFile .entries ();
1386- while (entries .hasMoreElements ()) {
1387- ZipEntry entry = entries .nextElement ();
1388- if (!entry .isDirectory ()) {
1389- InputStream in = zipFile .getInputStream (entry );
1390- try {
1391- File file = new File (unzipDir , entry .getName ());
1392- if (!file .getParentFile ().mkdirs ()) {
1393- if (!file .getParentFile ().isDirectory ()) {
1394- throw new IOException ("Mkdirs failed to create " +
1395- file .getParentFile ().toString ());
1396- }
1397- }
1398- OutputStream out = new FileOutputStream (file );
1399- try {
1400- byte [] buffer = new byte [8192 ];
1401- int i ;
1402- while ((i = in .read (buffer )) != -1 ) {
1403- out .write (buffer , 0 , i );
1404- }
1405- } finally {
1406- out .close ();
1407- }
1408- } finally {
1409- in .close ();
1410- }
1411- }
1412- }
1413- } finally {
1414- zipFile .close ();
1415- }
1417+ public static void unZip (File inFile , File toDir ) throws IOException {
1418+ try (ZipFile zipFile = new ZipFile (inFile )) {
1419+ extractZipFile (zipFile , toDir , null ); }
14161420 }
14171421
14181422 /**
@@ -1882,21 +1886,10 @@ public static int execCommand(String... command) throws ExecuteException, IOExce
18821886 public static void extractDirFromJar (String jarpath , String dir , File destdir ) {
18831887 _instance .extractDirFromJarImpl (jarpath , dir , destdir );
18841888 }
1885-
1889+
18861890 public void extractDirFromJarImpl (String jarpath , String dir , File destdir ) {
18871891 try (JarFile jarFile = new JarFile (jarpath )) {
1888- Enumeration <JarEntry > jarEnums = jarFile .entries ();
1889- while (jarEnums .hasMoreElements ()) {
1890- JarEntry entry = jarEnums .nextElement ();
1891- if (!entry .isDirectory () && entry .getName ().startsWith (dir )) {
1892- File aFile = new File (destdir , entry .getName ());
1893- aFile .getParentFile ().mkdirs ();
1894- try (FileOutputStream out = new FileOutputStream (aFile );
1895- InputStream in = jarFile .getInputStream (entry )) {
1896- IOUtils .copy (in , out );
1897- }
1898- }
1899- }
1892+ extractZipFile (jarFile , destdir , dir );
19001893 } catch (IOException e ) {
19011894 LOG .info ("Could not extract {} from {}" , dir , jarpath );
19021895 }
0 commit comments