| 1 18 package org.apache.tools.ant.taskdefs; 19 20 import java.io.ByteArrayInputStream ; 21 import java.io.ByteArrayOutputStream ; 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.OutputStream ; 28 import java.util.ArrayList ; 29 import java.util.Enumeration ; 30 import java.util.Hashtable ; 31 import java.util.Iterator ; 32 import java.util.Stack ; 33 import java.util.Vector ; 34 import java.util.zip.CRC32 ; 35 36 import org.apache.tools.ant.BuildException; 37 import org.apache.tools.ant.DirectoryScanner; 38 import org.apache.tools.ant.FileScanner; 39 import org.apache.tools.ant.Project; 40 import org.apache.tools.ant.types.ArchiveFileSet; 41 import org.apache.tools.ant.types.EnumeratedAttribute; 42 import org.apache.tools.ant.types.FileSet; 43 import org.apache.tools.ant.types.PatternSet; 44 import org.apache.tools.ant.types.Resource; 45 import org.apache.tools.ant.types.ResourceCollection; 46 import org.apache.tools.ant.types.ZipFileSet; 47 import org.apache.tools.ant.types.ZipScanner; 48 import org.apache.tools.ant.types.resources.ArchiveResource; 49 import org.apache.tools.ant.types.resources.FileResource; 50 import org.apache.tools.ant.util.FileNameMapper; 51 import org.apache.tools.ant.util.FileUtils; 52 import org.apache.tools.ant.util.GlobPatternMapper; 53 import org.apache.tools.ant.util.IdentityMapper; 54 import org.apache.tools.ant.util.MergingMapper; 55 import org.apache.tools.ant.util.ResourceUtils; 56 import org.apache.tools.zip.ZipEntry; 57 import org.apache.tools.zip.ZipExtraField; 58 import org.apache.tools.zip.ZipFile; 59 import org.apache.tools.zip.ZipOutputStream; 60 61 68 public class Zip extends MatchingTask { 69 71 protected File zipFile; 72 private ZipScanner zs; 74 private File baseDir; 75 protected Hashtable entries = new Hashtable (); 76 private Vector groupfilesets = new Vector (); 77 private Vector filesetsFromGroupfilesets = new Vector (); 78 protected String duplicate = "add"; 79 private boolean doCompress = true; 80 private boolean doUpdate = false; 81 private boolean savedDoUpdate = false; 83 private boolean doFilesonly = false; 84 protected String archiveType = "zip"; 85 86 private static final long EMPTY_CRC = new CRC32 ().getValue (); 88 protected String emptyBehavior = "skip"; 89 private Vector resources = new Vector (); 90 protected Hashtable addedDirs = new Hashtable (); 91 private Vector addedFiles = new Vector (); 92 93 protected boolean doubleFilePass = false; 94 protected boolean skipWriting = false; 95 96 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 97 98 100 104 private boolean addingNewFiles = false; 105 106 110 private String encoding; 111 112 118 private boolean keepCompression = false; 119 120 126 private boolean roundUp = true; 127 128 132 private String comment = ""; 133 134 private int level = ZipOutputStream.DEFAULT_COMPRESSION; 135 136 144 public void setZipfile(File zipFile) { 145 setDestFile(zipFile); 146 } 147 148 157 public void setFile(File file) { 158 setDestFile(file); 159 } 160 161 162 167 public void setDestFile(File destFile) { 168 this.zipFile = destFile; 169 } 170 171 176 public File getDestFile() { 177 return zipFile; 178 } 179 180 181 185 public void setBasedir(File baseDir) { 186 this.baseDir = baseDir; 187 } 188 189 194 public void setCompress(boolean c) { 195 doCompress = c; 196 } 197 198 203 public boolean isCompress() { 204 return doCompress; 205 } 206 207 212 public void setFilesonly(boolean f) { 213 doFilesonly = f; 214 } 215 216 221 public void setUpdate(boolean c) { 222 doUpdate = c; 223 savedDoUpdate = c; 224 } 225 226 230 public boolean isInUpdateMode() { 231 return doUpdate; 232 } 233 234 238 public void addFileset(FileSet set) { 239 add(set); 240 } 241 242 247 public void addZipfileset(ZipFileSet set) { 248 add(set); 249 } 250 251 256 public void add(ResourceCollection a) { 257 resources.add(a); 258 } 259 260 264 public void addZipGroupFileset(FileSet set) { 265 groupfilesets.addElement(set); 266 } 267 268 277 public void setDuplicate(Duplicate df) { 278 duplicate = df.getValue(); 279 } 280 281 285 public static class WhenEmpty extends EnumeratedAttribute { 286 290 public String [] getValues() { 291 return new String [] {"fail", "skip", "create"}; 292 } 293 } 294 295 305 public void setWhenempty(WhenEmpty we) { 306 emptyBehavior = we.getValue(); 307 } 308 309 317 public void setEncoding(String encoding) { 318 this.encoding = encoding; 319 } 320 321 326 public String getEncoding() { 327 return encoding; 328 } 329 330 337 public void setKeepCompression(boolean keep) { 338 keepCompression = keep; 339 } 340 341 347 public void setComment(String comment) { 348 this.comment = comment; 349 } 350 351 357 public String getComment() { 358 return comment; 359 } 360 361 367 public void setLevel(int level) { 368 this.level = level; 369 } 370 371 376 public int getLevel() { 377 return level; 378 } 379 380 394 public void setRoundUp(boolean r) { 395 roundUp = r; 396 } 397 398 402 public void execute() throws BuildException { 403 404 if (doubleFilePass) { 405 skipWriting = true; 406 executeMain(); 407 skipWriting = false; 408 executeMain(); 409 } else { 410 executeMain(); 411 } 412 } 413 414 419 public void executeMain() throws BuildException { 420 421 if (baseDir == null && resources.size() == 0 422 && groupfilesets.size() == 0 && "zip".equals(archiveType)) { 423 throw new BuildException("basedir attribute must be set, " 424 + "or at least one " 425 + "resource collection must be given!"); 426 } 427 428 if (zipFile == null) { 429 throw new BuildException("You must specify the " 430 + archiveType + " file to create!"); 431 } 432 433 if (zipFile.exists() && !zipFile.isFile()) { 434 throw new BuildException(zipFile + " is not a file."); 435 } 436 437 if (zipFile.exists() && !zipFile.canWrite()) { 438 throw new BuildException(zipFile + " is read-only."); 439 } 440 441 File renamedFile = null; 443 addingNewFiles = true; 444 445 if (doUpdate && !zipFile.exists()) { 448 doUpdate = false; 449 log("ignoring update attribute as " + archiveType 450 + " doesn't exist.", Project.MSG_DEBUG); 451 } 452 453 for (int i = 0; i < groupfilesets.size(); i++) { 455 456 log("Processing groupfileset ", Project.MSG_VERBOSE); 457 FileSet fs = (FileSet) groupfilesets.elementAt(i); 458 FileScanner scanner = fs.getDirectoryScanner(getProject()); 459 String [] files = scanner.getIncludedFiles(); 460 File basedir = scanner.getBasedir(); 461 for (int j = 0; j < files.length; j++) { 462 463 log("Adding file " + files[j] + " to fileset", 464 Project.MSG_VERBOSE); 465 ZipFileSet zf = new ZipFileSet(); 466 zf.setProject(getProject()); 467 zf.setSrc(new File (basedir, files[j])); 468 add(zf); 469 filesetsFromGroupfilesets.addElement(zf); 470 } 471 } 472 473 Vector vfss = new Vector (); 475 if (baseDir != null) { 476 FileSet fs = (FileSet) getImplicitFileSet().clone(); 477 fs.setDir(baseDir); 478 vfss.addElement(fs); 479 } 480 for (int i = 0; i < resources.size(); i++) { 481 ResourceCollection rc = (ResourceCollection) resources.elementAt(i); 482 vfss.addElement(rc); 483 } 484 485 ResourceCollection[] fss = new ResourceCollection[vfss.size()]; 486 vfss.copyInto(fss); 487 boolean success = false; 488 try { 489 ArchiveState state = getResourcesToAdd(fss, zipFile, false); 491 492 if (!state.isOutOfDate()) { 494 return; 495 } 496 497 if (!zipFile.exists() && state.isWithoutAnyResources()) { 498 createEmptyZip(zipFile); 499 return; 500 } 501 Resource[][] addThem = state.getResourcesToAdd(); 502 503 if (doUpdate) { 504 renamedFile = 505 FILE_UTILS.createTempFile("zip", ".tmp", 506 zipFile.getParentFile()); 507 renamedFile.deleteOnExit(); 508 509 try { 510 FILE_UTILS.rename(zipFile, renamedFile); 511 } catch (SecurityException e) { 512 throw new BuildException( 513 "Not allowed to rename old file (" 514 + zipFile.getAbsolutePath() 515 + ") to temporary file"); 516 } catch (IOException e) { 517 throw new BuildException( 518 "Unable to rename old file (" 519 + zipFile.getAbsolutePath() 520 + ") to temporary file"); 521 } 522 } 523 524 String action = doUpdate ? "Updating " : "Building "; 525 526 log(action + archiveType + ": " + zipFile.getAbsolutePath()); 527 528 ZipOutputStream zOut = null; 529 try { 530 if (!skipWriting) { 531 zOut = new ZipOutputStream(zipFile); 532 533 zOut.setEncoding(encoding); 534 zOut.setMethod(doCompress 535 ? ZipOutputStream.DEFLATED : ZipOutputStream.STORED); 536 zOut.setLevel(level); 537 } 538 initZipOutputStream(zOut); 539 540 for (int i = 0; i < fss.length; i++) { 542 if (addThem[i].length != 0) { 543 addResources(fss[i], addThem[i], zOut); 544 } 545 } 546 547 if (doUpdate) { 548 addingNewFiles = false; 549 ZipFileSet oldFiles = new ZipFileSet(); 550 oldFiles.setProject(getProject()); 551 oldFiles.setSrc(renamedFile); 552 oldFiles.setDefaultexcludes(false); 553 554 for (int i = 0; i < addedFiles.size(); i++) { 555 PatternSet.NameEntry ne = oldFiles.createExclude(); 556 ne.setName((String ) addedFiles.elementAt(i)); 557 } 558 DirectoryScanner ds = 559 oldFiles.getDirectoryScanner(getProject()); 560 ((ZipScanner) ds).setEncoding(encoding); 561 562 String [] f = ds.getIncludedFiles(); 563 Resource[] r = new Resource[f.length]; 564 for (int i = 0; i < f.length; i++) { 565 r[i] = ds.getResource(f[i]); 566 } 567 568 if (!doFilesonly) { 569 String [] d = ds.getIncludedDirectories(); 570 Resource[] dr = new Resource[d.length]; 571 for (int i = 0; i < d.length; i++) { 572 dr[i] = ds.getResource(d[i]); 573 } 574 Resource[] tmp = r; 575 r = new Resource[tmp.length + dr.length]; 576 System.arraycopy(dr, 0, r, 0, dr.length); 577 System.arraycopy(tmp, 0, r, dr.length, tmp.length); 578 } 579 addResources(oldFiles, r, zOut); 580 } 581 if (zOut != null) { 582 zOut.setComment(comment); 583 } 584 finalizeZipOutputStream(zOut); 585 586 if (doUpdate) { 589 if (!renamedFile.delete()) { 590 log ("Warning: unable to delete temporary file " 591 + renamedFile.getName(), Project.MSG_WARN); 592 } 593 } 594 success = true; 595 } finally { 596 try { 598 if (zOut != null) { 599 zOut.close(); 600 } 601 } catch (IOException ex) { 602 if (success) { 612 throw ex; 613 } 614 } 615 } 616 } catch (IOException ioe) { 617 String msg = "Problem creating " + archiveType + ": " 618 + ioe.getMessage(); 619 620 if ((!doUpdate || renamedFile != null) && !zipFile.delete()) { 622 msg += " (and the archive is probably corrupt but I could not " 623 + "delete it)"; 624 } 625 626 if (doUpdate && renamedFile != null) { 627 try { 628 FILE_UTILS.rename(renamedFile, zipFile); 629 } catch (IOException e) { 630 msg += " (and I couldn't rename the temporary file " 631 + renamedFile.getName() + " back)"; 632 } 633 } 634 635 throw new BuildException(msg, ioe, getLocation()); 636 } finally { 637 cleanUp(); 638 } 639 } 640 641 646 protected final boolean isAddingNewFiles() { 647 return addingNewFiles; 648 } 649 650 661 protected final void addResources(FileSet fileset, Resource[] resources, 662 ZipOutputStream zOut) 663 throws IOException { 664 665 String prefix = ""; 666 String fullpath = ""; 667 int dirMode = ArchiveFileSet.DEFAULT_DIR_MODE; 668 int fileMode = ArchiveFileSet.DEFAULT_FILE_MODE; 669 670 ArchiveFileSet zfs = null; 671 if (fileset instanceof ArchiveFileSet) { 672 zfs = (ArchiveFileSet) fileset; 673 prefix = zfs.getPrefix(getProject()); 674 fullpath = zfs.getFullpath(getProject()); 675 dirMode = zfs.getDirMode(getProject()); 676 fileMode = zfs.getFileMode(getProject()); 677 } 678 679 if (prefix.length() > 0 && fullpath.length() > 0) { 680 throw new BuildException("Both prefix and fullpath attributes must" 681 + " not be set on the same fileset."); 682 } 683 684 if (resources.length != 1 && fullpath.length() > 0) { 685 throw new BuildException("fullpath attribute may only be specified" 686 + " for filesets that specify a single" 687 + " file."); 688 } 689 690 if (prefix.length() > 0) { 691 if (!prefix.endsWith("/") && !prefix.endsWith("\\")) { 692 prefix += "/"; 693 } 694 addParentDirs(null, prefix, zOut, "", dirMode); 695 } 696 697 ZipFile zf = null; 698 try { 699 boolean dealingWithFiles = false; 700 File base = null; 701 702 if (zfs == null || zfs.getSrc(getProject()) == null) { 703 dealingWithFiles = true; 704 base = fileset.getDir(getProject()); 705 } else if (zfs instanceof ZipFileSet) { 706 zf = new ZipFile(zfs.getSrc(getProject()), encoding); 707 } 708 709 for (int i = 0; i < resources.length; i++) { 710 String name = null; 711 if (fullpath.length() > 0) { 712 name = fullpath; 713 } else { 714 name = resources[i].getName(); 715 } 716 name = name.replace(File.separatorChar, '/'); 717 718 if ("".equals(name)) { 719 continue; 720 } 721 if (resources[i].isDirectory() && !name.endsWith("/")) { 722 name = name + "/"; 723 } 724 725 if (!doFilesonly && !dealingWithFiles 726 && resources[i].isDirectory() 727 && !zfs.hasDirModeBeenSet()) { 728 int nextToLastSlash = name.lastIndexOf("/", 729 name.length() - 2); 730 if (nextToLastSlash != -1) { 731 addParentDirs(base, name.substring(0, 732 nextToLastSlash + 1), 733 zOut, prefix, dirMode); 734 } 735 if (zf != null) { 736 ZipEntry ze = zf.getEntry(resources[i].getName()); 737 addParentDirs(base, name, zOut, prefix, 738 ze.getUnixMode()); 739 } else { 740 ArchiveResource tr = (ArchiveResource) resources[i]; 741 addParentDirs(base, name, zOut, prefix, 742 tr.getMode()); 743 } 744 745 } else { 746 addParentDirs(base, name, zOut, prefix, dirMode); 747 } 748 749 if (!resources[i].isDirectory() && dealingWithFiles) { 750 File f = FILE_UTILS.resolveFile(base, 751 resources[i].getName()); 752 zipFile(f, zOut, prefix + name, fileMode); 753 } else if (!resources[i].isDirectory()) { 754 if (zf != null) { 755 ZipEntry ze = zf.getEntry(resources[i].getName()); 756 757 if (ze != null) { 758 boolean oldCompress = doCompress; 759 if (keepCompression) { 760 doCompress = (ze.getMethod() == ZipEntry.DEFLATED); 761 } 762 try { 763 zipFile(zf.getInputStream(ze), zOut, prefix + name, 764 ze.getTime(), zfs.getSrc(getProject()), 765 zfs.hasFileModeBeenSet() ? fileMode 766 : ze.getUnixMode()); 767 } finally { 768 doCompress = oldCompress; 769 } 770 } 771 } else { 772 ArchiveResource tr = (ArchiveResource) resources[i]; 773 InputStream is = null; 774 try { 775 is = tr.getInputStream(); 776 zipFile(is, zOut, prefix + name, 777 resources[i].getLastModified(), 778 zfs.getSrc(getProject()), 779 zfs.hasFileModeBeenSet() ? fileMode 780 : tr.getMode()); 781 } finally { 782  
|