package main
import (
+ "bytes"
+ "crypto/rand"
+ "flag"
"fmt"
+ "math/big"
"os"
"path/filepath"
- "math/rand"
"time"
)
func main() {
- root := "."
- if len(os.Args) > 1 {
- root = os.Args[1]
- }
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stdout, "pickrand.go: picks a random file.\n")
+ fmt.Fprintf(os.Stdout, "\n")
+ flag.PrintDefaults()
+ }
+ prevDays := flag.Int("n", 0, "The number of days back to look.")
+ flag.Parse()
+ var maxDuration time.Duration
+ if (*prevDays != 0) {
+ maxDuration = time.Duration(int64(*prevDays) * (24 * 60 * 60 * 1e9))
+ }
+
+ root := flag.Arg(0)
+ if (root == "") {
+ root = "."
+ }
files := make([]string, 0, 32)
err := filepath.Walk(root, func(p string, f os.FileInfo, err error) error {
if err != nil {
return err
}
+ if maxDuration != 0 {
+ var duration = time.Now().Sub(f.ModTime())
+ if duration > maxDuration {
+ return nil
+ }
+ }
if !f.IsDir() {
files = append(files, p)
}
fmt.Fprintf(os.Stderr, "** Error: %s\n", err.Error())
os.Exit(1)
}
- rand.Seed(time.Now().UTC().UnixNano())
- i := rand.Int31n(int32(len(files)))
- fmt.Printf("%s\n", root + "/" + files[i])
+ if len(files) == 0 {
+ fmt.Fprintf(os.Stderr, "No matching files found.\n")
+ os.Exit(1)
+ }
+ var b [16]byte
+ _, err = rand.Read(b[:])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to access cryptographic randomness. " +
+ "Error: %s\n\n", err.Error())
+ os.Exit(1)
+ }
+ i, err := rand.Int(bytes.NewReader(b[:]), big.NewInt(int64(len(files))))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get a random int. Error: %s\n", err.Error())
+ os.Exit(1)
+ }
+ j := int(i.Uint64())
+
+ fmt.Printf("%s\n", files[j])
}