mirror of
				https://github.com/datarhei/core.git
				synced 2025-11-01 03:42:51 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			169 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package fs
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| )
 | |
| 
 | |
| type SizedFilesystem interface {
 | |
| 	Filesystem
 | |
| 
 | |
| 	// Resize resizes the filesystem to the new size. Files may need to be deleted.
 | |
| 	Resize(size int64) error
 | |
| }
 | |
| 
 | |
| type PurgeFilesystem interface {
 | |
| 	// Purge will free up at least size number of bytes and returns the actual
 | |
| 	// freed space in bytes.
 | |
| 	Purge(size int64) int64
 | |
| }
 | |
| 
 | |
| type sizedFilesystem struct {
 | |
| 	Filesystem
 | |
| 
 | |
| 	// Size is the capacity of the filesystem in bytes
 | |
| 	maxSize int64
 | |
| 
 | |
| 	// Set true to automatically delete the oldest files until there's
 | |
| 	// enough space to store a new file
 | |
| 	purge bool
 | |
| }
 | |
| 
 | |
| var _ PurgeFilesystem = &sizedFilesystem{}
 | |
| 
 | |
| func NewSizedFilesystem(fs Filesystem, maxSize int64, purge bool) (SizedFilesystem, error) {
 | |
| 	r := &sizedFilesystem{
 | |
| 		Filesystem: fs,
 | |
| 		maxSize:    maxSize,
 | |
| 		purge:      purge,
 | |
| 	}
 | |
| 
 | |
| 	return r, nil
 | |
| }
 | |
| 
 | |
| func (r *sizedFilesystem) Size() (int64, int64) {
 | |
| 	currentSize, _ := r.Filesystem.Size()
 | |
| 
 | |
| 	return currentSize, r.maxSize
 | |
| }
 | |
| 
 | |
| func (r *sizedFilesystem) Resize(size int64) error {
 | |
| 	currentSize, _ := r.Size()
 | |
| 	if size >= currentSize {
 | |
| 		// If the new size is the same or larger than the current size,
 | |
| 		// nothing to do.
 | |
| 		r.maxSize = size
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// If the new size is less than the current size, purge some files.
 | |
| 	r.Purge(currentSize - size)
 | |
| 
 | |
| 	r.maxSize = size
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (r *sizedFilesystem) WriteFileReader(path string, rd io.Reader) (int64, bool, error) {
 | |
| 	currentSize, maxSize := r.Size()
 | |
| 	if maxSize <= 0 {
 | |
| 		return r.Filesystem.WriteFileReader(path, rd)
 | |
| 	}
 | |
| 
 | |
| 	data := bytes.Buffer{}
 | |
| 	size, err := data.ReadFrom(rd)
 | |
| 	if err != nil {
 | |
| 		return -1, false, err
 | |
| 	}
 | |
| 
 | |
| 	// reject if the new file is larger than the available space
 | |
| 	if size > maxSize {
 | |
| 		return -1, false, fmt.Errorf("File is too big")
 | |
| 	}
 | |
| 
 | |
| 	// Calculate the new size of the filesystem
 | |
| 	newSize := currentSize + size
 | |
| 
 | |
| 	// If the the new size is larger than the allowed size, we have to free
 | |
| 	// some space.
 | |
| 	if newSize > maxSize {
 | |
| 		if !r.purge {
 | |
| 			return -1, false, fmt.Errorf("not enough space on device")
 | |
| 		}
 | |
| 
 | |
| 		if r.Purge(size) < size {
 | |
| 			return -1, false, fmt.Errorf("not enough space on device")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return r.Filesystem.WriteFileReader(path, &data)
 | |
| }
 | |
| 
 | |
| func (r *sizedFilesystem) WriteFile(path string, data []byte) (int64, bool, error) {
 | |
| 	return r.WriteFileReader(path, bytes.NewBuffer(data))
 | |
| }
 | |
| 
 | |
| func (r *sizedFilesystem) WriteFileSafe(path string, data []byte) (int64, bool, error) {
 | |
| 	currentSize, maxSize := r.Size()
 | |
| 	if maxSize <= 0 {
 | |
| 		return r.Filesystem.WriteFile(path, data)
 | |
| 	}
 | |
| 
 | |
| 	size := int64(len(data))
 | |
| 
 | |
| 	// reject if the new file is larger than the available space
 | |
| 	if size > maxSize {
 | |
| 		return -1, false, fmt.Errorf("File is too big")
 | |
| 	}
 | |
| 
 | |
| 	// Calculate the new size of the filesystem
 | |
| 	newSize := currentSize + size
 | |
| 
 | |
| 	// If the the new size is larger than the allowed size, we have to free
 | |
| 	// some space.
 | |
| 	if newSize > maxSize {
 | |
| 		if !r.purge {
 | |
| 			return -1, false, fmt.Errorf("not enough space on device")
 | |
| 		}
 | |
| 
 | |
| 		if r.Purge(size) < size {
 | |
| 			return -1, false, fmt.Errorf("not enough space on device")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return r.Filesystem.WriteFileSafe(path, data)
 | |
| }
 | |
| 
 | |
| func (r *sizedFilesystem) Purge(size int64) int64 {
 | |
| 	if purger, ok := r.Filesystem.(PurgeFilesystem); ok {
 | |
| 		return purger.Purge(size)
 | |
| 	}
 | |
| 
 | |
| 	return 0
 | |
| 	/*
 | |
| 	   files := r.Filesystem.List("/", "")
 | |
| 
 | |
| 	   	sort.Slice(files, func(i, j int) bool {
 | |
| 	   		return files[i].ModTime().Before(files[j].ModTime())
 | |
| 	   	})
 | |
| 
 | |
| 	   var freed int64 = 0
 | |
| 
 | |
| 	   	for _, f := range files {
 | |
| 	   		r.Filesystem.Remove(f.Name())
 | |
| 	   		size -= f.Size()
 | |
| 	   		freed += f.Size()
 | |
| 	   		r.currentSize -= f.Size()
 | |
| 
 | |
| 	   		if size <= 0 {
 | |
| 	   			break
 | |
| 	   		}
 | |
| 	   	}
 | |
| 
 | |
| 	   files = nil
 | |
| 
 | |
| 	   return freed
 | |
| 	*/
 | |
| }
 | 
