Prevent recording output path replacement
This commit is contained in:
committed by
Brandon McGinty
parent
57961ffc9f
commit
65489fd367
+26
-6
@@ -57,18 +57,29 @@ func New(directory string, format string, now time.Time, frameSize int, interval
|
|||||||
if err := os.MkdirAll(directory, 0755); err != nil {
|
if err := os.MkdirAll(directory, 0755); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
path, err := reservePath(directory, now, format)
|
output, path, err := reserveOutput(directory, now, format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
args := ffmpegArgs(format, path)
|
args := ffmpegArgs(format)
|
||||||
cmd := exec.Command("ffmpeg", args...)
|
cmd := exec.Command("ffmpeg", args...)
|
||||||
|
// Pass the reserved file descriptor directly to ffmpeg. The file is never
|
||||||
|
// reopened by pathname, preventing replacement between reservation and use.
|
||||||
|
cmd.ExtraFiles = []*os.File{output}
|
||||||
stdin, err := cmd.StdinPipe()
|
stdin, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
_ = output.Close()
|
||||||
_ = os.Remove(path)
|
_ = os.Remove(path)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
|
_ = output.Close()
|
||||||
|
_ = os.Remove(path)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := output.Close(); err != nil {
|
||||||
|
_ = cmd.Process.Kill()
|
||||||
|
_ = cmd.Wait()
|
||||||
_ = os.Remove(path)
|
_ = os.Remove(path)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -96,13 +107,23 @@ func NormalizeFormat(format string) string {
|
|||||||
return format
|
return format
|
||||||
}
|
}
|
||||||
|
|
||||||
func reservePath(directory string, now time.Time, format string) (string, error) {
|
func reserveOutput(directory string, now time.Time, format string) (*os.File, string, error) {
|
||||||
for {
|
for {
|
||||||
path := UniquePath(directory, now, format)
|
path := UniquePath(directory, now, format)
|
||||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||||
if os.IsExist(err) {
|
if os.IsExist(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
return file, path, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reservePath remains available for callers that only need to reserve a name.
|
||||||
|
func reservePath(directory string, now time.Time, format string) (string, error) {
|
||||||
|
file, path, err := reserveOutput(directory, now, format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -111,7 +132,6 @@ func reservePath(directory string, now time.Time, format string) (string, error)
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return path, nil
|
return path, nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UniquePath(directory string, now time.Time, format string) string {
|
func UniquePath(directory string, now time.Time, format string) string {
|
||||||
@@ -270,7 +290,7 @@ func writePCM(w io.Writer, samples []int16) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ffmpegArgs(format string, path string) []string {
|
func ffmpegArgs(format string) []string {
|
||||||
args := []string{
|
args := []string{
|
||||||
"-loglevel", "error",
|
"-loglevel", "error",
|
||||||
"-f", "s16le",
|
"-f", "s16le",
|
||||||
@@ -281,5 +301,5 @@ func ffmpegArgs(format string, path string) []string {
|
|||||||
if format == FormatOpus {
|
if format == FormatOpus {
|
||||||
args = append(args, "-c:a", "libopus")
|
args = append(args, "-c:a", "libopus")
|
||||||
}
|
}
|
||||||
return append(args, "-y", path)
|
return append(args, "-f", format, "pipe:3")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user