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 }