Date:2014-08-18 15:35:56 (9 years 7 months ago)
Author:Maarten ter Huurne
Commit:fc4582a61fce2b51625a2dfac6d97ca9549e948d
Message:Write app settings files atomically

This is safer than the original code, which didn't use a temporary file
and could therefore leave partial files. Also it avoids a full sync(),
which can take a long time if for example a big file transfer is going
on or recently ended.
Files: src/linkapp.cpp (3 diffs)
src/utilities.cpp (2 diffs)
src/utilities.h (1 diff)

Change Details

src/linkapp.cpp
328328}
329329
330330bool LinkApp::save() {
331    if (!edited) return false;
331    if (!edited) return true;
332332
333333    std::ostringstream out;
334334    if (!isOpk()) {
...... 
348348
349349    if (out.tellp() > 0) {
350350        DEBUG("Saving app settings: %s\n", file.c_str());
351        ofstream f(file.c_str());
352        if (f.is_open()) {
353            f << out.str();
354            f.close();
355            sync();
356            return true;
357        } else {
358            ERROR("Error while opening the file '%s' for write.\n", file.c_str());
359            return false;
360        }
351        return writeStringToFile(file, out.str());
361352    } else {
362353        DEBUG("Empty app settings: %s\n", file.c_str());
363354        return unlink(file.c_str()) == 0 || errno == ENOENT;
...... 
560551}
561552
562553unique_ptr<Launcher> LinkApp::prepareLaunch(const string &selectedFile) {
563    save();
554    if (!save()) {
555        ERROR("Error saving app settings to '%s'.\n", file.c_str());
556    }
564557
565558    if (!isOpk()) {
566559        //Set correct working directory
src/utilities.cpp
2828//for browsing the filesystem
2929#include <sys/stat.h>
3030#include <sys/types.h>
31#include <fcntl.h>
3132#include <dirent.h>
3233#include <fstream>
3334#include <iostream>
...... 
8182    }
8283}
8384
85// Use C functions since STL doesn't seem to have any way of applying fsync().
86bool writeStringToFile(string const& filename, string const& data) {
87    // Open temporary file.
88    string tempname = filename + '~';
89    int fd = open(tempname.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC);
90    if (fd < 0) {
91        return false;
92    }
93
94    // Write temporary file.
95    bool ok = write(fd, data.c_str(), data.size()) >= 0;
96    if (ok) {
97        ok = fsync(fd) == 0;
98    }
99
100    // Close temporary file.
101    while (close(fd)) {
102        if (errno != EINTR) {
103            return false;
104        }
105    }
106
107    // Replace actual output file with temporary file.
108    if (ok) {
109        ok = rename(tempname.c_str(), filename.c_str()) == 0;
110    }
111
112    return ok;
113}
114
84115string parentDir(string const& dir) {
85116    // Note that size() is unsigned, so for short strings the '- 2' wraps
86117    // around and as a result the entire string is searched, which is fine.
src/utilities.h
4949/** Returns the contents of the given file as a string. */
5050std::string readFileAsString(std::string const& filename);
5151
52/**
53 * Writes the given string to a file.
54 * The update is done atomically but not durably; if you need durability
55 * when fsync() the parent directory afterwards.
56 * @return True iff the file was written successfully.
57 */
58bool writeStringToFile(std::string const& filename, std::string const& data);
59
5260std::string strreplace(std::string orig, const std::string &search, const std::string &replace);
5361std::string cmdclean(std::string cmdline);
5462

Archive Download the corresponding diff file



interactive