gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

memmap.go (9174B)


      1 // Copyright © 2014 Steve Francia <spf@spf13.com>.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 // http://www.apache.org/licenses/LICENSE-2.0
      7 //
      8 // Unless required by applicable law or agreed to in writing, software
      9 // distributed under the License is distributed on an "AS IS" BASIS,
     10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     11 // See the License for the specific language governing permissions and
     12 // limitations under the License.
     13 
     14 package afero
     15 
     16 import (
     17 	"fmt"
     18 	"io"
     19 	"log"
     20 	"os"
     21 	"path/filepath"
     22 	"strings"
     23 	"sync"
     24 	"time"
     25 
     26 	"github.com/spf13/afero/mem"
     27 )
     28 
     29 const chmodBits = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky // Only a subset of bits are allowed to be changed. Documented under os.Chmod()
     30 
     31 type MemMapFs struct {
     32 	mu   sync.RWMutex
     33 	data map[string]*mem.FileData
     34 	init sync.Once
     35 }
     36 
     37 func NewMemMapFs() Fs {
     38 	return &MemMapFs{}
     39 }
     40 
     41 func (m *MemMapFs) getData() map[string]*mem.FileData {
     42 	m.init.Do(func() {
     43 		m.data = make(map[string]*mem.FileData)
     44 		// Root should always exist, right?
     45 		// TODO: what about windows?
     46 		root := mem.CreateDir(FilePathSeparator)
     47 		mem.SetMode(root, os.ModeDir|0o755)
     48 		m.data[FilePathSeparator] = root
     49 	})
     50 	return m.data
     51 }
     52 
     53 func (*MemMapFs) Name() string { return "MemMapFS" }
     54 
     55 func (m *MemMapFs) Create(name string) (File, error) {
     56 	name = normalizePath(name)
     57 	m.mu.Lock()
     58 	file := mem.CreateFile(name)
     59 	m.getData()[name] = file
     60 	m.registerWithParent(file, 0)
     61 	m.mu.Unlock()
     62 	return mem.NewFileHandle(file), nil
     63 }
     64 
     65 func (m *MemMapFs) unRegisterWithParent(fileName string) error {
     66 	f, err := m.lockfreeOpen(fileName)
     67 	if err != nil {
     68 		return err
     69 	}
     70 	parent := m.findParent(f)
     71 	if parent == nil {
     72 		log.Panic("parent of ", f.Name(), " is nil")
     73 	}
     74 
     75 	parent.Lock()
     76 	mem.RemoveFromMemDir(parent, f)
     77 	parent.Unlock()
     78 	return nil
     79 }
     80 
     81 func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData {
     82 	pdir, _ := filepath.Split(f.Name())
     83 	pdir = filepath.Clean(pdir)
     84 	pfile, err := m.lockfreeOpen(pdir)
     85 	if err != nil {
     86 		return nil
     87 	}
     88 	return pfile
     89 }
     90 
     91 func (m *MemMapFs) registerWithParent(f *mem.FileData, perm os.FileMode) {
     92 	if f == nil {
     93 		return
     94 	}
     95 	parent := m.findParent(f)
     96 	if parent == nil {
     97 		pdir := filepath.Dir(filepath.Clean(f.Name()))
     98 		err := m.lockfreeMkdir(pdir, perm)
     99 		if err != nil {
    100 			// log.Println("Mkdir error:", err)
    101 			return
    102 		}
    103 		parent, err = m.lockfreeOpen(pdir)
    104 		if err != nil {
    105 			// log.Println("Open after Mkdir error:", err)
    106 			return
    107 		}
    108 	}
    109 
    110 	parent.Lock()
    111 	mem.InitializeDir(parent)
    112 	mem.AddToMemDir(parent, f)
    113 	parent.Unlock()
    114 }
    115 
    116 func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {
    117 	name = normalizePath(name)
    118 	x, ok := m.getData()[name]
    119 	if ok {
    120 		// Only return ErrFileExists if it's a file, not a directory.
    121 		i := mem.FileInfo{FileData: x}
    122 		if !i.IsDir() {
    123 			return ErrFileExists
    124 		}
    125 	} else {
    126 		item := mem.CreateDir(name)
    127 		mem.SetMode(item, os.ModeDir|perm)
    128 		m.getData()[name] = item
    129 		m.registerWithParent(item, perm)
    130 	}
    131 	return nil
    132 }
    133 
    134 func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
    135 	perm &= chmodBits
    136 	name = normalizePath(name)
    137 
    138 	m.mu.RLock()
    139 	_, ok := m.getData()[name]
    140 	m.mu.RUnlock()
    141 	if ok {
    142 		return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
    143 	}
    144 
    145 	m.mu.Lock()
    146 	// Dobule check that it doesn't exist.
    147 	if _, ok := m.getData()[name]; ok {
    148 		m.mu.Unlock()
    149 		return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
    150 	}
    151 	item := mem.CreateDir(name)
    152 	mem.SetMode(item, os.ModeDir|perm)
    153 	m.getData()[name] = item
    154 	m.registerWithParent(item, perm)
    155 	m.mu.Unlock()
    156 
    157 	return m.setFileMode(name, perm|os.ModeDir)
    158 }
    159 
    160 func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error {
    161 	err := m.Mkdir(path, perm)
    162 	if err != nil {
    163 		if err.(*os.PathError).Err == ErrFileExists {
    164 			return nil
    165 		}
    166 		return err
    167 	}
    168 	return nil
    169 }
    170 
    171 // Handle some relative paths
    172 func normalizePath(path string) string {
    173 	path = filepath.Clean(path)
    174 
    175 	switch path {
    176 	case ".":
    177 		return FilePathSeparator
    178 	case "..":
    179 		return FilePathSeparator
    180 	default:
    181 		return path
    182 	}
    183 }
    184 
    185 func (m *MemMapFs) Open(name string) (File, error) {
    186 	f, err := m.open(name)
    187 	if f != nil {
    188 		return mem.NewReadOnlyFileHandle(f), err
    189 	}
    190 	return nil, err
    191 }
    192 
    193 func (m *MemMapFs) openWrite(name string) (File, error) {
    194 	f, err := m.open(name)
    195 	if f != nil {
    196 		return mem.NewFileHandle(f), err
    197 	}
    198 	return nil, err
    199 }
    200 
    201 func (m *MemMapFs) open(name string) (*mem.FileData, error) {
    202 	name = normalizePath(name)
    203 
    204 	m.mu.RLock()
    205 	f, ok := m.getData()[name]
    206 	m.mu.RUnlock()
    207 	if !ok {
    208 		return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound}
    209 	}
    210 	return f, nil
    211 }
    212 
    213 func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) {
    214 	name = normalizePath(name)
    215 	f, ok := m.getData()[name]
    216 	if ok {
    217 		return f, nil
    218 	} else {
    219 		return nil, ErrFileNotFound
    220 	}
    221 }
    222 
    223 func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
    224 	perm &= chmodBits
    225 	chmod := false
    226 	file, err := m.openWrite(name)
    227 	if err == nil && (flag&os.O_EXCL > 0) {
    228 		return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileExists}
    229 	}
    230 	if os.IsNotExist(err) && (flag&os.O_CREATE > 0) {
    231 		file, err = m.Create(name)
    232 		chmod = true
    233 	}
    234 	if err != nil {
    235 		return nil, err
    236 	}
    237 	if flag == os.O_RDONLY {
    238 		file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data())
    239 	}
    240 	if flag&os.O_APPEND > 0 {
    241 		_, err = file.Seek(0, io.SeekEnd)
    242 		if err != nil {
    243 			file.Close()
    244 			return nil, err
    245 		}
    246 	}
    247 	if flag&os.O_TRUNC > 0 && flag&(os.O_RDWR|os.O_WRONLY) > 0 {
    248 		err = file.Truncate(0)
    249 		if err != nil {
    250 			file.Close()
    251 			return nil, err
    252 		}
    253 	}
    254 	if chmod {
    255 		return file, m.setFileMode(name, perm)
    256 	}
    257 	return file, nil
    258 }
    259 
    260 func (m *MemMapFs) Remove(name string) error {
    261 	name = normalizePath(name)
    262 
    263 	m.mu.Lock()
    264 	defer m.mu.Unlock()
    265 
    266 	if _, ok := m.getData()[name]; ok {
    267 		err := m.unRegisterWithParent(name)
    268 		if err != nil {
    269 			return &os.PathError{Op: "remove", Path: name, Err: err}
    270 		}
    271 		delete(m.getData(), name)
    272 	} else {
    273 		return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist}
    274 	}
    275 	return nil
    276 }
    277 
    278 func (m *MemMapFs) RemoveAll(path string) error {
    279 	path = normalizePath(path)
    280 	m.mu.Lock()
    281 	m.unRegisterWithParent(path)
    282 	m.mu.Unlock()
    283 
    284 	m.mu.RLock()
    285 	defer m.mu.RUnlock()
    286 
    287 	for p := range m.getData() {
    288 		if p == path || strings.HasPrefix(p, path+FilePathSeparator) {
    289 			m.mu.RUnlock()
    290 			m.mu.Lock()
    291 			delete(m.getData(), p)
    292 			m.mu.Unlock()
    293 			m.mu.RLock()
    294 		}
    295 	}
    296 	return nil
    297 }
    298 
    299 func (m *MemMapFs) Rename(oldname, newname string) error {
    300 	oldname = normalizePath(oldname)
    301 	newname = normalizePath(newname)
    302 
    303 	if oldname == newname {
    304 		return nil
    305 	}
    306 
    307 	m.mu.RLock()
    308 	defer m.mu.RUnlock()
    309 	if _, ok := m.getData()[oldname]; ok {
    310 		m.mu.RUnlock()
    311 		m.mu.Lock()
    312 		m.unRegisterWithParent(oldname)
    313 		fileData := m.getData()[oldname]
    314 		delete(m.getData(), oldname)
    315 		mem.ChangeFileName(fileData, newname)
    316 		m.getData()[newname] = fileData
    317 		m.registerWithParent(fileData, 0)
    318 		m.mu.Unlock()
    319 		m.mu.RLock()
    320 	} else {
    321 		return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound}
    322 	}
    323 
    324 	for p, fileData := range m.getData() {
    325 		if strings.HasPrefix(p, oldname+FilePathSeparator) {
    326 			m.mu.RUnlock()
    327 			m.mu.Lock()
    328 			delete(m.getData(), p)
    329 			p := strings.Replace(p, oldname, newname, 1)
    330 			m.getData()[p] = fileData
    331 			m.mu.Unlock()
    332 			m.mu.RLock()
    333 		}
    334 	}
    335 	return nil
    336 }
    337 
    338 func (m *MemMapFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
    339 	fileInfo, err := m.Stat(name)
    340 	return fileInfo, false, err
    341 }
    342 
    343 func (m *MemMapFs) Stat(name string) (os.FileInfo, error) {
    344 	f, err := m.Open(name)
    345 	if err != nil {
    346 		return nil, err
    347 	}
    348 	fi := mem.GetFileInfo(f.(*mem.File).Data())
    349 	return fi, nil
    350 }
    351 
    352 func (m *MemMapFs) Chmod(name string, mode os.FileMode) error {
    353 	mode &= chmodBits
    354 
    355 	m.mu.RLock()
    356 	f, ok := m.getData()[name]
    357 	m.mu.RUnlock()
    358 	if !ok {
    359 		return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
    360 	}
    361 	prevOtherBits := mem.GetFileInfo(f).Mode() & ^chmodBits
    362 
    363 	mode = prevOtherBits | mode
    364 	return m.setFileMode(name, mode)
    365 }
    366 
    367 func (m *MemMapFs) setFileMode(name string, mode os.FileMode) error {
    368 	name = normalizePath(name)
    369 
    370 	m.mu.RLock()
    371 	f, ok := m.getData()[name]
    372 	m.mu.RUnlock()
    373 	if !ok {
    374 		return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
    375 	}
    376 
    377 	m.mu.Lock()
    378 	mem.SetMode(f, mode)
    379 	m.mu.Unlock()
    380 
    381 	return nil
    382 }
    383 
    384 func (m *MemMapFs) Chown(name string, uid, gid int) error {
    385 	name = normalizePath(name)
    386 
    387 	m.mu.RLock()
    388 	f, ok := m.getData()[name]
    389 	m.mu.RUnlock()
    390 	if !ok {
    391 		return &os.PathError{Op: "chown", Path: name, Err: ErrFileNotFound}
    392 	}
    393 
    394 	mem.SetUID(f, uid)
    395 	mem.SetGID(f, gid)
    396 
    397 	return nil
    398 }
    399 
    400 func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
    401 	name = normalizePath(name)
    402 
    403 	m.mu.RLock()
    404 	f, ok := m.getData()[name]
    405 	m.mu.RUnlock()
    406 	if !ok {
    407 		return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound}
    408 	}
    409 
    410 	m.mu.Lock()
    411 	mem.SetModTime(f, mtime)
    412 	m.mu.Unlock()
    413 
    414 	return nil
    415 }
    416 
    417 func (m *MemMapFs) List() {
    418 	for _, x := range m.data {
    419 		y := mem.FileInfo{FileData: x}
    420 		fmt.Println(x.Name(), y.Size())
    421 	}
    422 }