diff --git a/cmd/age/age.go b/cmd/age/age.go index b28d8a4..cdca460 100644 --- a/cmd/age/age.go +++ b/cmd/age/age.go @@ -263,8 +263,16 @@ func main() { } } if name := outFlag; name != "" && name != "-" { + outFI, outErr := os.Stat(name) for _, f := range inUseFiles { - if f == absPath(name) { + same := f == absPath(name) + if !same && outErr == nil { + if fi, err := os.Stat(f); err == nil { + // Catch symlinks and hard links. + same = os.SameFile(fi, outFI) + } + } + if same { errorf("input and output file are the same: %q", name) } } diff --git a/cmd/age/testdata/output_file_alias.txt b/cmd/age/testdata/output_file_alias.txt new file mode 100644 index 0000000..9f19542 --- /dev/null +++ b/cmd/age/testdata/output_file_alias.txt @@ -0,0 +1,61 @@ +[!symlink] skip # no symlink support + +age -r age1xmwwc06ly3ee5rytxm9mflaz2u56jjj36s0mypdrwsvlul66mv4q47ryef -o test.age input + +# The output is a symlink to the input. +cp input inputcopy +symlink inputlink -> inputcopy +! age -r age1xmwwc06ly3ee5rytxm9mflaz2u56jjj36s0mypdrwsvlul66mv4q47ryef -o inputlink inputcopy +stderr 'input and output file are the same' +cmp inputcopy input + +# The input is a symlink to the output. +! age -r age1xmwwc06ly3ee5rytxm9mflaz2u56jjj36s0mypdrwsvlul66mv4q47ryef -o inputcopy inputlink +stderr 'input and output file are the same' +cmp inputcopy input + +# The output goes through a symlinked directory. +mkdir dir +cp input dir/inputcopy +symlink dirlink -> dir +! age -r age1xmwwc06ly3ee5rytxm9mflaz2u56jjj36s0mypdrwsvlul66mv4q47ryef -o dirlink/inputcopy dir/inputcopy +stderr 'input and output file are the same' +cmp dir/inputcopy input + +# The output is a symlink to the identity file. +cp key.txt keycopy +symlink keylink -> keycopy +! age -d -i keycopy -o keylink test.age +stderr 'input and output file are the same' +cmp keycopy key.txt + +# A distinct existing file is still a valid output. +cp input other +age -r age1xmwwc06ly3ee5rytxm9mflaz2u56jjj36s0mypdrwsvlul66mv4q47ryef -o other inputcopy +! cmp other input +cmp inputcopy input + +# A dangling symlink is still a valid output. +symlink new -> notexist +age -d -i key.txt -o new test.age +cmp notexist input + +# testscript has no hard link command, so the rest needs an external ln. +[!exec:ln] stop + +exec ln inputcopy inputhard +! age -r age1xmwwc06ly3ee5rytxm9mflaz2u56jjj36s0mypdrwsvlul66mv4q47ryef -o inputhard inputcopy +stderr 'input and output file are the same' +cmp inputcopy input + +exec ln keycopy keyhard +! age -d -i keycopy -o keyhard test.age +stderr 'input and output file are the same' +cmp keycopy key.txt + +-- input -- +age +-- key.txt -- +# created: 2021-02-02T13:09:43+01:00 +# public key: age1xmwwc06ly3ee5rytxm9mflaz2u56jjj36s0mypdrwsvlul66mv4q47ryef +AGE-SECRET-KEY-1EGTZVFFV20835NWYV6270LXYVK2VKNX2MMDKWYKLMGR48UAWX40Q2P2LM0