From 89dcb0c3b56de5e09c5693e65650e1e9a8e64d42 Mon Sep 17 00:00:00 2001 From: tw93 Date: Fri, 30 Jan 2026 15:06:30 +0800 Subject: [PATCH] fix: Use `du -P` for accurate size calculation and add timeouts to channel sends to prevent blocking. --- cmd/analyze/scanner.go | 37 ++++++++++++++++++++++++++++++------- lib/clean/apps.sh | 6 +++--- lib/clean/brew.sh | 2 +- lib/clean/project.sh | 2 +- lib/clean/user.sh | 2 +- lib/core/file_ops.sh | 4 ++-- 6 files changed, 38 insertions(+), 15 deletions(-) diff --git a/cmd/analyze/scanner.go b/cmd/analyze/scanner.go index 539fdb0..0d2bb6c 100644 --- a/cmd/analyze/scanner.go +++ b/cmd/analyze/scanner.go @@ -119,12 +119,16 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in size := getActualFileSize(fullPath, info) atomic.AddInt64(&total, size) - entryChan <- dirEntry{ + select { + case entryChan <- dirEntry{ Name: child.Name() + " →", Path: fullPath, Size: size, IsDir: isDir, LastAccess: getLastAccessTimeFromInfo(info), + }: + case <-time.After(100 * time.Millisecond): + // Skip if channel is blocked } continue } @@ -158,12 +162,15 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in atomic.AddInt64(&total, size) atomic.AddInt64(dirsScanned, 1) - entryChan <- dirEntry{ + select { + case entryChan <- dirEntry{ Name: name, Path: path, Size: size, IsDir: true, LastAccess: time.Time{}, + }: + case <-time.After(100 * time.Millisecond): } }(child.Name(), fullPath) continue @@ -188,12 +195,15 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in atomic.AddInt64(&total, size) atomic.AddInt64(dirsScanned, 1) - entryChan <- dirEntry{ + select { + case entryChan <- dirEntry{ Name: name, Path: path, Size: size, IsDir: true, LastAccess: time.Time{}, + }: + case <-time.After(100 * time.Millisecond): } }(child.Name(), fullPath) continue @@ -209,12 +219,15 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in atomic.AddInt64(&total, size) atomic.AddInt64(dirsScanned, 1) - entryChan <- dirEntry{ + select { + case entryChan <- dirEntry{ Name: name, Path: path, Size: size, IsDir: true, LastAccess: time.Time{}, + }: + case <-time.After(100 * time.Millisecond): } }(child.Name(), fullPath) continue @@ -230,18 +243,25 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in atomic.AddInt64(filesScanned, 1) atomic.AddInt64(bytesScanned, size) - entryChan <- dirEntry{ + select { + case entryChan <- dirEntry{ Name: child.Name(), Path: fullPath, Size: size, IsDir: false, LastAccess: getLastAccessTimeFromInfo(info), + }: + case <-time.After(100 * time.Millisecond): } + // Track large files only. if !shouldSkipFileForLargeTracking(fullPath) { minSize := atomic.LoadInt64(&largeFileMinSize) if size >= minSize { - largeFileChan <- fileEntry{Name: child.Name(), Path: fullPath, Size: size} + select { + case largeFileChan <- fileEntry{Name: child.Name(), Path: fullPath, Size: size}: + case <-time.After(100 * time.Millisecond): + } } } } @@ -516,7 +536,10 @@ func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, lar if !shouldSkipFileForLargeTracking(fullPath) && largeFileMinSize != nil { minSize := atomic.LoadInt64(largeFileMinSize) if size >= minSize { - largeFileChan <- fileEntry{Name: child.Name(), Path: fullPath, Size: size} + select { + case largeFileChan <- fileEntry{Name: child.Name(), Path: fullPath, Size: size}: + case <-time.After(100 * time.Millisecond): + } } } diff --git a/lib/clean/apps.sh b/lib/clean/apps.sh index 9fffe40..e9f193c 100644 --- a/lib/clean/apps.sh +++ b/lib/clean/apps.sh @@ -413,7 +413,7 @@ clean_orphaned_system_services() { fi orphaned_files+=("$plist") local size_kb - size_kb=$(sudo du -sk "$plist" 2> /dev/null | awk '{print $1}' || echo "0") + size_kb=$(sudo du -skP "$plist" 2> /dev/null | awk '{print $1}' || echo "0") ((total_orphaned_kb += size_kb)) ((orphaned_count++)) break @@ -444,7 +444,7 @@ clean_orphaned_system_services() { fi orphaned_files+=("$plist") local size_kb - size_kb=$(sudo du -sk "$plist" 2> /dev/null | awk '{print $1}' || echo "0") + size_kb=$(sudo du -skP "$plist" 2> /dev/null | awk '{print $1}' || echo "0") ((total_orphaned_kb += size_kb)) ((orphaned_count++)) break @@ -474,7 +474,7 @@ clean_orphaned_system_services() { fi orphaned_files+=("$helper") local size_kb - size_kb=$(sudo du -sk "$helper" 2> /dev/null | awk '{print $1}' || echo "0") + size_kb=$(sudo du -skP "$helper" 2> /dev/null | awk '{print $1}' || echo "0") ((total_orphaned_kb += size_kb)) ((orphaned_count++)) break diff --git a/lib/clean/brew.sh b/lib/clean/brew.sh index 6ccf2d6..89f930c 100644 --- a/lib/clean/brew.sh +++ b/lib/clean/brew.sh @@ -29,7 +29,7 @@ clean_homebrew() { local skip_cleanup=false local brew_cache_size=0 if [[ -d ~/Library/Caches/Homebrew ]]; then - brew_cache_size=$(run_with_timeout 3 du -sk ~/Library/Caches/Homebrew 2> /dev/null | awk '{print $1}') + brew_cache_size=$(run_with_timeout 3 du -skP ~/Library/Caches/Homebrew 2> /dev/null | awk '{print $1}') local du_exit=$? if [[ $du_exit -eq 0 && -n "$brew_cache_size" && "$brew_cache_size" -lt 51200 ]]; then skip_cleanup=true diff --git a/lib/clean/project.sh b/lib/clean/project.sh index e1ffa25..0774324 100644 --- a/lib/clean/project.sh +++ b/lib/clean/project.sh @@ -489,7 +489,7 @@ is_recently_modified() { get_dir_size_kb() { local path="$1" if [[ -d "$path" ]]; then - du -sk "$path" 2> /dev/null | awk '{print $1}' || echo "0" + du -skP "$path" 2> /dev/null | awk '{print $1}' || echo "0" else echo "0" fi diff --git a/lib/clean/user.sh b/lib/clean/user.sh index a67658f..46d9870 100644 --- a/lib/clean/user.sh +++ b/lib/clean/user.sh @@ -626,7 +626,7 @@ check_ios_device_backups() { if [[ -d "$backup_dir" ]]; then local backup_kb=$(get_path_size_kb "$backup_dir") if [[ -n "${backup_kb:-}" && "$backup_kb" -gt 102400 ]]; then - local backup_human=$(command du -sh "$backup_dir" 2> /dev/null | awk '{print $1}') + local backup_human=$(command du -shP "$backup_dir" 2> /dev/null | awk '{print $1}') if [[ -n "$backup_human" ]]; then note_activity echo -e " ${YELLOW}${ICON_WARNING}${NC} iOS backups: ${GREEN}${backup_human}${NC}${GRAY}, Path: $backup_dir${NC}" diff --git a/lib/core/file_ops.sh b/lib/core/file_ops.sh index 126fcf0..920c45b 100644 --- a/lib/core/file_ops.sh +++ b/lib/core/file_ops.sh @@ -267,7 +267,7 @@ safe_sudo_remove() { if sudo test -e "$path" 2> /dev/null; then local size_kb - size_kb=$(sudo du -sk "$path" 2> /dev/null | awk '{print $1}' || echo "0") + size_kb=$(sudo du -skP "$path" 2> /dev/null | awk '{print $1}' || echo "0") if [[ "$size_kb" -gt 0 ]]; then file_size=$(bytes_to_human "$((size_kb * 1024))") fi @@ -297,7 +297,7 @@ safe_sudo_remove() { local size_human="" if oplog_enabled; then if sudo test -e "$path" 2> /dev/null; then - size_kb=$(sudo du -sk "$path" 2> /dev/null | awk '{print $1}' || echo "0") + size_kb=$(sudo du -skP "$path" 2> /dev/null | awk '{print $1}' || echo "0") if [[ "$size_kb" =~ ^[0-9]+$ ]] && [[ "$size_kb" -gt 0 ]]; then size_human=$(bytes_to_human "$((size_kb * 1024))" 2> /dev/null || echo "${size_kb}KB") fi