Statistics
| Revision:

root / import / ext3D / trunk / install-extension3d / IzPack / src / lib / com / izforge / izpack / util / IoHelper.java @ 15280

History | View | Annotate | Download (22.1 KB)

1
/*
2
 *  $Id: IoHelper.java,v 1.1 2006/06/14 07:29:07 cesar Exp $
3
 *  IzPack
4
 *  Copyright (C) 2004 Klaus Bartz
5
 *
6
 *  File :               IoHelper.java
7
 *  Description :        Helper for IO related stuff.
8
 *  Author's email :     bartzkau@users.berlios.de
9
 *
10
 *  This program is free software; you can redistribute it and/or
11
 *  modify it under the terms of the GNU General Public License
12
 *  as published by the Free Software Foundation; either version 2
13
 *  of the License, or any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
21
 *  along with this program; if not, write to the Free Software
22
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23
 */
24

    
25
package com.izforge.izpack.util;
26

    
27
import java.io.BufferedInputStream;
28
import java.io.BufferedOutputStream;
29
import java.io.File;
30
import java.io.FileInputStream;
31
import java.io.FileOutputStream;
32
import java.io.IOException;
33
import java.util.Properties;
34
import java.util.StringTokenizer;
35

    
36
import com.izforge.izpack.installer.VariableSubstitutor;
37

    
38
/**
39
 * <p>Class  with some IO related helper.</p>
40
 *
41
 */
