infinitime/blefs/dir.go

157 lines
3.0 KiB
Go

package blefs
import (
"fmt"
"io/fs"
"strconv"
"time"
)
// Mkdir creates a directory at the given path
func (blefs *FS) Mkdir(path string) error {
// Create make directory request
err := blefs.request(
FSCmdMkdir,
true,
uint16(len(path)),
padding(4),
uint64(time.Now().UnixNano()),
path,
)
if err != nil {
return err
}
var status int8
// Upon receiving 0x41 (FSResponseMkdir), read status byte
blefs.on(FSResponseMkdir, func(data []byte) error {
return decode(data, &status)
})
// If status not ok, return error
if status != FSStatusOk {
return FSError{status}
}
return nil
}
// ReadDir returns a list of directory entries from the given path
func (blefs *FS) ReadDir(path string) ([]fs.DirEntry, error) {
// Create list directory request
err := blefs.request(
FSCmdListDir,
true,
uint16(len(path)),
path,
)
if err != nil {
return nil, err
}
var out []fs.DirEntry
for {
// Create new directory entry
listing := DirEntry{}
// Upon receiving 0x50 (FSResponseListDir)
blefs.on(FSResponseListDir, func(data []byte) error {
// Read data into listing
err := decode(
data,
&listing.status,
&listing.pathLen,
&listing.entryNum,
&listing.entries,
&listing.flags,
&listing.modtime,
&listing.size,
&listing.path,
)
if err != nil {
return err
}
return nil
})
// If status is not ok, return error
if listing.status != FSStatusOk {
return nil, FSError{listing.status}
}
// Stop once entry number equals total entries
if listing.entryNum == listing.entries {
break
}
// Append listing to slice
out = append(out, listing)
}
return out, nil
}
// DirEntry represents an entry from a directory listing
type DirEntry struct {
status int8
pathLen uint16
entryNum uint32
entries uint32
flags uint32
modtime uint64
size uint32
path string
}
// Name returns the name of the file described by the entry
func (de DirEntry) Name() string {
return de.path
}
// IsDir reports whether the entry describes a directory.
func (de DirEntry) IsDir() bool {
return de.flags&0b1 == 1
}
// Type returns the type bits for the entry.
func (de DirEntry) Type() fs.FileMode {
if de.IsDir() {
return fs.ModeDir
} else {
return 0
}
}
// Info returns the FileInfo for the file or subdirectory described by the entry.
func (de DirEntry) Info() (fs.FileInfo, error) {
return FileInfo{
name: de.path,
size: de.size,
modtime: de.modtime,
mode: de.Type(),
isDir: de.IsDir(),
}, nil
}
func (de DirEntry) String() string {
var isDirChar rune
if de.IsDir() {
isDirChar = 'd'
} else {
isDirChar = '-'
}
// Get human-readable value for file size
val, unit := bytesHuman(de.size)
prec := 0
// If value is less than 10, set precision to 1
if val < 10 {
prec = 1
}
// Convert float to string
valStr := strconv.FormatFloat(val, 'f', prec, 64)
// Return string formatted like so:
// - 10 kB file
// or:
// d 0 B .
return fmt.Sprintf(
"%c %3s %-2s %s",
isDirChar,
valStr,
unit,
de.path,
)
}