package asm import ( "bytes" "errors" "io" "os" "path" ) type FileGetter interface { // Get returns a stream for the provided file path Get(string) (io.ReadCloser, error) } type FilePutter interface { // Put returns a stream for the provided file path Put(string, io.Reader) error } type FileGetPutter interface { FileGetter FilePutter } // NewPathFileGetter returns a FileGetter that is for files relative to path relpath. func NewPathFileGetter(relpath string) FileGetter { return &pathFileGetter{root: relpath} } type pathFileGetter struct { root string } func (pfg pathFileGetter) Get(filename string) (io.ReadCloser, error) { // FIXME might should have a check for '../../../../etc/passwd' attempts? return os.Open(path.Join(pfg.root, filename)) } type bufferFileGetPutter struct { files map[string][]byte } func (bfgp bufferFileGetPutter) Get(name string) (io.ReadCloser, error) { if _, ok := bfgp.files[name]; !ok { return nil, errors.New("no such file") } b := bytes.NewBuffer(bfgp.files[name]) return &readCloserWrapper{b}, nil } func (bfgp *bufferFileGetPutter) Put(name string, r io.Reader) error { b := bytes.NewBuffer([]byte{}) if _, err := io.Copy(b, r); err != nil { return err } bfgp.files[name] = b.Bytes() return nil } type readCloserWrapper struct { io.Reader } func (w *readCloserWrapper) Close() error { return nil } // NewBufferFileGetPutter is simple in memory FileGetPutter // // Implication is this is memory intensive... // Probably best for testing or light weight cases. func NewBufferFileGetPutter() FileGetPutter { return &bufferFileGetPutter{ files: map[string][]byte{}, } }