package files import ( "net/url" "os" "path/filepath" "time" ) const FileDateFormat = "2006-01-02 15:04:05 MST" type DirStat struct { Files int64 FilesSize string FilesSizeUnit string Directories int64 } type DirEntry struct { Name string Link string Datetime time.Time Size string SizeUnit string } // ScanDirectory returns entries of directory which is located by its relative // path within a base directory. // // rel path should start/end with a / symbol. func ScanDirectory(base, rel string) (entries []DirEntry, stats DirStat, err error) { abs := base + rel dir, err := os.ReadDir(abs) if err != nil { return } var dirEntries []DirEntry = make([]DirEntry, 0) var fileEntries []DirEntry = make([]DirEntry, 0) var totalFilesSize int64 = 0 for _, ent := range dir { entry, _ := ent.Info() var isDirLink bool if entry.Mode().Type()&os.ModeSymlink != 0 { if slp, err := filepath.EvalSymlinks(filepath.Join(abs, entry.Name())); err == nil { lStat, _ := os.Lstat(slp) isDirLink = lStat.IsDir() } } if entry.IsDir() || isDirLink { dirEntries = append(dirEntries, DirEntry{ Name: entry.Name(), Link: url.PathEscape(entry.Name()) + "/", Datetime: entry.ModTime(), Size: "DIR", }) stats.Directories++ } else { sz, ui := convertFileSize(entry.Size()) fileEntries = append(fileEntries, DirEntry{ Name: entry.Name(), Link: "/file" + rel + url.PathEscape(entry.Name()), Datetime: entry.ModTime(), Size: sz, SizeUnit: ui, }) totalFilesSize += entry.Size() stats.Files++ } } stats.FilesSize, stats.FilesSizeUnit = convertFileSize(totalFilesSize) entries = append(entries, dirEntries...) entries = append(entries, fileEntries...) return }