Permit sorting of files in automatic directory listings by various factors.

This commit is contained in:
Solderpunk 2020-06-27 18:52:29 +02:00
parent 6da5ec79dd
commit 3f98a9edf1
3 changed files with 45 additions and 15 deletions

View File

@ -92,3 +92,5 @@ The following options can be set in `/etc/molly.conf`:
* `LogPath`: Path to log file (default value `molly.log`). Note that * `LogPath`: Path to log file (default value `molly.log`). Note that
all intermediate directories must exist, Molly Brown won't create all intermediate directories must exist, Molly Brown won't create
them for you. them for you.
* `DirectorySort`: A string specifying how to sort files in automatically generated directory listings. Must be one of "Name", "Size" or "Time" (default value "Name").
* `DirectoryReverse`: Boolean, if true automatically generated directory listings will list files in descending order of whatever `DirectorySort` is set to (default value false).

View File

@ -1,23 +1,26 @@
package main package main
import ( import (
"errors"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
) )
type Config struct { type Config struct {
Port int Port int
Hostname string Hostname string
CertPath string CertPath string
KeyPath string KeyPath string
DocBase string DocBase string
HomeDocBase string HomeDocBase string
GeminiExt string GeminiExt string
DefaultLang string DefaultLang string
LogPath string LogPath string
TempRedirects map[string]string TempRedirects map[string]string
PermRedirects map[string]string PermRedirects map[string]string
CGIPaths []string CGIPaths []string
SCGIPaths map[string]string SCGIPaths map[string]string
DirectorySort string
DirectoryReverse bool
} }
type MollyFile struct { type MollyFile struct {
@ -43,6 +46,7 @@ func getConfig(filename string) (Config, error) {
config.PermRedirects = make(map[string]string) config.PermRedirects = make(map[string]string)
config.CGIPaths = make([]string, 0) config.CGIPaths = make([]string, 0)
config.SCGIPaths = make(map[string]string) config.SCGIPaths = make(map[string]string)
config.DirectorySort = "Name"
// Return defaults if no filename given // Return defaults if no filename given
if filename == "" { if filename == "" {
@ -54,5 +58,13 @@ func getConfig(filename string) (Config, error) {
if err != nil { if err != nil {
return config, err return config, err
} }
// Validate pseudo-enums
switch config.DirectorySort {
case "Name", "Size", "Time":
default:
return config, errors.New("Invalid DirectorySort value.")
}
return config, nil return config, nil
} }

View File

@ -14,6 +14,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"sort"
"strings" "strings"
"time" "time"
) )
@ -154,7 +155,7 @@ func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry)
} else { } else {
conn.Write([]byte("20 text/gemini\r\n")) conn.Write([]byte("20 text/gemini\r\n"))
log.Status = 20 log.Status = 20
conn.Write([]byte(generateDirectoryListing(URL, path))) conn.Write([]byte(generateDirectoryListing(URL, path, config)))
} }
return return
} }
@ -263,7 +264,7 @@ func parseMollyFiles(path string, info os.FileInfo, config *Config) {
} }
func generateDirectoryListing(URL *url.URL, path string) string { func generateDirectoryListing(URL *url.URL, path string, config Config) string {
var listing string var listing string
files, err := ioutil.ReadDir(path) files, err := ioutil.ReadDir(path)
if err != nil { if err != nil {
@ -287,6 +288,21 @@ func generateDirectoryListing(URL *url.URL, path string) string {
up := filepath.Dir(URL.Path) up := filepath.Dir(URL.Path)
listing += fmt.Sprintf("=> %s %s\n", up, "..") listing += fmt.Sprintf("=> %s %s\n", up, "..")
} }
// Sort files
sort.SliceStable(files, func(i, j int) bool {
if config.DirectoryReverse {
i, j = j, i
}
if config.DirectorySort == "Name" {
return files[i].Name() < files[j].Name()
} else if config.DirectorySort == "Size" {
return files[i].Size() < files[j].Size()
} else if config.DirectorySort == "Time" {
return files[i].ModTime().Before(files[j].ModTime())
}
return false // Should not happen
})
// Format lines
for _, file := range files { for _, file := range files {
// Skip dotfiles // Skip dotfiles
if strings.HasPrefix(file.Name(), ".") { if strings.HasPrefix(file.Name(), ".") {