[FFmpeg-user] How to preserve file time

James Ralston ralston at pobox.com
Mon Aug 19 08:56:54 EEST 2024


On Sat, Aug 17, 2024 at 3:54 PM Ulf Zibis <Ulf.Zibis at cosoco.de> wrote:

> You can spin it however you like. The logic around the ‘-y’ option
> requires an extra additional OS call

It shouldn’t.

> in this case querying the existence of the file, before it is
> overwritten.

The fact that ffmpeg does it this way is a bug (albeit perhaps one of
convenience, since ffmpeg supports more operating systems than just
Unix/Linux).

Specifically: between the call to assert_file_overwrite() in
fftools/ffmpeg_opt.c, and the point where ffmpeg actually opens the
output file for writing, there is a window of time where another
process could create the same file.

Avoiding this race condition requires the cooperation of the operating
system.  For Unix/Linux, this is why the open() and creat() calls have
the O_EXCL flag.  When O_EXCL is specified along with O_CREAT, the
creat()/open() call is guaranteed to either create the file (if it
does not already exist) or fail (return -1) and set errno to EEXIST
(if the file already exists).  The OS implements this guarantee by
ensuring that the check for the existence of the file and the creation
of the file is atomic; no other process on the system is permitted to
interrupt it.

This is why programs sometimes accept an option to permit overwriting
an output file.  For a correctly-written program, under the hood, this
toggles whether the O_EXCL flag is used, which is a guarantee that
only the operating system can provide:

$ rm -f test.txt
$ strace -f /bin/sh -c 'echo test 1>test.txt' 2>&1 | grep '^open.*test'
openat(AT_FDCWD, "test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3

$ rm -f test.txt
$ strace -f /bin/sh -c 'set -C; echo test 1>test.txt' 2>&1 | grep '^open.*test'
openat(AT_FDCWD, "test.txt", O_WRONLY|O_CREAT|O_EXCL, 0666) = 3

This is why it must be implemented by the program, and not left to the
user; e.g.:

    #! /bin/sh
    #
    if ! [ -e output.mp4 ]; then
      # WRONG; race condition exists here, between the existence test
      # and the invocation of ffmpeg
      ffmpeg … -i infile.mp4 output.mp4
    fi

In contrast, since utime()/utimensat() have no O_EXCL flag, there is
no need to have the program implement file time manipulations itself.
Furthermore, depending on the operating system, there can be multiple
timestamps associated with a file, and those timestamps may or may not
have sub-second precision.  So having ffmpeg change the timestamp on
behalf of the user would not necessarily be straightforward.

In summary: ensuring that the output file is created safely, without
potentially overwriting an existing file, is the responsibility of the
program that creates the file, because only that program can leverage
the OS to avoid test-and-create race conditions.  But fiddling with
various timestamps of the output file after it has been written and
closed is the responsibility of the user, not ffmpeg.

(I will gently observe that the ffmpeg developers closed your feature
request ticket #11139 as wontfix (1), with pretty much the same
reasoning.)

1. https://trac.ffmpeg.org/ticket/11139


More information about the ffmpeg-user mailing list