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 70 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780
  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. import java.io.File;
  20. import java.io.FilenameFilter;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.io.InputStreamReader;
  24. import java.io.OutputStream;
  25. import java.io.Reader;
  26. import java.io.Writer;
  27. import java.net.HttpURLConnection;
  28. import java.net.JarURLConnection;
  29. import java.net.MalformedURLException;
  30. import java.net.URL;
  31. import java.net.URLConnection;
  32. import java.nio.channels.Channel;
  33. import java.text.DecimalFormat;
  34. import java.util.ArrayList;
  35. import java.util.Arrays;
  36. import java.util.Iterator;
  37. import java.util.List;
  38. import java.util.Random;
  39. import java.util.Stack;
  40. import java.util.StringTokenizer;
  41. import java.util.Vector;
  42. import java.util.jar.JarFile;
  43. import org.apache.tools.ant.BuildException;
  44. import org.apache.tools.ant.PathTokenizer;
  45. import org.apache.tools.ant.Project;
  46. import org.apache.tools.ant.launch.Locator;
  47. import org.apache.tools.ant.taskdefs.condition.Os;
  48. import org.apache.tools.ant.types.FilterSetCollection;
  49. import org.apache.tools.ant.types.resources.FileResource;
  50. /**
  51. * This class also encapsulates methods which allow Files to be
  52. * referred to using abstract path names which are translated to native
  53. * system file paths at runtime as well as copying files or setting
  54. * their last modification time.
  55. *
  56. */
  57. public class FileUtils {
  58. private static final int DELETE_RETRY_SLEEP_MILLIS = 10;
  59. private static final int EXPAND_SPACE = 50;
  60. private static final FileUtils PRIMARY_INSTANCE = new FileUtils();
  61. //get some non-crypto-grade randomness from various places.
  62. private static Random rand = new Random(System.currentTimeMillis()
  63. + Runtime.getRuntime().freeMemory());
  64. private static final boolean ON_NETWARE = Os.isFamily("netware");
  65. private static final boolean ON_DOS = Os.isFamily("dos");
  66. private static final boolean ON_WIN9X = Os.isFamily("win9x");
  67. private static final boolean ON_WINDOWS = Os.isFamily("windows");
  68. static final int BUF_SIZE = 8192;
  69. /**
  70. * The granularity of timestamps under FAT.
  71. */
  72. public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000;
  73. /**
  74. * The granularity of timestamps under Unix.
  75. */
  76. public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000;
  77. /**
  78. * The granularity of timestamps under the NT File System.
  79. * NTFS has a granularity of 100 nanoseconds, which is less
  80. * than 1 millisecond, so we round this up to 1 millisecond.
  81. */
  82. public static final long NTFS_FILE_TIMESTAMP_GRANULARITY = 1;
  83. /**
  84. * A one item cache for fromUri.
  85. * fromUri is called for each element when parsing ant build
  86. * files. It is a costly operation. This just caches the result
  87. * of the last call.
  88. */
  89. private Object cacheFromUriLock = new Object();
  90. private String cacheFromUriRequest = null;
  91. private String cacheFromUriResponse = null;
  92. /**
  93. * Factory method.
  94. *
  95. * @return a new instance of FileUtils.
  96. * @deprecated since 1.7.
  97. * Use getFileUtils instead,
  98. * FileUtils do not have state.
  99. */
  100. public static FileUtils newFileUtils() {
  101. return new FileUtils();
  102. }
  103. /**
  104. * Method to retrieve The FileUtils, which is shared by all users of this
  105. * method.
  106. * @return an instance of FileUtils.
  107. * @since Ant 1.6.3
  108. */
  109. public static FileUtils getFileUtils() {
  110. return PRIMARY_INSTANCE;
  111. }
  112. /**
  113. * Empty constructor.
  114. */
  115. protected FileUtils() {
  116. }
  117. /**
  118. * Get the URL for a file taking into account # characters.
  119. *
  120. * @param file the file whose URL representation is required.
  121. * @return The FileURL value.
  122. * @throws MalformedURLException if the URL representation cannot be
  123. * formed.
  124. */
  125. public URL getFileURL(File file) throws MalformedURLException {
  126. return new URL(file.toURI().toASCIIString());
  127. }
  128. /**
  129. * Convenience method to copy a file from a source to a destination.
  130. * No filtering is performed.
  131. *
  132. * @param sourceFile Name of file to copy from.
  133. * Must not be <code>null</code>.
  134. * @param destFile Name of file to copy to.
  135. * Must not be <code>null</code>.
  136. *
  137. * @throws IOException if the copying fails.
  138. */
  139. public void copyFile(String sourceFile, String destFile) throws IOException {
  140. copyFile(new File(sourceFile), new File(destFile), null, false, false);
  141. }
  142. /**
  143. * Convenience method to copy a file from a source to a destination
  144. * specifying if token filtering must be used.
  145. *
  146. * @param sourceFile Name of file to copy from.
  147. * Must not be <code>null</code>.
  148. * @param destFile Name of file to copy to.
  149. * Must not be <code>null</code>.
  150. * @param filters the collection of filters to apply to this copy.
  151. *
  152. * @throws IOException if the copying fails.
  153. */
  154. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters)
  155. throws IOException {
  156. copyFile(new File(sourceFile), new File(destFile), filters, false, false);
  157. }
  158. /**
  159. * Convenience method to copy a file from a source to a destination specifying if token
  160. * filtering must be used and if source files may overwrite newer destination files.
  161. *
  162. * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
  163. * @param destFile Name of file to copy to. Must not be <code>null</code>.
  164. * @param filters the collection of filters to apply to this copy.
  165. * @param overwrite Whether or not the destination file should be overwritten if it already
  166. * exists.
  167. *
  168. * @throws IOException if the copying fails.
  169. */
  170. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
  171. boolean overwrite) throws IOException {
  172. copyFile(new File(sourceFile), new File(destFile), filters, overwrite, false);
  173. }
  174. /**
  175. * Convenience method to copy a file from a source to a destination
  176. * specifying if token
  177. * filtering must be used, if source files may overwrite newer destination
  178. * files and the last
  179. * modified time of <code>destFile</code> file should be made equal to
  180. * the last modified time
  181. * of <code>sourceFile</code>.
  182. *
  183. * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
  184. * @param destFile Name of file to copy to. Must not be <code>null</code>.
  185. * @param filters the collection of filters to apply to this copy.
  186. * @param overwrite Whether or not the destination file should be
  187. * overwritten if it already exists.
  188. * @param preserveLastModified Whether or not the last modified time of
  189. * the resulting file
  190. * should be set to that of the source file.
  191. *
  192. * @throws IOException if the copying fails.
  193. */
  194. public void copyFile(String sourceFile, String destFile,
  195. FilterSetCollection filters,
  196. boolean overwrite, boolean preserveLastModified)
  197. throws IOException {
  198. copyFile(new File(sourceFile), new File(destFile), filters, overwrite,
  199. preserveLastModified);
  200. }
  201. /**
  202. * Convenience method to copy a file from a source to a destination specifying if token
  203. * filtering must be used, if source files may overwrite newer destination files and the last
  204. * modified time of <code>destFile</code> file should be made equal to the last modified time
  205. * of <code>sourceFile</code>.
  206. *
  207. * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
  208. * @param destFile Name of file to copy to. Must not be <code>null</code>.
  209. * @param filters the collection of filters to apply to this copy.
  210. * @param overwrite Whether or not the destination file should be overwritten if it already
  211. * exists.
  212. * @param preserveLastModified Whether or not the last modified time of the resulting file
  213. * should be set to that of the source file.
  214. * @param encoding the encoding used to read and write the files.
  215. *
  216. * @throws IOException if the copying fails.
  217. *
  218. * @since Ant 1.5
  219. */
  220. public void copyFile(String sourceFile, String destFile,
  221. FilterSetCollection filters, boolean overwrite,
  222. boolean preserveLastModified, String encoding) throws IOException {
  223. copyFile(new File(sourceFile), new File(destFile), filters,
  224. overwrite, preserveLastModified, encoding);
  225. }
  226. // CheckStyle:ParameterNumberCheck OFF - bc
  227. /**
  228. * Convenience method to copy a file from a source to a
  229. * destination specifying if token filtering must be used, if
  230. * filter chains must be used, if source files may overwrite
  231. * newer destination files and the last modified time of
  232. * <code>destFile</code> file should be made equal
  233. * to the last modified time of <code>sourceFile</code>.
  234. *
  235. * @param sourceFile Name of file to copy from.
  236. * Must not be <code>null</code>.
  237. * @param destFile Name of file to copy to.
  238. * Must not be <code>null</code>.
  239. * @param filters the collection of filters to apply to this copy.
  240. * @param filterChains filterChains to apply during the copy.
  241. * @param overwrite Whether or not the destination file should be
  242. * overwritten if it already exists.
  243. * @param preserveLastModified Whether or not the last modified time of
  244. * the resulting file should be set to that
  245. * of the source file.
  246. * @param encoding the encoding used to read and write the files.
  247. * @param project the project instance.
  248. *
  249. * @throws IOException if the copying fails.
  250. *
  251. * @since Ant 1.5
  252. */
  253. public void copyFile(String sourceFile, String destFile,
  254. FilterSetCollection filters, Vector filterChains,
  255. boolean overwrite, boolean preserveLastModified,
  256. String encoding, Project project) throws IOException {
  257. copyFile(new File(sourceFile), new File(destFile), filters, filterChains, overwrite,
  258. preserveLastModified, encoding, project);
  259. }
  260. /**
  261. * Convenience method to copy a file from a source to a destination specifying if token
  262. * filtering must be used, if filter chains must be used, if source files may overwrite newer
  263. * destination files and the last modified time of <code>destFile</code> file should be made
  264. * equal to the last modified time of <code>sourceFile</code>.
  265. *
  266. * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
  267. * @param destFile Name of file to copy to. Must not be <code>null</code>.
  268. * @param filters the collection of filters to apply to this copy.
  269. * @param filterChains filterChains to apply during the copy.
  270. * @param overwrite Whether or not the destination file should be overwritten if it already
  271. * exists.
  272. * @param preserveLastModified Whether or not the last modified time of the resulting file
  273. * should be set to that of the source file.
  274. * @param inputEncoding the encoding used to read the files.
  275. * @param outputEncoding the encoding used to write the files.
  276. * @param project the project instance.
  277. *
  278. * @throws IOException if the copying fails.
  279. *
  280. * @since Ant 1.6
  281. */
  282. public void copyFile(String sourceFile, String destFile,
  283. FilterSetCollection filters, Vector filterChains,
  284. boolean overwrite, boolean preserveLastModified,
  285. String inputEncoding, String outputEncoding,
  286. Project project) throws IOException {
  287. copyFile(new File(sourceFile), new File(destFile), filters, filterChains, overwrite,
  288. preserveLastModified, inputEncoding, outputEncoding, project);
  289. }
  290. /**
  291. * Convenience method to copy a file from a source to a destination. No filtering is performed.
  292. *
  293. * @param sourceFile the file to copy from. Must not be <code>null</code>.
  294. * @param destFile the file to copy to. Must not be <code>null</code>.
  295. *
  296. * @throws IOException if the copying fails.
  297. */
  298. public void copyFile(File sourceFile, File destFile) throws IOException {
  299. copyFile(sourceFile, destFile, null, false, false);
  300. }
  301. /**
  302. * Convenience method to copy a file from a source to a destination
  303. * specifying if token filtering must be used.
  304. *
  305. * @param sourceFile the file to copy from.
  306. * Must not be <code>null</code>.
  307. * @param destFile the file to copy to.
  308. * Must not be <code>null</code>.
  309. * @param filters the collection of filters to apply to this copy.
  310. *
  311. * @throws IOException if the copying fails.
  312. */
  313. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters)
  314. throws IOException {
  315. copyFile(sourceFile, destFile, filters, false, false);
  316. }
  317. /**
  318. * Convenience method to copy a file from a source to a
  319. * destination specifying if token filtering must be used and if
  320. * source files may overwrite newer destination files.
  321. *
  322. * @param sourceFile the file to copy from.
  323. * Must not be <code>null</code>.
  324. * @param destFile the file to copy to.
  325. * Must not be <code>null</code>.
  326. * @param filters the collection of filters to apply to this copy.
  327. * @param overwrite Whether or not the destination file should be
  328. * overwritten if it already exists.
  329. *
  330. * @throws IOException if the copying fails.
  331. */
  332. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
  333. boolean overwrite) throws IOException {
  334. copyFile(sourceFile, destFile, filters, overwrite, false);
  335. }
  336. /**
  337. * Convenience method to copy a file from a source to a
  338. * destination specifying if token filtering must be used, if
  339. * source files may overwrite newer destination files and the
  340. * last modified time of <code>destFile</code> file should be made equal
  341. * to the last modified time of <code>sourceFile</code>.
  342. *
  343. * @param sourceFile the file to copy from.
  344. * Must not be <code>null</code>.
  345. * @param destFile the file to copy to.
  346. * Must not be <code>null</code>.
  347. * @param filters the collection of filters to apply to this copy.
  348. * @param overwrite Whether or not the destination file should be
  349. * overwritten if it already exists.
  350. * @param preserveLastModified Whether or not the last modified time of
  351. * the resulting file should be set to that
  352. * of the source file.
  353. *
  354. * @throws IOException if the copying fails.
  355. */
  356. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
  357. boolean overwrite, boolean preserveLastModified) throws IOException {
  358. copyFile(sourceFile, destFile, filters, overwrite, preserveLastModified, null);
  359. }
  360. /**
  361. * Convenience method to copy a file from a source to a destination specifying if token
  362. * filtering must be used, if source files may overwrite newer destination files, the last
  363. * modified time of <code>destFile</code> file should be made equal to the last modified time
  364. * of <code>sourceFile</code> and which character encoding to assume.
  365. *
  366. * @param sourceFile the file to copy from. Must not be <code>null</code>.
  367. * @param destFile the file to copy to. Must not be <code>null</code>.
  368. * @param filters the collection of filters to apply to this copy.
  369. * @param overwrite Whether or not the destination file should be overwritten if it already
  370. * exists.
  371. * @param preserveLastModified Whether or not the last modified time of the resulting file
  372. * should be set to that of the source file.
  373. * @param encoding the encoding used to read and write the files.
  374. *
  375. * @throws IOException if the copying fails.
  376. *
  377. * @since Ant 1.5
  378. */
  379. public void copyFile(File sourceFile, File destFile,
  380. FilterSetCollection filters, boolean overwrite,
  381. boolean preserveLastModified, String encoding) throws IOException {
  382. copyFile(sourceFile, destFile, filters, null, overwrite,
  383. preserveLastModified, encoding, null);
  384. }
  385. /**
  386. * Convenience method to copy a file from a source to a
  387. * destination specifying if token filtering must be used, if
  388. * filter chains must be used, if source files may overwrite
  389. * newer destination files and the last modified time of
  390. * <code>destFile</code> file should be made equal
  391. * to the last modified time of <code>sourceFile</code>.
  392. *
  393. * @param sourceFile the file to copy from.
  394. * Must not be <code>null</code>.
  395. * @param destFile the file to copy to.
  396. * Must not be <code>null</code>.
  397. * @param filters the collection of filters to apply to this copy.
  398. * @param filterChains filterChains to apply during the copy.
  399. * @param overwrite Whether or not the destination file should be
  400. * overwritten if it already exists.
  401. * @param preserveLastModified Whether or not the last modified time of
  402. * the resulting file should be set to that
  403. * of the source file.
  404. * @param encoding the encoding used to read and write the files.
  405. * @param project the project instance.
  406. *
  407. * @throws IOException if the copying fails.
  408. *
  409. * @since Ant 1.5
  410. */
  411. public void copyFile(File sourceFile, File destFile,
  412. FilterSetCollection filters, Vector filterChains,
  413. boolean overwrite, boolean preserveLastModified,
  414. String encoding, Project project) throws IOException {
  415. copyFile(sourceFile, destFile, filters, filterChains,
  416. overwrite, preserveLastModified, encoding, encoding, project);
  417. }
  418. /**
  419. * Convenience method to copy a file from a source to a
  420. * destination specifying if token filtering must be used, if
  421. * filter chains must be used, if source files may overwrite
  422. * newer destination files and the last modified time of
  423. * <code>destFile</code> file should be made equal
  424. * to the last modified time of <code>sourceFile</code>.
  425. *
  426. * @param sourceFile the file to copy from.
  427. * Must not be <code>null</code>.
  428. * @param destFile the file to copy to.
  429. * Must not be <code>null</code>.
  430. * @param filters the collection of filters to apply to this copy.
  431. * @param filterChains filterChains to apply during the copy.
  432. * @param overwrite Whether or not the destination file should be
  433. * overwritten if it already exists.
  434. * @param preserveLastModified Whether or not the last modified time of
  435. * the resulting file should be set to that
  436. * of the source file.
  437. * @param inputEncoding the encoding used to read the files.
  438. * @param outputEncoding the encoding used to write the files.
  439. * @param project the project instance.
  440. *
  441. *
  442. * @throws IOException if the copying fails.
  443. *
  444. * @since Ant 1.6
  445. */
  446. public void copyFile(File sourceFile, File destFile,
  447. FilterSetCollection filters, Vector filterChains,
  448. boolean overwrite, boolean preserveLastModified,
  449. String inputEncoding, String outputEncoding,
  450. Project project) throws IOException {
  451. copyFile(sourceFile, destFile, filters, filterChains, overwrite, preserveLastModified,
  452. false, inputEncoding, outputEncoding, project);
  453. }
  454. /**
  455. * Convenience method to copy a file from a source to a
  456. * destination specifying if token filtering must be used, if
  457. * filter chains must be used, if source files may overwrite
  458. * newer destination files and the last modified time of
  459. * <code>destFile</code> file should be made equal
  460. * to the last modified time of <code>sourceFile</code>.
  461. *
  462. * @param sourceFile the file to copy from.
  463. * Must not be <code>null</code>.
  464. * @param destFile the file to copy to.
  465. * Must not be <code>null</code>.
  466. * @param filters the collection of filters to apply to this copy.
  467. * @param filterChains filterChains to apply during the copy.
  468. * @param overwrite Whether or not the destination file should be
  469. * overwritten if it already exists.
  470. * @param preserveLastModified Whether or not the last modified time of
  471. * the resulting file should be set to that
  472. * of the source file.
  473. * @param append whether to append to the destination file.
  474. * @param inputEncoding the encoding used to read the files.
  475. * @param outputEncoding the encoding used to write the files.
  476. * @param project the project instance.
  477. *
  478. *
  479. * @throws IOException if the copying fails.
  480. *
  481. * @since Ant 1.8
  482. */
  483. public void copyFile(File sourceFile, File destFile,
  484. FilterSetCollection filters, Vector filterChains,
  485. boolean overwrite, boolean preserveLastModified,
  486. boolean append,
  487. String inputEncoding, String outputEncoding,
  488. Project project) throws IOException {
  489. copyFile(sourceFile, destFile, filters, filterChains, overwrite,
  490. preserveLastModified, append, inputEncoding, outputEncoding,
  491. project, /* force: */ false);
  492. }
  493. /**
  494. * Convenience method to copy a file from a source to a
  495. * destination specifying if token filtering must be used, if
  496. * filter chains must be used, if source files may overwrite
  497. * newer destination files and the last modified time of
  498. * <code>destFile</code> file should be made equal
  499. * to the last modified time of <code>sourceFile</code>.
  500. *
  501. * @param sourceFile the file to copy from.
  502. * Must not be <code>null</code>.
  503. * @param destFile the file to copy to.
  504. * Must not be <code>null</code>.
  505. * @param filters the collection of filters to apply to this copy.
  506. * @param filterChains filterChains to apply during the copy.
  507. * @param overwrite Whether or not the destination file should be
  508. * overwritten if it already exists.
  509. * @param preserveLastModified Whether or not the last modified time of
  510. * the resulting file should be set to that
  511. * of the source file.
  512. * @param append whether to append to the destination file.
  513. * @param inputEncoding the encoding used to read the files.
  514. * @param outputEncoding the encoding used to write the files.
  515. * @param project the project instance.
  516. * @param force whether to overwrite read-only destination files.
  517. *
  518. * @throws IOException if the copying fails.
  519. *
  520. * @since Ant 1.8.2
  521. */
  522. public void copyFile(File sourceFile, File destFile,
  523. FilterSetCollection filters, Vector filterChains,
  524. boolean overwrite, boolean preserveLastModified,
  525. boolean append,
  526. String inputEncoding, String outputEncoding,
  527. Project project, boolean force) throws IOException {
  528. ResourceUtils.copyResource(new FileResource(sourceFile),
  529. new FileResource(destFile),
  530. filters, filterChains, overwrite,
  531. preserveLastModified, append, inputEncoding,
  532. outputEncoding, project, force);
  533. }
  534. // CheckStyle:ParameterNumberCheck ON
  535. /**
  536. * Calls File.setLastModified(long time). Originally written to
  537. * to dynamically bind to that call on Java1.2+.
  538. *
  539. * @param file the file whose modified time is to be set
  540. * @param time the time to which the last modified time is to be set.
  541. * if this is -1, the current time is used.
  542. */
  543. public void setFileLastModified(File file, long time) {
  544. ResourceUtils.setLastModified(new FileResource(file), time);
  545. }
  546. /**
  547. * Interpret the filename as a file relative to the given file
  548. * unless the filename already represents an absolute filename.
  549. * Differs from <code>new File(file, filename)</code> in that
  550. * the resulting File's path will always be a normalized,
  551. * absolute pathname. Also, if it is determined that
  552. * <code>filename</code> is context-relative, <code>file</code>
  553. * will be discarded and the reference will be resolved using
  554. * available context/state information about the filesystem.
  555. *
  556. * @param file the "reference" file for relative paths. This
  557. * instance must be an absolute file and must not contain
  558. * &quot;./&quot; or &quot;../&quot; sequences (same for \ instead
  559. * of /). If it is null, this call is equivalent to
  560. * <code>new java.io.File(filename).getAbsoluteFile()</code>.
  561. *
  562. * @param filename a file name.
  563. *
  564. * @return an absolute file.
  565. * @throws java.lang.NullPointerException if filename is null.
  566. */
  567. public File resolveFile(File file, String filename) {
  568. if (!isAbsolutePath(filename)) {
  569. char sep = File.separatorChar;
  570. filename = filename.replace('/', sep).replace('\\', sep);
  571. if (isContextRelativePath(filename)) {
  572. file = null;
  573. // on cygwin, our current directory can be a UNC;
  574. // assume user.dir is absolute or all hell breaks loose...
  575. String udir = System.getProperty("user.dir");
  576. if (filename.charAt(0) == sep && udir.charAt(0) == sep) {
  577. filename = dissect(udir)[0] + filename.substring(1);
  578. }
  579. }
  580. filename = new File(file, filename).getAbsolutePath();
  581. }
  582. return normalize(filename);
  583. }
  584. /**
  585. * On DOS and NetWare, the evaluation of certain file
  586. * specifications is context-dependent. These are filenames
  587. * beginning with a single separator (relative to current root directory)
  588. * and filenames with a drive specification and no intervening separator
  589. * (relative to current directory of the specified root).
  590. * @param filename the filename to evaluate.
  591. * @return true if the filename is relative to system context.
  592. * @throws java.lang.NullPointerException if filename is null.
  593. * @since Ant 1.7
  594. */
  595. public static boolean isContextRelativePath(String filename) {
  596. if (!(ON_DOS || ON_NETWARE) || filename.length() == 0) {
  597. return false;
  598. }
  599. char sep = File.separatorChar;
  600. filename = filename.replace('/', sep).replace('\\', sep);
  601. char c = filename.charAt(0);
  602. int len = filename.length();
  603. return (c == sep && (len == 1 || filename.charAt(1) != sep))
  604. || (Character.isLetter(c) && len > 1
  605. && filename.charAt(1) == ':'
  606. && (len == 2 || filename.charAt(2) != sep));
  607. }
  608. /**
  609. * Verifies that the specified filename represents an absolute path.
  610. * Differs from new java.io.File("filename").isAbsolute() in that a path
  611. * beginning with a double file separator--signifying a Windows UNC--must
  612. * at minimum match "\\a\b" to be considered an absolute path.
  613. * @param filename the filename to be checked.
  614. * @return true if the filename represents an absolute path.
  615. * @throws java.lang.NullPointerException if filename is null.
  616. * @since Ant 1.6.3
  617. */
  618. public static boolean isAbsolutePath(String filename) {
  619. int len = filename.length();
  620. if (len == 0) {
  621. return false;
  622. }
  623. char sep = File.separatorChar;
  624. filename = filename.replace('/', sep).replace('\\', sep);
  625. char c = filename.charAt(0);
  626. if (!(ON_DOS || ON_NETWARE)) {
  627. return (c == sep);
  628. }
  629. if (c == sep) {
  630. // CheckStyle:MagicNumber OFF
  631. if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) {
  632. return false;
  633. }
  634. // CheckStyle:MagicNumber ON
  635. int nextsep = filename.indexOf(sep, 2);
  636. return nextsep > 2 && nextsep + 1 < len;
  637. }
  638. int colon = filename.indexOf(':');
  639. return (Character.isLetter(c) && colon == 1
  640. && filename.length() > 2 && filename.charAt(2) == sep)
  641. || (ON_NETWARE && colon > 0);
  642. }
  643. /**
  644. * Translate a path into its native (platform specific) format.
  645. * <p>
  646. * This method uses PathTokenizer to separate the input path
  647. * into its components. This handles DOS style paths in a relatively
  648. * sensible way. The file separators are then converted to their platform
  649. * specific versions.
  650. *
  651. * @param toProcess The path to be translated.
  652. * May be <code>null</code>.
  653. *
  654. * @return the native version of the specified path or
  655. * an empty string if the path is <code>null</code> or empty.
  656. *
  657. * @since ant 1.7
  658. * @see PathTokenizer
  659. */
  660. public static String translatePath(String toProcess) {
  661. if (toProcess == null || toProcess.length() == 0) {
  662. return "";
  663. }
  664. StringBuffer path = new StringBuffer(toProcess.length() + EXPAND_SPACE);
  665. PathTokenizer tokenizer = new PathTokenizer(toProcess);
  666. while (tokenizer.hasMoreTokens()) {
  667. String pathComponent = tokenizer.nextToken();
  668. pathComponent = pathComponent.replace('/', File.separatorChar);
  669. pathComponent = pathComponent.replace('\\', File.separatorChar);
  670. if (path.length() != 0) {
  671. path.append(File.pathSeparatorChar);
  672. }
  673. path.append(pathComponent);
  674. }
  675. return path.toString();
  676. }
  677. /**
  678. * &quot;Normalize&quot; the given absolute path.
  679. *
  680. * <p>This includes:
  681. * <ul>
  682. * <li>Uppercase the drive letter if there is one.</li>
  683. * <li>Remove redundant slashes after the drive spec.</li>
  684. * <li>Resolve all ./, .\, ../ and ..\ sequences.</li>
  685. * <li>DOS style paths that start with a drive letter will have
  686. * \ as the separator.</li>
  687. * </ul>
  688. * <p>Unlike {@link File#getCanonicalPath()} this method
  689. * specifically does not resolve symbolic links.</p>
  690. *
  691. * <p>If the path tries to go beyond the file system root (i.e. it
  692. * contains more ".." segments than can be travelled up) the
  693. * method will return the original path unchanged.</p>
  694. *
  695. * @param path the path to be normalized.
  696. * @return the normalized version of the path.
  697. *
  698. * @throws java.lang.NullPointerException if path is null.
  699. */
  700. public File normalize(final String path) {
  701. Stack s = new Stack();
  702. String[] dissect = dissect(path);
  703. s.push(dissect[0]);
  704. StringTokenizer tok = new StringTokenizer(dissect[1], File.separator);
  705. while (tok.hasMoreTokens()) {
  706. String thisToken = tok.nextToken();
  707. if (".".equals(thisToken)) {
  708. continue;
  709. }
  710. if ("..".equals(thisToken)) {
  711. if (s.size() < 2) {
  712. // Cannot resolve it, so skip it.
  713. return new File(path);
  714. }
  715. s.pop();
  716. } else { // plain component
  717. s.push(thisToken);
  718. }
  719. }
  720. StringBuffer sb = new StringBuffer();
  721. final int size = s.size();
  722. for (int i = 0; i < size; i++) {
  723. if (i > 1) {
  724. // not before the filesystem root and not after it, since root
  725. // already contains one
  726. sb.append(File.separatorChar);
  727. }
  728. sb.append(s.elementAt(i));
  729. }
  730. return new File(sb.toString());
  731. }
  732. /**
  733. * Dissect the specified absolute path.
  734. * @param path the path to dissect.
  735. * @return String[] {root, remaining path}.
  736. * @throws java.lang.NullPointerException if path is null.
  737. * @since Ant 1.7
  738. */
  739. public String[] dissect(String path) {
  740. char sep = File.separatorChar;
  741. path = path.replace('/', sep).replace('\\', sep);
  742. // make sure we are dealing with an absolute path
  743. if (!isAbsolutePath(path)) {
  744. throw new BuildException(path + " is not an absolute path");
  745. }
  746. String root = null;
  747. int colon = path.indexOf(':');
  748. if (colon > 0 && (ON_DOS || ON_NETWARE)) {
  749. int next = colon + 1;
  750. root = path.substring(0, next);
  751. char[] ca = path.toCharArray();
  752. root += sep;
  753. //remove the initial separator; the root has it.
  754. next = (ca[next] == sep) ? next + 1 : next;
  755. StringBuffer sbPath = new StringBuffer();
  756. // Eliminate consecutive slashes after the drive spec:
  757. for (int i = next; i < ca.length; i++) {
  758. if (ca[i] != sep || ca[i - 1] != sep) {
  759. sbPath.append(ca[i]);
  760. }
  761. }
  762. path = sbPath.toString();
  763. } else if (path.length() > 1 && path.charAt(1) == sep) {
  764. // UNC drive
  765. int nextsep = path.indexOf(sep, 2);
  766. nextsep = path.indexOf(sep, nextsep + 1);
  767. root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path;
  768. path = path.substring(root.length());
  769. } else {
  770. root = File.separator;
  771. path = path.substring(1);
  772. }
  773. return new String[] {root, path};
  774. }
  775. /**
  776. * Returns a VMS String representation of a <code>File</code> object.
  777. * This is useful since the JVM by default internally converts VMS paths
  778. * to Unix style.
  779. * The returned String is always an absolute path.
  780. *
  781. * @param f The <code>File</code> to get the VMS path for.
  782. * @return The absolute VMS path to <code>f</code>.
  783. */
  784. public String toVMSPath(File f) {
  785. // format: "DEVICE:[DIR.SUBDIR]FILE"
  786. String osPath;
  787. String path = normalize(f.getAbsolutePath()).getPath();
  788. String name = f.getName();
  789. boolean isAbsolute = path.charAt(0) == File.separatorChar;
  790. // treat directories specified using .DIR syntax as files
  791. // CheckStyle:MagicNumber OFF
  792. boolean isDirectory = f.isDirectory()
  793. && !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4);
  794. // CheckStyle:MagicNumber ON
  795. String device = null;
  796. StringBuffer directory = null;
  797. String file = null;
  798. int index = 0;
  799. if (isAbsolute) {
  800. index = path.indexOf(File.separatorChar, 1);
  801. if (index == -1) {
  802. return path.substring(1) + ":[000000]";
  803. }
  804. device = path.substring(1, index++);
  805. }
  806. if (isDirectory) {
  807. directory = new StringBuffer(path.substring(index).replace(File.separatorChar, '.'));
  808. } else {
  809. int dirEnd = path.lastIndexOf(File.separatorChar, path.length());
  810. if (dirEnd == -1 || dirEnd < index) {
  811. file = path.substring(index);
  812. } else {
  813. directory = new StringBuffer(path.substring(index, dirEnd).
  814. replace(File.separatorChar, '.'));
  815. index = dirEnd + 1;
  816. if (path.length() > index) {
  817. file = path.substring(index);
  818. }
  819. }
  820. }
  821. if (!isAbsolute && directory != null) {
  822. directory.insert(0, '.');
  823. }
  824. osPath = ((device != null) ? device + ":" : "")
  825. + ((directory != null) ? "[" + directory + "]" : "")
  826. + ((file != null) ? file : "");
  827. return osPath;
  828. }
  829. /**
  830. * Create a File object for a temporary file in a given directory. Without
  831. * actually creating the file.
  832. *
  833. * <p>
  834. * The file denoted by the returned abstract pathname did not exist before
  835. * this method was invoked, any subsequent invocation of this method will
  836. * yield a different file name.
  837. * </p>
  838. * <p>
  839. * The filename is prefixNNNNNsuffix where NNNN is a random number.
  840. * </p>
  841. *
  842. * @param prefix
  843. * prefix before the random number.
  844. * @param suffix
  845. * file extension; include the '.'.
  846. * @param parentDir
  847. * Directory to create the temporary file in; java.io.tmpdir used
  848. * if not specified.
  849. *
  850. * @deprecated since ant 1.7.1 use createTempFile(String, String, File,
  851. * boolean, boolean) instead.
  852. * @return a File reference to the new, nonexistent temporary file.
  853. */
  854. public File createTempFile(String prefix, String suffix, File parentDir) {
  855. return createTempFile(prefix, suffix, parentDir, false, false);
  856. }
  857. private static final String NULL_PLACEHOLDER = "null";
  858. /**
  859. * Create a temporary file in a given directory.
  860. *
  861. * <p>The file denoted by the returned abstract pathname did not
  862. * exist before this method was invoked, any subsequent invocation
  863. * of this method will yield a different file name.</p>
  864. *
  865. * @param prefix prefix before the random number.
  866. * @param suffix file extension; include the '.'.
  867. * @param parentDir Directory to create the temporary file in;
  868. * java.io.tmpdir used if not specified.
  869. * @param deleteOnExit whether to set the tempfile for deletion on
  870. * normal VM exit.
  871. * @param createFile true if the file must actually be created. If false
  872. * chances exist that a file with the same name is created in the time
  873. * between invoking this method and the moment the file is actually created.
  874. * If possible set to true.
  875. *
  876. * @return a File reference to the new temporary file.
  877. * @since Ant 1.7.1
  878. */
  879. public File createTempFile(String prefix, String suffix, File parentDir,
  880. boolean deleteOnExit, boolean createFile) {
  881. File result = null;
  882. String parent = (parentDir == null)
  883. ? System.getProperty("java.io.tmpdir")
  884. : parentDir.getPath();
  885. if (prefix == null) {
  886. prefix = NULL_PLACEHOLDER;
  887. }
  888. if (suffix == null) {
  889. suffix = NULL_PLACEHOLDER;
  890. }
  891. if (createFile) {
  892. try {
  893. result = File.createTempFile(prefix, suffix, new File(parent));
  894. } catch (IOException e) {
  895. throw new BuildException("Could not create tempfile in "
  896. + parent, e);
  897. }
  898. } else {
  899. DecimalFormat fmt = new DecimalFormat("#####");
  900. synchronized (rand) {
  901. do {
  902. result = new File(parent, prefix
  903. + fmt.format(rand.nextInt(Integer.MAX_VALUE)) + suffix);
  904. } while (result.exists());
  905. }
  906. }
  907. if (deleteOnExit) {
  908. result.deleteOnExit();
  909. }
  910. return result;
  911. }
  912. /**
  913. * Create a File object for a temporary file in a given directory. Without
  914. * actually creating the file.
  915. *
  916. * <p>
  917. * The file denoted by the returned abstract pathname did not exist before
  918. * this method was invoked, any subsequent invocation of this method will
  919. * yield a different file name.
  920. * </p>
  921. * <p>
  922. * The filename is prefixNNNNNsuffix where NNNN is a random number.
  923. * </p>
  924. *
  925. * @param prefix
  926. * prefix before the random number.
  927. * @param suffix
  928. * file extension; include the '.'.
  929. * @param parentDir
  930. * Directory to create the temporary file in; java.io.tmpdir used
  931. * if not specified.
  932. * @param deleteOnExit
  933. * whether to set the tempfile for deletion on normal VM exit.
  934. *
  935. * @deprecated since ant 1.7.1 use createTempFile(String, String, File,
  936. * boolean, boolean) instead.
  937. * @return a File reference to the new, nonexistent temporary file.
  938. */
  939. public File createTempFile(String prefix, String suffix,
  940. File parentDir, boolean deleteOnExit) {
  941. return createTempFile(prefix, suffix, parentDir, deleteOnExit, false);
  942. }
  943. /**
  944. * Compares the contents of two files.
  945. *
  946. * @param f1 the file whose content is to be compared.
  947. * @param f2 the other file whose content is to be compared.
  948. *
  949. * @return true if the content of the files is the same.
  950. *
  951. * @throws IOException if the files cannot be read.
  952. */
  953. public boolean contentEquals(File f1, File f2) throws IOException {
  954. return contentEquals(f1, f2, false);
  955. }
  956. /**
  957. * Compares the contents of two files.
  958. *
  959. * @param f1 the file whose content is to be compared.
  960. * @param f2 the other file whose content is to be compared.
  961. * @param textfile true if the file is to be treated as a text file and
  962. * differences in kind of line break are to be ignored.
  963. *
  964. * @return true if the content of the files is the same.
  965. *
  966. * @throws IOException if the files cannot be read.
  967. * @since Ant 1.6.3
  968. */
  969. public boolean contentEquals(File f1, File f2, boolean textfile) throws IOException {
  970. return ResourceUtils.contentEquals(new FileResource(f1), new FileResource(f2), textfile);
  971. }
  972. /**
  973. * This was originally an emulation of {@link File#getParentFile} for JDK 1.1, but it is now
  974. * implemented using that method (Ant 1.6.3 onwards).
  975. *
  976. * @param f the file whose parent is required.
  977. * @return the given file's parent, or null if the file does not have a parent.
  978. * @since 1.10
  979. * @deprecated since 1.7. Just use {@link File#getParentFile} directly.
  980. */
  981. public File getParentFile(File f) {
  982. return (f == null) ? null : f.getParentFile();
  983. }
  984. /**
  985. * Read from reader till EOF.
  986. * @param rdr the reader from which to read.
  987. * @return the contents read out of the given reader.
  988. *
  989. * @throws IOException if the contents could not be read out from the
  990. * reader.
  991. */
  992. public static String readFully(Reader rdr) throws IOException {
  993. return readFully(rdr, BUF_SIZE);
  994. }
  995. /**
  996. * Read from reader till EOF.
  997. *
  998. * @param rdr the reader from which to read.
  999. * @param bufferSize the buffer size to use when reading.
  1000. *
  1001. * @return the contents read out of the given reader.
  1002. *
  1003. * @throws IOException if the contents could not be read out from the
  1004. * reader.
  1005. */
  1006. public static String readFully(Reader rdr, int bufferSize)
  1007. throws IOException {
  1008. if (bufferSize <= 0) {
  1009. throw new IllegalArgumentException("Buffer size must be greater "
  1010. + "than 0");
  1011. }
  1012. final char[] buffer = new char[bufferSize];
  1013. int bufferLength = 0;
  1014. StringBuffer textBuffer = null;
  1015. while (bufferLength != -1) {
  1016. bufferLength = rdr.read(buffer);
  1017. if (bufferLength > 0) {
  1018. textBuffer = (textBuffer == null) ? new StringBuffer() : textBuffer;
  1019. textBuffer.append(new String(buffer, 0, bufferLength));
  1020. }
  1021. }
  1022. return (textBuffer == null) ? null : textBuffer.toString();
  1023. }
  1024. /**
  1025. * Safe read fully - do not return a null for an empty reader.
  1026. * @param reader the input to read from.
  1027. * @return the string.
  1028. * @throws IOException if unable to read from reader.
  1029. * @since Ant 1.7.1
  1030. */
  1031. public static String safeReadFully(Reader reader) throws IOException {
  1032. String ret = readFully(reader);
  1033. return ret == null ? "" : ret;
  1034. }
  1035. /**
  1036. * This was originally an emulation of File.createNewFile for JDK 1.1,
  1037. * but it is now implemented using that method (Ant 1.6.3 onwards).
  1038. *
  1039. * <p>This method has historically <strong>not</strong> guaranteed that the
  1040. * operation was atomic. In its current implementation it is.
  1041. *
  1042. * @param f the file to be created.
  1043. * @return true if the file did not exist already.
  1044. * @throws IOException on error.
  1045. * @since Ant 1.5
  1046. */
  1047. public boolean createNewFile(File f) throws IOException {
  1048. return f.createNewFile();
  1049. }
  1050. /**
  1051. * Create a new file, optionally creating parent directories.
  1052. *
  1053. * @param f the file to be created.
  1054. * @param mkdirs <code>boolean</code> whether to create parent directories.
  1055. * @return true if the file did not exist already.
  1056. * @throws IOException on error.
  1057. * @since Ant 1.6.3
  1058. */
  1059. public boolean createNewFile(File f, boolean mkdirs) throws IOException {
  1060. File parent = f.getParentFile();
  1061. if (mkdirs && !(parent.exists())) {
  1062. parent.mkdirs();
  1063. }
  1064. return f.createNewFile();
  1065. }
  1066. /**
  1067. * Checks whether a given file is a symbolic link.
  1068. *
  1069. * <p>It doesn't really test for symbolic links but whether the
  1070. * canonical and absolute paths of the file are identical--this
  1071. * may lead to false positives on some platforms.</p>
  1072. *
  1073. * @param parent the parent directory of the file to test
  1074. * @param name the name of the file to test.
  1075. *
  1076. * @return true if the file is a symbolic link.
  1077. * @throws IOException on error.
  1078. * @since Ant 1.5
  1079. * @deprecated use SymbolicLinkUtils instead
  1080. */
  1081. public boolean isSymbolicLink(File parent, String name)
  1082. throws IOException {
  1083. SymbolicLinkUtils u = SymbolicLinkUtils.getSymbolicLinkUtils();
  1084. if (parent == null) {
  1085. return u.isSymbolicLink(name);
  1086. }
  1087. return u.isSymbolicLink(parent, name);
  1088. }
  1089. /**
  1090. * Removes a leading path from a second path.
  1091. *
  1092. * <p>This method uses {@link #normalize} under the covers and
  1093. * does not resolve symbolic links.</p>
  1094. *
  1095. * @param leading The leading path, must not be null, must be absolute.
  1096. * @param path The path to remove from, must not be null, must be absolute.
  1097. *
  1098. * @return path's normalized absolute if it doesn't start with
  1099. * leading; path's path with leading's path removed otherwise.
  1100. *
  1101. * @since Ant 1.5
  1102. */
  1103. public String removeLeadingPath(File leading, File path) {
  1104. String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
  1105. String p = normalize(path.getAbsolutePath()).getAbsolutePath();
  1106. if (l.equals(p)) {
  1107. return "";
  1108. }
  1109. // ensure that l ends with a /
  1110. // so we never think /foo was a parent directory of /foobar
  1111. if (!l.endsWith(File.separator)) {
  1112. l += File.separator;
  1113. }
  1114. return (p.startsWith(l)) ? p.substring(l.length()) : p;
  1115. }
  1116. /**
  1117. * Learn whether one path "leads" another.
  1118. *
  1119. * <p>This method uses {@link #normalize} under the covers and
  1120. * does not resolve symbolic links.</p>
  1121. *
  1122. * <p>If either path tries to go beyond the file system root
  1123. * (i.e. it contains more ".." segments than can be travelled up)
  1124. * the method will return false.</p>
  1125. *
  1126. * @param leading The leading path, must not be null, must be absolute.
  1127. * @param path The path to check, must not be null, must be absolute.
  1128. * @return true if path starts with leading; false otherwise.
  1129. * @since Ant 1.7
  1130. */
  1131. public boolean isLeadingPath(File leading, File path) {
  1132. String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
  1133. String p = normalize(path.getAbsolutePath()).getAbsolutePath();
  1134. if (l.equals(p)) {
  1135. return true;
  1136. }
  1137. // ensure that l ends with a /
  1138. // so we never think /foo was a parent directory of /foobar
  1139. if (!l.endsWith(File.separator)) {
  1140. l += File.separator;
  1141. }
  1142. // ensure "/foo/" is not considered a parent of "/foo/../../bar"
  1143. String up = File.separator + ".." + File.separator;
  1144. if (l.contains(up) || p.contains(up) || (p + File.separator).contains(up)) {
  1145. return false;
  1146. }
  1147. return p.startsWith(l);
  1148. }
  1149. /**
  1150. * Learn whether one path "leads" another.
  1151. *
  1152. * @param leading The leading path, must not be null, must be absolute.
  1153. * @param path The path to check, must not be null, must be absolute.
  1154. * @param resolveSymlinks whether symbolic links shall be resolved
  1155. * prior to comparing the paths.
  1156. * @return true if path starts with leading; false otherwise.
  1157. * @since Ant 1.9.13
  1158. * @throws IOException if resolveSymlinks is true and invoking
  1159. * getCanonicaPath on either argument throws an exception
  1160. */
  1161. public boolean isLeadingPath(File leading, File path, boolean resolveSymlinks)
  1162. throws IOException {
  1163. if (!resolveSymlinks) {
  1164. return isLeadingPath(leading, path);
  1165. }
  1166. String l = leading.getCanonicalPath();
  1167. String p = path.getCanonicalPath();
  1168. if (l.equals(p)) {
  1169. return true;
  1170. }
  1171. // ensure that l ends with a /
  1172. // so we never think /foo was a parent directory of /foobar
  1173. if (!l.endsWith(File.separator)) {
  1174. l += File.separator;
  1175. }
  1176. return p.startsWith(l);
  1177. }
  1178. /**
  1179. * Constructs a <code>file:</code> URI that represents the
  1180. * external form of the given pathname.
  1181. *
  1182. * <p>Will be an absolute URI if the given path is absolute.</p>
  1183. *
  1184. * <p>This code encodes non ASCII characters too.</p>
  1185. *
  1186. * <p>The coding of the output is the same as what File.toURI().toASCIIString() produces</p>
  1187. *
  1188. * See <a href="http://www.w3.org/TR/xml11/#dt-sysid">dt-sysid</a>
  1189. * which makes some mention of how
  1190. * characters not supported by URI Reference syntax should be escaped.
  1191. *
  1192. * @param path the path in the local file system.
  1193. * @return the URI version of the local path.
  1194. * @since Ant 1.6
  1195. */
  1196. public String toURI(String path) {
  1197. return new File(path).toURI().toASCIIString();
  1198. }
  1199. /**
  1200. * Constructs a file path from a <code>file:</code> URI.
  1201. *
  1202. * <p>Will be an absolute path if the given URI is absolute.</p>
  1203. *
  1204. * <p>Swallows '%' that are not followed by two characters,
  1205. * doesn't deal with non-ASCII characters.</p>
  1206. *
  1207. * @param uri the URI designating a file in the local filesystem.
  1208. * @return the local file system path for the file.
  1209. * @since Ant 1.6
  1210. */
  1211. public String fromURI(String uri) {
  1212. synchronized (cacheFromUriLock) {
  1213. if (uri.equals(cacheFromUriRequest)) {
  1214. return cacheFromUriResponse;
  1215. }
  1216. String path = Locator.fromURI(uri);
  1217. String ret = isAbsolutePath(path) ? normalize(path).getAbsolutePath() : path;
  1218. cacheFromUriRequest = uri;
  1219. cacheFromUriResponse = ret;
  1220. return ret;
  1221. }
  1222. }
  1223. /**
  1224. * Compares two filenames.
  1225. *
  1226. * <p>Unlike java.io.File#equals this method will try to compare
  1227. * the absolute paths and &quot;normalize&quot; the filenames
  1228. * before comparing them.</p>
  1229. *
  1230. * @param f1 the file whose name is to be compared.
  1231. * @param f2 the other file whose name is to be compared.
  1232. *
  1233. * @return true if the file are for the same file.
  1234. *
  1235. * @since Ant 1.5.3
  1236. */
  1237. public boolean fileNameEquals(File f1, File f2) {
  1238. return normalize(f1.getAbsolutePath()).getAbsolutePath().equals(
  1239. normalize(f2.getAbsolutePath()).getAbsolutePath());
  1240. }
  1241. /**
  1242. * Are the two File instances pointing to the same object on the
  1243. * file system?
  1244. *
  1245. * @param f1 File
  1246. * @param f2 File
  1247. * @return boolean
  1248. * @throws IOException if file name canonicalization fails
  1249. * @since Ant 1.8.2
  1250. */
  1251. public boolean areSame(File f1, File f2) throws IOException {
  1252. if (f1 == null && f2 == null) {
  1253. return true;
  1254. }
  1255. if (f1 == null || f2 == null) {
  1256. return false;
  1257. }
  1258. File f1Normalized = normalize(f1.getAbsolutePath());
  1259. File f2Normalized = normalize(f2.getAbsolutePath());
  1260. return f1Normalized.equals(f2Normalized)
  1261. || f1Normalized.getCanonicalFile().equals(f2Normalized
  1262. .getCanonicalFile());
  1263. }
  1264. /**
  1265. * Renames a file, even if that involves crossing file system boundaries.
  1266. *
  1267. * <p>This will remove <code>to</code> (if it exists), ensure that
  1268. * <code>to</code>'s parent directory exists and move
  1269. * <code>from</code>, which involves deleting <code>from</code> as
  1270. * well.</p>
  1271. *
  1272. * @param from the file to move.
  1273. * @param to the new file name.
  1274. * @throws IOException if anything bad happens during this
  1275. * process. Note that <code>to</code> may have been deleted
  1276. * already when this happens.
  1277. * @since Ant 1.6
  1278. */
  1279. public void rename(File from, File to) throws IOException {
  1280. // identical logic lives in Move.renameFile():
  1281. from = normalize(from.getAbsolutePath()).getCanonicalFile();
  1282. to = normalize(to.getAbsolutePath());
  1283. if (!from.exists()) {
  1284. System.err.println("Cannot rename nonexistent file " + from);
  1285. return;
  1286. }
  1287. if (from.getAbsolutePath().equals(to.getAbsolutePath())) {
  1288. System.err.println("Rename of " + from + " to " + to + " is a no-op.");
  1289. return;
  1290. }
  1291. if (to.exists() && !(areSame(from, to) || tryHardToDelete(to))) {
  1292. throw new IOException("Failed to delete " + to + " while trying to rename " + from);
  1293. }
  1294. File parent = to.getParentFile();
  1295. if (parent != null && !parent.isDirectory()
  1296. && !(parent.mkdirs() || parent.isDirectory())) {
  1297. throw new IOException("Failed to create directory " + parent
  1298. + " while trying to rename " + from);
  1299. }
  1300. if (!from.renameTo(to)) {
  1301. copyFile(from, to);
  1302. if (!tryHardToDelete(from)) {
  1303. throw new IOException("Failed to delete " + from + " while trying to rename it.");
  1304. }
  1305. }
  1306. }
  1307. /**
  1308. * Get the granularity of file timestamps. The choice is made based on OS, which is
  1309. * incorrect--it should really be by filesystem. We do not have an easy way to probe for file
  1310. * systems, however, so this heuristic gives us a decent default.
  1311. *
  1312. * @return the difference, in milliseconds, which two file timestamps must have in order for the
  1313. * two files to be considered to have different timestamps.
  1314. */
  1315. public long getFileTimestampGranularity() {
  1316. if (ON_WIN9X) {
  1317. return FAT_FILE_TIMESTAMP_GRANULARITY;
  1318. }
  1319. if (ON_WINDOWS) {
  1320. return NTFS_FILE_TIMESTAMP_GRANULARITY;
  1321. }
  1322. if (ON_DOS) {
  1323. return FAT_FILE_TIMESTAMP_GRANULARITY;
  1324. }
  1325. return UNIX_FILE_TIMESTAMP_GRANULARITY;
  1326. }
  1327. /**
  1328. * test whether a file or directory exists, with an error in the
  1329. * upper/lower case spelling of the name.
  1330. * Using this method is only interesting on case insensitive file systems
  1331. * (Windows).
  1332. * <p>
  1333. * It will return true only if 3 conditions are met:
  1334. * </p>
  1335. * <ul>
  1336. * <li>operating system is case insensitive</li>
  1337. * <li>file exists</li>
  1338. * <li>actual name from directory reading is different from the
  1339. * supplied argument</li>
  1340. * </ul>
  1341. * <p>
  1342. * The purpose is to identify files or directories on case-insensitive
  1343. * filesystems whose case is not what is expected.
  1344. * </p>
  1345. * Possibly to rename them afterwards to the desired upper/lowercase
  1346. * combination.
  1347. *
  1348. * @param localFile file to test
  1349. * @return true if the file exists and the case of the actual file
  1350. * is not the case of the parameter
  1351. * @since Ant 1.7.1
  1352. */
  1353. public boolean hasErrorInCase(File localFile) {
  1354. localFile = normalize(localFile.getAbsolutePath());
  1355. if (!localFile.exists()) {
  1356. return false;
  1357. }
  1358. final String localFileName = localFile.getName();
  1359. FilenameFilter ff = new FilenameFilter () {
  1360. public boolean accept(File dir, String name) {
  1361. return name.equalsIgnoreCase(localFileName) && (!name.equals(localFileName));
  1362. }
  1363. };
  1364. String[] names = localFile.getParentFile().list(ff);
  1365. return names != null && names.length == 1;
  1366. }
  1367. /**
  1368. * Returns true if the source is older than the dest.
  1369. * If the dest file does not exist, then the test returns false; it is
  1370. * implicitly not up do date.
  1371. * @param source source file (should be the older).
  1372. * @param dest dest file (should be the newer).
  1373. * @param granularity an offset added to the source time.
  1374. * @return true if the source is older than the dest after accounting
  1375. * for granularity.
  1376. * @since Ant 1.6.3
  1377. */
  1378. public boolean isUpToDate(File source, File dest, long granularity) {
  1379. //do a check for the destination file existing
  1380. if (!dest.exists()) {
  1381. //if it does not, then the file is not up to date.
  1382. return false;
  1383. }
  1384. long sourceTime = source.lastModified();
  1385. long destTime = dest.lastModified();
  1386. return isUpToDate(sourceTime, destTime, granularity);
  1387. }
  1388. /**
  1389. * Returns true if the source is older than the dest.
  1390. * @param source source file (should be the older).
  1391. * @param dest dest file (should be the newer).
  1392. * @return true if the source is older than the dest, taking the granularity into account.
  1393. * @since Ant 1.6.3
  1394. */
  1395. public boolean isUpToDate(File source, File dest) {
  1396. return isUpToDate(source, dest, getFileTimestampGranularity());
  1397. }
  1398. /**
  1399. * Compare two timestamps for being up to date using
  1400. * the specified granularity.
  1401. *
  1402. * @param sourceTime timestamp of source file.
  1403. * @param destTime timestamp of dest file.
  1404. * @param granularity os/filesys granularity.
  1405. * @return true if the dest file is considered up to date.
  1406. */
  1407. public boolean isUpToDate(long sourceTime, long destTime, long granularity) {
  1408. return destTime != -1 && destTime >= sourceTime + granularity;
  1409. }
  1410. /**
  1411. * Compare two timestamps for being up to date using the
  1412. * current granularity.
  1413. *
  1414. * @param sourceTime timestamp of source file.
  1415. * @param destTime timestamp of dest file.
  1416. * @return true if the dest file is considered up to date.
  1417. */
  1418. public boolean isUpToDate(long sourceTime, long destTime) {
  1419. return isUpToDate(sourceTime, destTime, getFileTimestampGranularity());
  1420. }
  1421. /**
  1422. * Close a Writer without throwing any exception if something went wrong.
  1423. * Do not attempt to close it if the argument is null.
  1424. * @param device output writer, can be null.
  1425. */
  1426. public static void close(Writer device) {
  1427. if (null != device) {
  1428. try {
  1429. device.close();
  1430. } catch (IOException e) {
  1431. //ignore
  1432. }
  1433. }
  1434. }
  1435. /**
  1436. * Close a Reader without throwing any exception if something went wrong.
  1437. * Do not attempt to close it if the argument is null.
  1438. *
  1439. * @param device Reader, can be null.
  1440. */
  1441. public static void close(Reader device) {
  1442. if (null != device) {
  1443. try {
  1444. device.close();
  1445. } catch (IOException e) {
  1446. //ignore
  1447. }
  1448. }
  1449. }
  1450. /**
  1451. * Close a stream without throwing any exception if something went wrong.
  1452. * Do not attempt to close it if the argument is null.
  1453. *
  1454. * @param device stream, can be null.
  1455. */
  1456. public static void close(OutputStream device) {
  1457. if (null != device) {
  1458. try {
  1459. device.close();
  1460. } catch (IOException e) {
  1461. //ignore
  1462. }
  1463. }
  1464. }
  1465. /**
  1466. * Close a stream without throwing any exception if something went wrong.
  1467. * Do not attempt to close it if the argument is null.
  1468. *
  1469. * @param device stream, can be null.
  1470. */
  1471. public static void close(InputStream device) {
  1472. if (null != device) {
  1473. try {
  1474. device.close();
  1475. } catch (IOException e) {
  1476. //ignore
  1477. }
  1478. }
  1479. }
  1480. /**
  1481. * Close a Channel without throwing any exception if something went wrong.
  1482. * Do not attempt to close it if the argument is null.
  1483. *
  1484. * @param device channel, can be null.
  1485. * @since Ant 1.8.0
  1486. */
  1487. public static void close(Channel device) {
  1488. if (null != device) {
  1489. try {
  1490. device.close();
  1491. } catch (IOException e) {
  1492. //ignore
  1493. }
  1494. }
  1495. }
  1496. /**
  1497. * Closes an URLConnection if its concrete implementation provides
  1498. * a way to close it that Ant knows of.
  1499. *
  1500. * @param conn connection, can be null
  1501. * @since Ant 1.8.0
  1502. */
  1503. public static void close(URLConnection conn) {
  1504. if (conn != null) {
  1505. try {
  1506. if (conn instanceof JarURLConnection) {
  1507. JarURLConnection juc = (JarURLConnection) conn;
  1508. JarFile jf = juc.getJarFile();
  1509. jf.close();
  1510. jf = null;
  1511. } else if (conn instanceof HttpURLConnection) {
  1512. ((HttpURLConnection) conn).disconnect();
  1513. }
  1514. } catch (IOException exc) {
  1515. //ignore
  1516. }
  1517. }
  1518. }
  1519. /**
  1520. * Delete the file with {@link File#delete()} if the argument is not null.
  1521. * Do nothing on a null argument.
  1522. * @param file file to delete.
  1523. */
  1524. public static void delete(File file) {
  1525. if (file != null) {
  1526. file.delete();
  1527. }
  1528. }
  1529. /**
  1530. * Accommodate Windows bug encountered in both Sun and IBM JDKs.
  1531. * Others possible. If the delete does not work, call System.gc(),
  1532. * wait a little and try again.
  1533. *
  1534. * @param f File
  1535. * @return whether deletion was successful
  1536. * @since Ant 1.8.0
  1537. */
  1538. public boolean tryHardToDelete(File f) {
  1539. return tryHardToDelete(f, ON_WINDOWS);
  1540. }
  1541. /**
  1542. * If delete does not work, call System.gc() if asked to, wait a
  1543. * little and try again.
  1544. *
  1545. * @param f File
  1546. * @param runGC boolean
  1547. * @return whether deletion was successful
  1548. * @since Ant 1.8.3
  1549. */
  1550. public boolean tryHardToDelete(File f, boolean runGC) {
  1551. if (!f.delete()) {
  1552. if (runGC) {
  1553. System.gc();
  1554. }
  1555. try {
  1556. Thread.sleep(DELETE_RETRY_SLEEP_MILLIS);
  1557. } catch (InterruptedException ex) {
  1558. // Ignore Exception
  1559. }
  1560. return f.delete();
  1561. }
  1562. return true;
  1563. }
  1564. /**
  1565. * Calculates the relative path between two files.
  1566. * <p>
  1567. * Implementation note:<br>This function may throw an IOException if an I/O error occurs
  1568. * because its use of the canonical pathname may require filesystem queries.
  1569. * </p>
  1570. *
  1571. * @param fromFile the <code>File</code> to calculate the path from
  1572. * @param toFile the <code>File</code> to calculate the path to
  1573. * @return the relative path between the files
  1574. * @throws Exception for undocumented reasons
  1575. * @see File#getCanonicalPath()
  1576. *
  1577. * @since Ant 1.7
  1578. */
  1579. public static String getRelativePath(File fromFile, File toFile) throws Exception { //NOSONAR
  1580. String fromPath = fromFile.getCanonicalPath();
  1581. String toPath = toFile.getCanonicalPath();
  1582. // build the path stack info to compare
  1583. String[] fromPathStack = getPathStack(fromPath);
  1584. String[] toPathStack = getPathStack(toPath);
  1585. if (0 < toPathStack.length && 0 < fromPathStack.length) {
  1586. if (!fromPathStack[0].equals(toPathStack[0])) {
  1587. // not the same device (would be "" on Linux/Unix)
  1588. return getPath(Arrays.asList(toPathStack));
  1589. }
  1590. } else {
  1591. // no comparison possible
  1592. return getPath(Arrays.asList(toPathStack));
  1593. }
  1594. int minLength = Math.min(fromPathStack.length, toPathStack.length);
  1595. int same = 1; // Used outside the for loop
  1596. // get index of parts which are equal
  1597. for (;
  1598. same < minLength && fromPathStack[same].equals(toPathStack[same]);
  1599. same++) {
  1600. // Do nothing
  1601. }
  1602. List relativePathStack = new ArrayList();
  1603. // if "from" part is longer, fill it up with ".."
  1604. // to reach path which is equal to both paths
  1605. for (int i = same; i < fromPathStack.length; i++) {
  1606. relativePathStack.add("..");
  1607. }
  1608. // fill it up path with parts which were not equal
  1609. for (int i = same; i < toPathStack.length; i++) {
  1610. relativePathStack.add(toPathStack[i]);
  1611. }
  1612. return getPath(relativePathStack);
  1613. }
  1614. /**
  1615. * Gets all names of the path as an array of <code>String</code>s.
  1616. *
  1617. * @param path to get names from
  1618. * @return <code>String</code>s, never <code>null</code>
  1619. *
  1620. * @since Ant 1.7
  1621. */
  1622. public static String[] getPathStack(String path) {
  1623. String normalizedPath = path.replace(File.separatorChar, '/');
  1624. return normalizedPath.split("/");
  1625. }
  1626. /**
  1627. * Gets path from a <code>List</code> of <code>String</code>s.
  1628. *
  1629. * @param pathStack <code>List</code> of <code>String</code>s to be concatenated as a path.
  1630. * @return <code>String</code>, never <code>null</code>
  1631. *
  1632. * @since Ant 1.7
  1633. */
  1634. public static String getPath(List pathStack) {
  1635. // can safely use '/' because Windows understands '/' as separator
  1636. return getPath(pathStack, '/');
  1637. }
  1638. /**
  1639. * Gets path from a <code>List</code> of <code>String</code>s.
  1640. *
  1641. * @param pathStack <code>List</code> of <code>String</code>s to be concatenated as a path.
  1642. * @param separatorChar <code>char</code> to be used as separator between names in path
  1643. * @return <code>String</code>, never <code>null</code>
  1644. *
  1645. * @since Ant 1.7
  1646. */
  1647. public static String getPath(final List pathStack, final char separatorChar) {
  1648. final StringBuffer buffer = new StringBuffer();
  1649. final Iterator iter = pathStack.iterator();
  1650. if (iter.hasNext()) {
  1651. buffer.append(iter.next());
  1652. }
  1653. while (iter.hasNext()) {
  1654. buffer.append(separatorChar);
  1655. buffer.append(iter.next());
  1656. }
  1657. return buffer.toString();
  1658. }
  1659. /**
  1660. * Get the default encoding.
  1661. * This is done by opening an InputStreamReader on
  1662. * a dummy InputStream and getting the encoding.
  1663. * Could use System.getProperty("file.encoding"), but cannot
  1664. * see where this is documented.
  1665. * @return the default file encoding.
  1666. */
  1667. public String getDefaultEncoding() {
  1668. InputStreamReader is = new InputStreamReader(
  1669. new InputStream() { //NOSONAR
  1670. public int read() {
  1671. return -1;
  1672. }
  1673. });
  1674. try {
  1675. return is.getEncoding();
  1676. } finally {
  1677. close(is);
  1678. }
  1679. }
  1680. }