forked from lug/matterbridge
		
	
		
			
				
	
	
		
			145 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package rice
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| )
 | |
| 
 | |
| // File implements the io.Reader, io.Seeker, io.Closer and http.File interfaces
 | |
| type File struct {
 | |
| 	// File abstracts file methods so the user doesn't see the difference between rice.virtualFile, rice.virtualDir and os.File
 | |
| 	// TODO: maybe use internal File interface and four implementations: *os.File, appendedFile, virtualFile, virtualDir
 | |
| 
 | |
| 	// real file on disk
 | |
| 	realF *os.File
 | |
| 
 | |
| 	// when embedded (go)
 | |
| 	virtualF *virtualFile
 | |
| 	virtualD *virtualDir
 | |
| 
 | |
| 	// when appended (zip)
 | |
| 	appendedF          *appendedFile
 | |
| 	appendedFileReader *bytes.Reader
 | |
| 	// TODO: is appendedFileReader subject of races? Might need a lock here..
 | |
| }
 | |
| 
 | |
| // Close is like (*os.File).Close()
 | |
| // Visit http://golang.org/pkg/os/#File.Close for more information
 | |
| func (f *File) Close() error {
 | |
| 	if f.appendedF != nil {
 | |
| 		if f.appendedFileReader == nil {
 | |
| 			return errors.New("already closed")
 | |
| 		}
 | |
| 		f.appendedFileReader = nil
 | |
| 		return nil
 | |
| 	}
 | |
| 	if f.virtualF != nil {
 | |
| 		return f.virtualF.close()
 | |
| 	}
 | |
| 	if f.virtualD != nil {
 | |
| 		return f.virtualD.close()
 | |
| 	}
 | |
| 	return f.realF.Close()
 | |
| }
 | |
| 
 | |
| // Stat is like (*os.File).Stat()
 | |
| // Visit http://golang.org/pkg/os/#File.Stat for more information
 | |
| func (f *File) Stat() (os.FileInfo, error) {
 | |
| 	if f.appendedF != nil {
 | |
| 		if f.appendedF.dir {
 | |
| 			return f.appendedF.dirInfo, nil
 | |
| 		}
 | |
| 		if f.appendedFileReader == nil {
 | |
| 			return nil, errors.New("file is closed")
 | |
| 		}
 | |
| 		return f.appendedF.zipFile.FileInfo(), nil
 | |
| 	}
 | |
| 	if f.virtualF != nil {
 | |
| 		return f.virtualF.stat()
 | |
| 	}
 | |
| 	if f.virtualD != nil {
 | |
| 		return f.virtualD.stat()
 | |
| 	}
 | |
| 	return f.realF.Stat()
 | |
| }
 | |
| 
 | |
| // Readdir is like (*os.File).Readdir()
 | |
| // Visit http://golang.org/pkg/os/#File.Readdir for more information
 | |
| func (f *File) Readdir(count int) ([]os.FileInfo, error) {
 | |
| 	if f.appendedF != nil {
 | |
| 		if f.appendedF.dir {
 | |
| 			fi := make([]os.FileInfo, 0, len(f.appendedF.children))
 | |
| 			for _, childAppendedFile := range f.appendedF.children {
 | |
| 				if childAppendedFile.dir {
 | |
| 					fi = append(fi, childAppendedFile.dirInfo)
 | |
| 				} else {
 | |
| 					fi = append(fi, childAppendedFile.zipFile.FileInfo())
 | |
| 				}
 | |
| 			}
 | |
| 			return fi, nil
 | |
| 		}
 | |
| 		//++ TODO: is os.ErrInvalid the correct error for Readdir on file?
 | |
| 		return nil, os.ErrInvalid
 | |
| 	}
 | |
| 	if f.virtualF != nil {
 | |
| 		return f.virtualF.readdir(count)
 | |
| 	}
 | |
| 	if f.virtualD != nil {
 | |
| 		return f.virtualD.readdir(count)
 | |
| 	}
 | |
| 	return f.realF.Readdir(count)
 | |
| }
 | |
| 
 | |
| // Read is like (*os.File).Read()
 | |
| // Visit http://golang.org/pkg/os/#File.Read for more information
 | |
| func (f *File) Read(bts []byte) (int, error) {
 | |
| 	if f.appendedF != nil {
 | |
| 		if f.appendedFileReader == nil {
 | |
| 			return 0, &os.PathError{
 | |
| 				Op:   "read",
 | |
| 				Path: filepath.Base(f.appendedF.zipFile.Name),
 | |
| 				Err:  errors.New("file is closed"),
 | |
| 			}
 | |
| 		}
 | |
| 		if f.appendedF.dir {
 | |
| 			return 0, &os.PathError{
 | |
| 				Op:   "read",
 | |
| 				Path: filepath.Base(f.appendedF.zipFile.Name),
 | |
| 				Err:  errors.New("is a directory"),
 | |
| 			}
 | |
| 		}
 | |
| 		return f.appendedFileReader.Read(bts)
 | |
| 	}
 | |
| 	if f.virtualF != nil {
 | |
| 		return f.virtualF.read(bts)
 | |
| 	}
 | |
| 	if f.virtualD != nil {
 | |
| 		return f.virtualD.read(bts)
 | |
| 	}
 | |
| 	return f.realF.Read(bts)
 | |
| }
 | |
| 
 | |
| // Seek is like (*os.File).Seek()
 | |
| // Visit http://golang.org/pkg/os/#File.Seek for more information
 | |
| func (f *File) Seek(offset int64, whence int) (int64, error) {
 | |
| 	if f.appendedF != nil {
 | |
| 		if f.appendedFileReader == nil {
 | |
| 			return 0, &os.PathError{
 | |
| 				Op:   "seek",
 | |
| 				Path: filepath.Base(f.appendedF.zipFile.Name),
 | |
| 				Err:  errors.New("file is closed"),
 | |
| 			}
 | |
| 		}
 | |
| 		return f.appendedFileReader.Seek(offset, whence)
 | |
| 	}
 | |
| 	if f.virtualF != nil {
 | |
| 		return f.virtualF.seek(offset, whence)
 | |
| 	}
 | |
| 	if f.virtualD != nil {
 | |
| 		return f.virtualD.seek(offset, whence)
 | |
| 	}
 | |
| 	return f.realF.Seek(offset, whence)
 | |
| }
 | 
