cmd/age: lazily open output file at first write

This avoids leaving behind an empty file when an error occurs before we
write the header (for example, because the passphrase is invalid). Do a
best-effort check before taking user input for whether the file exists
so we don't waste user effort. An error might still happen after user
input if other kind of open errors happen (for example, a permission
issue, or disk full).

Fixes #159
Fixes #57
Closes #169
This commit is contained in:
Filippo Valsorda
2021-01-02 17:58:29 +01:00
committed by Filippo Valsorda
parent 02ee8b969a
commit 97b6569a66

View File

@@ -167,11 +167,11 @@ func main() {
stdinInUse = true
}
if name := outFlag; name != "" && name != "-" {
f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
if err != nil {
logFatalf("Error: failed to open output file %q: %v", name, err)
if _, err := os.Stat(name); err == nil {
logFatalf("Error: output file %q exists", name)
}
defer f.Close()
f, close := lazyOpener(name)
defer close()
out = f
} else if terminal.IsTerminal(int(os.Stdout.Fd())) {
if armorFlag {
@@ -330,6 +330,33 @@ func passphrasePrompt() (string, error) {
return string(pass), nil
}
type WriterFunc func(p []byte) (n int, err error)
func (f WriterFunc) Write(p []byte) (n int, err error) { return f(p) }
// lazyOpener returns a Writer that opens the named file upon the first Write,
// and a function that calls Close on the file if it has been successfully
// opened, and returns nil otherwise.
func lazyOpener(name string) (w io.Writer, close func() error) {
var f *os.File
var openErr error
write := func(p []byte) (n int, err error) {
if f == nil && openErr == nil {
f, openErr = os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
}
if openErr != nil {
return 0, openErr
}
return f.Write(p)
}
return WriterFunc(write), func() error {
if f != nil {
return f.Close()
}
return nil
}
}
func logFatalf(format string, v ...interface{}) {
_log.Printf(format, v...)
_log.Fatalf("[ Did age not do what you expected? Could an error be more useful?" +