StoneThrow
StoneThrow

Reputation: 6285

C/C++: is there a way to create a nonzero-length file atomically?

I have a thread which watches a directory for file additions (using inotify if it exists, polling otherwise), and notifies a listener upon new files created in the watched directory. The listener has conditional logic based on the size of the created file, which it determines using int stat(const char *pathname, struct stat *statbuf).

In a separate thread, I create a nonzero-length file using std::ofstream; a simplified example of the file creation is:

std::ofstream ofs( "/path/to/file", std::ofstream::out );
ofs << "abc";
ofs.close()

Runtime behavior is that the listener, invoking stat(), sometimes sees the file as 0-length.

This is perfectly reasonable, since the file creation and content-addition are separate actions.

Question: Is there a way to atomically create a nonzero-length file using either C functions or C++03's stl?

Note: For the purpose of this question, I'm not interested in synchronization primitives, like mutexes or semaphores, to synchronize the two threads around the entire process of file-open, add content, close-file.

Upvotes: 3

Views: 188

Answers (2)

eerorika
eerorika

Reputation: 238441

Is there a way to atomically create a nonzero-length file using either C functions or C++03's stl?

Best approach would be to create the file elsewhere on the same filesystem, and then std::rename the file into the target file.

The standard doesn't really give explicit guarantees except for the post-coditions (either the file exists with new name, or the old name). Nothing about observable intermediate states. In practice, you're at the mercy of the file system. But if there is some standard operation that achieves what you want, then this is it. POSIX standard does require rename to be atomic.

Upvotes: 3

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215517

The base C language has no such concepts, and I don't think C++ does either. If you're talking about these type of things, you must be assuming POSIX or some other operating-system-level behavior specification.

Under POSIX, the way to do this kind of operation is to create the file with a temporary name, then rename it only after you finish writing it. You can do that in a different directory if they're both on the same device; if they're on different devices, whether that works is implementation-defined. The most portable way is to do it in the same directory, which means that your inotify (Linux-specific, BTW) listener should ignore files not matching the naming pattern it's looking for or ignore files in a particular temp namespace you choose as your convention.

Upvotes: 9

Related Questions