mirror of
https://github.com/rclone/rclone.git
synced 2025-01-11 00:40:03 +01:00
ncdu: fix issue where dir size is summed when file sizes are -1
Some backends may not provide size for all objects, and instead return -1. Existing version included these in directory sums, with strange results. With this commit rclone ncdu will consider negative sizes as zero, but add a new prefix flag '~' with a description that indicates the shown size is inaccurate. Fixes #6084
This commit is contained in:
parent
d77736c21a
commit
87c201c92a
@ -283,7 +283,7 @@ func (u *UI) biggestEntry() (biggest int64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := range u.entries {
|
for i := range u.entries {
|
||||||
size, _, _, _, _, _ := u.d.AttrI(u.sortPerm[i])
|
size, _, _, _, _, _, _ := u.d.AttrI(u.sortPerm[i])
|
||||||
if size > biggest {
|
if size > biggest {
|
||||||
biggest = size
|
biggest = size
|
||||||
}
|
}
|
||||||
@ -297,7 +297,7 @@ func (u *UI) hasEmptyDir() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := range u.entries {
|
for i := range u.entries {
|
||||||
_, count, isDir, _, _, _ := u.d.AttrI(u.sortPerm[i])
|
_, count, _, isDir, _, _, _ := u.d.AttrI(u.sortPerm[i])
|
||||||
if isDir && count == 0 {
|
if isDir && count == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -343,7 +343,7 @@ func (u *UI) Draw() error {
|
|||||||
if y >= h-1 {
|
if y >= h-1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
size, count, isDir, readable, entriesHaveErrors, err := u.d.AttrI(u.sortPerm[n])
|
size, count, countUnknownSize, isDir, readable, entriesHaveErrors, err := u.d.AttrI(u.sortPerm[n])
|
||||||
fg := termbox.ColorWhite
|
fg := termbox.ColorWhite
|
||||||
if entriesHaveErrors {
|
if entriesHaveErrors {
|
||||||
fg = termbox.ColorYellow
|
fg = termbox.ColorYellow
|
||||||
@ -364,6 +364,10 @@ func (u *UI) Draw() error {
|
|||||||
if !readable {
|
if !readable {
|
||||||
message = " [not read yet]"
|
message = " [not read yet]"
|
||||||
}
|
}
|
||||||
|
if countUnknownSize > 0 {
|
||||||
|
message = fmt.Sprintf(" [%d of %d files have unknown size, size may be underestimated]", countUnknownSize, count)
|
||||||
|
fileFlag = '~'
|
||||||
|
}
|
||||||
if entriesHaveErrors {
|
if entriesHaveErrors {
|
||||||
message = " [some subdirectories could not be read, size may be underestimated]"
|
message = " [some subdirectories could not be read, size may be underestimated]"
|
||||||
fileFlag = '.'
|
fileFlag = '.'
|
||||||
@ -383,7 +387,10 @@ func (u *UI) Draw() error {
|
|||||||
}
|
}
|
||||||
var averageSize float64
|
var averageSize float64
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
averageSize = float64(size) / float64(count)
|
countForAverage := count - countUnknownSize
|
||||||
|
if countForAverage > 0 {
|
||||||
|
averageSize = float64(size) / float64(countForAverage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if u.showDirAverageSize {
|
if u.showDirAverageSize {
|
||||||
ss := operations.SizeStringField(int64(averageSize), u.humanReadable, 9) + " "
|
ss := operations.SizeStringField(int64(averageSize), u.humanReadable, 9) + " "
|
||||||
@ -559,8 +566,8 @@ type ncduSort struct {
|
|||||||
// Less is part of sort.Interface.
|
// Less is part of sort.Interface.
|
||||||
func (ds *ncduSort) Less(i, j int) bool {
|
func (ds *ncduSort) Less(i, j int) bool {
|
||||||
var iAvgSize, jAvgSize float64
|
var iAvgSize, jAvgSize float64
|
||||||
isize, icount, _, _, _, _ := ds.d.AttrI(ds.sortPerm[i])
|
isize, icount, _, _, _, _, _ := ds.d.AttrI(ds.sortPerm[i])
|
||||||
jsize, jcount, _, _, _, _ := ds.d.AttrI(ds.sortPerm[j])
|
jsize, jcount, _, _, _, _, _ := ds.d.AttrI(ds.sortPerm[j])
|
||||||
iname, jname := ds.entries[ds.sortPerm[i]].Remote(), ds.entries[ds.sortPerm[j]].Remote()
|
iname, jname := ds.entries[ds.sortPerm[i]].Remote(), ds.entries[ds.sortPerm[j]].Remote()
|
||||||
if icount > 0 {
|
if icount > 0 {
|
||||||
iAvgSize = float64(isize / icount)
|
iAvgSize = float64(isize / icount)
|
||||||
|
@ -16,8 +16,9 @@ type Dir struct {
|
|||||||
parent *Dir
|
parent *Dir
|
||||||
path string
|
path string
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
count int64
|
|
||||||
size int64
|
size int64
|
||||||
|
count int64
|
||||||
|
countUnknownSize int64
|
||||||
entries fs.DirEntries
|
entries fs.DirEntries
|
||||||
dirs map[string]*Dir
|
dirs map[string]*Dir
|
||||||
readError error
|
readError error
|
||||||
@ -49,7 +50,13 @@ func newDir(parent *Dir, dirPath string, entries fs.DirEntries, err error) *Dir
|
|||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if o, ok := entry.(fs.Object); ok {
|
if o, ok := entry.(fs.Object); ok {
|
||||||
d.count++
|
d.count++
|
||||||
d.size += o.Size()
|
size := o.Size()
|
||||||
|
if size < 0 {
|
||||||
|
// Some backends may return -1 because size of object is not known
|
||||||
|
d.countUnknownSize++
|
||||||
|
} else {
|
||||||
|
d.size += size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set my directory entry in parent
|
// Set my directory entry in parent
|
||||||
@ -62,8 +69,9 @@ func newDir(parent *Dir, dirPath string, entries fs.DirEntries, err error) *Dir
|
|||||||
// Accumulate counts in parents
|
// Accumulate counts in parents
|
||||||
for ; parent != nil; parent = parent.parent {
|
for ; parent != nil; parent = parent.parent {
|
||||||
parent.mu.Lock()
|
parent.mu.Lock()
|
||||||
parent.count += d.count
|
|
||||||
parent.size += d.size
|
parent.size += d.size
|
||||||
|
parent.count += d.count
|
||||||
|
parent.countUnknownSize += d.countUnknownSize
|
||||||
if d.readError != nil {
|
if d.readError != nil {
|
||||||
parent.entriesHaveErrors = true
|
parent.entriesHaveErrors = true
|
||||||
}
|
}
|
||||||
@ -91,17 +99,24 @@ func (d *Dir) Remove(i int) {
|
|||||||
// Call with d.mu held
|
// Call with d.mu held
|
||||||
func (d *Dir) remove(i int) {
|
func (d *Dir) remove(i int) {
|
||||||
size := d.entries[i].Size()
|
size := d.entries[i].Size()
|
||||||
|
countUnknownSize := int64(0)
|
||||||
|
if size < 0 {
|
||||||
|
size = 0
|
||||||
|
countUnknownSize = 1
|
||||||
|
}
|
||||||
count := int64(1)
|
count := int64(1)
|
||||||
|
|
||||||
subDir, ok := d.getDir(i)
|
subDir, ok := d.getDir(i)
|
||||||
if ok {
|
if ok {
|
||||||
size = subDir.size
|
size = subDir.size
|
||||||
count = subDir.count
|
count = subDir.count
|
||||||
|
countUnknownSize = subDir.countUnknownSize
|
||||||
delete(d.dirs, path.Base(subDir.path))
|
delete(d.dirs, path.Base(subDir.path))
|
||||||
}
|
}
|
||||||
|
|
||||||
d.size -= size
|
d.size -= size
|
||||||
d.count -= count
|
d.count -= count
|
||||||
|
d.countUnknownSize -= countUnknownSize
|
||||||
d.entries = append(d.entries[:i], d.entries[i+1:]...)
|
d.entries = append(d.entries[:i], d.entries[i+1:]...)
|
||||||
|
|
||||||
dir := d
|
dir := d
|
||||||
@ -111,6 +126,7 @@ func (d *Dir) remove(i int) {
|
|||||||
parent.dirs[path.Base(dir.path)] = dir
|
parent.dirs[path.Base(dir.path)] = dir
|
||||||
parent.size -= size
|
parent.size -= size
|
||||||
parent.count -= count
|
parent.count -= count
|
||||||
|
parent.countUnknownSize -= countUnknownSize
|
||||||
dir = parent
|
dir = parent
|
||||||
parent.mu.Unlock()
|
parent.mu.Unlock()
|
||||||
}
|
}
|
||||||
@ -151,19 +167,19 @@ func (d *Dir) Attr() (size int64, count int64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AttrI returns the size, count and flags for the i-th directory entry
|
// AttrI returns the size, count and flags for the i-th directory entry
|
||||||
func (d *Dir) AttrI(i int) (size int64, count int64, isDir bool, readable bool, entriesHaveErrors bool, err error) {
|
func (d *Dir) AttrI(i int) (size int64, count int64, countUnknownSize int64, isDir bool, readable bool, entriesHaveErrors bool, err error) {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
subDir, isDir := d.getDir(i)
|
subDir, isDir := d.getDir(i)
|
||||||
|
|
||||||
if !isDir {
|
if !isDir {
|
||||||
return d.entries[i].Size(), 0, false, true, d.entriesHaveErrors, d.readError
|
return d.entries[i].Size(), 0, 0, false, true, d.entriesHaveErrors, d.readError
|
||||||
}
|
}
|
||||||
if subDir == nil {
|
if subDir == nil {
|
||||||
return 0, 0, true, false, false, nil
|
return 0, 0, 0, true, false, false, nil
|
||||||
}
|
}
|
||||||
size, count = subDir.Attr()
|
size, count = subDir.Attr()
|
||||||
return size, count, true, true, subDir.entriesHaveErrors, subDir.readError
|
return size, count, subDir.countUnknownSize, true, true, subDir.entriesHaveErrors, subDir.readError
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan the Fs passed in, returning a root directory channel and an
|
// Scan the Fs passed in, returning a root directory channel and an
|
||||||
|
Loading…
Reference in New Issue
Block a user