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  }