package disk import ( "errors" "os" "path/filepath" "strings" "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"` Profile *DiskProfile `json:"profile,omitempty"` } const MarkerDir = ".jukebox" const idFile = "disk.id" func Probe(mountPath string) (DiskInfo, error) { info := DiskInfo{MountPath: mountPath, State: DiskAbsent} if _, err := os.ReadDir(mountPath); err != nil { 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 if p, err := LoadProfile(mountPath); err == nil { info.Profile = p } return info, nil } func CheckWritable(path string) error { f, err := os.CreateTemp(path, ".jukebox-writecheck-*") if err != nil { return err } name := f.Name() if err := f.Close(); err != nil { _ = os.Remove(name) return err } return os.Remove(name) } 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 } _ = SaveProfile(mountPath, DefaultProfile()) return id, nil } func DBPath(mountPath string) string { return filepath.Join(mountPath, MarkerDir, "history.db") }