vendor/github.com/spf13/afero/mem/file.go
changeset 242 2a9ec03fe5a1
child 256 6d9efbef00a9
equal deleted inserted replaced
241:e77dad242f4c 242:2a9ec03fe5a1
       
     1 // Copyright © 2015 Steve Francia <spf@spf13.com>.
       
     2 // Copyright 2013 tsuru authors. All rights reserved.
       
     3 //
       
     4 // Licensed under the Apache License, Version 2.0 (the "License");
       
     5 // you may not use this file except in compliance with the License.
       
     6 // You may obtain a copy of the License at
       
     7 // http://www.apache.org/licenses/LICENSE-2.0
       
     8 //
       
     9 // Unless required by applicable law or agreed to in writing, software
       
    10 // distributed under the License is distributed on an "AS IS" BASIS,
       
    11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    12 // See the License for the specific language governing permissions and
       
    13 // limitations under the License.
       
    14 
       
    15 package mem
       
    16 
       
    17 import (
       
    18 	"bytes"
       
    19 	"errors"
       
    20 	"io"
       
    21 	"os"
       
    22 	"path/filepath"
       
    23 	"sync"
       
    24 	"sync/atomic"
       
    25 )
       
    26 
       
    27 import "time"
       
    28 
       
    29 const FilePathSeparator = string(filepath.Separator)
       
    30 
       
    31 type File struct {
       
    32 	// atomic requires 64-bit alignment for struct field access
       
    33 	at           int64
       
    34 	readDirCount int64
       
    35 	closed       bool
       
    36 	readOnly     bool
       
    37 	fileData     *FileData
       
    38 }
       
    39 
       
    40 func NewFileHandle(data *FileData) *File {
       
    41 	return &File{fileData: data}
       
    42 }
       
    43 
       
    44 func NewReadOnlyFileHandle(data *FileData) *File {
       
    45 	return &File{fileData: data, readOnly: true}
       
    46 }
       
    47 
       
    48 func (f File) Data() *FileData {
       
    49 	return f.fileData
       
    50 }
       
    51 
       
    52 type FileData struct {
       
    53 	sync.Mutex
       
    54 	name    string
       
    55 	data    []byte
       
    56 	memDir  Dir
       
    57 	dir     bool
       
    58 	mode    os.FileMode
       
    59 	modtime time.Time
       
    60 }
       
    61 
       
    62 func (d *FileData) Name() string {
       
    63 	d.Lock()
       
    64 	defer d.Unlock()
       
    65 	return d.name
       
    66 }
       
    67 
       
    68 func CreateFile(name string) *FileData {
       
    69 	return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()}
       
    70 }
       
    71 
       
    72 func CreateDir(name string) *FileData {
       
    73 	return &FileData{name: name, memDir: &DirMap{}, dir: true}
       
    74 }
       
    75 
       
    76 func ChangeFileName(f *FileData, newname string) {
       
    77 	f.Lock()
       
    78 	f.name = newname
       
    79 	f.Unlock()
       
    80 }
       
    81 
       
    82 func SetMode(f *FileData, mode os.FileMode) {
       
    83 	f.Lock()
       
    84 	f.mode = mode
       
    85 	f.Unlock()
       
    86 }
       
    87 
       
    88 func SetModTime(f *FileData, mtime time.Time) {
       
    89 	f.Lock()
       
    90 	setModTime(f, mtime)
       
    91 	f.Unlock()
       
    92 }
       
    93 
       
    94 func setModTime(f *FileData, mtime time.Time) {
       
    95 	f.modtime = mtime
       
    96 }
       
    97 
       
    98 func GetFileInfo(f *FileData) *FileInfo {
       
    99 	return &FileInfo{f}
       
   100 }
       
   101 
       
   102 func (f *File) Open() error {
       
   103 	atomic.StoreInt64(&f.at, 0)
       
   104 	atomic.StoreInt64(&f.readDirCount, 0)
       
   105 	f.fileData.Lock()
       
   106 	f.closed = false
       
   107 	f.fileData.Unlock()
       
   108 	return nil
       
   109 }
       
   110 
       
   111 func (f *File) Close() error {
       
   112 	f.fileData.Lock()
       
   113 	f.closed = true
       
   114 	if !f.readOnly {
       
   115 		setModTime(f.fileData, time.Now())
       
   116 	}
       
   117 	f.fileData.Unlock()
       
   118 	return nil
       
   119 }
       
   120 
       
   121 func (f *File) Name() string {
       
   122 	return f.fileData.Name()
       
   123 }
       
   124 
       
   125 func (f *File) Stat() (os.FileInfo, error) {
       
   126 	return &FileInfo{f.fileData}, nil
       
   127 }
       
   128 
       
   129 func (f *File) Sync() error {
       
   130 	return nil
       
   131 }
       
   132 
       
   133 func (f *File) Readdir(count int) (res []os.FileInfo, err error) {
       
   134 	if !f.fileData.dir {
       
   135 		return nil, &os.PathError{Op: "readdir", Path: f.fileData.name, Err: errors.New("not a dir")}
       
   136 	}
       
   137 	var outLength int64
       
   138 
       
   139 	f.fileData.Lock()
       
   140 	files := f.fileData.memDir.Files()[f.readDirCount:]
       
   141 	if count > 0 {
       
   142 		if len(files) < count {
       
   143 			outLength = int64(len(files))
       
   144 		} else {
       
   145 			outLength = int64(count)
       
   146 		}
       
   147 		if len(files) == 0 {
       
   148 			err = io.EOF
       
   149 		}
       
   150 	} else {
       
   151 		outLength = int64(len(files))
       
   152 	}
       
   153 	f.readDirCount += outLength
       
   154 	f.fileData.Unlock()
       
   155 
       
   156 	res = make([]os.FileInfo, outLength)
       
   157 	for i := range res {
       
   158 		res[i] = &FileInfo{files[i]}
       
   159 	}
       
   160 
       
   161 	return res, err
       
   162 }
       
   163 
       
   164 func (f *File) Readdirnames(n int) (names []string, err error) {
       
   165 	fi, err := f.Readdir(n)
       
   166 	names = make([]string, len(fi))
       
   167 	for i, f := range fi {
       
   168 		_, names[i] = filepath.Split(f.Name())
       
   169 	}
       
   170 	return names, err
       
   171 }
       
   172 
       
   173 func (f *File) Read(b []byte) (n int, err error) {
       
   174 	f.fileData.Lock()
       
   175 	defer f.fileData.Unlock()
       
   176 	if f.closed == true {
       
   177 		return 0, ErrFileClosed
       
   178 	}
       
   179 	if len(b) > 0 && int(f.at) == len(f.fileData.data) {
       
   180 		return 0, io.EOF
       
   181 	}
       
   182 	if int(f.at) > len(f.fileData.data) {
       
   183 		return 0, io.ErrUnexpectedEOF
       
   184 	}
       
   185 	if len(f.fileData.data)-int(f.at) >= len(b) {
       
   186 		n = len(b)
       
   187 	} else {
       
   188 		n = len(f.fileData.data) - int(f.at)
       
   189 	}
       
   190 	copy(b, f.fileData.data[f.at:f.at+int64(n)])
       
   191 	atomic.AddInt64(&f.at, int64(n))
       
   192 	return
       
   193 }
       
   194 
       
   195 func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
       
   196 	atomic.StoreInt64(&f.at, off)
       
   197 	return f.Read(b)
       
   198 }
       
   199 
       
   200 func (f *File) Truncate(size int64) error {
       
   201 	if f.closed == true {
       
   202 		return ErrFileClosed
       
   203 	}
       
   204 	if f.readOnly {
       
   205 		return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")}
       
   206 	}
       
   207 	if size < 0 {
       
   208 		return ErrOutOfRange
       
   209 	}
       
   210 	if size > int64(len(f.fileData.data)) {
       
   211 		diff := size - int64(len(f.fileData.data))
       
   212 		f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{00}, int(diff))...)
       
   213 	} else {
       
   214 		f.fileData.data = f.fileData.data[0:size]
       
   215 	}
       
   216 	setModTime(f.fileData, time.Now())
       
   217 	return nil
       
   218 }
       
   219 
       
   220 func (f *File) Seek(offset int64, whence int) (int64, error) {
       
   221 	if f.closed == true {
       
   222 		return 0, ErrFileClosed
       
   223 	}
       
   224 	switch whence {
       
   225 	case 0:
       
   226 		atomic.StoreInt64(&f.at, offset)
       
   227 	case 1:
       
   228 		atomic.AddInt64(&f.at, int64(offset))
       
   229 	case 2:
       
   230 		atomic.StoreInt64(&f.at, int64(len(f.fileData.data))+offset)
       
   231 	}
       
   232 	return f.at, nil
       
   233 }
       
   234 
       
   235 func (f *File) Write(b []byte) (n int, err error) {
       
   236 	if f.readOnly {
       
   237 		return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")}
       
   238 	}
       
   239 	n = len(b)
       
   240 	cur := atomic.LoadInt64(&f.at)
       
   241 	f.fileData.Lock()
       
   242 	defer f.fileData.Unlock()
       
   243 	diff := cur - int64(len(f.fileData.data))
       
   244 	var tail []byte
       
   245 	if n+int(cur) < len(f.fileData.data) {
       
   246 		tail = f.fileData.data[n+int(cur):]
       
   247 	}
       
   248 	if diff > 0 {
       
   249 		f.fileData.data = append(bytes.Repeat([]byte{00}, int(diff)), b...)
       
   250 		f.fileData.data = append(f.fileData.data, tail...)
       
   251 	} else {
       
   252 		f.fileData.data = append(f.fileData.data[:cur], b...)
       
   253 		f.fileData.data = append(f.fileData.data, tail...)
       
   254 	}
       
   255 	setModTime(f.fileData, time.Now())
       
   256 
       
   257 	atomic.StoreInt64(&f.at, int64(len(f.fileData.data)))
       
   258 	return
       
   259 }
       
   260 
       
   261 func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
       
   262 	atomic.StoreInt64(&f.at, off)
       
   263 	return f.Write(b)
       
   264 }
       
   265 
       
   266 func (f *File) WriteString(s string) (ret int, err error) {
       
   267 	return f.Write([]byte(s))
       
   268 }
       
   269 
       
   270 func (f *File) Info() *FileInfo {
       
   271 	return &FileInfo{f.fileData}
       
   272 }
       
   273 
       
   274 type FileInfo struct {
       
   275 	*FileData
       
   276 }
       
   277 
       
   278 // Implements os.FileInfo
       
   279 func (s *FileInfo) Name() string {
       
   280 	s.Lock()
       
   281 	_, name := filepath.Split(s.name)
       
   282 	s.Unlock()
       
   283 	return name
       
   284 }
       
   285 func (s *FileInfo) Mode() os.FileMode {
       
   286 	s.Lock()
       
   287 	defer s.Unlock()
       
   288 	return s.mode
       
   289 }
       
   290 func (s *FileInfo) ModTime() time.Time {
       
   291 	s.Lock()
       
   292 	defer s.Unlock()
       
   293 	return s.modtime
       
   294 }
       
   295 func (s *FileInfo) IsDir() bool {
       
   296 	s.Lock()
       
   297 	defer s.Unlock()
       
   298 	return s.dir
       
   299 }
       
   300 func (s *FileInfo) Sys() interface{} { return nil }
       
   301 func (s *FileInfo) Size() int64 {
       
   302 	if s.IsDir() {
       
   303 		return int64(42)
       
   304 	}
       
   305 	s.Lock()
       
   306 	defer s.Unlock()
       
   307 	return int64(len(s.data))
       
   308 }
       
   309 
       
   310 var (
       
   311 	ErrFileClosed        = errors.New("File is closed")
       
   312 	ErrOutOfRange        = errors.New("Out of range")
       
   313 	ErrTooLarge          = errors.New("Too large")
       
   314 	ErrFileNotFound      = os.ErrNotExist
       
   315 	ErrFileExists        = os.ErrExist
       
   316 	ErrDestinationExists = os.ErrExist
       
   317 )