2020-09-27 19:24:08 +00:00
|
|
|
package filesystem
|
|
|
|
|
|
|
|
import (
|
2024-03-13 03:44:55 +00:00
|
|
|
"encoding/json"
|
|
|
|
"io"
|
2020-11-29 21:20:24 +00:00
|
|
|
"strconv"
|
2020-09-27 19:24:08 +00:00
|
|
|
"time"
|
2021-01-16 20:03:55 +00:00
|
|
|
|
|
|
|
"github.com/gabriel-vasile/mimetype"
|
2024-03-13 03:44:55 +00:00
|
|
|
|
|
|
|
"github.com/pterodactyl/wings/internal/ufs"
|
2020-09-27 19:24:08 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Stat struct {
|
2024-03-13 03:44:55 +00:00
|
|
|
ufs.FileInfo
|
2020-09-27 19:24:08 +00:00
|
|
|
Mimetype string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Stat) MarshalJSON() ([]byte, error) {
|
|
|
|
return json.Marshal(struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Created string `json:"created"`
|
|
|
|
Modified string `json:"modified"`
|
|
|
|
Mode string `json:"mode"`
|
2020-11-29 21:20:24 +00:00
|
|
|
ModeBits string `json:"mode_bits"`
|
2020-09-27 19:24:08 +00:00
|
|
|
Size int64 `json:"size"`
|
|
|
|
Directory bool `json:"directory"`
|
|
|
|
File bool `json:"file"`
|
|
|
|
Symlink bool `json:"symlink"`
|
|
|
|
Mime string `json:"mime"`
|
|
|
|
}{
|
2021-01-16 20:03:55 +00:00
|
|
|
Name: s.Name(),
|
2020-11-29 23:13:07 +00:00
|
|
|
Created: s.CTime().Format(time.RFC3339),
|
2021-01-16 20:03:55 +00:00
|
|
|
Modified: s.ModTime().Format(time.RFC3339),
|
|
|
|
Mode: s.Mode().String(),
|
2024-03-13 03:44:55 +00:00
|
|
|
// Using `&ModePerm` on the file's mode will cause the mode to only have the permission values, and nothing else.
|
|
|
|
ModeBits: strconv.FormatUint(uint64(s.Mode()&ufs.ModePerm), 8),
|
2021-01-16 20:03:55 +00:00
|
|
|
Size: s.Size(),
|
|
|
|
Directory: s.IsDir(),
|
|
|
|
File: !s.IsDir(),
|
2024-07-28 09:39:44 +00:00
|
|
|
Symlink: s.Mode().Type()&ufs.ModeSymlink != 0,
|
2020-09-27 19:24:08 +00:00
|
|
|
Mime: s.Mimetype,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-03-13 03:44:55 +00:00
|
|
|
func statFromFile(f ufs.File) (Stat, error) {
|
|
|
|
s, err := f.Stat()
|
2020-09-27 19:24:08 +00:00
|
|
|
if err != nil {
|
2021-01-16 20:03:55 +00:00
|
|
|
return Stat{}, err
|
2020-09-27 19:24:08 +00:00
|
|
|
}
|
|
|
|
var m *mimetype.MIME
|
|
|
|
if !s.IsDir() {
|
2024-03-13 03:44:55 +00:00
|
|
|
m, err = mimetype.DetectReader(f)
|
2020-09-27 19:24:08 +00:00
|
|
|
if err != nil {
|
2021-01-16 20:03:55 +00:00
|
|
|
return Stat{}, err
|
2020-09-27 19:24:08 +00:00
|
|
|
}
|
2024-03-13 03:44:55 +00:00
|
|
|
if _, err := f.Seek(0, io.SeekStart); err != nil {
|
|
|
|
return Stat{}, err
|
|
|
|
}
|
2020-09-27 19:24:08 +00:00
|
|
|
}
|
2021-01-16 20:03:55 +00:00
|
|
|
st := Stat{
|
|
|
|
FileInfo: s,
|
2020-09-27 19:24:08 +00:00
|
|
|
Mimetype: "inode/directory",
|
|
|
|
}
|
|
|
|
if m != nil {
|
|
|
|
st.Mimetype = m.String()
|
|
|
|
}
|
2024-03-13 03:44:55 +00:00
|
|
|
return st, nil
|
|
|
|
}
|
2020-09-27 19:24:08 +00:00
|
|
|
|
2024-03-13 03:44:55 +00:00
|
|
|
// 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) {
|
|
|
|
f, err := fs.unixFS.Open(p)
|
|
|
|
if err != nil {
|
|
|
|
return Stat{}, err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
st, err := statFromFile(f)
|
|
|
|
if err != nil {
|
|
|
|
return Stat{}, err
|
|
|
|
}
|
2020-09-27 19:24:08 +00:00
|
|
|
return st, nil
|
|
|
|
}
|