Reject special files before preparing inputs
This commit is contained in:
@@ -635,6 +635,13 @@ func requireRegularReadableFile(path string, label string) error {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
return fmt.Errorf("%s path is required", label)
|
||||
}
|
||||
declared, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("inspect %s %q: %w", label, path, err)
|
||||
}
|
||||
if declared.Mode()&os.ModeSymlink != 0 || !declared.Mode().IsRegular() {
|
||||
return fmt.Errorf("%s %q is not a regular file without symlinks", label, path)
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open %s %q: %w", label, path, err)
|
||||
@@ -644,8 +651,13 @@ func requireRegularReadableFile(path string, label string) error {
|
||||
if statErr != nil {
|
||||
return fmt.Errorf("stat %s %q: %w", label, path, statErr)
|
||||
}
|
||||
if !info.Mode().IsRegular() {
|
||||
return fmt.Errorf("%s %q is not a regular file", label, path)
|
||||
current, currentErr := os.Lstat(path)
|
||||
if currentErr != nil {
|
||||
return fmt.Errorf("reinspect %s %q: %w", label, path, currentErr)
|
||||
}
|
||||
if !info.Mode().IsRegular() || current.Mode()&os.ModeSymlink != 0 || !current.Mode().IsRegular() ||
|
||||
!os.SameFile(info, declared) || !os.SameFile(info, current) {
|
||||
return fmt.Errorf("%s %q changed while being opened", label, path)
|
||||
}
|
||||
if closeErr != nil {
|
||||
return fmt.Errorf("close %s %q: %w", label, path, closeErr)
|
||||
|
||||
45
internal/stage/prepare_fifo_test.go
Normal file
45
internal/stage/prepare_fifo_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
//go:build unix
|
||||
|
||||
package stage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func TestPrepareStageRejectsSpellCatalogFIFOWithoutBlocking(t *testing.T) {
|
||||
env, m := setupPrepareEnv(t)
|
||||
root := filepath.Dir(env.Config.SessionPath)
|
||||
writeFile(t, filepath.Join(root, "audio", "a.flac"), "audio")
|
||||
env.Config.Session.Inputs.AudioFiles = []string{"./audio/a.flac"}
|
||||
|
||||
sourcePath := filepath.Join(root, "spells.fifo")
|
||||
if err := unix.Mkfifo(sourcePath, 0o644); err != nil {
|
||||
t.Fatalf("Mkfifo() error = %v", err)
|
||||
}
|
||||
env.Config.StableInputs.SpellCatalogFile = config.ResolvedInputFile{
|
||||
Path: "./spells.fifo",
|
||||
ConfigPath: env.Config.CampaignPath,
|
||||
Source: "campaign_config",
|
||||
}
|
||||
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := (prepareStage{}).Run(context.Background(), env, m)
|
||||
done <- err
|
||||
}()
|
||||
select {
|
||||
case err := <-done:
|
||||
if err == nil || !strings.Contains(err.Error(), "not a regular file") {
|
||||
t.Fatalf("prepare.Run() error = %v, want regular-file rejection", err)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("prepare.Run() blocked while inspecting a FIFO spell catalog")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user