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

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