openFile gives "file is locked" error on Linux when creating a non-existing file

Harendra Kumar harendra.kumar at gmail.com
Tue Oct 8 05:53:14 UTC 2024


Hi Viktor,

Thanks for looking into this.

This cannot be a TOCTOU bug as the code to check the existence of the
file is only introduced for debugging this issue, to report in case
the file exists for some reason.  Our understanding is that this file
cannot exist in the first place. We have never seen the "File exists"
message being printed, I will make that an error to make sure. The
tests create a temporary file using a random directory name in the
system temp directory, the directory is destroyed at the end of the
test. Also, tests do not run in parallel, we are using hspec to run
tests and it does not run tests in parallel unless we explicitly say
so, so there is no possibility that two tests could be trying to use
the same file. We will double check that. Also, this happens only on
Linux. We will also try the append mode as you suggested.

-harendra

On Mon, 7 Oct 2024 at 16:22, Viktor Dukhovni <ietf-dane at dukhovni.org> wrote:
>
> On Mon, Oct 07, 2024 at 08:25:21AM +0530, Harendra Kumar wrote:
>
> >             exists <- doesFileExist filepath
> >             if not exists
> >             then do
> >                 putStrLn $ "Creating file: " ++ (parent </> file)
> >                 openFile (parent </> file) WriteMode >>= hClose
> >                 putStrLn $ "Created file: " ++ (parent </> file)
> >             else error $ "File exists: " ++ filepath
>
> This is a classic TOCTOU bug.  The file can come into existence between
> the "doesFileExist" test and the attempt to create it.  To create a file
> only if it does not exist, you need to use an "open" variant that
> creates the file if necessary, and leaves it unmodified if it already
> exists.  "AppendMode" works for this, because you're closing the file
> immediately, so the fact that any writes would "append" is not material.
>
> So replace the above with:
>
>     openFile filepath AppendMode >>= hClose
>
> If you need to know whether the file got created by this call, or was
> found to exist already, you need a lower-level API, such as (Unix C):
>
>     /* In some cases 0600 is more appropriate */
>     int fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666);
>
>     if (fd >= 0) {
>         /* Just created */
>         (void) close(fd);
>         ...
>     } else if (errno == EEXIST) {
>         /* Already present */
>         ...
>     } else {
>         /* Permission or other problem */
>         ...
>     }
>
> --
>     Viktor.
> _______________________________________________
> ghc-devs mailing list
> ghc-devs at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


More information about the ghc-devs mailing list