Skip to content

Commit

Permalink
download_store: ensure that session files land on the disk
Browse files Browse the repository at this point in the history
Currently, save() stores session to the disk by:

- serialize to bencode and write to files with .new ext
- validate the new files
- rename new files, removing .new ext

Technically, this is done to make sure that session files on the
disk are always valid/uncorrupted. However, if catastrophic events
happen during save(), such as system crash / power outage, the actual
content of session files may not have been synced to the disk.

To make things much worse, rename() is atomic. That means we discarded
the previous session files without actually landing the new session files
on the disk, and we got a bunch of empty session files to deal with.

This commit adds a fsync step to ensure that session files land on the
disk.
  • Loading branch information
jesec committed Jul 3, 2023
1 parent 88fd968 commit f9a875b
Showing 1 changed file with 11 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/core/download_store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// DownloadStore handles the saving and listing of session torrents.

#include <cstdio>
#include <fcntl.h>
#include <fstream>
#include <unistd.h>

Expand Down Expand Up @@ -84,6 +85,7 @@ DownloadStore::write_bencode(const std::string& filename,
uint32_t skip_mask) {
torrent::Object tmp;
std::fstream output(filename.c_str(), std::ios::out | std::ios::trunc);
int fd = -1;

if (!output.is_open())
goto download_store_save_error;
Expand All @@ -103,6 +105,15 @@ DownloadStore::write_bencode(const std::string& filename,
goto download_store_save_error;

output.close();

// Ensure that the new file is actually written to the disk
fd = ::open(filename.c_str(), O_WRONLY);
if (fd < 0)
goto download_store_save_error;

fsync(fd);
::close(fd);

return true;

download_store_save_error:
Expand Down

0 comments on commit f9a875b

Please sign in to comment.