github.com/sashka/siva@v1.6.0/writer.go (about) 1 package siva 2 3 import ( 4 "errors" 5 "io" 6 ) 7 8 var ( 9 ErrMissingHeader = errors.New("WriteHeader was not called, or already flushed") 10 ErrClosedWriter = errors.New("Writer is closed") 11 ) 12 13 // A Writer provides sequential writing of a siva archive 14 type Writer interface { 15 io.Writer 16 io.Closer 17 WriteHeader(h *Header) error 18 Flush() error 19 } 20 21 type writer struct { 22 w *hashedWriter 23 index Index 24 oIndex OrderedIndex 25 current *IndexEntry 26 position uint64 27 closed bool 28 } 29 30 // NewWriter creates a new Writer writing to w. 31 func NewWriter(w io.Writer) Writer { 32 return newWriter(w) 33 } 34 35 func newWriter(w io.Writer) *writer { 36 return &writer{ 37 w: newHashedWriter(w), 38 } 39 } 40 41 // WriteHeader writes hdr and prepares to accept the file's contents. 42 func (w *writer) WriteHeader(h *Header) error { 43 if err := w.flushIfPending(); err != nil { 44 return err 45 } 46 47 w.current = &IndexEntry{ 48 Header: (*h), 49 Start: w.position, 50 } 51 52 w.current.Name = ToSafePath(h.Name) 53 54 w.index = append(w.index, w.current) 55 w.oIndex = w.oIndex.Update(w.current) 56 57 return nil 58 } 59 60 // Write writes to the current entry in the siva archive, WriteHeader should 61 // called before, if not returns ErrMissingHeader 62 func (w *writer) Write(b []byte) (int, error) { 63 if w.current == nil { 64 return 0, ErrMissingHeader 65 } 66 67 n, err := w.w.Write(b) 68 w.position += uint64(n) 69 70 return n, err 71 } 72 73 // Flush finishes writing the current file (optional) 74 func (w *writer) Flush() error { 75 if w.closed { 76 return ErrClosedWriter 77 } else if w.current == nil { 78 return ErrMissingHeader 79 } 80 81 w.current.Size = w.position - w.current.Start 82 w.current.CRC32 = w.w.Checksum() 83 w.current = nil 84 w.w.Reset() 85 return nil 86 } 87 88 func (w *writer) flushIfPending() error { 89 if w.closed { 90 return ErrClosedWriter 91 } else if w.current == nil { 92 return nil 93 } 94 return w.Flush() 95 } 96 97 // Close closes the siva archive, writing the Index footer to the current writer. 98 func (w *writer) Close() error { 99 defer func() { w.closed = true }() 100 101 if err := w.flushIfPending(); err != nil { 102 return err 103 } 104 105 err := w.index.WriteTo(w.w) 106 if err == ErrEmptyIndex { 107 return nil 108 } 109 110 return err 111 }