diskspace/file_entry.go

176 lines
3.1 KiB
Go
Raw Normal View History

2022-06-28 13:11:16 +02:00
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
2022-08-03 21:28:45 +02:00
"sort"
2022-06-28 13:11:16 +02:00
"strings"
)
type FileEntry struct {
2022-08-16 22:12:26 +02:00
path string
2022-06-28 13:11:16 +02:00
size *uint64
modSize *uint64
2022-08-16 22:12:26 +02:00
fileCount *uint64
modFileCount *uint64
parent Entry
2022-06-28 13:11:16 +02:00
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
}
2022-08-16 22:12:26 +02:00
e.size = &s
2022-06-28 13:11:16 +02:00
e.modSize = new(uint64)
*e.modSize = *e.size
2022-08-16 22:12:26 +02:00
f := uint64(1)
e.fileCount = &f
e.modFileCount = new(uint64)
*e.modFileCount = *e.fileCount
2022-06-28 13:11:16 +02:00
}
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 {
2022-08-16 22:12:26 +02:00
e.modify(-*e.size, -*e.fileCount) // underflow that is cancelling out perfectly
2022-06-28 13:11:16 +02:00
} else {
2022-08-16 22:12:26 +02:00
e.modify(*e.size, *e.fileCount)
2022-06-28 13:11:16 +02:00
}
2022-08-03 21:28:45 +02:00
// recalculate order of parent entries
pentries := e.Parent().Entries()
sort.Slice(pentries, func(i, j int) bool {
return pentries[i].SizeModified() < pentries[j].SizeModified()
})
2022-06-28 13:11:16 +02:00
}
func (e *FileEntry) RemovalMark() bool {
return e.removal
}
func (e *FileEntry) SizeModified() uint64 {
if e.size == nil {
e.Size()
}
return *e.modSize
}
2022-08-16 22:12:26 +02:00
func (e *FileEntry) modify(size uint64, fileCount uint64) {
*e.modSize = *e.modSize + size
*e.modFileCount = *e.modFileCount + fileCount
2022-06-28 13:11:16 +02:00
if e.parent != nil {
2022-08-16 22:12:26 +02:00
e.parent.modify(size, fileCount)
2022-06-28 13:11:16 +02:00
}
}
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())
}
}
}
2022-08-16 22:12:26 +02:00
func (e *FileEntry) FileCount() uint64 {
return *e.fileCount
}
func (e *FileEntry) FileCountModified() uint64 {
return *e.modFileCount
}