PageRenderTime 99ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/izpack-src/branches/4.3/src/lib/com/izforge/izpack/util/IoHelper.java

https://github.com/jponge/izpack-full-svn-history-copy
Java | 719 lines | 422 code | 38 blank | 259 comment | 71 complexity | 0c74b9c14368a771dc29c85f2982568c MD5 | raw file
  1. /*
  2. * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
  3. *
  4. * http://izpack.org/
  5. * http://izpack.codehaus.org/
  6. *
  7. * Copyright 2004 Elmar Klaus Bartz
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License");
  10. * you may not use this file except in compliance with the License.
  11. * You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing, software
  16. * distributed under the License is distributed on an "AS IS" BASIS,
  17. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. * See the License for the specific language governing permissions and
  19. * limitations under the License.
  20. */
  21. package com.izforge.izpack.util;
  22. import java.io.*;
  23. import java.util.Properties;
  24. import java.util.StringTokenizer;
  25. /**
  26. * <p>
  27. * Class with some IO related helper.
  28. * </p>
  29. */
  30. public class IoHelper
  31. {
  32. // This class uses the same values for family and flavor as
  33. // TargetFactory. But this class should not depends on TargetFactory,
  34. // because it is possible that TargetFactory is not bound. Therefore
  35. // the definition here again.
  36. // ------------------------------------------------------------------------
  37. // Constant Definitions
  38. // ------------------------------------------------------------------------
  39. /**
  40. * Placeholder during translatePath computing
  41. */
  42. private static final String MASKED_SLASH_PLACEHOLDER = "~&_&~";
  43. private static Properties envVars = null;
  44. /**
  45. * Default constructor
  46. */
  47. private IoHelper()
  48. {
  49. }
  50. /**
  51. * Copies the contents of inFile into outFile.
  52. *
  53. * @param inFile path of file which should be copied
  54. * @param outFile path of file to create and copy the contents of inFile into
  55. */
  56. public static void copyFile(String inFile, String outFile) throws IOException
  57. {
  58. copyFile(new File(inFile), new File(outFile));
  59. }
  60. /**
  61. * Creates an in- and output stream for the given File objects and copies all the data from the
  62. * specified input to the specified output.
  63. *
  64. * @param inFile File object for input
  65. * @param outFile File object for output
  66. * @throws IOException if an I/O error occurs
  67. */
  68. public static void copyFile(File inFile, File outFile) throws IOException
  69. {
  70. copyFile(inFile, outFile, null, null);
  71. }
  72. /**
  73. * Creates an in- and output stream for the given File objects and copies all the data from the
  74. * specified input to the specified output. If permissions is not null, a chmod will be done on
  75. * the output file.
  76. *
  77. * @param inFile File object for input
  78. * @param outFile File object for output
  79. * @param permissions permissions for the output file
  80. * @throws IOException if an I/O error occurs
  81. */
  82. public static void copyFile(File inFile, File outFile, String permissions) throws IOException
  83. {
  84. copyFile(inFile, outFile, permissions, null);
  85. }
  86. /**
  87. * Creates an in- and output stream for the given File objects and copies all the data from the
  88. * specified input to the specified output. If the VariableSubstitutor is not null, a substition
  89. * will be done during copy.
  90. *
  91. * @param inFile File object for input
  92. * @param outFile File object for output
  93. * @param vss substitutor which is used during copying
  94. * @throws IOException if an I/O error occurs
  95. */
  96. public static void copyFile(File inFile, File outFile, VariableSubstitutor vss)
  97. throws IOException
  98. {
  99. copyFile(inFile, outFile, null, vss);
  100. }
  101. /**
  102. * Creates an in- and output stream for the given File objects and copies all the data from the
  103. * specified input to the specified output. If the VariableSubstitutor is not null, a substition
  104. * will be done during copy. If permissions is not null, a chmod will be done on the output
  105. * file.
  106. *
  107. * @param inFile File object for input
  108. * @param outFile File object for output
  109. * @param permissions permissions for the output file
  110. * @param vs substitutor which is used during copying
  111. * @throws IOException if an I/O error occurs
  112. */
  113. public static void copyFile(File inFile, File outFile, String permissions,
  114. VariableSubstitutor vs) throws IOException
  115. {
  116. copyFile(inFile, outFile, permissions, vs, null);
  117. }
  118. /**
  119. * Creates an in- and output stream for the given File objects and copies all the data from the
  120. * specified input to the specified output. If the VariableSubstitutor is not null, a substition
  121. * will be done during copy. If permissions is not null, a chmod will be done on the output
  122. * file. If type is not null, that type is used as file type at substitution.
  123. *
  124. * @param inFile File object for input
  125. * @param outFile File object for output
  126. * @param permissions permissions for the output file
  127. * @param vs substitutor which is used during copying
  128. * @param type file type for the substitutor
  129. * @throws IOException if an I/O error occurs
  130. */
  131. public static void copyFile(File inFile, File outFile, String permissions,
  132. VariableSubstitutor vs, String type) throws IOException
  133. {
  134. FileOutputStream out = new FileOutputStream(outFile);
  135. FileInputStream in = new FileInputStream(inFile);
  136. copyStream(in, out, vs, type);
  137. if (permissions != null && IoHelper.supported("chmod"))
  138. {
  139. chmod(outFile.getAbsolutePath(), permissions);
  140. }
  141. }
  142. /**
  143. * Copies an input stream to an output stream. Both streams must already
  144. * be open. If the VariableSubstitutor is not null, a substition
  145. * will be done during copy.
  146. *
  147. * @param in stream object for input
  148. * @param out stream object for output
  149. * @param vs substitutor which is used during copying
  150. * @param type file type for the substitutor
  151. * @throws IOException if an I/O error occurs
  152. */
  153. public static void copyStream(InputStream in, OutputStream out, VariableSubstitutor vs, String type) throws IOException
  154. {
  155. if (vs == null)
  156. {
  157. byte[] buffer = new byte[5120];
  158. long bytesCopied = 0;
  159. int bytesInBuffer;
  160. while ((bytesInBuffer = in.read(buffer)) != -1)
  161. {
  162. out.write(buffer, 0, bytesInBuffer);
  163. bytesCopied += bytesInBuffer;
  164. }
  165. in.close();
  166. out.close();
  167. }
  168. else
  169. {
  170. BufferedInputStream bin = new BufferedInputStream(in, 5120);
  171. BufferedOutputStream bout = new BufferedOutputStream(out, 5120);
  172. vs.substitute(bin, bout, type, null);
  173. bin.close();
  174. bout.close();
  175. }
  176. }
  177. /**
  178. * Creates a temp file with delete on exit rule. The extension is extracted from the template if
  179. * possible, else the default extension is used. The contents of template will be copied into
  180. * the temporary file.
  181. *
  182. * @param template file to copy from and define file extension
  183. * @param defaultExtension file extension if no is contained in template
  184. * @return newly created and filled temporary file
  185. * @throws IOException
  186. */
  187. public static File copyToTempFile(File template, String defaultExtension) throws IOException
  188. {
  189. return copyToTempFile(template, defaultExtension, null);
  190. }
  191. /**
  192. * Creates a temp file with delete on exit rule. The contents of the input stream will be copied into
  193. * the temporary file. If the variable substitutor is not null, variables will be replaced
  194. * during copying.
  195. *
  196. * @param is input stream to copy from
  197. * @param ext file extension
  198. * @param vss substitutor which is used during copying
  199. * @return newly created and filled temporary file
  200. * @throws IOException
  201. */
  202. public static File copyToTempFile(InputStream is, String ext,
  203. VariableSubstitutor vss) throws IOException
  204. {
  205. File tmpFile = File.createTempFile("izpack_io", ext);
  206. tmpFile.deleteOnExit();
  207. IoHelper.copyStream(is, new FileOutputStream(tmpFile), vss, null);
  208. return tmpFile;
  209. }
  210. /**
  211. * Creates a temp file with delete on exit rule. The extension is extracted from the template if
  212. * possible, else the default extension is used. The contents of template will be copied into
  213. * the temporary file. If the variable substitutor is not null, variables will be replaced
  214. * during copying.
  215. *
  216. * @param template file to copy from and define file extension
  217. * @param defaultExtension file extension if no is contained in template
  218. * @param vss substitutor which is used during copying
  219. * @return newly created and filled temporary file
  220. * @throws IOException
  221. */
  222. public static File copyToTempFile(File template, String defaultExtension,
  223. VariableSubstitutor vss) throws IOException
  224. {
  225. String path = template.getCanonicalPath();
  226. int pos = path.lastIndexOf('.');
  227. String ext = path.substring(pos);
  228. if (ext == null)
  229. {
  230. ext = defaultExtension;
  231. }
  232. File tmpFile = File.createTempFile("izpack_io", ext);
  233. tmpFile.deleteOnExit();
  234. IoHelper.copyFile(template, tmpFile, vss);
  235. return tmpFile;
  236. }
  237. /**
  238. * Creates a temp file with delete on exit rule. The extension is extracted from the template if
  239. * possible, else the default extension is used. The contents of template will be copied into
  240. * the temporary file.
  241. *
  242. * @param template file to copy from and define file extension
  243. * @param defaultExtension file extension if no is contained in template
  244. * @return newly created and filled temporary file
  245. * @throws IOException
  246. */
  247. public static File copyToTempFile(String template, String defaultExtension) throws IOException
  248. {
  249. return copyToTempFile(new File(template), defaultExtension);
  250. }
  251. /**
  252. * Changes the permissions of the given file to the given POSIX permissions.
  253. *
  254. * @param file the file for which the permissions should be changed
  255. * @param permissions POSIX permissions to be set
  256. * @throws IOException if an I/O error occurs
  257. */
  258. public static void chmod(File file, String permissions) throws IOException
  259. {
  260. chmod(file.getAbsolutePath(), permissions);
  261. }
  262. /**
  263. * Changes the permissions of the given file to the given POSIX permissions. This method will be
  264. * raised an exception, if the OS is not UNIX.
  265. *
  266. * @param path the absolute path of the file for which the permissions should be changed
  267. * @param permissions POSIX permissions to be set
  268. * @throws IOException if an I/O error occurs
  269. */
  270. public static void chmod(String path, String permissions) throws IOException
  271. {
  272. // Perform UNIX
  273. if (OsVersion.IS_UNIX)
  274. {
  275. String[] params = {"chmod", permissions, path};
  276. String[] output = new String[2];
  277. FileExecutor fe = new FileExecutor();
  278. fe.executeCommand(params, output);
  279. }
  280. else
  281. {
  282. throw new IOException("Sorry, chmod not supported yet on " + OsVersion.OS_NAME + ".");
  283. }
  284. }
  285. /**
  286. * Returns the free (disk) space for the given path. If it is not ascertainable -1 returns.
  287. *
  288. * @param path path for which the free space should be detected
  289. * @return the free space for the given path
  290. */
  291. public static long getFreeSpace(String path)
  292. {
  293. long retval = -1;
  294. if (OsVersion.IS_WINDOWS)
  295. {
  296. String command = "cmd.exe";
  297. if (System.getProperty("os.name").toLowerCase().indexOf("windows 9") > -1)
  298. {
  299. return (-1);
  300. }
  301. String[] params = {command, "/C", "\"dir /D /-C \"" + path + "\"\""};
  302. String[] output = new String[2];
  303. FileExecutor fe = new FileExecutor();
  304. fe.executeCommand(params, output);
  305. retval = extractLong(output[0], -3, 3, "%");
  306. }
  307. else if (OsVersion.IS_SUNOS)
  308. {
  309. String[] params = {"df", "-k", path};
  310. String[] output = new String[2];
  311. FileExecutor fe = new FileExecutor();
  312. fe.executeCommand(params, output);
  313. retval = extractLong(output[0], -3, 3, "%") * 1024;
  314. }
  315. else if (OsVersion.IS_HPUX)
  316. {
  317. String[] params = {"bdf", path};
  318. String[] output = new String[2];
  319. FileExecutor fe = new FileExecutor();
  320. fe.executeCommand(params, output);
  321. retval = extractLong(output[0], -3, 3, "%") * 1024;
  322. }
  323. else if (OsVersion.IS_UNIX)
  324. {
  325. String[] params = {"df", "-Pk", path};
  326. String[] output = new String[2];
  327. FileExecutor fe = new FileExecutor();
  328. fe.executeCommand(params, output);
  329. retval = extractLong(output[0], -3, 3, "%") * 1024;
  330. }
  331. return retval;
  332. }
  333. /**
  334. * Returns whether the given method will be supported with the given environment. Some methods
  335. * of this class are not supported on all operation systems.
  336. *
  337. * @param method name of the method
  338. * @return true if the method will be supported with the current enivronment else false
  339. * @throws RuntimeException if the given method name does not exist
  340. */
  341. public static boolean supported(String method)
  342. {
  343. if ("getFreeSpace".equals(method))
  344. {
  345. if (OsVersion.IS_UNIX)
  346. {
  347. return true;
  348. }
  349. if (OsVersion.IS_WINDOWS)
  350. { // getFreeSpace do not work on Windows 98.
  351. if (System.getProperty("os.name").toLowerCase().indexOf("windows 9") > -1)
  352. {
  353. return (false);
  354. }
  355. return (true);
  356. }
  357. }
  358. else if ("chmod".equals(method))
  359. {
  360. if (OsVersion.IS_UNIX)
  361. {
  362. return true;
  363. }
  364. }
  365. else if ("copyFile".equals(method))
  366. {
  367. return true;
  368. }
  369. else if ("getPrimaryGroup".equals(method))
  370. {
  371. if (OsVersion.IS_UNIX)
  372. {
  373. return true;
  374. }
  375. }
  376. else if ("getenv".equals(method))
  377. {
  378. return true;
  379. }
  380. else
  381. {
  382. throw new RuntimeException("method name " + method + "not supported by this method");
  383. }
  384. return false;
  385. }
  386. /**
  387. * Returns the first existing parent directory in a path
  388. *
  389. * @param path path which should be scanned
  390. * @return the first existing parent directory in a path
  391. */
  392. public static File existingParent(File path)
  393. {
  394. File result = path;
  395. while (!result.exists())
  396. {
  397. if (result.getParent() == null)
  398. {
  399. return result;
  400. }
  401. result = result.getParentFile();
  402. }
  403. return result;
  404. }
  405. /**
  406. * Extracts a long value from a string in a special manner. The string will be broken into
  407. * tokens with a standard StringTokenizer. Arround the assumed place (with the given half range)
  408. * the tokens are scaned reverse for a token which represents a long. if useNotIdentifier is not
  409. * null, tokens which are contains this string will be ignored. The first founded long returns.
  410. *
  411. * @param in the string which should be parsed
  412. * @param assumedPlace token number which should contain the value
  413. * @param halfRange half range for detection range
  414. * @param useNotIdentifier string which determines tokens which should be ignored
  415. * @return founded long
  416. */
  417. private static long extractLong(String in, int assumedPlace, int halfRange,
  418. String useNotIdentifier)
  419. {
  420. long retval = -1;
  421. StringTokenizer st = new StringTokenizer(in);
  422. int length = st.countTokens();
  423. int i;
  424. int currentRange = 0;
  425. String[] interestedEntries = new String[halfRange + halfRange];
  426. for (i = 0; i < length - halfRange + assumedPlace; ++i)
  427. {
  428. st.nextToken(); // Forget this entries.
  429. }
  430. for (i = 0; i < halfRange + halfRange; ++i)
  431. { // Put the interesting Strings into an intermediaer array.
  432. if (st.hasMoreTokens())
  433. {
  434. interestedEntries[i] = st.nextToken();
  435. currentRange++;
  436. }
  437. }
  438. for (i = currentRange - 1; i >= 0; --i)
  439. {
  440. if (useNotIdentifier != null && interestedEntries[i].indexOf(useNotIdentifier) > -1)
  441. {
  442. continue;
  443. }
  444. try
  445. {
  446. retval = Long.parseLong(interestedEntries[i]);
  447. }
  448. catch (NumberFormatException nfe)
  449. {
  450. continue;
  451. }
  452. break;
  453. }
  454. return retval;
  455. }
  456. /**
  457. * Returns the primary group of the current user. This feature will be supported only on Unix.
  458. * On other systems null returns.
  459. *
  460. * @return the primary group of the current user
  461. */
  462. public static String getPrimaryGroup()
  463. {
  464. if (supported("getPrimaryGroup"))
  465. {
  466. if (OsVersion.IS_SUNOS)
  467. { // Standard id of SOLARIS do not support -gn.
  468. String[] params = {"id"};
  469. String[] output = new String[2];
  470. FileExecutor fe = new FileExecutor();
  471. fe.executeCommand(params, output);
  472. // No we have "uid=%u(%s) gid=%u(%s)"
  473. if (output[0] != null)
  474. {
  475. StringTokenizer st = new StringTokenizer(output[0], "()");
  476. int length = st.countTokens();
  477. if (length >= 4)
  478. {
  479. for (int i = 0; i < 3; ++i)
  480. {
  481. st.nextToken();
  482. }
  483. return (st.nextToken());
  484. }
  485. }
  486. return (null);
  487. }
  488. else
  489. {
  490. String[] params = {"id", "-gn"};
  491. String[] output = new String[2];
  492. FileExecutor fe = new FileExecutor();
  493. fe.executeCommand(params, output);
  494. return output[0];
  495. }
  496. }
  497. else
  498. {
  499. return null;
  500. }
  501. }
  502. /**
  503. * Returns a string resulting from replacing all occurrences of what in this string with with.
  504. * In opposite to the String.replaceAll method this method do not use regular expression or
  505. * other methods which are only available in JRE 1.4 and later. This method was special made to
  506. * mask masked slashes to avert a conversion during path translation.
  507. *
  508. * @param destination string for which the replacing should be performed
  509. * @param what what string should be replaced
  510. * @param with with what string what should be replaced
  511. * @return a new String object if what was found in the given string, else the given string self
  512. */
  513. public static String replaceString(String destination, String what, String with)
  514. {
  515. if (destination.indexOf(what) >= 0)
  516. { // what found, with (placeholder) not included in destination ->
  517. // perform changing.
  518. StringBuffer buf = new StringBuffer();
  519. int last = 0;
  520. int current = destination.indexOf(what);
  521. int whatLength = what.length();
  522. while (current >= 0)
  523. { // Do not use Methods from JRE 1.4 and higher ...
  524. if (current > 0)
  525. {
  526. buf.append(destination.substring(last, current));
  527. }
  528. buf.append(with);
  529. last = current + whatLength;
  530. current = destination.indexOf(what, last);
  531. }
  532. if (destination.length() > last)
  533. {
  534. buf.append(destination.substring(last));
  535. }
  536. return buf.toString();
  537. }
  538. return destination;
  539. }
  540. /**
  541. * Translates a relative path to a local system path.
  542. *
  543. * @param destination The path to translate.
  544. * @return The translated path.
  545. */
  546. public static String translatePath(String destination, VariableSubstitutor vs)
  547. {
  548. // Parse for variables
  549. destination = vs.substitute(destination, null);
  550. // Convert the file separator characters
  551. // destination = destination.replace('/', File.separatorChar);
  552. // Undo the conversion if the slashes was masked with
  553. // a backslash
  554. // Not all occurencies of slashes are path separators. To differ
  555. // between it we allow to mask a slash with a backslash infront.
  556. // Unfortunately we cannot use String.replaceAll because it
  557. // handles backslashes in the replacement string in a special way
  558. // and the method exist only beginning with JRE 1.4.
  559. // Therefore the little bit crude way following ...
  560. if (destination.indexOf("\\/") >= 0 && destination.indexOf(MASKED_SLASH_PLACEHOLDER) < 0)
  561. { // Masked slash found, placeholder not included in destination ->
  562. // perform masking.
  563. destination = replaceString(destination, "\\/", MASKED_SLASH_PLACEHOLDER);
  564. // Masked slashes changed to MASKED_SLASH_PLACEHOLDER.
  565. // Replace unmasked slashes.
  566. destination = destination.replace('/', File.separatorChar);
  567. // Replace the MASKED_SLASH_PLACEHOLDER to slashes; masking
  568. // backslashes will
  569. // be removed.
  570. destination = replaceString(destination, MASKED_SLASH_PLACEHOLDER, "/");
  571. }
  572. else
  573. {
  574. destination = destination.replace('/', File.separatorChar);
  575. }
  576. return destination;
  577. }
  578. /**
  579. * Returns the value of the environment variable given by key. This method is a work around for
  580. * VM versions which do not support getenv in an other way. At the first call all environment
  581. * variables will be loaded via an exec. On Windows keys are not case sensitive.
  582. *
  583. * @param key variable name for which the value should be resolved
  584. * @return the value of the environment variable given by key
  585. */
  586. public static String getenv(String key)
  587. {
  588. if (envVars == null)
  589. {
  590. loadEnv();
  591. }
  592. if (envVars == null)
  593. {
  594. return (null);
  595. }
  596. if (OsVersion.IS_WINDOWS)
  597. {
  598. key = key.toUpperCase();
  599. }
  600. return (String) (envVars.get(key));
  601. }
  602. /**
  603. * Loads all environment variables via an exec.
  604. */
  605. private static void loadEnv()
  606. {
  607. String[] output = new String[2];
  608. String[] params;
  609. if (OsVersion.IS_WINDOWS)
  610. {
  611. String command = "cmd.exe";
  612. if (System.getProperty("os.name").toLowerCase().indexOf("windows 9") > -1)
  613. {
  614. command = "command.com";
  615. }
  616. String[] paramst = {command, "/C", "set"};
  617. params = paramst;
  618. }
  619. else
  620. {
  621. String[] paramst = {"env"};
  622. params = paramst;
  623. }
  624. FileExecutor fe = new FileExecutor();
  625. fe.executeCommand(params, output);
  626. if (output[0].length() <= 0)
  627. {
  628. return;
  629. }
  630. String lineSep = System.getProperty("line.separator");
  631. StringTokenizer st = new StringTokenizer(output[0], lineSep);
  632. envVars = new Properties();
  633. String var = null;
  634. while (st.hasMoreTokens())
  635. {
  636. String line = st.nextToken();
  637. if (line.indexOf('=') == -1)
  638. { // May be a env var with a new line in it.
  639. if (var == null)
  640. {
  641. var = lineSep + line;
  642. }
  643. else
  644. {
  645. var += lineSep + line;
  646. }
  647. }
  648. else
  649. { // New var, perform the previous one.
  650. setEnvVar(var);
  651. var = line;
  652. }
  653. }
  654. setEnvVar(var);
  655. }
  656. /**
  657. * Extracts key and value from the given string var. The key should be separated from the value
  658. * by a sign. On Windows all chars of the key are translated to upper case.
  659. *
  660. * @param var
  661. */
  662. private static void setEnvVar(String var)
  663. {
  664. if (var == null)
  665. {
  666. return;
  667. }
  668. int index = var.indexOf('=');
  669. if (index < 0)
  670. {
  671. return;
  672. }
  673. String key = var.substring(0, index);
  674. // On windows change all key chars to upper.
  675. if (OsVersion.IS_WINDOWS)
  676. {
  677. key = key.toUpperCase();
  678. }
  679. envVars.setProperty(key, var.substring(index + 1));
  680. }
  681. }