github.com/rck/u-root@v0.0.0-20180106144920-7eb602e381bb/pkg/gzip/file.go (about)

     1  package gzip
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  
     8  	"github.com/u-root/u-root/pkg/null"
     9  )
    10  
    11  // File is a file path to be compressed or decompressed.
    12  type File struct {
    13  	Path    string
    14  	Options *Options
    15  }
    16  
    17  // outputPath removes the path suffix on decompress and adds it on compress.
    18  // In the case of when options stdout or test are enabled it returns the path
    19  // as is.
    20  func (f *File) outputPath() string {
    21  	if f.Options.Stdout || f.Options.Test {
    22  		return f.Path
    23  	} else if f.Options.Decompress {
    24  		return f.Path[:len(f.Path)-len(f.Options.Suffix)]
    25  	}
    26  	return f.Path + f.Options.Suffix
    27  }
    28  
    29  // CheckPath validates the input file path. Checks on compression
    30  // if the path has the correct suffix, and on decompression checks
    31  // that it doesn't have the suffix. Allows override by force option.
    32  func (f *File) CheckPath() error {
    33  	_, err := os.Stat(f.Path)
    34  	if os.IsNotExist(err) {
    35  		return fmt.Errorf("skipping, %s does not exist", f.Path)
    36  	} else if os.IsPermission(err) {
    37  		return fmt.Errorf("skipping, %s permission denied", f.Path)
    38  	}
    39  
    40  	if !f.Options.Force {
    41  		if f.Options.Decompress {
    42  			if !strings.HasSuffix(f.Path, f.Options.Suffix) {
    43  				return fmt.Errorf("skipping, %s does not have %s suffix", f.Path, f.Options.Suffix)
    44  			}
    45  		} else {
    46  			if strings.HasSuffix(f.Path, f.Options.Suffix) {
    47  				return fmt.Errorf("skipping, %s already has %s suffix", f.Path, f.Options.Suffix)
    48  			}
    49  		}
    50  	}
    51  	return nil
    52  }
    53  
    54  // CheckOutputPath checks if output is attempting to write binary to stdout if
    55  // stdout is a device. Also checks if output path already exists. Allow
    56  // override via force option.
    57  func (f *File) CheckOutputPath() error {
    58  	_, err := os.Stat(f.outputPath())
    59  	if !os.IsNotExist(err) && !f.Options.Stdout && !f.Options.Test && !f.Options.Force {
    60  		return fmt.Errorf("skipping, %s already exist", f.outputPath())
    61  	} else if os.IsPermission(err) {
    62  		return fmt.Errorf("skipping, %s permission denied", f.outputPath())
    63  	}
    64  	return nil
    65  }
    66  
    67  // CheckOutputStdout checks if output is attempting to write binary to stdout
    68  // if stdout is a device.
    69  func (f *File) CheckOutputStdout() error {
    70  	if f.Options.Stdout {
    71  		stat, _ := os.Stdout.Stat()
    72  		if !f.Options.Decompress && !f.Options.Force && (stat.Mode()&os.ModeDevice) != 0 {
    73  			return fmt.Errorf("fatal, trying to write compressed data to a terminal/device (use -f to force)")
    74  		}
    75  	}
    76  	return nil
    77  }
    78  
    79  // Cleanup removes input file. Overrided with keep option. Skipped if
    80  // stdout or test option is true.
    81  func (f *File) Cleanup() error {
    82  	if !f.Options.Keep && !f.Options.Stdout && !f.Options.Test {
    83  		return os.Remove(f.Path)
    84  	}
    85  	return nil
    86  }
    87  
    88  // Process either compresses or decompressed the input file based on
    89  // the associated file.options.
    90  func (f *File) Process() error {
    91  	i, err := os.Open(f.Path)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	defer i.Close()
    96  
    97  	// Use the null.WriteNameCloser interface so both *os.File and
    98  	// null.WriteNameClose can be assigned to var o without any type casting below.
    99  	var o null.WriteNameCloser
   100  
   101  	if f.Options.Test {
   102  		o = null.WriteNameClose
   103  	} else if f.Options.Stdout {
   104  		o = os.Stdout
   105  	} else {
   106  		if o, err = os.Create(f.outputPath()); err != nil {
   107  			return err
   108  		}
   109  	}
   110  
   111  	if f.Options.Verbose && !f.Options.Quiet {
   112  		fmt.Fprintf(os.Stderr, "%s to %s\n", i.Name(), o.Name())
   113  	}
   114  
   115  	if f.Options.Decompress {
   116  		if err := Decompress(i, o, f.Options.Blocksize, f.Options.Processes); err != nil {
   117  			if !f.Options.Stdout {
   118  				o.Close()
   119  			}
   120  			return err
   121  		}
   122  	} else {
   123  		if err := Compress(i, o, f.Options.Level, f.Options.Blocksize, f.Options.Processes); err != nil {
   124  			if !f.Options.Stdout {
   125  				o.Close()
   126  			}
   127  			return err
   128  		}
   129  	}
   130  
   131  	if f.Options.Stdout {
   132  		return nil
   133  	}
   134  	return o.Close()
   135  }