This patch unifies the behavior of utils_write_file() with write_data_to_disk() so all 3 methods of file saving are supported.
From having a look at where this function is used, by Geany it's used only to store configuration files in the .config directory and some auxiliary functions like writing the export file by the exporter plugin. In the geany-plugins project this function is used only for saving configuration files.
Before this patch, by ignoring the default GIO file operation settings, the fwrite() method was used by default for saving configuration files which wasn't very safe and could lead to configuration file loss under some extreme conditions.
The documentation of this function was changed to reflect the situation better than now - the previous comment made the impression that file permissions were always preserved with this method but it wasn't the case and depended on the exact configuration. Technically this is an API change but since this function is used for saving configuration files only in practice, it should not be a problem.
See https://github.com/geany/geany/issues/3946 for more context. You can view, comment on, or merge this pull request online at:
https://github.com/geany/geany/pull/3947
-- Commit Summary --
* Also use GIO when using utils_write_file()
-- File Changes --
M src/utils.c (24)
-- Patch Links --
https://github.com/geany/geany/pull/3947.patch https://github.com/geany/geany/pull/3947.diff
@techee pushed 1 commit.
12fdaaf91ffb69d19077f5d0482174145e393b28 Also use GIO when using utils_write_file()
My concern is that, as I said on https://github.com/geany/geany/issues/3946#issuecomment-2345723499 there is a reasonable chance of the config files and the data files being on different places and need different saving methods. Only #3946 and @techee (during debugging) have seen the config loss (or at least all that reported it). Whereas there are a number of reports of config and data files being different places. So forcing the file save method to be the same may be worse.
As you mentioned in https://github.com/geany/geany/issues/3946, using the GIO method only might be best for config files indeed and I can modify the patch if this is the preferred way. With this patch I just wanted to make sure that `fwrite()` isn't used as the default method for saving config files which IMO is the worst option of them all.
Only https://github.com/geany/geany/issues/3946 and @techee (during debugging)
Over years, this happened to me quite a few times and
Geany, to my recollection is the only application that yields that erratic behaviour
from #3946 resonated with me because Geany really is the only application where I experienced this and it's kind of embarrassing. It's true that I haven't seen it for a long time but I suspect it's because file systems got better rather than fixing something on the Geany side.
Over years, this happened to me quite a few times and
Tsk tsk, didn't report it :wink:
It's true that I haven't seen it for a long time but I suspect it's because file systems got better rather than fixing something on the Geany side.
Its true that Geany improved by saving settings more often, (not sure it it is yet every change but getting close) and it became more reliable so crashes during saving happened less (debugging Geany or plugin changes excepted). And using a better config saving method will improve again, but in the end saving can always be interrupted by internal causes, or external causes.
Geany really is the only application where I experienced this and it's kind of embarrassing.
Similar to my report of #3733 where Vscode survived a system failure with all settings and modified buffers intact and Geany lost all buffer modifications. So I can now understand why users shutdown or logout with the app still open and expect things to come back, it "just happens" with chromium/electron based apps so we get regular issues about it.
Thats why I keep plugging it, it would be a tiny @techee change (<30000 lines ;-) to save buffers and their associated document settings in the config directory, it could even be in save actions plugin.
Anyway back to the PR.
My suggestion is that all keyfiles should be written with `g_replace_contents()` because it works in all cases, that is why it is the default for data file saving. As it is an atomic (rename) save with metadata copy if possible, the window for losing all settings gets very small (but not zero), but it falls back to the truncate and write over if the metadata copy or the rename fails. Effectively it does both the other methods so they are not needed any more[^1].
And as an aside I suspect it will prevent rooters ending up with keyfiles owned by root since `g_replace_contents()` copies old metadata to the new file before renaming, meaning it should end up still being owned by the user. (analysis, subject to testing :-).
[^1]: and its because of the fallback to truncate and overwrite that it has the "unsafe" in the setting that selects it for saving document files, in that case its no more safe than that option. Annoyingly it makes a backup of the file in the truncate case, but it never uses that backup in the case of failure (I just checked the GIO bug is still open). Saving document files still needs the options for the reasons explained in my file saving [thesis](https://wiki.geany.org/config/all_you_never_wanted_to_know_about_file_saving).
Closed #3947.
Thats why I keep plugging it, it would be a tiny @techee change (<30000 lines ;-) to save buffers and their associated document settings in the config directory, it could even be in save actions plugin.
Futile ;-). No more heroic projects for the near future.
My suggestion is that all keyfiles should be written with g_replace_contents() because it works in all cases, that is why it is the default for data file saving.
Agree. I've created https://github.com/geany/geany/pull/3950 and I'm closing this PR in favor of that one.
Saving document files still needs the options for the reasons explained in my file saving [thesis](https://wiki.geany.org/config/all_you_never_wanted_to_know_about_file_saving) but thats not so relevant to keyfiles. [↩](https://github.com/geany/geany/pull/3947#user-content-fnref-1-34e7c30cc17831...)
Nice, I didn't know about that one.
Saving document files still needs the options for the reasons explained in my file saving [thesis](https://wiki.geany.org/config/all_you_never_wanted_to_know_about_file_saving) but thats not so relevant to keyfiles.
By the way, one thing the "thesis" doesn't mention is the use of `fsync()` which I believe is the cause of #3946. Both `g_file_set_contents()` and `g_file_replace_contents()` call it but not the `fwrite()` method (and maybe we should add it to this method as well to be sure). If something goes wrong during shutdown and `sync()` isn't called (which really should happen but things may go wrong), one may lose all the data like in
https://lwn.net/Articles/322823/
(I think this got mitigated in later ext4 versions and isn't as a big problem like in this article)
Yeah, that article is 15 years olde, and SSDs were not common at that point either and they add another layer of caching and erase and write in hardware blocks, not filesystem sectors.
Just to be clear, the thesis was intended to address saving document files, ie `document.c:write_data_to_disk()` which is not used for settings, temporary files, run script files, or any other detritus :-)
It might not hurt to add an `fsync()` to the `write_data_to_disk()` truncate and overwrite method for a local filesystem, but a lot of care needs to be put into what it might do to remote slow networked storage or if it will actually do anything in that case. That should be a separate issue so those things can be considered before adding it, if at all.
IMO #3946 is simply Geany not getting to finish writing its settings between getting a close signal and the OS killing it with extreme prejudice because it hasn't closed yet. Even with SSDs, when shutdown is happening, lots of stuff is being written by all the processes being closed, the OS itself syncing the file systems, etc etc so there is not guarantee that Geany will get its data written to disk because the disk is so busy, and the CPU is so busy with all those processes closing Geany might not even get scheduled, so even if settings saving has `fsync()`, it simply won't have time to do it.
The best solution is this PR to make saving settings atomic if it can and `fsync()`ed in any case. It can still be lost if atomic is not possible in some cases and the truncate and overwrite doesn't finish, but its less likely.
github-comments@lists.geany.org