writer.go raw

   1  /* 
   2  Copyright (c) 2013 Blake Smith <blakesmith0@gmail.com>
   3  
   4  Permission is hereby granted, free of charge, to any person obtaining a copy
   5  of this software and associated documentation files (the "Software"), to deal
   6  in the Software without restriction, including without limitation the rights
   7  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8  copies of the Software, and to permit persons to whom the Software is
   9  furnished to do so, subject to the following conditions:
  10  
  11  The above copyright notice and this permission notice shall be included in
  12  all copies or substantial portions of the Software.
  13  
  14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20  THE SOFTWARE.
  21  */
  22  package ar
  23  
  24  import (
  25  	"errors"
  26  	"io"
  27  	"strconv"
  28  )
  29  
  30  var (
  31  	ErrWriteTooLong    = errors.New("ar: write too long")
  32  )
  33  
  34  // Writer provides sequential writing of an ar archive.
  35  // An ar archive is sequence of header file pairs
  36  // Call WriteHeader to begin writing a new file, then call Write to supply the file's data
  37  //
  38  // Example:
  39  // archive := ar.NewWriter(writer)
  40  // archive.WriteGlobalHeader()
  41  // header := new(ar.Header)
  42  // header.Size = 15 // bytes
  43  // if err := archive.WriteHeader(header); err != nil {
  44  // 	return err
  45  // }
  46  // io.Copy(archive, data)
  47  type Writer struct {
  48  	w io.Writer
  49  	nb int64 // number of unwritten bytes for the current file entry
  50  }
  51  
  52  // Create a new ar writer that writes to w
  53  func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
  54  
  55  func (aw *Writer) numeric(b []byte, x int64) {
  56  	s := strconv.FormatInt(x, 10)
  57  	for len(s) < len(b) {
  58  		s = s + " "
  59  	}
  60  	copy(b, []byte(s))
  61  }
  62  
  63  func (aw *Writer) octal(b []byte, x int64) {
  64  	s := "100" + strconv.FormatInt(x, 8)
  65  	for len(s) < len(b) {
  66  		s = s + " "
  67  	}
  68  	copy(b, []byte(s))
  69  }
  70  
  71  func (aw *Writer) string(b []byte, str string) {
  72  	s := str
  73  	for len(s) < len(b) {
  74  		s = s + " "
  75  	}
  76  	copy(b, []byte(s))
  77  }
  78  
  79  // Writes to the current entry in the ar archive
  80  // Returns ErrWriteTooLong if more than header.Size
  81  // bytes are written after a call to WriteHeader
  82  func (aw *Writer) Write(b []byte) (n int, err error) {
  83  	if int64(len(b)) > aw.nb {
  84  		b = b[0:aw.nb]
  85  		err = ErrWriteTooLong
  86  	}
  87  	n, werr := aw.w.Write(b)
  88  	aw.nb -= int64(n)
  89  	if werr != nil {
  90  		return n, werr
  91  	}
  92  
  93  	if len(b)%2 == 1 { // data size must be aligned to an even byte
  94  		n2, _ := aw.w.Write([]byte{'\n'})
  95  		return n+n2, err
  96  	}
  97  
  98  	return
  99  }
 100  
 101  func (aw *Writer) WriteGlobalHeader() error {
 102  	_, err := aw.w.Write([]byte(GLOBAL_HEADER))
 103  	return err
 104  }
 105  
 106  // Writes the header to the underlying writer and prepares
 107  // to receive the file payload
 108  func (aw *Writer) WriteHeader(hdr *Header) error {
 109  	aw.nb = int64(hdr.Size)
 110  	header := make([]byte, HEADER_BYTE_SIZE)
 111  	s := slicer(header)
 112  
 113  	aw.string(s.next(16), hdr.Name)
 114  	aw.numeric(s.next(12), hdr.ModTime.Unix())
 115  	aw.numeric(s.next(6), int64(hdr.Uid))
 116  	aw.numeric(s.next(6), int64(hdr.Gid))
 117  	aw.octal(s.next(8), hdr.Mode)
 118  	aw.numeric(s.next(10), hdr.Size)
 119  	aw.string(s.next(2), "`\n")
 120  
 121  	_, err := aw.w.Write(header)
 122  
 123  	return err
 124  }
 125