|
Boost : |
Subject: Re: [boost] [filesystems]
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2019-03-14 20:12:24
> I have this innocent piece of code:
>
> namespace fs = boost::filesystem;
> auto path = getFilename(); // returns a string
> fs::create_directories(fs::path(path).parent_path());
> std::ofstream ofs(path + "~");
> ofs << info;
> ofs.close();
> fs::rename(path + "~", path);
>
> which causes the exception:
>
> boost::filesystem::rename: No such file or directory: "../9f/061b4f7a5e529c964659226eedd4e5~", "../9f/061b4f7a5e529c964659226eedd4e5"
>
> However, I have no idea how that could happen. I use the rename, so that a reading process never sees an empty file, but only no file or filed with info. Is there any race involved between ofs.close() and fs:rename()? The code was executed on a distributed network filesystem (lustre).
>
> Any ideas anyone?
Your code is racy. POSIX offers no guarantee that a file entry continues
to exist after an open(). At any moment the file entry may be renamed,
deleted, or otherwise disappear or mutate.
Your filing system is therefore entirely within specification if the
file entry is not there after an open() returns. You should adjust your
code to be correct.
(To write correct code, you may wish to look into renameat(). You would
create an anonymous inode using O_TMPFILE, write its contents, open a
handle to the destination directory using O_PATH, and renameat() your
temporary inode over the destination file entry, atomically replacing
it. If this sounds involved, the P1031 Low level file i/o reference
implementation library LLFIO lets you do this portably using a somewhat
less low level interface)
Niall
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk