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

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