1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 package org.apache.tools.ant.util; 19 20 import org.apache.tools.ant.BuildException; 21 import org.apache.tools.ant.taskdefs.condition.Os; 22 23 import java.io.File; 24 import java.util.Random; 25 26 /** 27 * This class also encapsulates methods which allow Files to be 28 * referred to using abstract path names which are translated to native 29 * system file paths at runtime as well as copying files or setting 30 * their last modification time. 31 * 32 */ 33 public class FileUtils { 34 private static final int DELETE_RETRY_SLEEP_MILLIS = 10; 35 private static final int EXPAND_SPACE = 50; 36 private static final FileUtils PRIMARY_INSTANCE = new FileUtils(); 37 38 //get some non-crypto-grade randomness from various places. 39 private static Random rand = new Random(System.currentTimeMillis() 40 + Runtime.getRuntime().freeMemory()); 41 42 private static final boolean ON_NETWARE = Os.isFamily("netware"); 43 private static final boolean ON_DOS = Os.isFamily("dos"); 44 private static final boolean ON_WIN9X = Os.isFamily("win9x"); 45 private static final boolean ON_WINDOWS = Os.isFamily("windows"); 46 47 static final int BUF_SIZE = 8192; 48 49 50 /** 51 * The granularity of timestamps under FAT. 52 */ 53 public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000; 54 55 /** 56 * The granularity of timestamps under Unix. 57 */ 58 public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000; 59 60 /** 61 * The granularity of timestamps under the NT File System. 62 * NTFS has a granularity of 100 nanoseconds, which is less 63 * than 1 millisecond, so we round this up to 1 millisecond. 64 */ 65 public static final long NTFS_FILE_TIMESTAMP_GRANULARITY = 1; 66 67 /** 68 * A one item cache for fromUri. 69 * fromUri is called for each element when parseing ant build 70 * files. It is a costly operation. This just caches the result 71 * of the last call. 72 */ 73 private Object cacheFromUriLock = new Object(); 74 private String cacheFromUriRequest = null; 75 private String cacheFromUriResponse = null; 76 77 /** 78 * Factory method. 79 * 80 * @return a new instance of FileUtils. 81 * @deprecated since 1.7. 82 * Use getFileUtils instead, 83 * FileUtils do not have state. 84 */ 85 @Deprecated 86 public static FileUtils newFileUtils() { 87 return new FileUtils(); 88 } 89 90 /** 91 * Method to retrieve The FileUtils, which is shared by all users of this 92 * method. 93 * @return an instance of FileUtils. 94 * @since Ant 1.6.3 95 */ 96 public static FileUtils getFileUtils() { 97 return PRIMARY_INSTANCE; 98 } 99 100 /** 101 * Empty constructor. 102 */ 103 protected FileUtils() { 104 } 105 106 /** 107 * Verifies that the specified filename represents an absolute path. 108 * Differs from new java.io.File("filename").isAbsolute() in that a path 109 * beginning with a double file separator--signifying a Windows UNC--must 110 * at minimum match "\\a\b" to be considered an absolute path. 111 * @param filename the filename to be checked. 112 * @return true if the filename represents an absolute path. 113 * @throws java.lang.NullPointerException if filename is null. 114 * @since Ant 1.6.3 115 */ 116 public static boolean isAbsolutePath(String filename) { 117 int len = filename.length(); 118 if (len == 0) { 119 return false; 120 } 121 char sep = File.separatorChar; 122 filename = filename.replace('/', sep).replace('\\', sep); 123 char c = filename.charAt(0); 124 if (!(ON_DOS || ON_NETWARE)) { 125 return (c == sep); 126 } 127 if (c == sep) { 128 // CheckStyle:MagicNumber OFF 129 if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) { 130 return false; 131 } 132 // CheckStyle:MagicNumber ON 133 int nextsep = filename.indexOf(sep, 2); 134 return nextsep > 2 && nextsep + 1 < len; 135 } 136 int colon = filename.indexOf(':'); 137 return (Character.isLetter(c) && colon == 1 138 && filename.length() > 2 && filename.charAt(2) == sep) 139 || (ON_NETWARE && colon > 0); 140 } 141 142 /** 143 * Dissect the specified absolute path. 144 * @param path the path to dissect. 145 * @return String[] {root, remaining path}. 146 * @throws java.lang.NullPointerException if path is null. 147 * @since Ant 1.7 148 */ 149 public String[] dissect(String path) { 150 char sep = File.separatorChar; 151 path = path.replace('/', sep).replace('\\', sep); 152 153 // make sure we are dealing with an absolute path 154 if (!isAbsolutePath(path)) { 155 throw new BuildException(path + " is not an absolute path"); 156 } 157 String root = null; 158 int colon = path.indexOf(':'); 159 if (colon > 0 && (ON_DOS || ON_NETWARE)) { 160 161 int next = colon + 1; 162 root = path.substring(0, next); 163 char[] ca = path.toCharArray(); 164 root += sep; 165 //remove the initial separator; the root has it. 166 next = (ca[next] == sep) ? next + 1 : next; 167 168 StringBuffer sbPath = new StringBuffer(); 169 // Eliminate consecutive slashes after the drive spec: 170 for (int i = next; i < ca.length; i++) { 171 if (ca[i] != sep || ca[i - 1] != sep) { 172 sbPath.append(ca[i]); 173 } 174 } 175 path = sbPath.toString(); 176 } else if (path.length() > 1 && path.charAt(1) == sep) { 177 // UNC drive 178 int nextsep = path.indexOf(sep, 2); 179 nextsep = path.indexOf(sep, nextsep + 1); 180 root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path; 181 path = path.substring(root.length()); 182 } else { 183 root = File.separator; 184 path = path.substring(1); 185 } 186 return new String[] {root, path}; 187 } 188 189 } 190