[Geany-devel] Changed file saving implementation for systems with GIO

Lex Trotman elextr at xxxxx
Sun Nov 7 05:31:24 UTC 2010


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



More information about the Devel mailing list