You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

FileUtils.java 32 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2001-2002 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant.util;
  55. import java.io.BufferedInputStream;
  56. import java.io.BufferedReader;
  57. import java.io.BufferedWriter;
  58. import java.io.File;
  59. import java.io.FileInputStream;
  60. import java.io.FileOutputStream;
  61. import java.io.FileReader;
  62. import java.io.FileWriter;
  63. import java.io.IOException;
  64. import java.io.InputStream;
  65. import java.io.InputStreamReader;
  66. import java.io.OutputStreamWriter;
  67. import java.io.Reader;
  68. import java.lang.reflect.Method;
  69. import java.net.MalformedURLException;
  70. import java.net.URL;
  71. import java.text.DecimalFormat;
  72. import java.util.Random;
  73. import java.util.Stack;
  74. import java.util.StringTokenizer;
  75. import java.util.Vector;
  76. import org.apache.tools.ant.BuildException;
  77. import org.apache.tools.ant.Project;
  78. import org.apache.tools.ant.filters.util.ChainReaderHelper;
  79. import org.apache.tools.ant.taskdefs.condition.Os;
  80. import org.apache.tools.ant.types.FilterSetCollection;
  81. /**
  82. * This class also encapsulates methods which allow Files to be
  83. * refered to using abstract path names which are translated to native
  84. * system file paths at runtime as well as copying files or setting
  85. * there last modification time.
  86. *
  87. * @author duncan@x180.com
  88. * @author Conor MacNeill
  89. * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
  90. * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a>
  91. * @author <a href="mailto:jtulley@novell.com">Jeff Tulley</a>
  92. *
  93. * @version $Revision$
  94. */
  95. public class FileUtils {
  96. private static Random rand = new Random(System.currentTimeMillis());
  97. private static Object lockReflection = new Object();
  98. private static java.lang.reflect.Method setLastModified = null;
  99. private boolean onNetWare = Os.isFamily("netware");
  100. /**
  101. * Factory method.
  102. */
  103. public static FileUtils newFileUtils() {
  104. return new FileUtils();
  105. }
  106. /**
  107. * Empty constructor.
  108. */
  109. protected FileUtils() {}
  110. /**
  111. * Get the URL for a file taking into account # characters
  112. *
  113. * @param file the file whose URL representation is required.
  114. * @return The FileURL value
  115. * @throws MalformedURLException if the URL representation cannot be
  116. * formed.
  117. */
  118. public URL getFileURL(File file) throws MalformedURLException {
  119. String uri = "file:" + file.getAbsolutePath().replace('\\', '/');
  120. for (int i = uri.indexOf('#'); i != -1; i = uri.indexOf('#')) {
  121. uri = uri.substring(0, i) + "%23" + uri.substring(i + 1);
  122. }
  123. if (file.isDirectory()) {
  124. uri += "/";
  125. }
  126. return new URL(uri);
  127. }
  128. /**
  129. * Convienence method to copy a file from a source to a destination.
  130. * No filtering is performed.
  131. *
  132. * @throws IOException
  133. */
  134. public void copyFile(String sourceFile, String destFile) throws IOException {
  135. copyFile(new File(sourceFile), new File(destFile), null, false, false);
  136. }
  137. /**
  138. * Convienence method to copy a file from a source to a destination
  139. * specifying if token filtering must be used.
  140. *
  141. * @throws IOException
  142. */
  143. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters)
  144. throws IOException {
  145. copyFile(new File(sourceFile), new File(destFile), filters, false, false);
  146. }
  147. /**
  148. * Convienence method to copy a file from a source to a
  149. * destination specifying if token filtering must be used and if
  150. * source files may overwrite newer destination files.
  151. *
  152. * @throws IOException
  153. */
  154. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
  155. boolean overwrite) throws IOException {
  156. copyFile(new File(sourceFile), new File(destFile), filters,
  157. overwrite, false);
  158. }
  159. /**
  160. * Convienence method to copy a file from a source to a
  161. * destination specifying if token filtering must be used, if
  162. * source files may overwrite newer destination files and the
  163. * last modified time of <code>destFile</code> file should be made equal
  164. * to the last modified time of <code>sourceFile</code>.
  165. *
  166. * @throws IOException
  167. */
  168. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
  169. boolean overwrite, boolean preserveLastModified)
  170. throws IOException {
  171. copyFile(new File(sourceFile), new File(destFile), filters,
  172. overwrite, preserveLastModified);
  173. }
  174. /**
  175. * Convienence method to copy a file from a source to a
  176. * destination specifying if token filtering must be used, if
  177. * source files may overwrite newer destination files and the
  178. * last modified time of <code>destFile</code> file should be made equal
  179. * to the last modified time of <code>sourceFile</code>.
  180. *
  181. * @throws IOException
  182. *
  183. * @since 1.14, Ant 1.5
  184. */
  185. public void copyFile(String sourceFile, String destFile,
  186. FilterSetCollection filters, boolean overwrite,
  187. boolean preserveLastModified, String encoding)
  188. throws IOException {
  189. copyFile(new File(sourceFile), new File(destFile), filters,
  190. overwrite, preserveLastModified, encoding);
  191. }
  192. /**
  193. * Convienence method to copy a file from a source to a
  194. * destination specifying if token filtering must be used, if
  195. * filter chains must be used, if source files may overwrite
  196. * newer destination files and the last modified time of
  197. * <code>destFile</code> file should be made equal
  198. * to the last modified time of <code>sourceFile</code>.
  199. *
  200. * @throws IOException
  201. *
  202. * @since 1.15, Ant 1.5
  203. */
  204. public void copyFile(String sourceFile, String destFile,
  205. FilterSetCollection filters, Vector filterChains,
  206. boolean overwrite, boolean preserveLastModified,
  207. String encoding, Project project)
  208. throws IOException {
  209. copyFile(new File(sourceFile), new File(destFile), filters,
  210. filterChains, overwrite, preserveLastModified,
  211. encoding, project);
  212. }
  213. /**
  214. * Convienence method to copy a file from a source to a destination.
  215. * No filtering is performed.
  216. *
  217. * @throws IOException
  218. */
  219. public void copyFile(File sourceFile, File destFile) throws IOException {
  220. copyFile(sourceFile, destFile, null, false, false);
  221. }
  222. /**
  223. * Convienence method to copy a file from a source to a destination
  224. * specifying if token filtering must be used.
  225. *
  226. * @throws IOException
  227. */
  228. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters)
  229. throws IOException {
  230. copyFile(sourceFile, destFile, filters, false, false);
  231. }
  232. /**
  233. * Convienence method to copy a file from a source to a
  234. * destination specifying if token filtering must be used and if
  235. * source files may overwrite newer destination files.
  236. *
  237. * @throws IOException
  238. */
  239. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
  240. boolean overwrite) throws IOException {
  241. copyFile(sourceFile, destFile, filters, overwrite, false);
  242. }
  243. /**
  244. * Convienence method to copy a file from a source to a
  245. * destination specifying if token filtering must be used, if
  246. * source files may overwrite newer destination files and the
  247. * last modified time of <code>destFile</code> file should be made equal
  248. * to the last modified time of <code>sourceFile</code>.
  249. *
  250. * @throws IOException
  251. */
  252. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
  253. boolean overwrite, boolean preserveLastModified)
  254. throws IOException {
  255. copyFile(sourceFile, destFile, filters, overwrite,
  256. preserveLastModified, null);
  257. }
  258. /**
  259. * Convienence method to copy a file from a source to a
  260. * destination specifying if token filtering must be used, if
  261. * source files may overwrite newer destination files, the last
  262. * modified time of <code>destFile</code> file should be made
  263. * equal to the last modified time of <code>sourceFile</code> and
  264. * which character encoding to assume.
  265. *
  266. * @throws IOException
  267. *
  268. * @since 1.14, Ant 1.5
  269. */
  270. public void copyFile(File sourceFile, File destFile,
  271. FilterSetCollection filters, boolean overwrite,
  272. boolean preserveLastModified, String encoding)
  273. throws IOException {
  274. copyFile(sourceFile, destFile, filters, null, overwrite,
  275. preserveLastModified, encoding, null);
  276. }
  277. /**
  278. * Convienence method to copy a file from a source to a
  279. * destination specifying if token filtering must be used, if
  280. * filter chains must be used, if source files may overwrite
  281. * newer destination files and the last modified time of
  282. * <code>destFile</code> file should be made equal
  283. * to the last modified time of <code>sourceFile</code>.
  284. *
  285. * @throws IOException
  286. *
  287. * @since 1.15, Ant 1.5
  288. */
  289. public void copyFile(File sourceFile, File destFile,
  290. FilterSetCollection filters, Vector filterChains,
  291. boolean overwrite, boolean preserveLastModified,
  292. String encoding, Project project)
  293. throws IOException {
  294. if (overwrite || !destFile.exists() ||
  295. destFile.lastModified() < sourceFile.lastModified()) {
  296. if (destFile.exists() && destFile.isFile()) {
  297. destFile.delete();
  298. }
  299. // ensure that parent dir of dest file exists!
  300. // not using getParentFile method to stay 1.1 compat
  301. File parent = getParentFile(destFile);
  302. if (!parent.exists()) {
  303. parent.mkdirs();
  304. }
  305. final boolean filterSetsAvailable = (filters != null
  306. && filters.hasFilters());
  307. final boolean filterChainsAvailable = (filterChains != null
  308. && filterChains.size() > 0);
  309. if (filterSetsAvailable || filterChainsAvailable) {
  310. BufferedReader in = null;
  311. BufferedWriter out = null;
  312. try {
  313. if (encoding == null) {
  314. in = new BufferedReader(new FileReader(sourceFile));
  315. out = new BufferedWriter(new FileWriter(destFile));
  316. } else {
  317. in =
  318. new BufferedReader(new InputStreamReader(
  319. new FileInputStream(sourceFile),
  320. encoding));
  321. out =
  322. new BufferedWriter(new OutputStreamWriter(
  323. new FileOutputStream(destFile),
  324. encoding));
  325. }
  326. if (filterChainsAvailable) {
  327. ChainReaderHelper crh = new ChainReaderHelper();
  328. crh.setBufferSize(8192);
  329. crh.setPrimaryReader(in);
  330. crh.setFilterChains(filterChains);
  331. crh.setProject(project);
  332. Reader rdr = crh.getAssembledReader();
  333. in = new BufferedReader(rdr);
  334. }
  335. int length;
  336. String newline = null;
  337. String line = in.readLine();
  338. while (line != null) {
  339. if (line.length() == 0) {
  340. out.newLine();
  341. } else {
  342. if (filterSetsAvailable) {
  343. newline = filters.replaceTokens(line);
  344. } else {
  345. newline = line;
  346. }
  347. out.write(newline);
  348. out.newLine();
  349. }
  350. line = in.readLine();
  351. }
  352. } finally {
  353. if (out != null) {
  354. out.close();
  355. }
  356. if (in != null) {
  357. in.close();
  358. }
  359. }
  360. } else {
  361. FileInputStream in = null;
  362. FileOutputStream out = null;
  363. try {
  364. in = new FileInputStream(sourceFile);
  365. out = new FileOutputStream(destFile);
  366. byte[] buffer = new byte[8 * 1024];
  367. int count = 0;
  368. do {
  369. out.write(buffer, 0, count);
  370. count = in.read(buffer, 0, buffer.length);
  371. } while (count != -1);
  372. } finally {
  373. if (out != null) {
  374. out.close();
  375. }
  376. if (in != null) {
  377. in.close();
  378. }
  379. }
  380. }
  381. if (preserveLastModified) {
  382. setFileLastModified(destFile, sourceFile.lastModified());
  383. }
  384. }
  385. }
  386. /**
  387. * see whether we have a setLastModified method in File and return it.
  388. */
  389. protected final Method getSetLastModified() {
  390. if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
  391. return null;
  392. }
  393. if (setLastModified == null) {
  394. synchronized (lockReflection) {
  395. if (setLastModified == null) {
  396. try {
  397. setLastModified =
  398. java.io.File.class.getMethod("setLastModified",
  399. new Class[] {Long.TYPE});
  400. } catch (NoSuchMethodException nse) {
  401. throw new BuildException("File.setlastModified not in JDK > 1.1?",
  402. nse);
  403. }
  404. }
  405. }
  406. }
  407. return setLastModified;
  408. }
  409. /**
  410. * Calls File.setLastModified(long time) in a Java 1.1 compatible way.
  411. */
  412. public void setFileLastModified(File file, long time) throws BuildException {
  413. if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
  414. return;
  415. }
  416. Long[] times = new Long[1];
  417. if (time < 0) {
  418. times[0] = new Long(System.currentTimeMillis());
  419. } else {
  420. times[0] = new Long(time);
  421. }
  422. try {
  423. getSetLastModified().invoke(file, times);
  424. } catch (java.lang.reflect.InvocationTargetException ite) {
  425. Throwable nested = ite.getTargetException();
  426. throw new BuildException("Exception setting the modification time "
  427. + "of " + file, nested);
  428. } catch (Throwable other) {
  429. throw new BuildException("Exception setting the modification time "
  430. + "of " + file, other);
  431. }
  432. }
  433. /**
  434. * Interpret the filename as a file relative to the given file -
  435. * unless the filename already represents an absolute filename.
  436. *
  437. * @param file the "reference" file for relative paths. This
  438. * instance must be an absolute file and must not contain
  439. * &quot;./&quot; or &quot;../&quot; sequences (same for \ instead
  440. * of /). If it is null, this call is equivalent to
  441. * <code>new java.io.File(filename)</code>.
  442. *
  443. * @param filename a file name
  444. *
  445. * @return an absolute file that doesn't contain &quot;./&quot; or
  446. * &quot;../&quot; sequences and uses the correct separator for
  447. * the current platform.
  448. */
  449. public File resolveFile(File file, String filename) {
  450. filename = filename.replace('/', File.separatorChar)
  451. .replace('\\', File.separatorChar);
  452. // deal with absolute files
  453. if (!onNetWare) {
  454. if (filename.startsWith(File.separator)
  455. || (filename.length() >= 2
  456. && Character.isLetter(filename.charAt(0))
  457. && filename.charAt(1) == ':')) {
  458. return normalize(filename);
  459. }
  460. } else {
  461. // the assumption that the : will appear as the second character in
  462. // the path name breaks down when NetWare is a supported platform.
  463. // Netware volumes are of the pattern: "data:\"
  464. int colon = filename.indexOf(":");
  465. if (filename.startsWith(File.separator)
  466. || (colon > -1)) {
  467. return normalize(filename);
  468. }
  469. }
  470. if (file == null) {
  471. return new File(filename);
  472. }
  473. File helpFile = new File(file.getAbsolutePath());
  474. StringTokenizer tok = new StringTokenizer(filename, File.separator);
  475. while (tok.hasMoreTokens()) {
  476. String part = tok.nextToken();
  477. if (part.equals("..")) {
  478. helpFile = getParentFile(helpFile);
  479. if (helpFile == null) {
  480. String msg = "The file or path you specified ("
  481. + filename + ") is invalid relative to "
  482. + file.getPath();
  483. throw new BuildException(msg);
  484. }
  485. } else if (part.equals(".")) {
  486. // Do nothing here
  487. } else {
  488. helpFile = new File(helpFile, part);
  489. }
  490. }
  491. return new File(helpFile.getAbsolutePath());
  492. }
  493. /**
  494. * &quot;normalize&quot; the given absolute path.
  495. *
  496. * <p>This includes:
  497. * <ul>
  498. * <li>Uppercase the drive letter if there is one.</li>
  499. * <li>Remove redundant slashes after the drive spec.</li>
  500. * <li>resolve all ./, .\, ../ and ..\ sequences.</li>
  501. * <li>DOS style paths that start with a drive letter will have
  502. * \ as the separator.</li>
  503. * </ul>
  504. *
  505. * @throws java.lang.NullPointerException if the file path is
  506. * equal to null.
  507. */
  508. public File normalize(String path) {
  509. String orig = path;
  510. path = path.replace('/', File.separatorChar)
  511. .replace('\\', File.separatorChar);
  512. // make sure we are dealing with an absolute path
  513. int colon = path.indexOf(":");
  514. if (!onNetWare) {
  515. if (!path.startsWith(File.separator) &&
  516. !(path.length() >= 2 &&
  517. Character.isLetter(path.charAt(0)) &&
  518. colon == 1)) {
  519. String msg = path + " is not an absolute path";
  520. throw new BuildException(msg);
  521. }
  522. } else {
  523. if (!path.startsWith(File.separator)
  524. && (colon == -1)) {
  525. String msg = path + " is not an absolute path";
  526. throw new BuildException(msg);
  527. }
  528. }
  529. boolean dosWithDrive = false;
  530. String root = null;
  531. // Eliminate consecutive slashes after the drive spec
  532. if ((!onNetWare &&
  533. path.length() >= 2 &&
  534. Character.isLetter(path.charAt(0)) &&
  535. path.charAt(1) == ':') ||
  536. (onNetWare && colon > -1)) {
  537. dosWithDrive = true;
  538. char[] ca = path.replace('/', '\\').toCharArray();
  539. StringBuffer sbRoot = new StringBuffer();
  540. for (int i = 0; i < colon; i++) {
  541. sbRoot.append(Character.toUpperCase(ca[i]));
  542. }
  543. sbRoot.append(':');
  544. if (colon + 1 < path.length()) {
  545. sbRoot.append(File.separatorChar);
  546. }
  547. root = sbRoot.toString();
  548. // Eliminate consecutive slashes after the drive spec
  549. StringBuffer sbPath = new StringBuffer();
  550. for (int i = colon + 1; i < ca.length; i++) {
  551. if ((ca[i] != '\\') ||
  552. (ca[i] == '\\' && ca[i - 1] != '\\')) {
  553. sbPath.append(ca[i]);
  554. }
  555. }
  556. path = sbPath.toString().replace('\\', File.separatorChar);
  557. } else {
  558. if (path.length() == 1) {
  559. root = File.separator;
  560. path = "";
  561. } else if (path.charAt(1) == File.separatorChar) {
  562. // UNC drive
  563. root = File.separator + File.separator;
  564. path = path.substring(2);
  565. } else {
  566. root = File.separator;
  567. path = path.substring(1);
  568. }
  569. }
  570. Stack s = new Stack();
  571. s.push(root);
  572. StringTokenizer tok = new StringTokenizer(path, File.separator);
  573. while (tok.hasMoreTokens()) {
  574. String thisToken = tok.nextToken();
  575. if (".".equals(thisToken)) {
  576. continue;
  577. } else if ("..".equals(thisToken)) {
  578. if (s.size() < 2) {
  579. throw new BuildException("Cannot resolve path " + orig);
  580. } else {
  581. s.pop();
  582. }
  583. } else { // plain component
  584. s.push(thisToken);
  585. }
  586. }
  587. StringBuffer sb = new StringBuffer();
  588. for (int i = 0; i < s.size(); i++) {
  589. if (i > 1) {
  590. // not before the filesystem root and not after it, since root
  591. // already contains one
  592. sb.append(File.separatorChar);
  593. }
  594. sb.append(s.elementAt(i));
  595. }
  596. path = sb.toString();
  597. if (dosWithDrive) {
  598. path = path.replace('/', '\\');
  599. }
  600. return new File(path);
  601. }
  602. /**
  603. * Create a temporary file in a given directory.
  604. *
  605. * <p>The file denoted by the returned abstract pathname did not
  606. * exist before this method was invoked, any subsequent invocation
  607. * of this method will yield a different file name.</p>
  608. *
  609. * <p>This method is different to File.createTempFile of JDK 1.2
  610. * as it doesn't create the file itself and doesn't use platform
  611. * specific temporary directory when the parentDir attribute is
  612. * null.</p>
  613. *
  614. * @param parentDir Directory to create the temporary file in -
  615. * current working directory will be assumed if this parameter is
  616. * null.
  617. *
  618. * @since 1.8
  619. */
  620. public File createTempFile(String prefix, String suffix, File parentDir) {
  621. File result = null;
  622. String parent = null;
  623. if (parentDir != null) {
  624. parent = parentDir.getPath();
  625. }
  626. DecimalFormat fmt = new DecimalFormat("#####");
  627. synchronized (rand) {
  628. do {
  629. result = new File(parent,
  630. prefix + fmt.format(rand.nextInt())
  631. + suffix);
  632. } while (result.exists());
  633. }
  634. return result;
  635. }
  636. /**
  637. * Compares the contents of two files.
  638. *
  639. * <p>simple but sub-optimal comparision algorithm. written for
  640. * working rather than fast. Better would be a block read into
  641. * buffers followed by long comparisions apart from the final 1-7
  642. * bytes.</p>
  643. *
  644. * @since 1.9
  645. */
  646. public boolean contentEquals(File f1, File f2) throws IOException {
  647. if (f1.exists() != f2.exists()) {
  648. return false;
  649. }
  650. if (!f1.exists()) {
  651. // two not existing files are equal
  652. return true;
  653. }
  654. if (f1.isDirectory() || f2.isDirectory()) {
  655. // don't want to compare directory contents for now
  656. return false;
  657. }
  658. if (f1.equals(f2)) {
  659. // same filename => true
  660. return true;
  661. }
  662. if (f1.length() != f2.length()) {
  663. // different size =>false
  664. return false;
  665. }
  666. InputStream in1 = null;
  667. InputStream in2 = null;
  668. try {
  669. in1 = new BufferedInputStream(new FileInputStream(f1));
  670. in2 = new BufferedInputStream(new FileInputStream(f2));
  671. int expectedByte = in1.read();
  672. while (expectedByte != -1) {
  673. if (expectedByte != in2.read()) {
  674. return false;
  675. }
  676. expectedByte = in1.read();
  677. }
  678. if (in2.read() != -1) {
  679. return false;
  680. }
  681. return true;
  682. } finally {
  683. if (in1 != null) {
  684. try {
  685. in1.close();
  686. } catch (IOException e) {}
  687. }
  688. if (in2 != null) {
  689. try {
  690. in2.close();
  691. } catch (IOException e) {}
  692. }
  693. }
  694. }
  695. /**
  696. * Emulation of File.getParentFile for JDK 1.1
  697. *
  698. * @since 1.10
  699. */
  700. public File getParentFile(File f) {
  701. if (f != null) {
  702. String p = f.getParent();
  703. if (p != null) {
  704. return new File(p);
  705. }
  706. }
  707. return null;
  708. }
  709. /**
  710. * Read from reader till EOF
  711. */
  712. public static final String readFully(Reader rdr) throws IOException {
  713. return readFully(rdr, 8192);
  714. }
  715. /**
  716. * Read from reader till EOF
  717. */
  718. public static final String readFully(Reader rdr, int bufferSize) throws IOException {
  719. if (bufferSize <= 0) {
  720. throw new IllegalArgumentException("Buffer size must be greater "
  721. + "than 0");
  722. }
  723. final char[] buffer = new char[bufferSize];
  724. int bufferLength = 0;
  725. String text = null;
  726. StringBuffer textBuffer = null;
  727. while (bufferLength != -1) {
  728. bufferLength = rdr.read(buffer);
  729. if (bufferLength != -1) {
  730. if (textBuffer == null) {
  731. textBuffer = new StringBuffer(
  732. new String(buffer, 0, bufferLength));
  733. } else {
  734. textBuffer.append(new String(buffer, 0, bufferLength));
  735. }
  736. }
  737. }
  738. if (textBuffer != null) {
  739. text = textBuffer.toString();
  740. }
  741. return text;
  742. }
  743. /**
  744. * Emulation of File.createNewFile for JDK 1.1.
  745. *
  746. * <p>This method does <strong>not</strong> guarantee that the
  747. * operation is atomic.</p>
  748. *
  749. * @since 1.21, Ant 1.5
  750. */
  751. public boolean createNewFile(File f) throws IOException {
  752. if (f != null) {
  753. if (f.exists()) {
  754. return false;
  755. }
  756. FileOutputStream fos = null;
  757. try {
  758. fos = new FileOutputStream(f);
  759. fos.write(new byte[0]);
  760. } finally {
  761. if (fos != null) {
  762. fos.close();
  763. }
  764. }
  765. return true;
  766. }
  767. return false;
  768. }
  769. /**
  770. * Checks whether a given file is a symbolic link.
  771. *
  772. * <p>It doesn't really test for symbolic links but whether the
  773. * canonical and absolute paths of the file are identical - this
  774. * may lead to false positives on some platforms.</p>
  775. *
  776. * @param parent the parent directory of the file to test
  777. * @param name the name of the file to test.
  778. *
  779. * @since Ant 1.5
  780. */
  781. public boolean isSymbolicLink(File parent, String name)
  782. throws IOException {
  783. File resolvedParent = new File(parent.getCanonicalPath());
  784. File toTest = new File(resolvedParent, name);
  785. return !toTest.getAbsolutePath().equals(toTest.getCanonicalPath());
  786. }
  787. /**
  788. * Removes a leading path from a second path.
  789. *
  790. * @param leading The leading path, must not be null, must be absolute.
  791. * @param path The path to remove from, must not be null, must be absolute.
  792. *
  793. * @return path's normalized absolute if it doesn't start with
  794. * leading, path's path with leading's path removed otherwise.
  795. *
  796. * @since Ant 1.5
  797. */
  798. public String removeLeadingPath(File leading, File path) {
  799. // if leading's path ends with a slash, it will be stripped by
  800. // normalize - we always add one so we never think /foo was a
  801. // parent directory of /foobar
  802. String l = normalize(leading.getAbsolutePath()).getAbsolutePath()
  803. + File.separator;
  804. String p = normalize(path.getAbsolutePath()).getAbsolutePath();
  805. if (p.startsWith(l)) {
  806. return p.substring(l.length());
  807. } else {
  808. return p;
  809. }
  810. }
  811. }