github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/base/dsfs/file.go (about)

     1  package dsfs
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"io/fs"
    10  	"io/ioutil"
    11  	"os"
    12  	"time"
    13  
    14  	"github.com/qri-io/qfs"
    15  )
    16  
    17  // JSONFile is a convenenience method for creating a file from a json.Marshaller
    18  func JSONFile(name string, m json.Marshaler) (fs.File, error) {
    19  	data, err := m.MarshalJSON()
    20  	if err != nil {
    21  		log.Debug(err.Error())
    22  		return nil, err
    23  	}
    24  	return NewMemfileBytes(name, data), nil
    25  }
    26  
    27  func fileBytes(file qfs.File, err error) ([]byte, error) {
    28  	if err != nil {
    29  		log.Debug(err.Error())
    30  		return nil, err
    31  	}
    32  	return ioutil.ReadAll(file)
    33  }
    34  
    35  type fsFileInfo struct {
    36  	name  string      // base name of the file
    37  	size  int64       // length in bytes for regular files; system-dependent for others
    38  	mode  fs.FileMode // file mode bits
    39  	mtime time.Time   // modification time
    40  	sys   interface{}
    41  }
    42  
    43  var _ os.FileInfo = (*fsFileInfo)(nil)
    44  
    45  func (fi fsFileInfo) Name() string       { return fi.name }
    46  func (fi fsFileInfo) Size() int64        { return fi.size }
    47  func (fi fsFileInfo) Mode() fs.FileMode  { return fi.mode }
    48  func (fi fsFileInfo) ModTime() time.Time { return fi.mtime }
    49  func (fi fsFileInfo) IsDir() bool        { return fi.mode.IsDir() }
    50  func (fi fsFileInfo) Sys() interface{}   { return fi.sys }
    51  
    52  func (fi *fsFileInfo) SetFilename(name string) error {
    53  	fi.name = name
    54  	return nil
    55  }
    56  
    57  type fsDirEntry struct {
    58  	name   string
    59  	isFile bool
    60  }
    61  
    62  var _ fs.DirEntry = (*fsDirEntry)(nil)
    63  
    64  func (de fsDirEntry) Name() string { return de.name }
    65  func (de fsDirEntry) IsDir() bool  { return !de.isFile }
    66  func (de fsDirEntry) Type() fs.FileMode {
    67  	if de.isFile {
    68  		return 0
    69  	}
    70  	return fs.ModeDir
    71  }
    72  func (de fsDirEntry) Info() (fs.FileInfo, error) { return nil, errors.New("fsDirEntry.FileInfo") }
    73  
    74  // memfile is an in-memory file
    75  type memfile struct {
    76  	fi  os.FileInfo
    77  	buf io.Reader
    78  }
    79  
    80  // Confirm that memfile satisfies the File interface
    81  var _ = (fs.File)(&memfile{})
    82  
    83  // NewFileWithInfo creates a new open file with provided file information
    84  func NewFileWithInfo(fi fs.FileInfo, r io.Reader) (fs.File, error) {
    85  	switch fi.Mode() {
    86  	case os.ModeDir:
    87  		return nil, fmt.Errorf("NewFileWithInfo doesn't support creating directories")
    88  	default:
    89  		return &memfile{
    90  			fi:  fi,
    91  			buf: r,
    92  		}, nil
    93  	}
    94  }
    95  
    96  // NewMemfileReader creates a file from an io.Reader
    97  func NewMemfileReader(name string, r io.Reader) fs.File {
    98  	return &memfile{
    99  		fi: &fsFileInfo{
   100  			name: name,
   101  			size: int64(-1),
   102  			mode: 0,
   103  			// mtime: Timestamp(),
   104  		},
   105  		buf: r,
   106  	}
   107  }
   108  
   109  // NewMemfileBytes creates a file from a byte slice
   110  func NewMemfileBytes(name string, data []byte) fs.File {
   111  	return &memfile{
   112  		fi: &fsFileInfo{
   113  			name: name,
   114  			size: int64(len(data)),
   115  			mode: 0,
   116  			// mtime: Timestamp(),
   117  		},
   118  		buf: bytes.NewBuffer(data),
   119  	}
   120  }
   121  
   122  // Stat returns information for this file
   123  func (m memfile) Stat() (fs.FileInfo, error) {
   124  	return m.fi, nil
   125  }
   126  
   127  // Read implements the io.Reader interface
   128  func (m memfile) Read(p []byte) (int, error) {
   129  	return m.buf.Read(p)
   130  }
   131  
   132  // Close closes the file, if the backing reader implements the io.Closer interface
   133  // it will call close on the backing Reader
   134  func (m memfile) Close() error {
   135  	if closer, ok := m.buf.(io.Closer); ok {
   136  		return closer.Close()
   137  	}
   138  	return nil
   139  }