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