src/share/classes/sun/tools/jar/Main.java

Print this page

        

*** 24,36 **** */ package sun.tools.jar; import java.io.*; ! import java.nio.file.Path; ! import java.nio.file.Files; import java.util.*; import java.util.zip.*; import java.util.jar.*; import java.util.jar.Manifest; import java.text.MessageFormat; import sun.misc.JarIndex; --- 24,37 ---- */ package sun.tools.jar; import java.io.*; ! import java.nio.file.*; ! import java.nio.file.attribute.*; import java.util.*; + import java.util.concurrent.*; import java.util.zip.*; import java.util.jar.*; import java.util.jar.Manifest; import java.text.MessageFormat; import sun.misc.JarIndex;
*** 71,81 **** * vflag: verbose * flag0: no zip compression (store only) * Mflag: DO NOT generate a manifest file (just ZIP) * iflag: generate jar index */ ! boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag; static final String MANIFEST_DIR = "META-INF/"; static final String VERSION = "1.0"; private static ResourceBundle rsrc; --- 72,84 ---- * vflag: verbose * flag0: no zip compression (store only) * Mflag: DO NOT generate a manifest file (just ZIP) * iflag: generate jar index */ ! boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, mtflag; ! ! int threadNum; static final String MANIFEST_DIR = "META-INF/"; static final String VERSION = "1.0"; private static ResourceBundle rsrc;
*** 195,206 **** // on stdout along with file data // error("Warning: -v option ignored"); vflag = false; } } ! expand(null, files, false); ! create(new BufferedOutputStream(out, 4096), manifest); if (in != null) { in.close(); } out.close(); } else if (uflag) { --- 198,209 ---- // on stdout along with file data // error("Warning: -v option ignored"); vflag = false; } } ! //expand(null, files, false); ! create(files, new BufferedOutputStream(out, 4096), manifest); if (in != null) { in.close(); } out.close(); } else if (uflag) {
*** 251,261 **** in.close(); } } } else if (xflag) { replaceFSC(files); ! if (fname != null && files != null) { extract(fname, files); } else { InputStream in = (fname == null) ? new FileInputStream(FileDescriptor.in) : new FileInputStream(fname); --- 254,267 ---- in.close(); } } } else if (xflag) { replaceFSC(files); ! ! if (mtflag && fname != null) { ! extract2(fname, files); ! } else if (fname != null && files != null) { extract(fname, files); } else { InputStream in = (fname == null) ? new FileInputStream(FileDescriptor.in) : new FileInputStream(fname);
*** 359,368 **** --- 365,380 ---- iflag = true; break; case 'e': ename = args[count++]; break; + case 'T': + mtflag = true; + threadNum = flags.charAt(++i) - '0'; + if (threadNum <= 0) + threadNum = 1; + break; default: error(formatMsg("error.illegal.option", String.valueOf(flags.charAt(i)))); usageError(); return false;
*** 457,470 **** ok = false; } } } /** * Creates a new JAR file. */ ! void create(OutputStream out, Manifest manifest) throws IOException { ZipOutputStream zos = new JarOutputStream(out); if (flag0) { zos.setMethod(ZipOutputStream.STORED); --- 469,571 ---- ok = false; } } } + //void expand2(File[] files, ArrayList elist, ExecutorService es) { + void expand2(File[] files, Queue elist, ExecutorService es) { + if (files == null) { + return; + } + for (File f :files) { + if (f.isFile()) { + if (entries.add(f)) { + if (f.length() > MAXBUFSIZE) { + elist.add(f); + } else { + DefWork job = new DefWork(f); + elist.add(es.submit(job, job)); + } + } + } else if (f.isDirectory()) { + if (entries.add(f)) { + elist.add(f); + expand2(f.listFiles(), elist, es); + } + } else { + error(formatMsg("error.nosuch.fileordir", String.valueOf(f))); + ok = false; + } + } + } + + private static int MAXBUFSIZE = 1024 * 1024 * 50; + private ThreadLocal<Deflater> tlDef = new ThreadLocal<>(); + private ThreadLocal<CRC32> tlCrc = new ThreadLocal<>(); + private ThreadLocal<byte[]> tlBuf = new ThreadLocal<>(); + + private class DefByteArrayOutputStream extends ByteArrayOutputStream { + DefByteArrayOutputStream(int size) { + super(size); + } + byte[] getByteArray() { + return buf; + } + } + + private class DefWork implements Runnable { + File f; + DefByteArrayOutputStream dbaos; + long size; + long csize; + long crc; + IOException x; + + DefWork(File f) { + this.f = f; + } + + public void run() { + long len = f.length(); + dbaos = new DefByteArrayOutputStream((int)len); + Deflater def = tlDef.get(); + if (def == null) + def = new Deflater(Deflater.DEFAULT_COMPRESSION, true); + CRC32 crc32 = tlCrc.get(); + if (crc32 == null) + crc32 = new CRC32(); + byte[] buf = tlBuf.get(); + if (buf == null) + buf = new byte[8192]; + DeflaterOutputStream dos = new DeflaterOutputStream(dbaos, def); + try (InputStream in = new FileInputStream(f)) { + int n; + while ((n = in.read(buf)) != -1) { + dos.write(buf, 0, n); + crc32.update(buf, 0, n); + } + dos.close(); + } catch (IOException x) { + x.printStackTrace(); + this.x = x; + } + size = def.getBytesRead(); + csize = def.getBytesWritten(); + crc = crc32.getValue(); + def.reset(); + tlDef.set(def); + crc32.reset(); + tlCrc.set(crc32); + tlBuf.set(buf); + } + } + + /** * Creates a new JAR file. */ ! void create(String[] files, OutputStream out, Manifest manifest) throws IOException { ZipOutputStream zos = new JarOutputStream(out); if (flag0) { zos.setMethod(ZipOutputStream.STORED);
*** 485,498 **** --- 586,726 ---- } zos.putNextEntry(e); manifest.write(zos); zos.closeEntry(); } + + if (!mtflag || flag0) { + expand(null, files, false); for (File file: entries) { addFile(zos, file); } + } else { + System.out.println("mtCreate: threadNum=" + threadNum + "..."); + final ExecutorService es = Executors.newFixedThreadPool(threadNum); + + final File[] fs = new File[files.length]; + for (int i = 0; i < files.length; i++) + fs[i] = new File(files[i]); + + + final Queue elist = new ConcurrentLinkedQueue(); + final Object LAST = new Object(); + es.submit(new Runnable() { + public void run() { + expand2(fs, elist, es); + elist.add(LAST); + } + }); + + /* + ArrayList elist = new ArrayList(); + expand2(fs, elist, es); + */ + + /* + expand(null, files, false); + ArrayList elist = new ArrayList(entries.size()); + for (File f: entries) { + if (f.isDirectory() || f.length() > MAXBUFSIZE) { + elist.add(f); + } else { + DefWork job = new DefWork(f); + elist.add(es.submit(job, job)); + } + } + */ + + //for (Object o : elist) { + + while(true) { + Object o = elist.poll(); + if (o == null) + continue; + if (o == LAST) + break; + + + + File file = null; + DefWork work = null; + if (o instanceof File) + file = (File)o; + else { + try { + work = (DefWork)((java.util.concurrent.Future)o).get(); + } catch (Exception x) { + x.printStackTrace(); + continue; + } + file = work.f; + } + String name = file.getPath(); + boolean isDir = file.isDirectory(); + if (isDir) { + name = name.endsWith(File.separator) ? name : + (name + File.separator); + } + name = entryName(name); + + if (name.equals("") || name.equals(".") || name.equals(zname)) { + return; + } else if ((name.equals(MANIFEST_DIR) || name.equals(MANIFEST_NAME)) + && !Mflag) { + if (vflag) { + output(formatMsg("out.ignore.entry", name)); + } + return; + } + long size = isDir ? 0 : file.length(); + if (vflag) { + //outprint(formatMsg("out.adding", name)); + System.out.println(formatMsg("out.adding", name)); + } + ZipEntry e = new ZipEntry(name); + e.setTime(file.lastModified()); + if (size == 0) { + e.setMethod(ZipEntry.STORED); + e.setSize(0); + e.setCrc(0); + } + if (work != null && work.dbaos != null) { + e.setMethod(ZipEntry.DEFLATED); + e.setSize(work.size); + e.setCompressedSize(work.csize); + e.setCrc(work.crc); + zos.writeNextEntry(e, work.dbaos.getByteArray(), 0, work.dbaos.size()); + work.dbaos = null; + } else { + zos.putNextEntry(e); + if (!isDir) { + copy(file, zos); + } + zos.closeEntry(); + } + /* report how much compression occurred. */ + if (vflag) { + size = e.getSize(); + long csize = e.getCompressedSize(); + //out.print(formatMsg2("out.size", String.valueOf(size), + System.out.println(formatMsg2("out.size", String.valueOf(size), + String.valueOf(csize))); + if (e.getMethod() == ZipEntry.DEFLATED) { + long ratio = 0; + if (size != 0) { + ratio = ((size - csize) * 100) / size; + } + output(formatMsg("out.deflated", String.valueOf(ratio))); + } else { + output(getMsg("out.stored")); + } + } + } + es.shutdown(); + } zos.close(); + } private char toUpperCaseASCII(char c) { return (c < 'a' || c > 'z') ? c : (char) (c + 'A' - 'a'); }
*** 917,931 **** --- 1145,1227 ---- } zf.close(); updateLastModifiedTime(dirs); } + void extract2(String fname, String files[]) throws IOException { + System.out.println("mtExtract: threadNum=" + threadNum + "..."); + final ZipFile zf = new ZipFile(fname); + final Set<ZipEntry> dirs = newDirSet(); + Enumeration<? extends ZipEntry> zes = zf.entries(); + + class ExtractWork implements Runnable { + IOException ioe; + ZipEntry e; + InputStream is; + ExtractWork(InputStream is, ZipEntry e) { + this.is = is; + this.e = e; + } + public void run() { + try { + dirs.add(extractFile(is, e)); + } catch (IOException ioe) { + this.ioe = ioe; + } + } + } + + final ExecutorService es = Executors.newFixedThreadPool(threadNum); + final Queue<Future<ExtractWork>> works = new ConcurrentLinkedQueue<>(); + + while (zes.hasMoreElements()) { + ZipEntry e = zes.nextElement(); + InputStream is; + + if (files == null) { + if (e.isDirectory()) { + dirs.add(extractFile(null, e)); + } else { + ExtractWork work = new ExtractWork(zf.getInputStream(e), e); + works.add(es.submit(work, work)); + } + } else { + String name = e.getName(); + for (String file : files) { + if (name.startsWith(file)) { + if (e.isDirectory()) { + dirs.add(extractFile(null, e)); + } else { + ExtractWork work = new ExtractWork(zf.getInputStream(e), e); + works.add(es.submit(work, work)); + } + } + } + } + } + Future<ExtractWork> f; + while((f = works.poll()) != null) { + while (!f.isDone()) { + Thread.yield(); + } + try { + if (f.get().ioe != null) + throw f.get().ioe; + } catch (Exception ire) {} + } + zf.close(); + updateLastModifiedTime(dirs); + es.shutdown(); + } + + /** * Extracts next entry from JAR file, creating directories as needed. If * the entry is for a directory which doesn't exist prior to this * invocation, returns that entry, otherwise returns null. */ + ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException { ZipEntry rc = null; String name = e.getName(); File f = new File(e.getName().replace('/', File.separatorChar)); if (e.isDirectory()) {
*** 940,950 **** f.getPath())); } else { rc = e; } } - if (vflag) { output(formatMsg("out.create", name)); } } else { if (f.getParent() != null) { --- 1236,1245 ----