15716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet/*
25716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  Licensed to the Apache Software Foundation (ASF) under one or more
35716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  contributor license agreements.  See the NOTICE file distributed with
45716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  this work for additional information regarding copyright ownership.
55716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  The ASF licenses this file to You under the Apache License, Version 2.0
65716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  (the "License"); you may not use this file except in compliance with
75716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  the License.  You may obtain a copy of the License at
85716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *
95716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *
115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  Unless required by applicable law or agreed to in writing, software
125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  distributed under the License is distributed on an "AS IS" BASIS,
135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  See the License for the specific language governing permissions and
155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *  limitations under the License.
165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *
175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */
185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetpackage org.apache.tools.ant.util;
195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetimport org.apache.tools.ant.BuildException;
215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetimport org.apache.tools.ant.taskdefs.condition.Os;
225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetimport java.io.File;
245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetimport java.util.Random;
255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet/**
275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * This class also encapsulates methods which allow Files to be
285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * referred to using abstract path names which are translated to native
295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * system file paths at runtime as well as copying files or setting
305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * their last modification time.
315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet *
325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */
335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetpublic class FileUtils {
345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private static final int DELETE_RETRY_SLEEP_MILLIS = 10;
355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private static final int EXPAND_SPACE = 50;
365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private static final FileUtils PRIMARY_INSTANCE = new FileUtils();
375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    //get some non-crypto-grade randomness from various places.
395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private static Random rand = new Random(System.currentTimeMillis()
405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            + Runtime.getRuntime().freeMemory());
415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private static final boolean ON_NETWARE = Os.isFamily("netware");
435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private static final boolean ON_DOS = Os.isFamily("dos");
445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private static final boolean ON_WIN9X = Os.isFamily("win9x");
455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private static final boolean ON_WINDOWS = Os.isFamily("windows");
465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    static final int BUF_SIZE = 8192;
485716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
495716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
505716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
515716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * The granularity of timestamps under FAT.
525716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
535716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000;
545716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
555716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
565716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * The granularity of timestamps under Unix.
575716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
585716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000;
595716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
605716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
615716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * The granularity of timestamps under the NT File System.
625716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * NTFS has a granularity of 100 nanoseconds, which is less
635716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * than 1 millisecond, so we round this up to 1 millisecond.
645716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
655716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    public static final long NTFS_FILE_TIMESTAMP_GRANULARITY = 1;
665716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
675716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
685716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * A one item cache for fromUri.
695716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * fromUri is called for each element when parseing ant build
705716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * files. It is a costly operation. This just caches the result
715716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * of the last call.
725716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
735716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private Object cacheFromUriLock = new Object();
745716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private String cacheFromUriRequest = null;
755716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    private String cacheFromUriResponse = null;
765716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
775716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
785716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * Factory method.
795716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     *
805716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @return a new instance of FileUtils.
815716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @deprecated since 1.7.
825716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     *             Use getFileUtils instead,
835716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * FileUtils do not have state.
845716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
855716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    @Deprecated
865716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    public static FileUtils newFileUtils() {
875716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        return new FileUtils();
885716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    }
895716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
905716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
915716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * Method to retrieve The FileUtils, which is shared by all users of this
925716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * method.
935716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @return an instance of FileUtils.
945716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @since Ant 1.6.3
955716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
965716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    public static FileUtils getFileUtils() {
975716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        return PRIMARY_INSTANCE;
985716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    }
995716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
1005716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
1015716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * Empty constructor.
1025716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
1035716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    protected FileUtils() {
1045716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    }
1055716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
1065716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
1075716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * Verifies that the specified filename represents an absolute path.
1085716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * Differs from new java.io.File("filename").isAbsolute() in that a path
1095716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * beginning with a double file separator--signifying a Windows UNC--must
1105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * at minimum match "\\a\b" to be considered an absolute path.
1115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @param filename the filename to be checked.
1125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @return true if the filename represents an absolute path.
1135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @throws java.lang.NullPointerException if filename is null.
1145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @since Ant 1.6.3
1155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
1165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    public static boolean isAbsolutePath(String filename) {
1175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        int len = filename.length();
1185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        if (len == 0) {
1195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            return false;
1205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        }
1215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        char sep = File.separatorChar;
1225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        filename = filename.replace('/', sep).replace('\\', sep);
1235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        char c = filename.charAt(0);
1245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        if (!(ON_DOS || ON_NETWARE)) {
1255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            return (c == sep);
1265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        }
1275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        if (c == sep) {
1285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            // CheckStyle:MagicNumber OFF
1295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) {
1305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet                return false;
1315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            }
1325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            // CheckStyle:MagicNumber ON
1335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            int nextsep = filename.indexOf(sep, 2);
1345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            return nextsep > 2 && nextsep + 1 < len;
1355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        }
1365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        int colon = filename.indexOf(':');
1375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        return (Character.isLetter(c) && colon == 1
1385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet                && filename.length() > 2 && filename.charAt(2) == sep)
1395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet                || (ON_NETWARE && colon > 0);
1405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    }
1415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
1425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    /**
1435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * Dissect the specified absolute path.
1445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @param path the path to dissect.
1455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @return String[] {root, remaining path}.
1465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @throws java.lang.NullPointerException if path is null.
1475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     * @since Ant 1.7
1485716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet     */
1495716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    public String[] dissect(String path) {
1505716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        char sep = File.separatorChar;
1515716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        path = path.replace('/', sep).replace('\\', sep);
1525716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
1535716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        // make sure we are dealing with an absolute path
1545716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        if (!isAbsolutePath(path)) {
1555716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            throw new BuildException(path + " is not an absolute path");
1565716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        }
1575716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        String root = null;
1585716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        int colon = path.indexOf(':');
1595716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        if (colon > 0 && (ON_DOS || ON_NETWARE)) {
1605716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
1615716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            int next = colon + 1;
1625716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            root = path.substring(0, next);
1635716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            char[] ca = path.toCharArray();
1645716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            root += sep;
1655716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            //remove the initial separator; the root has it.
1665716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            next = (ca[next] == sep) ? next + 1 : next;
1675716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
1685716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            StringBuffer sbPath = new StringBuffer();
1695716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            // Eliminate consecutive slashes after the drive spec:
1705716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            for (int i = next; i < ca.length; i++) {
1715716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet                if (ca[i] != sep || ca[i - 1] != sep) {
1725716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet                    sbPath.append(ca[i]);
1735716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet                }
1745716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            }
1755716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            path = sbPath.toString();
1765716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        } else if (path.length() > 1 && path.charAt(1) == sep) {
1775716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            // UNC drive
1785716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            int nextsep = path.indexOf(sep, 2);
1795716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            nextsep = path.indexOf(sep, nextsep + 1);
1805716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path;
1815716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            path = path.substring(root.length());
1825716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        } else {
1835716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            root = File.separator;
1845716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet            path = path.substring(1);
1855716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        }
1865716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet        return new String[] {root, path};
1875716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet    }
1885716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet
1895716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet}
190