Modify stat to embed os.FileInfo differently and update file content reader

This commit is contained in:
Dane Everitt
2021-01-16 12:03:55 -08:00
parent 67ecbd667a
commit 2968ea3498
9 changed files with 60 additions and 75 deletions

View File

@@ -38,7 +38,7 @@ type Filesystem struct {
isTest bool
}
// Creates a new Filesystem instance for a given server.
// New creates a new Filesystem instance for a given server.
func New(root string, size int64, denylist []string) *Filesystem {
return &Filesystem{
root: root,
@@ -50,27 +50,27 @@ func New(root string, size int64, denylist []string) *Filesystem {
}
}
// Returns the root path for the Filesystem instance.
// Path returns the root path for the Filesystem instance.
func (fs *Filesystem) Path() string {
return fs.root
}
// Returns a reader for a file instance.
func (fs *Filesystem) File(p string) (*os.File, os.FileInfo, error) {
// File returns a reader for a file instance as well as the stat information.
func (fs *Filesystem) File(p string) (*os.File, Stat, error) {
cleaned, err := fs.SafePath(p)
if err != nil {
return nil, nil, err
return nil, Stat{}, err
}
st, err := os.Stat(cleaned)
st, err := fs.Stat(cleaned)
if err != nil {
return nil, nil, err
return nil, Stat{}, err
}
if st.IsDir() {
return nil, nil, &Error{code: ErrCodeIsDirectory}
return nil, Stat{}, &Error{code: ErrCodeIsDirectory}
}
f, err := os.Open(cleaned)
if err != nil {
return nil, nil, err
return nil, Stat{}, err
}
return f, st, nil
}
@@ -437,9 +437,9 @@ func (fo *fileOpener) open(path string, flags int, perm os.FileMode) (*os.File,
}
}
// Lists the contents of a given directory and returns stat information about each
// file and folder within it.
func (fs *Filesystem) ListDirectory(p string) ([]*Stat, error) {
// ListDirectory lists the contents of a given directory and returns stat
// information about each file and folder within it.
func (fs *Filesystem) ListDirectory(p string) ([]Stat, error) {
cleaned, err := fs.SafePath(p)
if err != nil {
return nil, err
@@ -455,7 +455,7 @@ func (fs *Filesystem) ListDirectory(p string) ([]*Stat, error) {
// You must initialize the output of this directory as a non-nil value otherwise
// when it is marshaled into a JSON object you'll just get 'null' back, which will
// break the panel badly.
out := make([]*Stat, len(files))
out := make([]Stat, len(files))
// Iterate over all of the files and directories returned and perform an async process
// to get the mime-type for them all.
@@ -482,15 +482,10 @@ func (fs *Filesystem) ListDirectory(p string) ([]*Stat, error) {
}
}
st := &Stat{
Info: f,
Mimetype: d,
}
st := Stat{FileInfo: f, Mimetype: d}
if m != nil {
st.Mimetype = m.String()
}
out[idx] = st
}(i, file)
}
@@ -500,17 +495,16 @@ func (fs *Filesystem) ListDirectory(p string) ([]*Stat, error) {
// Sort the output alphabetically to begin with since we've run the output
// through an asynchronous process and the order is gonna be very random.
sort.SliceStable(out, func(i, j int) bool {
if out[i].Info.Name() == out[j].Info.Name() || out[i].Info.Name() > out[j].Info.Name() {
if out[i].Name() == out[j].Name() || out[i].Name() > out[j].Name() {
return true
}
return false
})
// Then, sort it so that directories are listed first in the output. Everything
// will continue to be alphabetized at this point.
sort.SliceStable(out, func(i, j int) bool {
return out[i].Info.IsDir()
return out[i].IsDir()
})
return out, nil

View File

@@ -2,14 +2,15 @@ package filesystem
import (
"encoding/json"
"github.com/gabriel-vasile/mimetype"
"os"
"strconv"
"time"
"github.com/gabriel-vasile/mimetype"
)
type Stat struct {
Info os.FileInfo
os.FileInfo
Mimetype string
}
@@ -26,50 +27,48 @@ func (s *Stat) MarshalJSON() ([]byte, error) {
Symlink bool `json:"symlink"`
Mime string `json:"mime"`
}{
Name: s.Info.Name(),
Name: s.Name(),
Created: s.CTime().Format(time.RFC3339),
Modified: s.Info.ModTime().Format(time.RFC3339),
Mode: s.Info.Mode().String(),
Modified: s.ModTime().Format(time.RFC3339),
Mode: s.Mode().String(),
// Using `&os.ModePerm` on the file's mode will cause the mode to only have the permission values, and nothing else.
ModeBits: strconv.FormatUint(uint64(s.Info.Mode()&os.ModePerm), 8),
Size: s.Info.Size(),
Directory: s.Info.IsDir(),
File: !s.Info.IsDir(),
Symlink: s.Info.Mode().Perm()&os.ModeSymlink != 0,
ModeBits: strconv.FormatUint(uint64(s.Mode()&os.ModePerm), 8),
Size: s.Size(),
Directory: s.IsDir(),
File: !s.IsDir(),
Symlink: s.Mode().Perm()&os.ModeSymlink != 0,
Mime: s.Mimetype,
})
}
// Stats a file or folder and returns the base stat object from go along with the
// MIME data that can be used for editing files.
func (fs *Filesystem) Stat(p string) (*Stat, error) {
// Stat stats a file or folder and returns the base stat object from go along
// with the MIME data that can be used for editing files.
func (fs *Filesystem) Stat(p string) (Stat, error) {
cleaned, err := fs.SafePath(p)
if err != nil {
return nil, err
return Stat{}, err
}
return fs.unsafeStat(cleaned)
}
func (fs *Filesystem) unsafeStat(p string) (*Stat, error) {
func (fs *Filesystem) unsafeStat(p string) (Stat, error) {
s, err := os.Stat(p)
if err != nil {
return nil, err
return Stat{}, err
}
var m *mimetype.MIME
if !s.IsDir() {
m, err = mimetype.DetectFile(p)
if err != nil {
return nil, err
return Stat{}, err
}
}
st := &Stat{
Info: s,
st := Stat{
FileInfo: s,
Mimetype: "inode/directory",
}
if m != nil {
st.Mimetype = m.String()
}

View File

@@ -5,9 +5,9 @@ import (
"time"
)
// Returns the time that the file/folder was created.
// CTime returns the time that the file/folder was created.
func (s *Stat) CTime() time.Time {
st := s.Info.Sys().(*syscall.Stat_t)
st := s.Sys().(*syscall.Stat_t)
return time.Unix(st.Ctimespec.Sec, st.Ctimespec.Nsec)
}

View File

@@ -7,7 +7,7 @@ import (
// Returns the time that the file/folder was created.
func (s *Stat) CTime() time.Time {
st := s.Info.Sys().(*syscall.Stat_t)
st := s.Sys().(*syscall.Stat_t)
// Do not remove these "redundant" type-casts, they are required for 32-bit builds to work.
return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec))

View File

@@ -8,5 +8,5 @@ import (
// However, I have no idea how to do this on windows, so we're skipping it
// for right now.
func (s *Stat) CTime() time.Time {
return s.Info.ModTime()
return s.ModTime()
}