0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU General
0007: * Public License Version 2 only ("GPL") or the Common Development and Distribution
0008: * License("CDDL") (collectively, the "License"). You may not use this file except in
0009: * compliance with the License. You can obtain a copy of the License at
0010: * http://www.netbeans.org/cddl-gplv2.html or nbbuild/licenses/CDDL-GPL-2-CP. See the
0011: * License for the specific language governing permissions and limitations under the
0012: * License. When distributing the software, include this License Header Notice in
0013: * each file and include the License file at nbbuild/licenses/CDDL-GPL-2-CP. Sun
0014: * designates this particular file as subject to the "Classpath" exception as
0015: * provided by Sun in the GPL Version 2 section of the License file that
0016: * accompanied this code. If applicable, add the following below the License Header,
0017: * with the fields enclosed by brackets [] replaced by your own identifying
0018: * information: "Portions Copyrighted [year] [name of copyright owner]"
0019: *
0020: * Contributor(s):
0021: *
0022: * The Original Software is NetBeans. The Initial Developer of the Original Software
0023: * is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun Microsystems, Inc. All
0024: * Rights Reserved.
0025: *
0026: * If you wish your version of this file to be governed by only the CDDL or only the
0027: * GPL Version 2, indicate your decision by adding "[Contributor] elects to include
0028: * this software in this distribution under the [CDDL or GPL Version 2] license." If
0029: * you do not indicate a single choice of license, a recipient has the option to
0030: * distribute your version of this file under either the CDDL, the GPL Version 2 or
0031: * to extend the choice of license to its licensees as provided above. However, if
0032: * you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then
0033: * the option applies only if the new code is made subject to such option by the
0034: * copyright holder.
0035: */
0036:
0037: package org.netbeans.installer.utils;
0038:
0039: import java.io.BufferedReader;
0040: import java.io.ByteArrayInputStream;
0041: import java.io.Closeable;
0042: import java.io.File;
0043: import java.io.FileInputStream;
0044: import java.io.FileOutputStream;
0045: import java.io.FileReader;
0046: import java.io.IOException;
0047: import java.io.InputStream;
0048: import java.io.InputStreamReader;
0049: import java.io.OutputStream;
0050: import java.io.Reader;
0051: import java.nio.charset.Charset;
0052: import java.security.MessageDigest;
0053: import java.security.NoSuchAlgorithmException;
0054: import java.util.Arrays;
0055: import java.util.Date;
0056: import java.util.Enumeration;
0057: import java.util.HashMap;
0058: import java.util.LinkedList;
0059: import java.util.List;
0060: import java.util.Map;
0061: import java.util.jar.JarFile;
0062: import java.util.regex.Matcher;
0063: import java.util.regex.Pattern;
0064: import java.util.zip.CRC32;
0065: import java.util.zip.ZipEntry;
0066: import java.util.zip.ZipFile;
0067: import java.util.zip.ZipOutputStream;
0068: import org.netbeans.installer.utils.exceptions.NativeException;
0069: import org.netbeans.installer.utils.exceptions.XMLException;
0070: import org.netbeans.installer.utils.helper.ExecutionResults;
0071: import org.netbeans.installer.utils.helper.FilesList;
0072: import org.netbeans.installer.utils.helper.FileEntry;
0073: import org.netbeans.installer.utils.helper.Pair;
0074: import org.netbeans.installer.utils.progress.CompositeProgress;
0075: import org.netbeans.installer.utils.progress.Progress;
0076: import org.netbeans.installer.utils.system.NativeUtils;
0077:
0078: /**
0079: *
0080: * @author Kirill Sorokin
0081: */
0082: public final class FileUtils {
0083: /////////////////////////////////////////////////////////////////////////////////
0084: // Static
0085:
0086: // file/stream read/write ///////////////////////////////////////////////////////
0087: public static String readFile(final File file) throws IOException {
0088: final Reader reader = new BufferedReader(new FileReader(file));
0089: try {
0090: final char[] buffer = new char[BUFFER_SIZE];
0091: final StringBuilder stringBuilder = new StringBuilder();
0092: int readLength;
0093: while ((readLength = reader.read(buffer)) != -1) {
0094: stringBuilder.append(buffer, 0, readLength);
0095: }
0096: return stringBuilder.toString();
0097: } finally {
0098: try {
0099: reader.close();
0100: } catch (IOException ignord) {
0101: }
0102: }
0103: }
0104:
0105: public static FilesList writeFile(final File file,
0106: final CharSequence string) throws IOException {
0107: return writeFile(file, string, Charset.defaultCharset().name(),
0108: false);
0109: }
0110:
0111: public static FilesList writeFile(final File file,
0112: final CharSequence string, final String charset)
0113: throws IOException {
0114: return writeFile(file, string, charset, false);
0115: }
0116:
0117: public static FilesList appendFile(final File file,
0118: final CharSequence string) throws IOException {
0119: return writeFile(file, string, Charset.defaultCharset().name(),
0120: true);
0121: }
0122:
0123: public static FilesList appendFile(final File file,
0124: final CharSequence string, final String charset)
0125: throws IOException {
0126: return writeFile(file, string, charset, true);
0127: }
0128:
0129: public static FilesList writeFile(final File file,
0130: final CharSequence string, final boolean append)
0131: throws IOException {
0132: return writeFile(file, string, Charset.defaultCharset().name(),
0133: append);
0134: }
0135:
0136: public static FilesList writeFile(final File file,
0137: final CharSequence string, final String charset,
0138: final boolean append) throws IOException {
0139: return writeFile(file, new ByteArrayInputStream(string
0140: .toString().getBytes(charset)), append);
0141: }
0142:
0143: public static FilesList writeFile(final File file,
0144: final InputStream input) throws IOException {
0145: return writeFile(file, input, false);
0146: }
0147:
0148: public static FilesList appendFile(final File file,
0149: final InputStream input) throws IOException {
0150: return writeFile(file, input, true);
0151: }
0152:
0153: public static FilesList writeFile(final File file,
0154: final InputStream input, final boolean append)
0155: throws IOException {
0156: final FilesList list = new FilesList();
0157:
0158: if (!exists(file)) {
0159: if (!exists(file.getParentFile())) {
0160: list.add(mkdirs(file.getParentFile()));
0161: }
0162:
0163: file.createNewFile();
0164: list.add(file);
0165: }
0166:
0167: FileOutputStream output = null;
0168: try {
0169: output = new FileOutputStream(file, append);
0170: StreamUtils.transferData(input, output);
0171: } finally {
0172: if (output != null) {
0173: try {
0174: output.close();
0175: } catch (IOException e) {
0176: ErrorManager
0177: .notifyDebug(ResourceUtils.getString(
0178: FileUtils.class,
0179: ERROR_CLOSE_STREAM_KEY), e);
0180: }
0181: }
0182: }
0183:
0184: return list;
0185: }
0186:
0187: public static String readFirstLine(final File file)
0188: throws IOException {
0189: BufferedReader reader = new BufferedReader(
0190: new InputStreamReader(new FileInputStream(file)));
0191: try {
0192: return reader.readLine();
0193: } finally {
0194: try {
0195: reader.close();
0196: } catch (IOException ignord) {
0197: }
0198: }
0199: }
0200:
0201: public static List<String> readStringList(final File file)
0202: throws IOException {
0203: final List<String> list = new LinkedList<String>();
0204: for (String line : StringUtils.splitByLines((readFile(file)))) {
0205: list.add(line);
0206: }
0207: return list;
0208: }
0209:
0210: public static FilesList writeStringList(final File file,
0211: final List<String> list) throws IOException {
0212: return writeStringList(file, list, Charset.defaultCharset()
0213: .name(), false);
0214: }
0215:
0216: public static FilesList writeStringList(final File file,
0217: final List<String> list, final String charset)
0218: throws IOException {
0219: return writeStringList(file, list, charset, false);
0220: }
0221:
0222: public static FilesList writeStringList(final File file,
0223: final List<String> list, final boolean append)
0224: throws IOException {
0225: return writeStringList(file, list, Charset.defaultCharset()
0226: .name(), append);
0227: }
0228:
0229: public static FilesList writeStringList(final File file,
0230: final List<String> list, final String charset,
0231: final boolean append) throws IOException {
0232: StringBuilder builder = new StringBuilder();
0233:
0234: for (int i = 0; i < list.size(); i++) {
0235: builder.append(list.get(i));
0236: if (i != list.size() - 1) {
0237: builder.append(SystemUtils.getLineSeparator());
0238: }
0239: }
0240:
0241: return writeFile(file, builder, charset, append);
0242: }
0243:
0244: // file metadata ////////////////////////////////////////////////////////////////
0245: public static Date getLastModified(final File file) {
0246: if (!exists(file)) {
0247: return null;
0248: }
0249: Date date = null;
0250: try {
0251: long modif = file.lastModified();
0252: date = new Date(modif);
0253: } catch (SecurityException ex) {
0254: ex = null;
0255: }
0256: return date;
0257: }
0258:
0259: public static long getSize(final File file) {
0260: long size = 0;
0261:
0262: if (file != null && exists(file)) {
0263: try {
0264: if (file.isDirectory()) {
0265: File[] files = file.listFiles();
0266: if (files != null) {
0267: for (File f : files) {
0268: size += getSize(f);
0269: }
0270: }
0271: } else {
0272: size = file.length();
0273: }
0274: } catch (SecurityException e) {
0275: ErrorManager.notifyError(ResourceUtils.getString(
0276: FileUtils.class,
0277: ERROR_FILE_SECURITY_EXCEPTION_KEY, file), e);
0278: }
0279: }
0280:
0281: return size;
0282: }
0283:
0284: public static long getFreeSpace(final File file) {
0285: long freeSpace = 0;
0286:
0287: try {
0288: freeSpace = SystemUtils.getNativeUtils().getFreeSpace(file);
0289: } catch (NativeException e) {
0290: ErrorManager.notifyError(ResourceUtils.getString(
0291: FileUtils.class, ERROR_CANT_GET_FREE_SPACE_KEY,
0292: file), e);
0293: }
0294:
0295: return freeSpace;
0296: }
0297:
0298: public static long getCrc32(final File file) throws IOException {
0299: InputStream input = null;
0300: try {
0301: input = new FileInputStream(file);
0302: return getCrc32(input);
0303: } finally {
0304: if (input != null) {
0305: try {
0306: input.close();
0307: } catch (IOException ignord) {
0308: }
0309: }
0310: }
0311: }
0312:
0313: public static long getCrc32(final InputStream input)
0314: throws IOException {
0315: CRC32 crc = new CRC32();
0316: final byte[] buffer = new byte[BUFFER_SIZE];
0317: int readLength;
0318: while ((readLength = input.read(buffer)) != -1) {
0319: crc.update(buffer, 0, readLength);
0320: }
0321: return crc.getValue();
0322: }
0323:
0324: public static String getMd5(final File file) throws IOException {
0325: return StringUtils.asHexString(getMd5Bytes(file));
0326: }
0327:
0328: public static String getMd5(final InputStream input)
0329: throws IOException {
0330: return StringUtils.asHexString(getMd5Bytes(input));
0331: }
0332:
0333: public static byte[] getMd5Bytes(final File file)
0334: throws IOException {
0335: try {
0336: return getDigestBytes(file, MD5_DIGEST_NAME);
0337: } catch (NoSuchAlgorithmException e) {
0338: ErrorManager.notifyCritical(ResourceUtils.getString(
0339: FileUtils.class, ERROR_MD5_NOT_SUPPORTED_KEY), e);
0340: }
0341:
0342: return null;
0343: }
0344:
0345: public static byte[] getMd5Bytes(final InputStream input)
0346: throws IOException {
0347: try {
0348: return getDigestBytes(input, MD5_DIGEST_NAME);
0349: } catch (NoSuchAlgorithmException e) {
0350: ErrorManager.notifyCritical(ResourceUtils.getString(
0351: FileUtils.class, ERROR_MD5_NOT_SUPPORTED_KEY), e);
0352: }
0353:
0354: return null;
0355: }
0356:
0357: public static String getSha1(final File file) throws IOException {
0358: return StringUtils.asHexString(getSha1Bytes(file));
0359: }
0360:
0361: public static byte[] getSha1Bytes(final File file)
0362: throws IOException {
0363: try {
0364: return getDigestBytes(file, SHA1_DIGEST_NAME);
0365: } catch (NoSuchAlgorithmException e) {
0366: ErrorManager.notifyCritical(ResourceUtils.getString(
0367: FileUtils.class, ERROR_SHA1_NOT_SUPPORTED_KEY), e);
0368: }
0369:
0370: return null;
0371: }
0372:
0373: public static byte[] getDigestBytes(final File file,
0374: final String algorithm) throws IOException,
0375: NoSuchAlgorithmException {
0376: InputStream input = null;
0377: try {
0378: input = new FileInputStream(file);
0379: return getDigestBytes(input, algorithm);
0380: } finally {
0381: if (input != null) {
0382: try {
0383: input.close();
0384: } catch (IOException ex) {
0385: LogManager.log(ex);
0386: }
0387: }
0388: }
0389: }
0390:
0391: public static byte[] getDigestBytes(final InputStream input,
0392: final String algorithm) throws IOException,
0393: NoSuchAlgorithmException {
0394: MessageDigest md = MessageDigest.getInstance(algorithm);
0395: md.reset();
0396:
0397: final byte[] buffer = new byte[BUFFER_SIZE];//todo: here was 10240?? discus
0398: int readLength;
0399: while ((readLength = input.read(buffer)) != -1) {
0400: md.update(buffer, 0, readLength);
0401: }
0402:
0403: return md.digest();
0404: }
0405:
0406: public static boolean isEmpty(final File file) {
0407: if (!exists(file)) {
0408: return true;
0409: }
0410:
0411: if (file.isDirectory()) {
0412: File[] list = file.listFiles();
0413: if (list != null) {
0414: for (File child : list) {
0415: if (!isEmpty(child)) {
0416: return false;
0417: }
0418: }
0419: }
0420: return true;
0421: } else {
0422: return false;
0423: }
0424: }
0425:
0426: public static boolean canRead(final File file) {
0427: return canAccessFile(file, true);
0428: }
0429:
0430: public static boolean canWrite(final File file) {
0431: return canAccessFile(file, false);
0432: }
0433:
0434: public static boolean isJarFile(final File file) {
0435: if (file.getName().endsWith(JAR_EXTENSION)) {
0436: JarFile jar = null;
0437: try {
0438: jar = new JarFile(file);
0439: return true;
0440: } catch (IOException e) {
0441: ErrorManager.notifyDebug(ResourceUtils.getString(
0442: FileUtils.class, ERROR_NOT_JAR_FILE_KEY, file),
0443: e);
0444: return false;
0445: } finally {
0446: if (jar != null) {
0447: try {
0448: jar.close();
0449: } catch (IOException e) {
0450: ErrorManager.notifyDebug(ResourceUtils
0451: .getString(FileUtils.class,
0452: ERROR_CANT_CLOSE_JAR_KEY, jar
0453: .getName()), e);
0454: }
0455: }
0456: }
0457: } else {
0458: return false;
0459: }
0460: }
0461:
0462: public static boolean isSigned(final File file) throws IOException {
0463: JarFile jar = new JarFile(file);
0464:
0465: try {
0466: if (jar.getEntry(SUN_MICR_RSA) == null) {
0467: return false;
0468: }
0469: if (jar.getEntry(SUN_MICR_SF) == null) {
0470: return false;
0471: }
0472: return true;
0473: } finally {
0474: jar.close();
0475: }
0476: }
0477:
0478: public static boolean exists(final File file) {
0479: if (file.exists()) {
0480: return true;
0481: } else if (!file.isFile() && !file.isDirectory()) {
0482: final File parent = file.getParentFile();
0483: if ((parent == null) || !parent.exists()) {
0484: return false;
0485: }
0486:
0487: final File[] children = parent.listFiles();
0488: if (children == null) {
0489: return false;
0490: }
0491:
0492: for (File child : children) {
0493: if (child.equals(file)) {
0494: return true;
0495: }
0496: }
0497: }
0498:
0499: return false;
0500: }
0501:
0502: public static boolean isParent(final File candidate, final File file) {
0503: File parent = file.getParentFile();
0504:
0505: while ((parent != null) && !candidate.equals(parent)) {
0506: parent = parent.getParentFile();
0507: }
0508:
0509: return (parent != null) && candidate.equals(parent);
0510: }
0511:
0512: public static File getRoot(final File fileRequested,
0513: final List<File> roots) {
0514: File result = null;
0515: File file = fileRequested;
0516: try {
0517: file = file.getCanonicalFile();
0518: } catch (IOException e) {
0519: LogManager.log("... cannot get canonical file for " + file);
0520: }
0521: for (File root : roots) {
0522: if (isParent(root, file)) {
0523: if (result == null
0524: || (result.getAbsolutePath().length() < root
0525: .getAbsolutePath().length())) {
0526: result = root;
0527: }
0528: }
0529: }
0530: if (result == null) {
0531: if (SystemUtils.isWindows()
0532: && FileUtils.isUNCPath(file.getPath())) {
0533: return getRoot(file);
0534: }
0535: }
0536: return result;
0537: }
0538:
0539: public static long countChildren(final File file) {
0540: long count = 0;
0541:
0542: if (!file.exists()) {
0543: return 0;
0544: } else {
0545: count++;
0546: }
0547:
0548: final File[] children = file.listFiles();
0549: if (children != null) {
0550: for (File child : children) {
0551: count += countChildren(child);
0552: }
0553: }
0554:
0555: return count;
0556: }
0557:
0558: // in-file string replacement ///////////////////////////////////////////////////
0559: public static void modifyFile(final File file, final String token,
0560: final Object replacement) throws IOException {
0561: modifyFile(file, token, replacement, false);
0562: }
0563:
0564: public static void modifyFile(final File file, final String token,
0565: final Object replacement, final boolean regexp)
0566: throws IOException {
0567: final Map<String, Object> replacementMap = new HashMap<String, Object>();
0568:
0569: replacementMap.put(token, replacement);
0570:
0571: modifyFile(file, replacementMap, regexp);
0572: }
0573:
0574: public static void modifyFile(final File file,
0575: final Map<String, Object> map) throws IOException {
0576: modifyFile(file, map, false);
0577: }
0578:
0579: public static void modifyFile(final File file,
0580: final Map<String, Object> map, final boolean regexp)
0581: throws IOException {
0582: if (!exists(file)) {
0583: return;
0584: }
0585:
0586: if (file.isDirectory()) {
0587: for (File child : file.listFiles()) {
0588: modifyFile(child, map, regexp);
0589: }
0590: } else {
0591: // if the file is larger than 100 Kb - skip it
0592: if (file.length() > 1024 * 100) {
0593: return;
0594: }
0595:
0596: final String original = readFile(file);
0597:
0598: String modified = new String(original);
0599: for (String token : map.keySet()) {
0600: final Object object = map.get(token);
0601:
0602: final String replacement;
0603: if (object instanceof File) {
0604: replacement = ((File) object).getAbsolutePath();
0605: } else {
0606: replacement = object.toString();
0607: }
0608:
0609: if (regexp) {
0610: modified = Pattern
0611: .compile(token, Pattern.MULTILINE).matcher(
0612: modified).replaceAll(replacement);
0613: } else {
0614: modified = modified.toString().replace(token,
0615: replacement);
0616: }
0617: }
0618:
0619: if (!modified.equals(original)) {
0620: LogManager.log("modifying file: "
0621: + file.getAbsolutePath());
0622:
0623: writeFile(file, modified);
0624: }
0625: }
0626: }
0627:
0628: public static void modifyFiles(final List<File> files,
0629: final Map<String, Object> map, final boolean regexp)
0630: throws IOException {
0631: modifyFiles(files, map, regexp, new Progress());
0632: }
0633:
0634: public static void modifyFiles(final List<File> files,
0635: final Map<String, Object> map, final boolean regexp,
0636: final Progress progress) throws IOException {
0637: progress.setPercentage(Progress.START);
0638:
0639: for (int i = 0; i < files.size(); i++) {
0640: modifyFile(files.get(i), map, regexp);
0641:
0642: progress
0643: .setPercentage(Progress.COMPLETE * i / files.size());
0644: }
0645:
0646: progress.setPercentage(Progress.COMPLETE);
0647: }
0648:
0649: // file operations //////////////////////////////////////////////////////////////
0650: public static void deleteFile(final File file) throws IOException {
0651: deleteFile(file, false);
0652: }
0653:
0654: public static void deleteFile(final File file,
0655: final Progress progress) throws IOException {
0656: deleteFile(file, false, progress);
0657: }
0658:
0659: public static void deleteFile(final File file, final boolean recurse)
0660: throws IOException {
0661: deleteFile(file, recurse, new Progress());
0662: }
0663:
0664: public static void deleteFile(final File file,
0665: final boolean recurse, final Progress progress)
0666: throws IOException {
0667: final long childrenCount;
0668: if (recurse) {
0669: childrenCount = countChildren(file);
0670: } else {
0671: childrenCount = 1;
0672: }
0673:
0674: deleteFile(file, recurse, progress, 0, childrenCount == 0 ? 1
0675: : childrenCount);
0676: progress.setPercentage(Progress.COMPLETE);
0677: }
0678:
0679: public static void deleteFiles(final List<File> files)
0680: throws IOException {
0681: deleteFiles(files, new Progress());
0682: }
0683:
0684: public static void deleteFiles(final List<File> files,
0685: final Progress progress) throws IOException {
0686: long count = 0;
0687:
0688: for (File file : files) {
0689: count = deleteFile(file, false, progress, count, files
0690: .size());
0691: }
0692: progress.setPercentage(Progress.COMPLETE);
0693: }
0694:
0695: public static void deleteFiles(final File... files)
0696: throws IOException {
0697: deleteFiles(new Progress(), files);
0698: }
0699:
0700: public static void deleteFiles(final Progress progress,
0701: final File... files) throws IOException {
0702: deleteFiles(Arrays.asList(files), progress);
0703: }
0704:
0705: public static void deleteFiles(final FilesList files)
0706: throws IOException {
0707: deleteFiles(files, new Progress());
0708: }
0709:
0710: public static void deleteFiles(final FilesList files,
0711: final Progress progress) throws IOException {
0712: long count = 0;
0713:
0714: for (FileEntry entry : files) {
0715: count = deleteFile(entry.getFile(), false, progress, count,
0716: files.getSize());
0717: }
0718: progress.setPercentage(Progress.COMPLETE);
0719: }
0720:
0721: public static void deleteEmptyParents(final File file)
0722: throws IOException {
0723: if (!exists(file)) {
0724: final File parent = file.getParentFile();
0725:
0726: if (isEmpty(parent)) {
0727: deleteWithEmptyParents(parent);
0728: }
0729: }
0730: }
0731:
0732: public static void deleteWithEmptyParents(final File file)
0733: throws IOException {
0734: if (file == null) {
0735: return;
0736: }
0737:
0738: File probe = file;
0739: do {
0740: deleteFile(probe);
0741: probe = probe.getParentFile();
0742: } while ((probe != null) && isEmpty(probe));
0743: }
0744:
0745: public static void deleteOnExit(final File file) {
0746: SystemUtils.getNativeUtils().addDeleteOnExitFile(file);
0747: }
0748:
0749: public static File createTempFile() throws IOException {
0750: return createTempFile(SystemUtils.getTempDirectory());
0751: }
0752:
0753: public static File createTempFile(final File parent)
0754: throws IOException {
0755: return createTempFile(parent, true);
0756: }
0757:
0758: public static File createTempFile(final File parent,
0759: final boolean create) throws IOException {
0760: return createTempFile(parent, create, false);
0761: }
0762:
0763: public static File createTempFile(final File parent,
0764: final boolean create, final boolean directory)
0765: throws IOException {
0766: final File file = File.createTempFile("nbi-", ".tmp", parent);
0767:
0768: if (!create || directory) {
0769: file.delete();
0770: }
0771: if (create && directory) {
0772: mkdirs(file);
0773: }
0774:
0775: file.deleteOnExit();
0776:
0777: return file;
0778: }
0779:
0780: public static FilesList copyFile(final File source,
0781: final File target) throws IOException {
0782: return copyFile(source, target, false);
0783: }
0784:
0785: public static FilesList copyFile(final File source,
0786: final File target, final Progress progress)
0787: throws IOException {
0788: return copyFile(source, target, false, progress);
0789: }
0790:
0791: public static FilesList copyFile(final File source,
0792: final File target, final boolean recurse)
0793: throws IOException {
0794: return copyFile(source, target, recurse, new Progress());
0795: }
0796:
0797: public static FilesList copyFile(final File source,
0798: final File target, final boolean recurse,
0799: final Progress progress) throws IOException {
0800: final FilesList list = new FilesList();
0801:
0802: final long childrenCount;
0803: if (recurse) {
0804: childrenCount = countChildren(source);
0805: } else {
0806: childrenCount = 1;
0807: }
0808:
0809: copyFile(source, target, recurse, list, progress, 0,
0810: childrenCount == 0 ? 1 : childrenCount);
0811: progress.setPercentage(Progress.COMPLETE);
0812:
0813: return list;
0814: }
0815:
0816: public static FilesList moveFile(final File source,
0817: final File target) throws IOException {
0818: return moveFile(source, target, new Progress());
0819: }
0820:
0821: public static FilesList moveFile(final File source,
0822: final File target, final Progress progress)
0823: throws IOException {
0824: final FilesList list = new FilesList();
0825:
0826: progress.setDetail(StringUtils.format(MESSAGE_MOVING, source,
0827: target));
0828: if (!source.renameTo(target)) {
0829: final CompositeProgress composite = new CompositeProgress();
0830: final Progress copyProgress = new Progress();
0831: final Progress deleteProgress = new Progress();
0832:
0833: composite.synchronizeTo(progress);
0834: composite.addChild(copyProgress, 80);
0835: composite.addChild(deleteProgress, 20);
0836:
0837: list.add(copyFile(source, target, true, copyProgress));
0838:
0839: deleteFile(source, true, deleteProgress);
0840: } else {
0841: list.add(target);
0842: }
0843: progress.setPercentage(Progress.COMPLETE);
0844:
0845: return list;
0846: }
0847:
0848: // archive operations ///////////////////////////////////////////////////////////
0849: public static void zip(final File file,
0850: final ZipOutputStream output, final File root,
0851: final List<File> excludes) throws IOException {
0852: if (excludes.contains(file)) {
0853: return;
0854: }
0855:
0856: final String entryName = file.getAbsolutePath().substring(
0857: root.getAbsolutePath().length() + 1);
0858:
0859: if (file.isDirectory()) {
0860: output.putNextEntry(new ZipEntry(entryName + SLASH));
0861:
0862: final File[] children = file.listFiles();
0863: if (children != null) {
0864: for (File child : children) {
0865: zip(child, output, root, excludes);
0866: }
0867: }
0868: } else {
0869: output.putNextEntry(new ZipEntry(entryName));
0870: StreamUtils.transferFile(file, output);
0871: }
0872: }
0873:
0874: public static FilesList unzip(final File source, final File target)
0875: throws IOException {
0876: return extractAll(source, target, null, new Progress());
0877: }
0878:
0879: public static FilesList unzip(final File source, final File target,
0880: final Progress progress) throws IOException {
0881: return extractAll(source, target, null, progress);
0882: }
0883:
0884: public static FilesList unjar(final File source, final File target)
0885: throws IOException, XMLException {
0886: return unjar(source, target, new Progress());
0887: }
0888:
0889: public static FilesList unjar(final File source, final File target,
0890: final Progress progress) throws IOException, XMLException {
0891: return extractAll(source, target, METAINF_MASK, progress);
0892: }
0893:
0894: public static boolean zipEntryExists(final File file,
0895: final String entry) throws IOException {
0896: ZipFile zip = new ZipFile(file);
0897:
0898: try {
0899: return zip.getEntry(entry) != null;
0900: } finally {
0901: zip.close();
0902: }
0903: }
0904:
0905: public static boolean jarEntryExists(final File file,
0906: final String entry) throws IOException {
0907: JarFile jar = new JarFile(file);
0908:
0909: try {
0910: return jar.getEntry(entry) != null;
0911: } finally {
0912: jar.close();
0913: }
0914: }
0915:
0916: public static File extractJarEntry(final String entry,
0917: final File source) throws IOException {
0918: return extractJarEntry(entry, source, FileUtils
0919: .createTempFile());
0920: }
0921:
0922: public static File extractJarEntry(final String entry,
0923: final File source, final File target) throws IOException {
0924: JarFile jar = new JarFile(source);
0925: FileOutputStream out = new FileOutputStream(target);
0926:
0927: try {
0928: StreamUtils.transferData(jar.getInputStream(jar
0929: .getEntry(entry)), out);
0930:
0931: return target;
0932: } finally {
0933: jar.close();
0934: out.close();
0935: }
0936: }
0937:
0938: public static String getJarAttribute(final File file,
0939: final String name) throws IOException {
0940: JarFile jar = new JarFile(file);
0941:
0942: try {
0943: return jar.getManifest().getMainAttributes().getValue(name);
0944: } finally {
0945: try {
0946: jar.close();
0947: } catch (IOException e) {
0948: ErrorManager.notifyDebug(ResourceUtils.getString(
0949: FileUtils.class, ERROR_CANT_CLOSE_JAR_KEY, jar
0950: .getName()), e);
0951: }
0952: }
0953: }
0954:
0955: // pack200/unpack200 ////////////////////////////////////////////////////////////
0956: public static File pack(final File source) throws IOException {
0957: final File target = new File(source.getParentFile(), source
0958: .getName()
0959: + PACK_GZ_SUFFIX);
0960: if (SystemUtils.isWindows()
0961: && source.getAbsolutePath().length() > 255) {
0962: /*
0963: * WORKAROUND for two issues (and 6612389 in BugTrack):
0964: * http://www.netbeans.org/issues/show_bug.cgi?id=96548
0965: * http://www.netbeans.org/issues/show_bug.cgi?id=97984
0966: * The issue is that unpack200/pack200 doesn`t support long path names
0967: * Copy source to tmp dir, unpack it there and copy to target.
0968: */
0969: File tmpSource = null;
0970: File tmpTarget = null;
0971: try {
0972: tmpSource = File.createTempFile(source.getName(),
0973: ".jar");
0974: copyFile(source, tmpSource);
0975: tmpTarget = pack(tmpSource);
0976: deleteFile(tmpSource);
0977: tmpSource = null;
0978: copyFile(tmpTarget, target);
0979: deleteFile(tmpTarget);
0980: tmpTarget = null;
0981: } finally {
0982: if (tmpSource != null) {
0983: deleteFile(tmpSource);
0984: }
0985: if (tmpTarget != null) {
0986: deleteFile(tmpTarget);
0987: }
0988: }
0989: } else {
0990: ExecutionResults er = SystemUtils.executeCommand(
0991: SystemUtils.getPacker().getAbsolutePath(), target
0992: .getAbsolutePath(), source
0993: .getAbsolutePath());
0994: if (er.getErrorCode() != 0) {
0995: throw new IOException(ResourceUtils.getString(
0996: FileUtils.class, ERROR_PACK200_FAILED_KEY, er
0997: .getErrorCode(), er.getStdOut(), er
0998: .getStdErr()));
0999: }
1000: }
1001:
1002: return target;
1003: }
1004:
1005: public static File unpack(final File source) throws IOException {
1006: final String name = source.getName();
1007: final File target = new File(source.getParentFile(), name
1008: .substring(0, name.length() - PACK_GZ_SUFFIX.length()));
1009:
1010: if (SystemUtils.isWindows()
1011: && source.getAbsolutePath().length() > 255) {
1012: /*
1013: * WORKAROUND for two issues (and 6612389 in BugTrack):
1014: * http://www.netbeans.org/issues/show_bug.cgi?id=96548
1015: * http://www.netbeans.org/issues/show_bug.cgi?id=97984
1016: * The issue is that unpack200/pack200 doesn`t support long path names
1017: * Copy source to tmp dir, unpack it there and copy to target.
1018: */
1019: File tmpSource = null;
1020: File tmpTarget = null;
1021: try {
1022: tmpSource = File.createTempFile(target.getName(),
1023: ".tmp" + PACK_GZ_SUFFIX);
1024: copyFile(source, tmpSource);
1025: tmpTarget = unpack(tmpSource);
1026: deleteFile(tmpSource);
1027: tmpSource = null;
1028: copyFile(tmpTarget, target);
1029: deleteFile(tmpTarget);
1030: tmpTarget = null;
1031: } finally {
1032: if (tmpSource != null) {
1033: deleteFile(tmpSource);
1034: }
1035: if (tmpTarget != null) {
1036: deleteFile(tmpTarget);
1037: }
1038: }
1039: } else {
1040: ExecutionResults er = SystemUtils.executeCommand(
1041: SystemUtils.getUnpacker().getAbsolutePath(), source
1042: .getAbsolutePath(), target
1043: .getAbsolutePath());
1044: if (er.getErrorCode() != 0) {
1045: if (er.getErrorCode() == -1073741801) {
1046: // Workaround for the issue in lvprcsrv.exe process
1047: // http://www.netbeans.org/issues/show_bug.cgi?id=117334
1048: LogManager.log("\n\n");
1049: LogManager.log("Attention!");
1050: LogManager
1051: .log("You have run into the Issue 117334");
1052: LogManager
1053: .log("http://www.netbeans.org/issues/show_bug.cgi?id=117334");
1054: LogManager
1055: .log("This is the result of error in process lvprcsrv.exe (Logitech QuickCam)");
1056: LogManager
1057: .log("You should turn it off if you have had any issues during installations");
1058: LogManager.log("\n\n");
1059: } else {
1060: throw new IOException(ResourceUtils.getString(
1061: FileUtils.class,
1062: ERROR_UNPACK200_FAILED_KEY, er
1063: .getErrorCode(), er.getStdOut(), er
1064: .getStdErr()));
1065: }
1066: }
1067: }
1068: return target;
1069: }
1070:
1071: // miscellaneous ////////////////////////////////////////////////////////////////
1072: public static FilesList mkdirs(final File file) throws IOException {
1073: FilesList list = new FilesList();
1074:
1075: if (!exists(file.getParentFile())) {
1076: list.add(mkdirs(file.getParentFile()));
1077: }
1078:
1079: if (exists(file) && file.isFile()) {
1080: throw new IOException(ResourceUtils.getString(
1081: FileUtils.class,
1082: ERROR_CANT_CREATE_DIR_EXIST_FILE_KEY, file));
1083: }
1084:
1085: if (!exists(file)) {
1086: if (file.mkdir()) {
1087: list.add(file);
1088: } else {
1089: throw new IOException(ResourceUtils.getString(
1090: FileUtils.class, ERROR_CANT_CREATE_DIR_KEY,
1091: file));
1092: }
1093: }
1094:
1095: return list;
1096: }
1097:
1098: public static String getRelativePath(final File source,
1099: final File target) {
1100: String path;
1101:
1102: if (source.equals(target)) { // simplest - source equals target
1103: path = source.isDirectory() ? CURRENT : target.getName();
1104: } else if (isParent(source, target)) { // simple - source is target's parent
1105: final String sourcePath = source.getAbsolutePath().replace(
1106: BACKSLASH, SLASH);
1107: final String targetPath = target.getAbsolutePath().replace(
1108: BACKSLASH, SLASH);
1109:
1110: if (sourcePath.endsWith(SLASH)) {
1111: path = targetPath.substring(sourcePath.length());
1112: } else {
1113: path = targetPath.substring(sourcePath.length() + 1);
1114: }
1115: } else if (isParent(target, source)) { // simple - target is source's parent
1116: path = source.isDirectory() ? PARENT : CURRENT;
1117:
1118: File parent = source.getParentFile();
1119: while (!parent.equals(target)) {
1120: path += SLASH + PARENT;
1121: parent = parent.getParentFile();
1122: }
1123: } else { // tricky - the files are unrelated
1124: // first we need to find a common parent for the files
1125: File parent = source.getParentFile();
1126: while ((parent != null) && !isParent(parent, target)) {
1127: parent = parent.getParentFile();
1128: }
1129:
1130: // if there is no common parent, we cannot deduct a relative path
1131: if (parent == null) {
1132: return null;
1133: }
1134:
1135: path = getRelativePath(source, parent) + SLASH
1136: + getRelativePath(parent, target);
1137: }
1138:
1139: // some final beautification
1140: if (path.startsWith(CURRENT + SLASH)) {
1141: if (path.length() > 2) {
1142: path = path.substring(2);
1143: } else {
1144: path = path.substring(0, 1);
1145: }
1146: }
1147: path = path.replace(SLASH + CURRENT + SLASH, SLASH);
1148:
1149: return path;
1150: }
1151:
1152: public static boolean isUNCPath(String path) {
1153: return SystemUtils.getNativeUtils().isUNCPath(path);
1154: }
1155:
1156: public static File eliminateRelativity(final String path) {
1157: String corrected = path;
1158:
1159: if (SystemUtils.isWindows() && isUNCPath(corrected)) {
1160: // don`t correct UNC paths that starts with \\<servername>
1161: corrected = corrected.substring(0, 2)
1162: + corrected.substring(2).replace(BACKSLASH, SLASH);
1163: } else {
1164: corrected = corrected.replace(BACKSLASH, SLASH);
1165: }
1166:
1167: while (corrected.indexOf(SLASH + SLASH) != -1) {
1168: corrected = corrected.replace(SLASH + SLASH, SLASH);
1169: }
1170:
1171: while (corrected.indexOf(SLASH + CURRENT + SLASH) != -1) {
1172: corrected = corrected.replace(SLASH + CURRENT + SLASH,
1173: SLASH);
1174: }
1175:
1176: final Pattern pattern = Pattern
1177: .compile("(\\/([^\\/]+)\\/\\.\\.\\/)");
1178:
1179: Matcher matcher = pattern.matcher(corrected);
1180: while (matcher.find()) {
1181: if (matcher.group(2).equals(PARENT)) {
1182: continue;
1183: } else {
1184: corrected = corrected.replace(matcher.group(), SLASH);
1185: matcher = pattern.matcher(corrected);
1186: }
1187: }
1188:
1189: if (corrected.endsWith(SLASH + CURRENT)) {
1190: corrected = corrected.substring(0, corrected.length()
1191: - SLASH.length() - CURRENT.length());
1192: }
1193:
1194: if (corrected.endsWith(SLASH + PARENT)) {
1195: int index = corrected.lastIndexOf(SLASH, corrected.length()
1196: - SLASH.length() - PARENT.length() - 1);
1197: if (index != -1) {
1198: corrected = corrected.substring(0, index);
1199: }
1200: }
1201:
1202: return new File(corrected);
1203: }
1204:
1205: public static File getRoot(final File file) {
1206: return SystemUtils.getNativeUtils().getRoot(file);
1207: }
1208:
1209: public static File findFile(final File directory,
1210: final String filename) {
1211: if (directory.getName().equals(filename)) {
1212: return directory;
1213: }
1214:
1215: final File[] children = directory.listFiles();
1216: if (children != null) {
1217: for (File child : children) {
1218: final File match = findFile(child, filename);
1219:
1220: if (match != null) {
1221: return match;
1222: }
1223: }
1224: }
1225:
1226: return null;
1227: }
1228:
1229: // private //////////////////////////////////////////////////////////////////////
1230: private static long deleteFile(final File file,
1231: final boolean recurse, final Progress progress,
1232: final long start, final long total) throws IOException {
1233: long count = start;
1234:
1235: if (SystemUtils.isDeletingAllowed(file)) {
1236: final boolean isDir = file.isDirectory();
1237: final String type = (isDir) ? "directory" : "file";
1238: if (isDir && recurse) {
1239: final File[] children = file.listFiles();
1240: if (children != null) {
1241: for (File child : children) {
1242: count = deleteFile(child, true, progress,
1243: count, total);
1244: }
1245: }
1246: }
1247:
1248: LogManager.log("deleting " + type + ": " + file);
1249:
1250: progress.setDetail(StringUtils.format(
1251: isDir ? MESSAGE_DELETE_DIR : MESSAGE_DELETE_FILE,
1252: file));
1253:
1254: if (!exists(file)) {
1255: LogManager.log(" ... " + type + " does not exist");
1256: SystemUtils.getNativeUtils().removeDeleteOnExitFile(
1257: file);
1258: } else {
1259: if (!file.delete()) {
1260: deleteOnExit(file);
1261: }
1262: }
1263:
1264: count++;
1265: progress.setPercentage(Progress.COMPLETE * count / total);
1266: }
1267:
1268: return count;
1269: }
1270:
1271: private static long copyFile(final File source, final File target,
1272: final boolean recurse, final FilesList list,
1273: final Progress progress, final long start, final long total)
1274: throws IOException {
1275: long count = start;
1276:
1277: if (!exists(source)) {
1278: LogManager.log(" ... " + source + " does not exist");
1279: return count;
1280: }
1281:
1282: if (source.isFile()) {
1283: LogManager
1284: .log("copying file: " + source + " to: " + target);
1285: progress.setDetail(StringUtils.format(MESSAGE_COPY_FILE,
1286: source, target));
1287:
1288: if (!source.canRead()) {
1289: throw new IOException(ResourceUtils.getString(
1290: FileUtils.class, ERROR_SOURCE_NOT_READABLE_KEY,
1291: source));
1292: }
1293:
1294: if (exists(target) && !target.isFile()) {
1295: throw new IOException(ResourceUtils.getString(
1296: FileUtils.class, ERROR_DEST_NOT_FILE_KEY,
1297: target));
1298: }
1299:
1300: File parent = target.getParentFile();
1301: if (!exists(parent)) {
1302: list.add(mkdirs(parent));
1303: }
1304:
1305: if (!exists(target) && !target.createNewFile()) {
1306: throw new IOException(ResourceUtils.getString(
1307: FileUtils.class, ERROR_DEST_CREATION_KEY,
1308: target));
1309: }
1310:
1311: if (!target.canWrite()) {
1312: throw new IOException(ResourceUtils.getString(
1313: FileUtils.class, ERROR_DEST_NOT_WRITABLE_KEY,
1314: target));
1315: }
1316:
1317: FileInputStream in = null;
1318: FileOutputStream out = null;
1319: try {
1320: StreamUtils.transferData(in = new FileInputStream(
1321: source), out = new FileOutputStream(target));
1322: list.add(target);
1323: } finally {
1324: try {
1325: out.close();
1326: } catch (IOException e) {
1327: ErrorManager
1328: .notifyDebug(ResourceUtils.getString(
1329: FileUtils.class,
1330: ERROR_CLOSE_STREAM_KEY), e);
1331: }
1332: try {
1333: in.close();
1334: } catch (IOException e) {
1335: ErrorManager
1336: .notifyDebug(ResourceUtils.getString(
1337: FileUtils.class,
1338: ERROR_CLOSE_STREAM_KEY), e);
1339: }
1340: }
1341: } else {
1342: LogManager.log("copying directory: " + source + " to: "
1343: + target + (recurse ? " with recursion" : ""));
1344: progress.setDetail(StringUtils.format(
1345: MESSAGE_COPY_DIRECTORY, source, target));
1346:
1347: list.add(mkdirs(target));
1348: if (recurse) {
1349: for (File file : source.listFiles()) {
1350: count = copyFile(file, new File(target, file
1351: .getName()), recurse, list, progress,
1352: count, total);
1353: }
1354: }
1355: }
1356:
1357: count++;
1358: progress.setPercentage(Progress.COMPLETE * count / total);
1359:
1360: return count;
1361: }
1362:
1363: private static boolean canAccessDirectoryReal(final File file,
1364: final boolean isReadNotWrite) {
1365: if (isReadNotWrite) {
1366: boolean result = (file.listFiles() != null);
1367: // LogManager.indent();
1368: // LogManager.log(ErrorLevel.DEBUG, "READ: Real Level Access DIR: " + ((result) ? "TRUE" : "FALSE"));
1369: // LogManager.unindent();
1370: return result;
1371: } else {
1372: try {
1373: FileUtils.createTempFile(file).delete();
1374: // LogManager.indent();
1375: // LogManager.log(ErrorLevel.DEBUG, "WRITE: Real Level Access DIR: TRUE");
1376: // LogManager.unindent();
1377: return true;
1378: } catch (IOException e) {
1379: // LogManager.indent();
1380: // LogManager.log(ErrorLevel.DEBUG, "WRITE: Real Level Access DIR: FALSE");
1381: // LogManager.unindent();
1382: return false;
1383: }
1384: }
1385: }
1386:
1387: private static boolean canAccessFileReal(final File file,
1388: final boolean isReadNotWrite) {
1389: Closeable stream = null;
1390: LogManager.indent();
1391: try {
1392: stream = (isReadNotWrite) ? new FileInputStream(file)
1393: : new FileOutputStream(file);
1394: //LogManager.log(ErrorLevel.DEBUG,
1395: // ((isReadNotWrite) ? "READ:" : "WRITE:") + "Real Level Access File: TRUE");
1396: return true;
1397: } catch (IOException ex) {
1398: //LogManager.log(ErrorLevel.DEBUG,
1399: // ((isReadNotWrite) ? "READ:" : "WRITE:") + "Real Level Access File: FALSE");
1400: return false;
1401: } finally {
1402: LogManager.unindent();
1403: if (stream != null) {
1404: try {
1405: stream.close();
1406: } catch (IOException ex) {
1407: LogManager.log(ex);
1408: }
1409: }
1410: }
1411: }
1412:
1413: private static boolean canAccessFile(final File fileToCheck,
1414: final boolean isReadNotWrite) {
1415: File file = fileToCheck;
1416:
1417: // if file doesn`t exist then get it existing parent
1418: if (!exists(file)) {
1419: File parent = file;
1420: do {
1421: parent = parent.getParentFile();
1422: } while ((parent != null) && !exists(parent));
1423:
1424: if ((parent == null) || !parent.isDirectory()) {
1425: return false;
1426: } else {
1427: file = parent;
1428: }
1429: }
1430:
1431: //first of all check java implementation
1432: boolean javaAccessCheck = (isReadNotWrite) ? file.canRead()
1433: : file.canWrite();
1434:
1435: // don`t treat read-only attributes for directories as "can`t write" on windows
1436: if (SystemUtils.isWindows() && !isReadNotWrite
1437: && file.isDirectory()) {
1438: javaAccessCheck = true;
1439: }
1440:
1441: if (javaAccessCheck) {
1442: boolean result = true;
1443: boolean needCheckDirectory = true;
1444:
1445: try {
1446: // Native checking
1447: result = SystemUtils.getNativeUtils().checkFileAccess(
1448: file, isReadNotWrite);
1449:
1450: if (!isReadNotWrite) {
1451: // we don`t want to check for writing if OS says smth specific
1452: needCheckDirectory = false;
1453: }
1454: } catch (NativeException ex) {
1455: // most probably there is smth wrong with OS
1456: LogManager.log(ex);
1457: }
1458:
1459: if (!result) { // some limitations by OS
1460: return false;
1461: }
1462:
1463: if (file.isFile()) {
1464: return canAccessFileReal(file, isReadNotWrite);
1465: } else if (file.isDirectory() && (needCheckDirectory)) {
1466: return canAccessDirectoryReal(file, isReadNotWrite);
1467: } else { // file is directory, access==read || (access==write & OSCheck==true)
1468: return true;
1469: }
1470: } else {
1471: return false;
1472: }
1473: }
1474:
1475: private static FilesList extractAll(final File file,
1476: final File target, final String excludes,
1477: final Progress progress) throws IOException {
1478: final FilesList list = new FilesList();
1479:
1480: // first some basic validation of the destination directory
1481: if (exists(target) && target.isFile()) {
1482: throw new IOException(ResourceUtils.getString(
1483: FileUtils.class, ERROR_UNJAR_TODIR_KEY, target));
1484: } else if (!exists(target)) {
1485: list.add(mkdirs(target));
1486: }
1487:
1488: final ZipFile zip = new ZipFile(file);
1489:
1490: try {
1491: FilesList extracted = null;
1492: boolean extractedWithList = false;
1493:
1494: // first we try to extract with the given list
1495: if (zipEntryExists(file, FILES_LIST_ENTRY)) {
1496: try {
1497: final File initialList = extractJarEntry(
1498: FILES_LIST_ENTRY, file);
1499: final FilesList toExtract = new FilesList()
1500: .loadXml(initialList, target);
1501:
1502: deleteFile(initialList);
1503: extracted = extractByList(zip, target, toExtract,
1504: progress);
1505: toExtract.clear();
1506:
1507: extractedWithList = true;
1508: } catch (XMLException e) {
1509: ErrorManager.notifyDebug(ResourceUtils.getString(
1510: FileUtils.class,
1511: ERROR_LOAD_XML_FILE_LIST_KEY), e);
1512: }
1513: }
1514:
1515: if (!extractedWithList) {
1516: extracted = extractNormal(zip, target, excludes,
1517: progress);
1518: }
1519:
1520: list.add(extracted);
1521: extracted.clear();
1522: } finally {
1523: zip.close();
1524: }
1525:
1526: return list;
1527: }
1528:
1529: private static FilesList extractByList(final ZipFile zip,
1530: final File target, final FilesList list,
1531: final Progress progress) throws IOException {
1532: final FilesList newList = new FilesList();
1533: final String targetPath = target.getAbsolutePath();
1534:
1535: final int total = list.getSize();
1536:
1537: int extracted = 0;
1538: for (FileEntry listEntry : list) {
1539: // check for cancel status
1540: if (progress.isCanceled())
1541: return newList;
1542:
1543: final String listEntryName = listEntry.getName();
1544: final File listEntryFile = listEntry.getFile();
1545:
1546: final String zipEntryName = listEntryName
1547: .substring(targetPath.length() + 1);
1548:
1549: // increase the extracted files count and update the progress percentage
1550: extracted++;
1551: progress.setPercentage(Progress.COMPLETE * extracted
1552: / total);
1553:
1554: // set the progress detail and add a log entry
1555: progress.setDetail(StringUtils.format(MESSAGE_EXTRACTING,
1556: listEntryFile));
1557: LogManager.log("extracting " + listEntryFile);
1558:
1559: if (listEntry.isDirectory()) {
1560: newList.add(mkdirs(listEntryFile));
1561: } else {
1562: final ZipEntry zipEntry = zip.getEntry(zipEntryName);
1563:
1564: newList.add(mkdirs(listEntryFile.getParentFile()));
1565:
1566: // actual data transfer
1567: InputStream in = null;
1568: OutputStream out = null;
1569: try {
1570: in = zip.getInputStream(zipEntry);
1571: out = new FileOutputStream(listEntryFile);
1572:
1573: StreamUtils.transferData(in, out);
1574: } finally {
1575: if (in != null) {
1576: in.close();
1577: }
1578: if (out != null) {
1579: out.close();
1580: }
1581: }
1582:
1583: if (listEntry.isPackedJarFile()) {
1584: final File packed = listEntry.getFile();
1585: ;
1586: final File unpacked = unpack(packed);
1587:
1588: deleteFile(packed);
1589:
1590: listEntry = new FileEntry(unpacked, listEntry
1591: .getSize(), listEntry.getMd5(), listEntry
1592: .isJarFile(), false, listEntry
1593: .isSignedJarFile(), listEntry
1594: .getLastModified(), listEntry
1595: .getPermissions());
1596: }
1597:
1598: listEntryFile.setLastModified(listEntry
1599: .getLastModified());
1600:
1601: SystemUtils.setPermissions(listEntry.getFile(),
1602: listEntry.getPermissions(),
1603: NativeUtils.FA_MODE_SET);
1604: }
1605:
1606: newList.add(listEntry);
1607: }
1608:
1609: return newList;
1610: }
1611:
1612: private static FilesList extractNormal(final ZipFile zip,
1613: final File target, final String excludes,
1614: final Progress progress) throws IOException {
1615: final FilesList list = new FilesList();
1616:
1617: Enumeration<? extends ZipEntry> entries;
1618:
1619: int total = 0;
1620: int extracted = 0;
1621:
1622: // then we count the entries, to correctly display progress
1623: entries = (Enumeration<? extends ZipEntry>) zip.entries();
1624: while (entries.hasMoreElements()) {
1625: total++;
1626: entries.nextElement();
1627: }
1628:
1629: // and only after that we actually extract them
1630: entries = (Enumeration<? extends ZipEntry>) zip.entries();
1631: while (entries.hasMoreElements()) {
1632: // check for cancel status
1633: if (progress.isCanceled())
1634: return list;
1635:
1636: final ZipEntry entry = entries.nextElement();
1637:
1638: // increase the extracted files count and update the progress percentage
1639: extracted++;
1640: progress.setPercentage(Progress.COMPLETE * extracted
1641: / total);
1642:
1643: // if the entry name matches the excludes pattern, we skip it
1644: if ((excludes != null) && entry.getName().matches(excludes)) {
1645: continue;
1646: }
1647:
1648: // create the target file for this entry
1649: final File file = new File(target, entry.getName())
1650: .getAbsoluteFile();
1651:
1652: // set the progress detail and add a log entry
1653: progress.setDetail(StringUtils.format(MESSAGE_EXTRACTING,
1654: file));
1655: LogManager.log("extracting " + file);
1656:
1657: if (entry.getName().endsWith(SLASH)) {
1658: // some validation (this is a directory entry and thus an existing
1659: // file will definitely break things)
1660: if (exists(file) && !file.isDirectory()) {
1661: throw new IOException(ResourceUtils.getString(
1662: FileUtils.class,
1663: ERROR_OUTPUT_DIR_ENTRY_KEY, file));
1664: }
1665:
1666: // if the directory does not exist, it will be created and added to
1667: // the extracted files list (if it exists already, it will not
1668: // appear in the list)
1669: if (!exists(file)) {
1670: list.add(mkdirs(file));
1671: }
1672: } else {
1673: // some validation of the file's parent directory
1674: final File parent = file.getParentFile();
1675: if (!exists(parent)) {
1676: list.add(mkdirs(parent));
1677: }
1678:
1679: // some validation of the file itself
1680: if (exists(file) && !file.isFile()) {
1681: throw new IOException(ResourceUtils.getString(
1682: FileUtils.class,
1683: ERROR_OUTPUT_FILE_ENTRY_KEY, file));
1684: }
1685:
1686: // actual data transfer
1687: InputStream in = null;
1688: OutputStream out = null;
1689: try {
1690: in = zip.getInputStream(entry);
1691: out = new FileOutputStream(file);
1692:
1693: StreamUtils.transferData(in, out);
1694: } finally {
1695: if (in != null) {
1696: in.close();
1697: }
1698: if (out != null) {
1699: out.close();
1700: }
1701: }
1702:
1703: // as opposed to directories, we always add files to the list, as
1704: // even if they exist, they will be overwritten
1705: list.add(file);
1706: }
1707:
1708: // correct the entry's modification time, so it corresponds to the real
1709: // time of the file in archive
1710: file.setLastModified(entry.getTime());
1711: }
1712:
1713: return list;
1714: }
1715:
1716: /////////////////////////////////////////////////////////////////////////////////
1717: // Instance
1718: private FileUtils() {
1719: // does nothing
1720: }
1721:
1722: /////////////////////////////////////////////////////////////////////////////////
1723: // Constants
1724: public static final int BUFFER_SIZE = 65536; // NOMAGI
1725:
1726: public static final String SLASH = "/"; // NOI18N
1727: public static final String BACKSLASH = "\\"; // NOI18N
1728: public static final String METAINF_MASK = "META-INF.*"; // NOI18N
1729:
1730: public static final String JAR_EXTENSION = ".jar"; // NOI18N
1731: public static final String PROPERTIES_EXTENSION = ".properties"; // NOI18N
1732: public static final String PACK_GZ_SUFFIX = ".pack.gz"; // NOI18N
1733: public static final String SUN_MICR_RSA = "META-INF/SUN_MICR.RSA"; // NOI18N
1734: public static final String SUN_MICR_SF = "META-INF/SUN_MICR.SF"; // NOI18N
1735: public static final String FILES_LIST_ENTRY = "META-INF/files.list";//NOI18N
1736: public static final String CURRENT = "."; // NOI18N
1737: public static final String PARENT = ".."; // NOI18N
1738: public static final String SHA1_DIGEST_NAME = "SHA1";//NOI18N
1739: public static final String MD5_DIGEST_NAME = "MD5";//NOI18N
1740: public static final String INFO_PLIST_STUB = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1741: + "<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">\n"
1742: + "<plist version=\"0.9\">\n"
1743: + " <dict>\n"
1744: + " \n"
1745: + " <key>CFBundleName</key>\n"
1746: + " <string>{0}</string>\n"
1747: + " \n"
1748: + " <key>CFBundleVersion</key>\n"
1749: + " <string>{1}</string>\n"
1750: + " \n"
1751: + " <key>CFBundleExecutable</key>\n"
1752: + " <string>{3}</string>\n"
1753: + " \n"
1754: + " <key>CFBundlePackageType</key>\n"
1755: + " <string>APPL</string>\n"
1756: + " \n"
1757: + " <key>CFBundleShortVersionString</key>\n"
1758: + " <string>{2}</string>\n"
1759: + " \n"
1760: + " <key>CFBundleSignature</key>\n"
1761: + " <string>????</string>\n"
1762: + " \n"
1763: + " <key>CFBundleInfoDictionaryVersion</key>\n"
1764: + " <string>6.0</string>\n"
1765: + " \n"
1766: + " <key>CFBundleIconFile</key>\n"
1767: + " <string>{4}</string>\n"
1768: + " </dict>\n"
1769: + "</plist>\n";
1770:
1771: public static final String ERROR_OUTPUT_FILE_ENTRY_KEY = "FU.error.output.file.entry";// NOI18N
1772:
1773: public static final String ERROR_OUTPUT_DIR_ENTRY_KEY = "FU.error.output.dir.entry";// NOI18N
1774: public static final String MESSAGE_MOVING = ResourceUtils
1775: .getString(FileUtils.class, "FU.message.moving");//NOI18N
1776: public static final String MESSAGE_EXTRACTING = ResourceUtils
1777: .getString(FileUtils.class, "FU.message.extracting");//NOI18N
1778: public static final String ERROR_LOAD_XML_FILE_LIST_KEY = "FU.error.load.xml.file.list";//NOI18N
1779: public static final String ERROR_UNJAR_TODIR_KEY = "FU.error.unjar.todir";//NOI18N
1780: public static final String MESSAGE_COPY_DIRECTORY = ResourceUtils
1781: .getString(FileUtils.class, "FU.message.copy.dir");//NOI18N
1782: public static final String MESSAGE_COPY_FILE = ResourceUtils
1783: .getString(FileUtils.class, "FU.message.copy.file");//NOI18N
1784: public static final String ERROR_CLOSE_STREAM_KEY = "FU.error.close.stream";//NOI18N
1785: public static final String ERROR_SOURCE_NOT_READABLE_KEY = "FU.error.source.not.readable";//NOI18N
1786: public static final String ERROR_DEST_NOT_FILE_KEY = "FU.error.dest.not.file";//NOI18N
1787: public static final String ERROR_DEST_CREATION_KEY = "FU.error.dest.creation";//NOI18N
1788: public static final String ERROR_DEST_NOT_WRITABLE_KEY = "FU.error.dest.not.writable";//NOI18N
1789: public static final String ERROR_CANT_GET_FREE_SPACE_KEY = "FU.error.freespace";//NOI18N
1790: public static final String ERROR_CANT_CLOSE_JAR_KEY = "FU.error.cannot.close.jar";//NOI18N
1791: public static final String ERROR_CANT_CREATE_DIR_EXIST_FILE_KEY = "FU.error.cannot.create.dir.exist.file";//NOI18N
1792: public static final String ERROR_CANT_CREATE_DIR_KEY = "FU.error.cannot.create.dir";//NOI18N
1793: public static final String ERROR_NOT_JAR_FILE_KEY = "FU.error.not.jar.file";//NOI18N
1794: public static final String ERROR_SHA1_NOT_SUPPORTED_KEY = "FU.error.sha1.not.supported";//NOI18N
1795: public static final String ERROR_MD5_NOT_SUPPORTED_KEY = "FU.error.md5.not.supported";//NOI18N
1796: public static final String ERROR_FILE_SECURITY_EXCEPTION_KEY = "FU.error.file.security.exception";//NOI18N
1797: public static final String MESSAGE_DELETE_FILE = ResourceUtils
1798: .getString(FileUtils.class, "FU.message.delete.file");//NOI18N
1799: public static final String MESSAGE_DELETE_DIR = ResourceUtils
1800: .getString(FileUtils.class, "FU.message.delete.dir");//NOI18N
1801: public static final String ERROR_PACK200_FAILED_KEY = "FU.error.pack200.failed";//NOI18N
1802: public static final String ERROR_UNPACK200_FAILED_KEY = "FU.error.unpack200.failed";//NOI18N
1803: }
|