package filesystem import ( "encoding/json" "io" "strconv" "time" "github.com/gabriel-vasile/mimetype" "github.com/pterodactyl/wings/internal/ufs" ) type Stat struct { ufs.FileInfo 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"` ModeBits string `json:"mode_bits"` Size int64 `json:"size"` Directory bool `json:"directory"` File bool `json:"file"` Symlink bool `json:"symlink"` Mime string `json:"mime"` }{ Name: s.Name(), Created: s.CTime().Format(time.RFC3339), Modified: s.ModTime().Format(time.RFC3339), Mode: s.Mode().String(), // 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), Size: s.Size(), Directory: s.IsDir(), File: !s.IsDir(), Symlink: s.Mode().Perm()&ufs.ModeSymlink != 0, Mime: s.Mimetype, }) } func statFromFile(f ufs.File) (Stat, error) { s, err := f.Stat() if err != nil { return Stat{}, err } var m *mimetype.MIME if !s.IsDir() { m, err = mimetype.DetectReader(f) if err != nil { return Stat{}, err } if _, err := f.Seek(0, io.SeekStart); err != nil { return Stat{}, err } } st := Stat{ FileInfo: s, Mimetype: "inode/directory", } if m != nil { st.Mimetype = m.String() } return st, nil } // 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 } return st, nil }