You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DateKeys/cmd/datekeys/collect.go

100 lines
2.8 KiB

package main
import (
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"g.activething.com/go/DateKeys/capsule"
)
// collect returns the files named by the -in arguments: a file by its name,
// and a folder by its name followed by the path of each file below it, as a
// browser names the files of a folder (webkitRelativePath). Folders are
// walked with Lstat, following no link, and only regular files are
// accepted. The files that systems create on their own are left out of
// folders, and listed in skipped (spec §62.1 rule 15). With mtime, each
// file keeps its modification time (rule 16).
func collect(ins []string, mtime bool) (sources []capsule.Source, skipped []string, err error) {
for _, in := range ins {
abs, err := filepath.Abs(in)
if err != nil {
return nil, nil, err
}
base := filepath.Base(abs)
info, err := os.Lstat(abs)
if err != nil {
return nil, nil, err
}
switch {
case info.Mode().IsRegular():
sources = append(sources, fileSource(abs, base, info, mtime))
continue
case !info.IsDir():
return nil, nil, notRegular(in, info)
}
err = filepath.WalkDir(abs, func(p string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if p == abs {
return nil
}
if systemFile(d.Name(), d.IsDir()) {
skipped = append(skipped, p)
if d.IsDir() {
return filepath.SkipDir
}
return nil
}
if d.IsDir() {
return nil
}
info, err := d.Info()
if err != nil {
return err
}
if !info.Mode().IsRegular() {
return notRegular(p, info)
}
rel, err := filepath.Rel(abs, p)
if err != nil {
return err
}
sources = append(sources, fileSource(p, base+"/"+filepath.ToSlash(rel), info, mtime))
return nil
})
if err != nil {
return nil, nil, err
}
}
return sources, skipped, nil
}
func notRegular(path string, info fs.FileInfo) error {
return fmt.Errorf("%s is not a regular file (%s): only regular files are encrypted, and links are not followed", path, info.Mode().Type())
}
// fileSource is the Source of the local file at path, stored as name.
func fileSource(path, name string, info fs.FileInfo, mtime bool) capsule.Source {
s := capsule.Source{Path: name, Size: info.Size(), Open: func() (io.ReadCloser, error) { return os.Open(path) }}
if mtime {
s.ModTime = info.ModTime()
}
return s
}
// systemFile reports the files and folders that systems create on their
// own, which the official SDK leaves out by default: .DS_Store, Thumbs.db,
// desktop.ini, ._* and __MACOSX (spec §62.1 rule 15).
func systemFile(name string, dir bool) bool {
if dir {
return name == "__MACOSX"
}
return strings.EqualFold(name, ".DS_Store") || strings.EqualFold(name, "Thumbs.db") ||
strings.EqualFold(name, "desktop.ini") || strings.HasPrefix(name, "._")
}

Powered by TurnKey Linux.