package disk import ( "errors" "os" "path/filepath" "strings" "syscall" "github.com/google/uuid" ) type DiskState string const ( DiskAbsent DiskState = "absent" DiskForeign DiskState = "foreign" DiskKnown DiskState = "known" ) type DiskInfo struct { State DiskState `json:"state"` DiskID string `json:"disk_id"` TotalBytes int64 `json:"total_bytes"` FreeBytes int64 `json:"free_bytes"` MountPath string `json:"mount_path"` } const markerDir = ".jukebox" const idFile = "disk.id" func Probe(mountPath string) (DiskInfo, error) { info := DiskInfo{MountPath: mountPath, State: DiskAbsent} entries, err := os.ReadDir(mountPath) if err != nil || len(entries) == 0 { return info, nil } total, free, err := DiskUsage(mountPath) if err != nil { return info, nil } info.TotalBytes = total info.FreeBytes = free idPath := filepath.Join(mountPath, markerDir, idFile) data, err := os.ReadFile(idPath) if errors.Is(err, os.ErrNotExist) { info.State = DiskForeign return info, nil } if err != nil { info.State = DiskForeign return info, nil } info.DiskID = strings.TrimSpace(string(data)) info.State = DiskKnown return info, nil } func InitDisk(mountPath string) (string, error) { dir := filepath.Join(mountPath, markerDir) if err := os.MkdirAll(dir, 0o755); err != nil { return "", err } id := uuid.New().String() idPath := filepath.Join(dir, idFile) if err := os.WriteFile(idPath, []byte(id), 0o644); err != nil { return "", err } return id, nil } func DBPath(mountPath string) string { return filepath.Join(mountPath, markerDir, "history.db") } func DiskUsage(mountPath string) (total, free int64, err error) { var stat syscall.Statfs_t if err = syscall.Statfs(mountPath, &stat); err != nil { return 0, 0, err } total = int64(stat.Blocks) * int64(stat.Bsize) free = int64(stat.Bavail) * int64(stat.Bsize) return total, free, nil }