When writing new C++ code, I mostly try to use
std::filesystem
rather than
the C POSIX functions directly. I prefer std::filestem
not necessarily for
portability reasons, but because code using std::filesystem
tends to be easier
to be shorter and easier to read than code that uses the C POSIX API directly.
Still, there are a lot of tricky Linux or POSIX-specific things you can do with
the C APIs, so in situations where I'm writing tricky or non-portable code I
don't mind the fact that I have to use the C APIs. As an extremely simple
example, POSIX provides both stat(2)
and
fstat(2)
. The difference
between the two is that with stat(2)
you specify the file path as a const char*
string, whereas fstat(2)
takes an open file descriptor and reads the
status of that fd. The main advantage of fstat(2)
that using it correctly can
prevent TOCTTOU
races (it can also be ever so slightly more efficient in the case where you
need to open a handle to the file anyway, but TOCTTOU is its raison d'ĂȘtre).
While it's a little annoying that std::filesystem
doesn't provide an analog to
fstat(2)
(e.g. perhaps a function that takes a std::fstream
as a parameter),
I consider this a somewhat fringe use case, and it might be difficult to
implement in the STL for portability reasons anyway, so I'm willing to give it a
pass.
However, there are some other deficiencies in std::filsystem
that there are
really no excuses for. One such example is getting the last-modified time (or
"mtime") of a file. Normally on Unix-like operating systems you would do this by
calling one of the stat
family of functions, and then reading the st_mtim
field from the stat struct. This struct also contains a lot of other useful
information, such as the file permissions, the file owner, etc. This means with
the most basic POSIX file status function, stat(2)
, you can make a single
system call and then read all of these attributes. Doing this with a single
stat(2)
call is important not just for efficiency reasons, but also ensures
that you have an atomic view of the file status.
For some baffling reason C++17 provides a stat(2)
analog called
std::filesystem::file_status()
which lets you access various file status information including the file
type and
permissions,
but the returned file status object doesn't let you access other basic fields
such as the last-modified time. There's another function named
std::filesystem::last_write_time()
that will give the last-modified time, but this function only accepts a
std::filesystem::path
, meaning that using this method will re-stat the file.
This means that if you want to use std::filesystem
instead of the POSIX APIs
directly you'll likely end up calling stat(2)
multiple times on the same file
path. Besides the TOCTTOU problems, this is just inefficient.
This is just one of many complaints I have with std::filesystem
, and is a
simple example of why std::filesystem
is currently only good for toy use
cases. The good news is that these are problems that can be addressed in future
C++ standards revisions, so hopefully this is just a temporary problem we have
to live with.