PageRenderTime 58ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

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

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