42
public class IoHelper
43
{
44
  // This class uses the same values for family and flavor as
45
  // TargetFactory. But this class should not depends on TargetFactory,
46
  // because it is possible that TargetFactory is not bound. Therefore
47
  // the definition here again.
48
  
49
  // ------------------------------------------------------------------------
50
  // Constant Definitions
51
  // ------------------------------------------------------------------------
52

    
53
  /** Placeholder during translatePath computing */
54
  private static final String MASKED_SLASH_PLACEHOLDER = "?&_&?";
55
  
56
  private static Properties envVars = null;
57
        /**
58
         * Default constructor
59
         */
60
  private IoHelper()
61
  {
62
  }
63

    
64
  /**
65
   * Copies the contents of inFile into outFile.
66
   * 
67
   * @param inFile path of file which should be copied
68
   * @param outFile path of file to create and copy the contents
69
   * of inFile into
70
   */
71
  public static void copyFile(String inFile, String outFile) 
72
    throws IOException
73
  {
74
     copyFile( new File(inFile), new File(outFile) );    
75
  }
76
  /**
77
   * Creates an in- and output stream for the given File objects and
78
   * copies all the data from the specified input  to the specified
79
   * output.
80
   * @param  inFile               File object for input
81
   * @param  outFile              File object for output
82
   * @exception  IOException  if an I/O error occurs
83
   */
84
  public static void copyFile(File inFile, File outFile)
85
    throws IOException
86
  {
87
    copyFile(inFile, outFile, null, null);
88
  }
89
  
90
  /**
91
   * Creates an in- and output stream for the given File objects and
92
   * copies all the data from the specified input  to the specified
93
   * output.
94
   * If permissions is not null, a chmod will
95
   * be done on the output file.
96
   * @param  inFile               File object for input
97
   * @param  outFile              File object for output
98
   * @param permissions           permissions for the output file 
99
   * @exception  IOException  if an I/O error occurs
100
   */
101
  public static void copyFile(File inFile, File outFile, String permissions)
102
    throws IOException
103
  {
104
    copyFile(inFile, outFile, permissions, null);
105
  }
106
  
107
  /**
108
   * Creates an in- and output stream for the given File objects and
109
   * copies all the data from the specified input  to the specified
110
   * output. If the VariableSubstitutor is not null, a substition will
111
   * be done during copy.
112
   *
113
   * @param  inFile               File object for input
114
   * @param  outFile              File object for output
115
   * @param vss                   substitutor which is used during copying
116
   * @exception  IOException  if an I/O error occurs
117
   */
118
  public static void copyFile(File inFile, File outFile, VariableSubstitutor vss)
119
    throws IOException
120
  {
121
    copyFile(inFile, outFile, null, vss);
122
  }
123
  
124
  /**
125
   * Creates an in- and output stream for the given File objects and
126
   * copies all the data from the specified input  to the specified
127
   * output. If the VariableSubstitutor is not null, a substition will
128
   * be done during copy. If permissions is not null, a chmod will
129
   * be done on the output file.
130
   *
131
   * @param  inFile               File object for input
132
   * @param  outFile              File object for output
133
   * @param permissions           permissions for the output file 
134
   * @param vs                    substitutor which is used during copying
135
   * @exception  IOException  if an I/O error occurs
136
   */
137
  public static void copyFile(File inFile, File outFile, String permissions,
138
    VariableSubstitutor vs)
139
    throws IOException
140
  {
141
    copyFile( inFile, outFile, permissions, vs, null);
142
  }
143
    
144
  /**
145
   * Creates an in- and output stream for the given File objects and
146
   * copies all the data from the specified input  to the specified
147
   * output. If the VariableSubstitutor is not null, a substition will
148
   * be done during copy. If permissions is not null, a chmod will
149
   * be done on the output file. If type is not null, that type is
150
   * used as file type at substitution.
151
   *
152
   * @param  inFile               File object for input
153
   * @param  outFile              File object for output
154
   * @param permissions           permissions for the output file 
155
   * @param vs                    substitutor which is used during copying
156
   * @param type                  file type for the substitutor
157
   * @exception  IOException  if an I/O error occurs
158
   */
159
  public static void copyFile(File inFile, File outFile, String permissions,
160
    VariableSubstitutor vs, String type)
161
    throws IOException
162
  {
163
    FileOutputStream out = new FileOutputStream(outFile);
164
    FileInputStream in  = new FileInputStream(inFile);
165
    if( vs == null )
166
    {
167
      byte[] buffer = new byte[5120];
168
      long bytesCopied = 0;
169
      int bytesInBuffer;
170
      while ((bytesInBuffer = in.read(buffer)) != -1)
171
      {
172
        out.write(buffer, 0, bytesInBuffer);
173
        bytesCopied += bytesInBuffer;
174
      }
175
      in.close();
176
      out.close();
177
    }
178
    else
179
    {
180
      BufferedInputStream bin = new BufferedInputStream(in, 5120);
181
      BufferedOutputStream bout = new BufferedOutputStream(out, 5120);
182
      vs.substitute(bin, bout, type, null);
183
      bin.close();
184
      bout.close();
185
    }
186
    if( permissions != null && IoHelper.supported("chmod"))
187
    {
188
      chmod(outFile.getAbsolutePath(), permissions );
189
    }
190
  }
191

    
192
  /**
193
   * Creates a temp file with delete on exit rule. The extension
194
   * is extracted from the template if possible, else the
195
   * default extension is used. The contents of template will be
196
   * copied into the temporary file.
197
   * @param template file to copy from and define file extension
198
   * @param defaultExtension file extension if no is contained in template
199
   * @return newly created and filled temporary file
200
   * @throws IOException
201
   */
202
  public static File copyToTempFile( File template, String defaultExtension) throws IOException
203
  {
204
    return copyToTempFile(template, defaultExtension, null);
205
  }
206

    
207
  /**
208
   * Creates a temp file with delete on exit rule. The extension
209
   * is extracted from the template if possible, else the
210
   * default extension is used. The contents of template will be
211
   * copied into the temporary file. If the variable substitutor
212
   * is not null, variables will be replaced during copying.
213
   * @param template file to copy from and define file extension
214
   * @param defaultExtension file extension if no is contained in template
215
   * @param vss substitutor which is used during copying
216
   * @return newly created and filled temporary file
217
   * @throws IOException
218
   */
219
  public static File copyToTempFile( File template, String defaultExtension,
220
     VariableSubstitutor vss) throws IOException
221
  {
222
    String path = template.getCanonicalPath();
223
    int pos = path.lastIndexOf('.');
224
    String ext = path.substring(pos);
225
    if( ext == null )
226
      ext = defaultExtension;
227
    File tmpFile = File.createTempFile("izpack_io", ext);
228
    tmpFile.deleteOnExit();
229
    IoHelper.copyFile(template, tmpFile, vss);
230
    return tmpFile;
231
  }
232
  
233
  
234
  /**
235
   * Creates a temp file with delete on exit rule. The extension
236
   * is extracted from the template if possible, else the
237
   * default extension is used. The contents of template will be
238
   * copied into the temporary file.
239
   * @param template file to copy from and define file extension
240
   * @param defaultExtension file extension if no is contained in template
241
   * @return newly created and filled temporary file
242
   * @throws IOException
243
   */
244
  public static File copyToTempFile( String template, String defaultExtension) throws IOException
245
  {
246
    return copyToTempFile(new File(template), defaultExtension);
247
  }
248
  
249
  
250
  
251
  /**
252
   * Changes the permissions of the given file to the given POSIX permissions.
253
   * @param file the file for which the permissions should be changed
254
   * @param permissions POSIX permissions to be set
255
   * @throws IOException   if an I/O error occurs
256
   */
257
  public static void chmod(File file, String permissions) throws IOException
258
  {
259
    chmod( file.getAbsolutePath(), permissions);
260
  }
261
  
262
  /**
263
   * Changes the permissions of the given file to the given POSIX permissions.
264
   * This method will be raised an exception, if the OS is not UNIX.
265
   * @param path the absolute path of the file for which the permissions should be changed
266
   * @param permissions POSIX permissions to be set
267
   * @throws IOException   if an I/O error occurs
268
   */
269
  public static void chmod(String path, String permissions) throws IOException
270
  {
271
    // Perform UNIX
272
    if (OsVersion.IS_UNIX)
273
    {
274
      String[] params = {"chmod", permissions, path};
275
      String[] output = new String[2];
276
      FileExecutor fe = new FileExecutor();
277
      fe.executeCommand(params, output);
278
    }
279
    else
280
    {
281
      throw new IOException("Sorry, chmod not supported yet on " + OsVersion.OS_NAME + ".");
282
    }
283
  }
284
  
285
  /**
286
   * Returns the free (disk) space for the given path.
287
   * If it is not ascertainable -1 returns.
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
    int state;
295
    if( OsVersion.IS_WINDOWS )
296
    {
297
      String command = "cmd.exe";
298
      if( System.getProperty("os.name").toLowerCase().indexOf("windows 9") > -1)
299
        command = "command.com";
300
      String[] params = {command, "/C", "\"dir /D /-C \"" + path + "\"\""};
301
      String[] output = new String[2];
302
      FileExecutor fe = new FileExecutor();
303
      state = fe.executeCommand(params, output);
304
      retval = extractLong(output[0], -3, 3, "%");
305
    }
306
    else if( OsVersion.IS_SUNOS )
307
    {
308
      String[] params = {"df", "-k", path};
309
      String[] output = new String[2];
310
      FileExecutor fe = new FileExecutor();
311
      state = fe.executeCommand(params, output);
312
      retval = extractLong(output[0], -3, 3, "%") * 1024;
313
    }    
314
    else if( OsVersion.IS_UNIX )
315
    {
316
      String[] params = {"df", "-Pk", path};
317
      String[] output = new String[2];
318
      FileExecutor fe = new FileExecutor();
319
      state = fe.executeCommand(params, output);
320
      retval = extractLong(output[0], -3, 3, "%") * 1024;
321
    }    
322
    return retval;
323
  }
324

    
325
  /**
326
   * Returns whether the given method will be supported with
327
   * the given environment. Some methods of this class are not
328
   * supported on all operation systems. 
329
   * @param method name of the method 
330
   * @return true if the method will be supported with the current
331
   * enivronment else false
332
   * @throws RuntimeException if the given method name does not exist
333
   */
334
  public static boolean supported(String method)
335
  {
336
    if(method.equals("getFreeSpace"))
337
    {
338
      if( OsVersion.IS_UNIX || OsVersion.IS_WINDOWS)
339
        return true;
340
    }
341
    else if(method.equals("chmod" ) ) 
342
    {
343
      if(OsVersion.IS_UNIX)
344
        return true;
345
    }
346
    else if(method.equals("copyFile")) 
347
    {
348
       return true;
349
    }
350
    else if(method.equals("getPrimaryGroup")) 
351
    {
352
      if(OsVersion.IS_UNIX)
353
        return true;
354
    }
355
    else if(method.equals("getenv")) 
356
    {
357
       return true;
358
    }
359
    else
360
    {
361
      throw new RuntimeException("method name " + method + "not supported by this method");
362
    }
363
    return false;
364
    
365
    
366
  }
367

    
368
  /**
369
   * Returns the first existing parent directory in a path
370
   * @param path path which should be scanned
371
   * @return the first existing parent directory in a path
372
   */
373
  public static File existingParent(File path) 
374
  {
375
    File result = path;
376
    while ( ! result.exists() )
377
    {
378
      if (result.getParent() == null)
379
        return result;
380
      result = result.getParentFile();
381
    }
382
    return result;
383
  }
384

    
385

    
386
  /**
387
   * Extracts a long value from a string in a special manner.
388
   * The string will be broken into tokens with a standard StringTokenizer.
389
   * Arround the assumed place (with the given half range) the tokens are
390
   * scaned reverse for a token which represents a long. if useNotIdentifier
391
   * is not null, tokens which are contains this string will be ignored.
392
   * The first founded long returns.
393
   * @param in the string which should be parsed
394
   * @param assumedPlace token number which should contain the value
395
   * @param halfRange half range for detection range
396
   * @param useNotIdentifier string which determines tokens which should be ignored
397
   * @return founded long
398
   */
399
  private static long extractLong(String in, int assumedPlace, int halfRange, String useNotIdentifier) 
400
  {
401
    long retval = -1;
402
    StringTokenizer st = new StringTokenizer(in);
403
    int length = st.countTokens();
404
    int i;
405
    int currentRange = 0;
406
    String[] interestedEntries = new String[halfRange + halfRange];
407
    int praeScan = 0;
408
    if( assumedPlace < 0)
409
    { // Measured from end.
410
      praeScan = length - halfRange + assumedPlace;
411
    }
412
    else
413
    { // Messured from start.
414
      praeScan =  assumedPlace - halfRange;
415
    }
416
    for( i = 0; i < length - halfRange + assumedPlace; ++i)
417
      st.nextToken(); // Forget this entries.
418
    
419
    for( i = 0; i < halfRange + halfRange; ++i)
420
    { // Put the interesting Strings into an intermediaer array.
421
      if( st.hasMoreTokens())
422
      {
423
        interestedEntries[i] = st.nextToken();
424
        currentRange++;
425
      }
426
    }
427
   
428
    for( i = currentRange - 1; i >= 0; --i)
429
    {
430
      if( useNotIdentifier != null && interestedEntries[i].indexOf (useNotIdentifier) > -1)
431
        continue;
432
      try
433
      {
434
        retval = Long.parseLong(interestedEntries[i]);
435
      }
436
      catch(NumberFormatException nfe )
437
      {
438
        continue;
439
      }
440
      break;
441
    }
442
    return retval; 
443
  }
444
  
445
  /**
446
   * Returns the primary group of the current user.
447
   * This feature will be supported only on Unix. On
448
   * other systems null returns.
449
   * @return the primary group of the current user
450
   */
451
  public static String getPrimaryGroup()
452
  {
453
    if(  supported("getPrimaryGroup"))
454
    {
455
      if( OsVersion.IS_SUNOS )
456
      { // Standard id of SOLARIS do not support -gn.
457
        String[] params = {"id"};
458
        String[] output = new String[2];
459
        FileExecutor fe = new FileExecutor();
460
        fe.executeCommand(params, output);
461
        // No we have "uid=%u(%s) gid=%u(%s)"
462
        if( output[0] != null)
463
        {
464
          StringTokenizer st = new StringTokenizer(output[0], "()");
465
          int length = st.countTokens();
466
          if( length >= 4)
467
          {
468
            for(int i =0; i < 3; ++i)
469
              st.nextToken();
470
            return( st.nextToken());
471
          }
472
        }
473
        return( null);
474
      }
475
      else
476
      {
477
        String[] params = {"id", "-gn"};
478
        String[] output = new String[2];
479
        FileExecutor fe = new FileExecutor();
480
        fe.executeCommand(params, output);
481
        return output[0];
482
      }
483
    }
484
    else
485
      return null;
486
  }
487

    
488
  /**
489
   * Returns a  string resulting from replacing all occurrences of what
490
   * in this string with with. In opposite to the String.replaceAll method
491
   * this method do not use regular expression or other methods which are
492
   * only available in JRE 1.4 and later. This method was special made to
493
   * mask masked slashes to avert a conversion during path translation.
494
   * @param destination string for which the replacing should be performed
495
   * @param what what string should be replaced
496
   * @param with with what string what should be replaced
497
   * @return a new String object if what was found in the given string, else
498
   * the given string self
499
   */
500
  public static String replaceString(String destination, String what, String with)
501
  {
502
    if( destination.indexOf(what) >= 0 )
503
    { // what found, with (placeholder) not included in destination ->
504
      // perform changing.
505
      StringBuffer buf = new StringBuffer();
506
      int last = 0;
507
      int current =  destination.indexOf(what);
508
      int whatLength = what.length(); 
509
      while( current >= 0 )
510
      { // Do not use Methods from JRE 1.4 and higher ...
511
        if( current > 0 )
512
          buf.append(destination.substring(last, current));
513
        buf.append(with);
514
        last = current + whatLength;
515
        current = destination.indexOf(what, last);
516
      }
517
      if( destination.length() > last  )
518
        buf.append(destination.substring(last));
519
      return buf.toString();
520
    }
521
    return destination;
522
  }
523
  /**
524
   *  Translates a relative path to a local system path.
525
   *
526
   * @param  destination  The path to translate.
527
   * @return              The translated path.
528
   */
529
  public static String translatePath(String destination, VariableSubstitutor vs)
530
  {
531
    // Parse for variables
532
    destination = vs.substitute(destination, null);
533

    
534
    // Convert the file separator characters
535
    
536
    //destination = destination.replace('/', File.separatorChar);
537
    // Undo the conversion if the slashes was masked with 
538
    // a backslash
539

    
540
    // Not all occurencies of slashes are path separators. To differ
541
    // between it we allow to mask a slash with a backslash infront.
542
    // Unfortunately we cannot use String.replaceAll because it
543
    // handles backslashes in the replacement string in a special way
544
    // and the method exist only beginning with JRE 1.4.
545
    // Therefore the little bit crude way following ...
546
    if( destination.indexOf("\\/") >= 0 && 
547
      destination.indexOf(MASKED_SLASH_PLACEHOLDER) < 0)
548
    { // Masked slash found, placeholder not included in destination ->
549
      // perform masking.
550
      destination = replaceString(destination, "\\/",MASKED_SLASH_PLACEHOLDER);
551
      // Masked slashes changed to MASKED_SLASH_PLACEHOLDER.
552
      // Replace unmasked slashes.
553
      destination = destination.replace('/', File.separatorChar);
554
      // Replace the MASKED_SLASH_PLACEHOLDER to slashes; masking backslashes will 
555
      // be removed.
556
      destination = replaceString(destination, MASKED_SLASH_PLACEHOLDER, "/");
557
    }
558
    else
559
      destination = destination.replace('/', File.separatorChar);
560
    return destination;
561
  }
562

    
563
  /**
564
   * Returns the value of the environment variable given
565
   * by key. This method is a work around for VM versions which
566
   * do not support getenv in an other way.
567
   * At the first call all environment variables will be loaded via
568
   * an exec.  
569
   * On Windows keys are not case sensitive.
570
   * @param key variable name for which the value should be resolved
571
   * @return the value of the environment variable given
572
   * by key
573
   */
574
  public static String getenv(String key)
575
  {
576
    if( envVars == null)
577
      loadEnv();
578
    if( envVars == null)
579
      return( null );
580
    if( OsVersion.IS_WINDOWS )
581
      key = key.toUpperCase();
582
    return(String) ( envVars.get(key));
583
  }
584
  
585
  /**
586
   * Loads all environment variables via an exec.
587
   */
588
  private static void loadEnv()
589
  {
590
    String retval = null;
591
    int state;
592
    String[] output = new String[2];
593
    String[] params;
594
    if( OsVersion.IS_WINDOWS )
595
    {
596
      String command = "cmd.exe";
597
      if( System.getProperty("os.name").toLowerCase().indexOf("windows 9") > -1)
598
        command = "command.com";
599
      String[] paramst = {command, "/C", "set"};
600
      params = paramst;
601
    }
602
    else 
603
    {
604
      String[] paramst = {"env"};
605
      params = paramst;
606
    }    
607
    FileExecutor fe = new FileExecutor();
608
    state = fe.executeCommand(params, output);
609
    if( output[0].length() <= 0 )
610
      return;
611
    String lineSep = System.getProperty("line.separator");
612
    StringTokenizer st = new StringTokenizer(output[0], lineSep);
613
    envVars = new Properties();
614
    String var = null;
615
    int index = 0;
616
    while(st.hasMoreTokens())
617
    {
618
      String line = st.nextToken();
619
      if( line.indexOf('=') == -1)
620
      { // May be a env var with a new line in it.
621
        if( var == null )
622
        {
623
          var = lineSep + line;
624
        }
625
        else
626
        {
627
          var += lineSep + line;
628
        }
629
      }
630
      else
631
      { // New var, perform the previous one.
632
        setEnvVar(var);
633
        var = line;
634
      }
635
    }
636
    setEnvVar(var);
637
  }
638
  
639
  /**
640
   * Extracts key and value from the given string var.
641
   * The key should be separated from the value by a sign.
642
   * On Windows all chars of the key are translated to upper case.
643
   * @param var
644
   */
645
  private static void setEnvVar( String var )
646
  {
647
    if( var == null)
648
      return;
649
    int index = var.indexOf('=');
650
    if( index < 0 )
651
      return;
652
    String key = var.substring(0, index);
653
    // On windows change all key chars to upper.
654
    if( OsVersion.IS_WINDOWS )
655
      key = key.toUpperCase();
656
    envVars.setProperty(key, var.substring(index + 1));
657
    
658
  }
659
}