package main
import (
"fmt"
"os"
"path/filepath"
"sync"
)
// go-fakedu - toy approximation of the du (disk usage)
// toy program to learn go concurrency structures
type FileInfo struct {
path string
info os.FileInfo
}
type SafeArraySlice struct {
m sync.Mutex
data []int64
}
func NewSafeIntArraySlice() *SafeArraySlice {
return &SafeArraySlice{
m: sync.Mutex{},
data: make([]int64, 100),
}
}
func (a *SafeArraySlice) AppendIntArraySlice(i int64) {
a.m.Lock()
defer a.m.Unlock()
a.data = append(a.data, i)
}
func enumFiles(dir string) {
fileCh := make(chan FileInfo)
errCh := make(chan error, 1) // Buffered channel to prevent blocking
var wg sync.WaitGroup
file_size_storage := NewSafeIntArraySlice()
// Start a goroutine for walking the file tree
go func() {
// Send any errors to the errCh channel
errCh <- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
fileCh <- FileInfo{path, info}
}
return nil
})
close(fileCh) // Close the fileCh channel after walking is done
}()
// Start a goroutine to process files
go func() {
for path := range fileCh {
wg.Add(1)
go func(fInfo FileInfo) {
defer wg.Done()
// Process file (e.g., read, hash, etc.)
fmt.Println(fInfo.path, fInfo.info.Size())
file_size_storage.AppendIntArraySlice(fInfo.info.Size())
}(path)
}
wg.Wait()
close(errCh) // Close the errCh channel after all processing is done
}()
// Check for errors from filepath.Walk
if err := <-errCh; err != nil {
fmt.Println("Error walking the file tree:", err)
return
}
// Not getting a lock here as by now we know
// that nothing is currently accessing this slice
var size int64 = 0
for _, value := range file_size_storage.data {
size = size + value
}
fmt.Println("Total size: ", float32(size)/(1<<20), "MBs")
}
func main() {
args := os.Args
if len(args) < 2 {
fmt.Println("Must provide path to directory")
os.Exit(1)
}
enumFiles(args[1])
}