diskspace/file_entry.go
2022-08-03 21:28:50 +02:00

157 lines
2.7 KiB
Go

package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"sort"
"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)
}
// recalculate order of parent entries
pentries := e.Parent().Entries()
sort.Slice(pentries, func(i, j int) bool {
return pentries[i].SizeModified() < pentries[j].SizeModified()
})
}
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())
}
}
}