To summarize a long thread I'd like to propose the following process. Its based on GIO but handling fails better.
In pseudocode (sorry if it wraps in your mailer) since I'm not sure if we want to implement it in GIO calls, C library calls or system calls. See below.
To write a Geany buffer contents to Target_File
1 if Target_File does not exist, create it (try to do this in one step to avoid races) 2 if ( no backup required and unsafe save ) or Target_File just created then 3 open Target_File as target_stream for writing or use created stream 4 write contents to target_stream 5 if not unsafe save then 6 sync target_stream 7 close target_stream 8 else 9 open temp_file as target_stream for write in same directory as Target_File 10 try to set GID, UID and permissions on temp_file to the same as Target_File 11 if temp_file GID, UID and permissions are not the same as Target_File then 12 open Target_File for read and copy Target_file to target_stream 13 close Target_file and target_stream and sync target_stream 14 open Target_File for write as target_stream 15 write contents to target_stream 16 sync and close target_stream 17 if target_stream was writing to temp_file then 18 if backup required then 19 rename Target_File to backup_file 20 rename temp_file to Target_File 21 else 22 if backup required then 23 rename temp_file to backup_file 24 else 25 delete temp_file
The normal paths do only one data transfer and steps involving filesystem interaction are: first time, unsafe - 1, 3, 4, 7 first time safe - 1, 3, 4, 6, 7 unsafe, no backup - 3, 4, 7 with backup - 9, 10, 11, 15, 16, 19, 20 safe no backup - 9, 10, 11, 15, 16, 20
Fallback if it has trouble with permissions require three data transfers and are are: with backup - 9, 10, 12, 13, 14, 15, 16, 23 without backup - 9, 10, 12, 13, 14, 15, 16, 25
If anything goes wrong at any step except line 10 then give the system error message and an error message as below and close target_stream if its open and any other stream that is open.
Note that this error handling leaves temp file and backup files. This is deliberate to give the best chance of still having the old and new data exist in case Geany crashes before we fix the problem, after all running out of disk may crash the whole system or cause the system to close applications.
State of the disk if failure at the indicated line and suggested error message (in quotes):
1 no Target_File "Can't create Target_File, save unsuccessful" 3, 9 Target_File with old contents "Can't open Target_File for writing, save unsuccessful" 4, 6, 7 Target_File with unknown contents "Error writing Target_File, save unsuccessful" 12, 13 Target_File with old contents, temp_file with unknown contents "Error writing temporary file temp_file, Target_File not changed" 14 Target_File with old contents and temp_file the same "Can't open Target_File for writing, save unsuccessful, temporary file temp_file is backup" 15, 16 if target_stream is writing to temp_file Target_File with old contents, temp_file with unknown contents "Error writing temporary file temp_file, Target_File not changed, save unsuccessful" else temp_file with old contents Target_File with unknown contents "Error writing Target_File, save unsuccessful, temporary file temp_file is backup" 19 Target_File with old contents, temp_file with new contents "Can't rename Target_File to backup_file, temporary file temp_file contains saved data" 20 no Target_File, temp_file with new contents, backup_file with old contents "Can't rename temporary file temp_file containing saved data to Target_File" 23 Target_file with new contents, temp_file with old contents "Save successful, but can't rename temporary file temp_file to backup_file" 24 Target_file with new contents, temp_file with old contents "Save successful, but can't delete temporary file temp_file"
Feel free to throw bricks.
Implementing in GIO but just using create, stream open, sync, close not replace or set contents etc could benefit from improved performance of GIO VFS but I'm not sure that lines 10 and 11 can be done in GIO. Otherwise implement with POSIX system calls & use fdatasync that "should" sync critical metadata as well.
Cheers Lex