file.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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. package mem
  15. import (
  16. "bytes"
  17. "errors"
  18. "io"
  19. "os"
  20. "path/filepath"
  21. "sync"
  22. "sync/atomic"
  23. )
  24. import "time"
  25. const FilePathSeparator = string(filepath.Separator)
  26. type File struct {
  27. // atomic requires 64-bit alignment for struct field access
  28. at int64
  29. readDirCount int64
  30. closed bool
  31. readOnly bool
  32. fileData *FileData
  33. }
  34. func NewFileHandle(data *FileData) *File {
  35. return &File{fileData: data}
  36. }
  37. func NewReadOnlyFileHandle(data *FileData) *File {
  38. return &File{fileData: data, readOnly: true}
  39. }
  40. func (f File) Data() *FileData {
  41. return f.fileData
  42. }
  43. type FileData struct {
  44. sync.Mutex
  45. name string
  46. data []byte
  47. memDir Dir
  48. dir bool
  49. mode os.FileMode
  50. modtime time.Time
  51. }
  52. func (d FileData) Name() string {
  53. return d.name
  54. }
  55. func CreateFile(name string) *FileData {
  56. return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()}
  57. }
  58. func CreateDir(name string) *FileData {
  59. return &FileData{name: name, memDir: &DirMap{}, dir: true}
  60. }
  61. func ChangeFileName(f *FileData, newname string) {
  62. f.name = newname
  63. }
  64. func SetMode(f *FileData, mode os.FileMode) {
  65. f.mode = mode
  66. }
  67. func SetModTime(f *FileData, mtime time.Time) {
  68. f.modtime = mtime
  69. }
  70. func GetFileInfo(f *FileData) *FileInfo {
  71. return &FileInfo{f}
  72. }
  73. func (f *File) Open() error {
  74. atomic.StoreInt64(&f.at, 0)
  75. atomic.StoreInt64(&f.readDirCount, 0)
  76. f.fileData.Lock()
  77. f.closed = false
  78. f.fileData.Unlock()
  79. return nil
  80. }
  81. func (f *File) Close() error {
  82. f.fileData.Lock()
  83. f.closed = true
  84. if !f.readOnly {
  85. SetModTime(f.fileData, time.Now())
  86. }
  87. f.fileData.Unlock()
  88. return nil
  89. }
  90. func (f *File) Name() string {
  91. return f.fileData.name
  92. }
  93. func (f *File) Stat() (os.FileInfo, error) {
  94. return &FileInfo{f.fileData}, nil
  95. }
  96. func (f *File) Sync() error {
  97. return nil
  98. }
  99. func (f *File) Readdir(count int) (res []os.FileInfo, err error) {
  100. var outLength int64
  101. f.fileData.Lock()
  102. files := f.fileData.memDir.Files()[f.readDirCount:]
  103. if count > 0 {
  104. if len(files) < count {
  105. outLength = int64(len(files))
  106. } else {
  107. outLength = int64(count)
  108. }
  109. if len(files) == 0 {
  110. err = io.EOF
  111. }
  112. } else {
  113. outLength = int64(len(files))
  114. }
  115. f.readDirCount += outLength
  116. f.fileData.Unlock()
  117. res = make([]os.FileInfo, outLength)
  118. for i := range res {
  119. res[i] = &FileInfo{files[i]}
  120. }
  121. return res, err
  122. }
  123. func (f *File) Readdirnames(n int) (names []string, err error) {
  124. fi, err := f.Readdir(n)
  125. names = make([]string, len(fi))
  126. for i, f := range fi {
  127. _, names[i] = filepath.Split(f.Name())
  128. }
  129. return names, err
  130. }
  131. func (f *File) Read(b []byte) (n int, err error) {
  132. f.fileData.Lock()
  133. defer f.fileData.Unlock()
  134. if f.closed == true {
  135. return 0, ErrFileClosed
  136. }
  137. if len(b) > 0 && int(f.at) == len(f.fileData.data) {
  138. return 0, io.EOF
  139. }
  140. if len(f.fileData.data)-int(f.at) >= len(b) {
  141. n = len(b)
  142. } else {
  143. n = len(f.fileData.data) - int(f.at)
  144. }
  145. copy(b, f.fileData.data[f.at:f.at+int64(n)])
  146. atomic.AddInt64(&f.at, int64(n))
  147. return
  148. }
  149. func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
  150. atomic.StoreInt64(&f.at, off)
  151. return f.Read(b)
  152. }
  153. func (f *File) Truncate(size int64) error {
  154. if f.closed == true {
  155. return ErrFileClosed
  156. }
  157. if f.readOnly {
  158. return &os.PathError{"truncate", f.fileData.name, errors.New("file handle is read only")}
  159. }
  160. if size < 0 {
  161. return ErrOutOfRange
  162. }
  163. if size > int64(len(f.fileData.data)) {
  164. diff := size - int64(len(f.fileData.data))
  165. f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{00}, int(diff))...)
  166. } else {
  167. f.fileData.data = f.fileData.data[0:size]
  168. }
  169. SetModTime(f.fileData, time.Now())
  170. return nil
  171. }
  172. func (f *File) Seek(offset int64, whence int) (int64, error) {
  173. if f.closed == true {
  174. return 0, ErrFileClosed
  175. }
  176. switch whence {
  177. case 0:
  178. atomic.StoreInt64(&f.at, offset)
  179. case 1:
  180. atomic.AddInt64(&f.at, int64(offset))
  181. case 2:
  182. atomic.StoreInt64(&f.at, int64(len(f.fileData.data))+offset)
  183. }
  184. return f.at, nil
  185. }
  186. func (f *File) Write(b []byte) (n int, err error) {
  187. if f.readOnly {
  188. return 0, &os.PathError{"write", f.fileData.name, errors.New("file handle is read only")}
  189. }
  190. n = len(b)
  191. cur := atomic.LoadInt64(&f.at)
  192. f.fileData.Lock()
  193. defer f.fileData.Unlock()
  194. diff := cur - int64(len(f.fileData.data))
  195. var tail []byte
  196. if n+int(cur) < len(f.fileData.data) {
  197. tail = f.fileData.data[n+int(cur):]
  198. }
  199. if diff > 0 {
  200. f.fileData.data = append(bytes.Repeat([]byte{00}, int(diff)), b...)
  201. f.fileData.data = append(f.fileData.data, tail...)
  202. } else {
  203. f.fileData.data = append(f.fileData.data[:cur], b...)
  204. f.fileData.data = append(f.fileData.data, tail...)
  205. }
  206. SetModTime(f.fileData, time.Now())
  207. atomic.StoreInt64(&f.at, int64(len(f.fileData.data)))
  208. return
  209. }
  210. func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
  211. atomic.StoreInt64(&f.at, off)
  212. return f.Write(b)
  213. }
  214. func (f *File) WriteString(s string) (ret int, err error) {
  215. return f.Write([]byte(s))
  216. }
  217. func (f *File) Info() *FileInfo {
  218. return &FileInfo{f.fileData}
  219. }
  220. type FileInfo struct {
  221. *FileData
  222. }
  223. // Implements os.FileInfo
  224. func (s *FileInfo) Name() string {
  225. _, name := filepath.Split(s.name)
  226. return name
  227. }
  228. func (s *FileInfo) Mode() os.FileMode { return s.mode }
  229. func (s *FileInfo) ModTime() time.Time { return s.modtime }
  230. func (s *FileInfo) IsDir() bool { return s.dir }
  231. func (s *FileInfo) Sys() interface{} { return nil }
  232. func (s *FileInfo) Size() int64 {
  233. if s.IsDir() {
  234. return int64(42)
  235. }
  236. return int64(len(s.data))
  237. }
  238. var (
  239. ErrFileClosed = errors.New("File is closed")
  240. ErrOutOfRange = errors.New("Out of range")
  241. ErrTooLarge = errors.New("Too large")
  242. ErrFileNotFound = os.ErrNotExist
  243. ErrFileExists = os.ErrExist
  244. ErrDestinationExists = os.ErrExist
  245. )