package asar import ( "bytes" "errors" "io" ) type SizedReaderAt interface { io.ReaderAt Size() int64 } type WriterReaderAtWriterTo interface { io.Writer io.ReaderAt io.WriterTo } type BytesReadAtWriter struct { s []byte i int64 } func NewBytesReadAtWriter(s []byte) *BytesReadAtWriter { return &BytesReadAtWriter{s: s, i: 0} } func (b *BytesReadAtWriter) Write(p []byte) (n int, err error) { b.s = append(b.s, p...) return len(p), nil } func (b *BytesReadAtWriter) ReadAt(p []byte, off int64) (n int, err error) { // cannot modify state - see io.ReaderAt if off < 0 { return 0, errors.New("negative offset") } if off >= int64(len(b.s)) { return 0, io.EOF } n = copy(p, b.s[off:]) if n < len(p) { err = io.EOF } return } func (b *BytesReadAtWriter) WriteTo(w io.Writer) (n int64, err error) { return io.Copy(w, bytes.NewReader(b.s)) } type FilesystemStorage struct { existing SizedReaderAt new WriterReaderAtWriterTo newOffset int64 } func NewFilesystemStorage(existing SizedReaderAt, new WriterReaderAtWriterTo) *FilesystemStorage { return &FilesystemStorage{ existing: existing, new: new, newOffset: 0, } } func (fs *FilesystemStorage) Size() int64 { return fs.existing.Size() + fs.newOffset } func (fs *FilesystemStorage) ReadAt(p []byte, off int64) (n int, err error) { existingSize := fs.existing.Size() if off < existingSize { // error when cross boundary if off+int64(len(p)) > existingSize { return 0, io.ErrUnexpectedEOF } return fs.existing.ReadAt(p, off) } return fs.new.ReadAt(p, off-existingSize) } func (fs *FilesystemStorage) Write(p []byte) (n int, err error) { n, err = fs.new.Write(p) fs.newOffset += int64(n) return } func (fs *FilesystemStorage) WriteTo(w io.Writer) (n int64, err error) { // write existing n, err = io.Copy(w, io.NewSectionReader(fs.existing, 0, fs.existing.Size())) if err != nil { return n, err } n2, err := fs.new.WriteTo(w) return n + n2, err }