diff options
Diffstat (limited to 'utils/fs/memory/memory.go')
-rw-r--r-- | utils/fs/memory/memory.go | 364 |
1 files changed, 0 insertions, 364 deletions
diff --git a/utils/fs/memory/memory.go b/utils/fs/memory/memory.go deleted file mode 100644 index 54dd497..0000000 --- a/utils/fs/memory/memory.go +++ /dev/null @@ -1,364 +0,0 @@ -package memory - -import ( - "errors" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "time" - - "gopkg.in/src-d/go-git.v4/utils/fs" -) - -const separator = '/' - -// Memory a very convenient filesystem based on memory files -type Memory struct { - base string - s *storage - tempCount int -} - -//New returns a new Memory filesystem -func New() *Memory { - return &Memory{ - base: "/", - s: &storage{make(map[string]*file, 0)}, - } -} - -func (fs *Memory) Create(filename string) (fs.File, error) { - return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0) -} - -func (fs *Memory) Open(filename string) (fs.File, error) { - return fs.OpenFile(filename, os.O_RDONLY, 0) -} - -func (fs *Memory) OpenFile(filename string, flag int, perm os.FileMode) (fs.File, error) { - fullpath := fs.Join(fs.base, filename) - f, ok := fs.s.files[fullpath] - - if !ok && !isCreate(flag) { - return nil, os.ErrNotExist - } - - if f == nil { - fs.s.files[fullpath] = newFile(fs.base, fullpath, flag) - return fs.s.files[fullpath], nil - } - - n := newFile(fs.base, fullpath, flag) - n.content = f.content - - if isAppend(flag) { - n.position = int64(n.content.Len()) - } - - if isTruncate(flag) { - n.content.Truncate() - } - - return n, nil -} - -func (fs *Memory) Stat(filename string) (fs.FileInfo, error) { - fullpath := fs.Join(fs.base, filename) - - if _, ok := fs.s.files[filename]; ok { - return newFileInfo(fs.base, fullpath, fs.s.files[filename].content.Len()), nil - } - - info, err := fs.ReadDir(filename) - if err == nil && len(info) != 0 { - return newFileInfo(fs.base, fullpath, len(info)), nil - } - - return nil, os.ErrNotExist -} - -func (fs *Memory) ReadDir(base string) (entries []fs.FileInfo, err error) { - base = fs.Join(fs.base, base) - - appendedDirs := make(map[string]bool, 0) - for fullpath, f := range fs.s.files { - if !strings.HasPrefix(fullpath, base) { - continue - } - - fullpath, _ = filepath.Rel(base, fullpath) - parts := strings.Split(fullpath, string(separator)) - - if len(parts) == 1 { - entries = append(entries, &fileInfo{name: parts[0], size: f.content.Len()}) - continue - } - - if _, ok := appendedDirs[parts[0]]; ok { - continue - } - - entries = append(entries, &fileInfo{name: parts[0], isDir: true}) - appendedDirs[parts[0]] = true - } - - return -} - -var maxTempFiles = 1024 * 4 - -func (fs *Memory) TempFile(dir, prefix string) (fs.File, error) { - var fullpath string - for { - if fs.tempCount >= maxTempFiles { - return nil, errors.New("max. number of tempfiles reached") - } - - fullpath = fs.getTempFilename(dir, prefix) - if _, ok := fs.s.files[fullpath]; !ok { - break - } - } - - return fs.Create(fullpath) -} - -func (fs *Memory) getTempFilename(dir, prefix string) string { - fs.tempCount++ - filename := fmt.Sprintf("%s_%d_%d", prefix, fs.tempCount, time.Now().UnixNano()) - return fs.Join(fs.base, dir, filename) -} - -func (fs *Memory) Rename(from, to string) error { - from = fs.Join(fs.base, from) - to = fs.Join(fs.base, to) - - if _, ok := fs.s.files[from]; !ok { - return os.ErrNotExist - } - - fs.s.files[to] = fs.s.files[from] - fs.s.files[to].BaseFilename = to - delete(fs.s.files, from) - - return nil -} - -func (fs *Memory) Remove(filename string) error { - fullpath := fs.Join(fs.base, filename) - if _, ok := fs.s.files[fullpath]; !ok { - return os.ErrNotExist - } - - delete(fs.s.files, fullpath) - return nil -} - -func (fs *Memory) Join(elem ...string) string { - return filepath.Join(elem...) -} - -func (fs *Memory) Dir(path string) fs.Filesystem { - return &Memory{ - base: fs.Join(fs.base, path), - s: fs.s, - } -} - -func (fs *Memory) Base() string { - return fs.base -} - -type file struct { - fs.BaseFile - - content *content - position int64 - flag int -} - -func newFile(base, fullpath string, flag int) *file { - filename, _ := filepath.Rel(base, fullpath) - - return &file{ - BaseFile: fs.BaseFile{BaseFilename: filename}, - content: &content{}, - flag: flag, - } -} - -func (f *file) Read(b []byte) (int, error) { - n, err := f.ReadAt(b, f.position) - if err != nil { - return 0, err - } - - return n, err -} - -func (f *file) ReadAt(b []byte, off int64) (int, error) { - if f.IsClosed() { - return 0, fs.ErrClosed - } - - if !isReadAndWrite(f.flag) && !isReadOnly(f.flag) { - return 0, errors.New("read not supported") - } - - n, err := f.content.ReadAt(b, off) - f.position += int64(n) - - return n, err -} - -func (f *file) Seek(offset int64, whence int) (int64, error) { - if f.IsClosed() { - return 0, fs.ErrClosed - } - - switch whence { - case io.SeekCurrent: - f.position += offset - case io.SeekStart: - f.position = offset - case io.SeekEnd: - f.position = int64(f.content.Len()) - offset - } - - return f.position, nil -} - -func (f *file) Write(p []byte) (int, error) { - if f.IsClosed() { - return 0, fs.ErrClosed - } - - if !isReadAndWrite(f.flag) && !isWriteOnly(f.flag) { - return 0, errors.New("write not supported") - } - - n, err := f.content.WriteAt(p, f.position) - f.position += int64(n) - - return n, err -} - -func (f *file) Close() error { - if f.IsClosed() { - return errors.New("file already closed") - } - - f.Closed = true - return nil -} - -func (f *file) Open() error { - f.Closed = false - return nil -} - -type fileInfo struct { - name string - size int - isDir bool -} - -func newFileInfo(base, fullpath string, size int) *fileInfo { - filename, _ := filepath.Rel(base, fullpath) - - return &fileInfo{ - name: filename, - size: size, - } -} - -func (fi *fileInfo) Name() string { - return fi.name -} - -func (fi *fileInfo) Size() int64 { - return int64(fi.size) -} - -func (fi *fileInfo) Mode() os.FileMode { - return os.FileMode(0) -} - -func (*fileInfo) ModTime() time.Time { - return time.Now() -} - -func (fi *fileInfo) IsDir() bool { - return fi.isDir -} - -func (*fileInfo) Sys() interface{} { - return nil -} - -type storage struct { - files map[string]*file -} - -type content struct { - bytes []byte -} - -func (c *content) WriteAt(p []byte, off int64) (int, error) { - prev := len(c.bytes) - c.bytes = append(c.bytes[:off], p...) - if len(c.bytes) < prev { - c.bytes = c.bytes[:prev] - } - - return len(p), nil -} - -func (c *content) ReadAt(b []byte, off int64) (int, error) { - size := int64(len(c.bytes)) - if off >= size { - return 0, io.EOF - } - - l := int64(len(b)) - if off+l > size { - l = size - off - } - - n := copy(b, c.bytes[off:off+l]) - return n, nil -} - -func (c *content) Truncate() { - c.bytes = make([]byte, 0) -} - -func (c *content) Len() int { - return len(c.bytes) -} - -func isCreate(flag int) bool { - return flag&os.O_CREATE != 0 -} - -func isAppend(flag int) bool { - return flag&os.O_APPEND != 0 -} - -func isTruncate(flag int) bool { - return flag&os.O_TRUNC != 0 -} - -func isReadAndWrite(flag int) bool { - return flag&os.O_RDWR != 0 -} - -func isReadOnly(flag int) bool { - return flag == os.O_RDONLY -} - -func isWriteOnly(flag int) bool { - return flag&os.O_WRONLY != 0 -} |