[Geany-devel] Changed file saving implementation for systems with GIO
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.
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
9 open temp_file as target_stream for write in same directory as
10 try to set GID, UID and permissions on temp_file to the same as
11 if temp_file GID, UID and permissions are not the same as
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
22 if backup required then
23 rename temp_file to backup_file
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
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"
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
"Can't rename temporary file temp_file containing saved data
23 Target_file with new contents, temp_file with old contents
"Save successful, but can't rename temporary file temp_file to
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.
More information about the Devel