157 lines
3.0 KiB
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,
|
||
|
)
|
||
|
}
|