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 }