150 lines
2.5 KiB
Go
150 lines
2.5 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
type FileEntry struct {
|
||
|
path string
|
||
|
size *uint64
|
||
|
modSize *uint64
|
||
|
parent Entry
|
||
|
|
||
|
removal bool
|
||
|
noPerm bool
|
||
|
isMount bool
|
||
|
isExec bool
|
||
|
}
|
||
|
|
||
|
var _ Entry = &FileEntry{}
|
||
|
|
||
|
func (e *FileEntry) Name() string {
|
||
|
return filepath.Base(e.path)
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) Path() string {
|
||
|
return e.path
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) Size() uint64 {
|
||
|
if e.size == nil {
|
||
|
e.Scan(nil, nil)
|
||
|
}
|
||
|
|
||
|
return *e.size
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) Entries() []Entry {
|
||
|
return []Entry{}
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) String() string {
|
||
|
var ic string
|
||
|
if e.isExec {
|
||
|
ic = icon("app")
|
||
|
} else {
|
||
|
ic = icon(filepath.Ext(e.Path()))
|
||
|
}
|
||
|
|
||
|
if e.removal {
|
||
|
return ColorRed.Sprintf(
|
||
|
"%s %s (%s / %s)",
|
||
|
ic, e.Name(), fmtSize(e.SizeModified()), fmtSize(e.Size()),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
if e.isExec {
|
||
|
return ColorGreen.Sprintf("%s %s (%s)", ic, e.Name(), fmtSize(e.Size()))
|
||
|
}
|
||
|
|
||
|
return fmt.Sprintf("%s %s (%s)", ic, e.Name(), fmtSize(e.Size()))
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) stringRecursive(depth, maxDepth int, b *strings.Builder) {
|
||
|
if depth > maxDepth {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
b.WriteString(strings.Repeat(" ", depth))
|
||
|
b.WriteString(e.String())
|
||
|
b.WriteRune('\n')
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) StringRecursive(depth int) string {
|
||
|
b := new(strings.Builder)
|
||
|
e.stringRecursive(0, depth, b)
|
||
|
return b.String()
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) Scan(ch chan<- string, mounts map[string]struct{}) {
|
||
|
if ch != nil {
|
||
|
ch <- e.Path()
|
||
|
}
|
||
|
|
||
|
s := uint64(0)
|
||
|
if fi, err := os.Lstat(e.Path()); err == nil {
|
||
|
s = uint64(fi.Size())
|
||
|
e.isExec = fi.Mode()&0x41 > 0 // 0x41 == 0b001000001 == rwXrwxrwX
|
||
|
} else if errors.Is(err, os.ErrPermission) {
|
||
|
e.noPerm = true
|
||
|
}
|
||
|
e.size = &s
|
||
|
|
||
|
e.modSize = new(uint64)
|
||
|
*e.modSize = *e.size
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) Parent() Entry {
|
||
|
return e.parent
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) Entry(path string) Entry {
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) IsDir() bool {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) SetRemovalMark(mark bool) {
|
||
|
e.removal = mark
|
||
|
if mark {
|
||
|
e.modifySize(-*e.size)
|
||
|
} else {
|
||
|
e.modifySize(*e.size)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) RemovalMark() bool {
|
||
|
return e.removal
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) SizeModified() uint64 {
|
||
|
if e.size == nil {
|
||
|
e.Size()
|
||
|
}
|
||
|
|
||
|
return *e.modSize
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) modifySize(modifier uint64) {
|
||
|
*e.modSize += modifier
|
||
|
if e.parent != nil {
|
||
|
e.parent.modifySize(modifier)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *FileEntry) RemovalStats(stats *RemovalStats) {
|
||
|
if e.RemovalMark() {
|
||
|
stats.Files++
|
||
|
stats.Bytes += *e.size
|
||
|
if e.Parent() != nil && !e.Parent().RemovalMark() {
|
||
|
stats.Paths = append(stats.Paths, e.Path())
|
||
|
}
|
||
|
}
|
||
|
}
|