github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/Unknwon/cae/tz/read.go (about) 1 // Copyright 2014 Unknown 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations 13 // under the License. 14 15 package tz 16 17 import ( 18 "archive/tar" 19 "compress/gzip" 20 "io" 21 "os" 22 "strings" 23 ) 24 25 // A ReadCloser represents a caller closable file reader. 26 type ReadCloser struct { 27 f *os.File 28 File []*tar.Header 29 } 30 31 // Close closes the tar.gz file, rendering it unusable for I/O. 32 func (rc *ReadCloser) Close() error { 33 return rc.f.Close() 34 } 35 36 // openFile opens a tar.gz file with gzip and tar decoders. 37 func openFile(name string) (*tar.Reader, *os.File, error) { 38 f, err := os.Open(name) 39 if err != nil { 40 return nil, nil, err 41 } 42 43 gr, err := gzip.NewReader(f) 44 if err != nil { 45 f.Close() 46 return nil, nil, err 47 } 48 49 return tar.NewReader(gr), f, nil 50 } 51 52 // openReader opens the tar.gz file specified by name and return a tar.Reader. 53 func openReader(name string) (*ReadCloser, error) { 54 tr, f, err := openFile(name) 55 if err != nil { 56 return nil, err 57 } 58 59 r := new(ReadCloser) 60 if err := r.init(tr); err != nil { 61 return nil, err 62 } 63 r.f = f 64 return r, nil 65 } 66 67 // init initializes a new ReadCloser. 68 func (rc *ReadCloser) init(r *tar.Reader) error { 69 defer rc.Close() 70 71 rc.File = make([]*tar.Header, 0, 10) 72 for { 73 h, err := r.Next() 74 if err == io.EOF { 75 break 76 } else if err != nil { 77 return err 78 } 79 80 rc.File = append(rc.File, h) 81 } 82 return nil 83 } 84 85 // syncFiles syncs file information from file system to memroy object. 86 func (tz *TzArchive) syncFiles() { 87 tz.files = make([]*File, tz.NumFiles) 88 for i, f := range tz.File { 89 tz.files[i] = &File{} 90 tz.files[i].Header = f 91 tz.files[i].Name = strings.Replace(f.Name, "\\", "/", -1) 92 if f.FileInfo().IsDir() && !strings.HasSuffix(tz.files[i].Name, "/") { 93 tz.files[i].Name += "/" 94 } 95 } 96 } 97 98 // Open is the generalized open call; most users will use Open 99 // instead. It opens the named tar.gz file with specified flag 100 // (O_RDONLY etc.) if applicable. If successful, 101 // methods on the returned TzArchive can be used for I/O. 102 // If there is an error, it will be of type *PathError. 103 func (tz *TzArchive) Open(name string, flag int, perm os.FileMode) error { 104 if flag&os.O_CREATE != 0 { 105 fw, err := os.Create(name) 106 if err != nil { 107 return err 108 } 109 110 gw := gzip.NewWriter(fw) 111 tw := tar.NewWriter(gw) 112 if err = tw.Close(); err != nil { 113 return err 114 } else if err = gw.Close(); err != nil { 115 return err 116 } else if err = fw.Close(); err != nil { 117 return err 118 } 119 } 120 121 rc, err := openReader(name) 122 if err != nil { 123 return err 124 } 125 126 tz.ReadCloser = rc 127 tz.FileName = name 128 tz.NumFiles = len(rc.File) 129 tz.Flag = flag 130 tz.Permission = perm 131 tz.isHasChanged = false 132 133 tz.syncFiles() 134 return nil 135 }