[Geany-devel] Safe file saving - permissions issue

Lex Trotman elextr at xxxxx
Sat Apr 3 01:06:40 UTC 2010


2010/4/2 Алексей Антипов <1a_antipov at mail.ru>

> As goes from GLib sources, the final replace strategy is backend-dependent.
> For local files: (from GLib sources, gio/glocalfileoutputstream.c,
> handle_overwrite_open):
>  /* We use two backup strategies.
>   * The first one (which is faster) consist in saving to a
>   * tmp file then rename the original file to the backup and the
>   * tmp file to the original name. This is fast but doesn't work
>   * when the file is a link (hard or symbolic) or when we can't
>

I don't understand why it fails with a hard link, all files *are* hard links
so that means it would never work, do you understand what they mean?


>   * write to the current dir or can't set the permissions on the
>   * new file.
>   * The second strategy consist simply in copying the old file
>   * to a backup file and rewrite the contents of the file.
>   */
>

Yup, thats as I understand the process


> For smb:// files (from GVFS sources, daemon/gvfsbackendsmb.c, do_replace)
>  /* Backup strategy:
>       *
>       * By default we:
>       *  1) save to a tmp file (that doesn't exist already)
>       *  2) rename orig file to backup file
>       *     (or delete it if no backup)
>       *  3) rename tmp file to orig file
>       *
>       * However, this can fail if we can't write to the directory.
>       * In that case we just truncate the file, after having
>       * copied directly to the backup filename.
>       */
>

I don't like the bit about truncating the file, how did it copy the backup
if it can't write?



> SFTP backend strategy is much more complex
> So, let's sum it all up
>
> 1. There are (at least) 3 different ways to save a file:
>  - Use POSIX fopen()/fwrite() API
>  - Use g_file_set_contents()
>  - Use GIO API
>
> 2. On remote filesystems at least first (and probably second) API relies on
> GIO (via virtual filesystem calls or direct
> GIO calls in newer GLib versions)


> 3. No API guarantees that data on remote filesystem won't be lost and the
> save would be "atomic", as the implementation
> is in the backend, which can be buggy etc.
>

Yes, so Geany should be careful but not paranoid, some things it just can't
control.


>
> 4. The strategy used by GIO on local filesystem seems satisfactory for
> "safe file saving" needs.
>

Yes, its probably the best.


>
> 5. All we can do is minimize the probability of data loss due to our code
> issues. We cannot directly affect troubles in
> GLib and GVFS (IMHO they are messy, but one should contact these projects'
> teams to improve that)
>

Agree


>
> 6. The less (buggy) code there is between Geany and final data transfers
> (either to disk, or via HTTP/FTP/SMB/SSH/whatever-else), the more reliable
> our project is
>

Agree


>
> 7. That's why the use of direct GIO calls instead of fopen() or
> g_file_set_contents() is attractive. Consider the chains:
> (1) fopen()/fwrite() -> VFS call -> GIO g_file_do_something() -> Backend ->
> Final data transfer
>

I don't understand why the C library calls fopen and fwrite call GIO, for
file systems supported natively on the platform they should directly perform
actions on that file system, for others they would have to go via fuse and
the path you have shown, unless GVFS is taking over the whole file system
and forcing all file system operations via itself :-( very bad if so.
Impacts performance, reliability and maintainability.


> OR
> (2a) g_file_set_contents -> fopen()/fwrite() -> VFS call -> GIO
> g_file_do_something() -> Backend -> Final data transfer
> OR
>

As per note above.


> (2b) g_file_set_contents -> GIO g_file_do_something() -> Backend -> Final
> data transfer
> OR
> (3) GIO g_file_do_something() -> Backend -> Final data transfer
>
> 8. The only alternative for g_file_replace here is to write our own backup
> algorithm implementation, preferably based on direct GIO calls.
>
>
As I said above Geany needs to be careful, not paranoid, so I don't think
adding another layer is sensible.  Geany also needs to be portable so it
needs to handle GIO when available and non-GIO when not and windows with
similar levels of competence.  If there are problems in the backends I would
not expect Geany to compensate for them.

Cheers
Lex



> Fri, 2 Apr 2010 21:35:49 +1100 письмо от Lex Trotman <elextr at gmail.com>:
>
> > On 2 April 2010 03:07, Nick Treleaven <nick.treleaven at btinternet.com>
> wrote:
> >
> > > On Thu, 1 Apr 2010 12:41:13 +0100
> > > Nick Treleaven <nick.treleaven at btinternet.com> wrote:
> > >
> > > > > Btw, the bugs with GVFS didn't appear with GNOME 2.26 (and probably
> > > before), so I think we can safely use fopen() and fprintf()/fwrite()
> there.
> > > Then, your proposal about version separation (use GIO with GLib>=2.16
> and
> > > fopen()/g_file_set_contents() with other) is extremely attractive. Do
> you
> > > know if there is a way to get GLib version at runtime, not at
> compile-time
> > > (so that there is no need to rebuild all the packages for different
> > > versions)?
> > > > >
> > > > > I'm going to start working on it; if this is OK, I'll send a patch
> > > ASAP.
> > > >
> > > > BTW There is another problem that file saving should solve - not
> > > > losing existing file data when there is no space to save the new
> file.
> > > > Does g_file_replace_contents() handle this problem?
> (g_file_set_contents
> > > > () does handle this but as you mention has other problems).
> > >
> > > According to the docs for g_file_replace, which g_file_replace_contents
> > > uses internally, this case may be handled:
> > >
> > > "This will try to replace the file in the safest way possible so that
> > > any errors during the writing will not affect an already existing copy
> > > of the file. For instance, for local files it may write to a temporary
> > > file and then atomically rename over the destination when the stream is
> > > closed."
> > > http://library.gnome.org/devel/gio/unstable/GFile.html#g-file-replace
> > >
> > > Hopefully it still keeps permissions if the rename is done(!)
> > >
> >
> > I would doubt it :-( its creating the new temporary file then renaming
> that
> > to the original name.  This leaves it with the permissions of the
> temporary
> > file ie those of a new file.
> > It might work if it copies the attributes of the old file to the
> temporary
> > first, but thats a backend dependent action since permissions depend on
> the
> > filesystem..
> > But it does leave the old file unharmed on out of space :-)
> >
> > The problem is that remote file systems (most anyway)  do not actually
> have
> > an atomic rename and delete operation.  In fact many actually have race
> > conditions when you try to remove the old file and then rename the
> temporary
> > as a non-atomic pair of operations.  So just because it seems to work for
> > one application doesn't mean it will allways work for it with a different
> > remote file system.  Something like that can be the cause of an empty
> file.
> >
> > Cheers
> > Lex
> >
> >
> > > Regards,
> > > Nick
> > > _______________________________________________
> > > Geany-devel mailing list
> > > Geany-devel at uvena.de
> > > http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel
> > >
> >
> > _______________________________________________
> > Geany-devel mailing list
> > Geany-devel at uvena.de
> > http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel
> >
> >
>
>
> "Барахолка" на Товары@Mail.Ru. Покупай дешево, продавай выгодно.
> http://r.mail.ru/cln4270/torg.mail.ru/used/
>  _______________________________________________
> Geany-devel mailing list
> Geany-devel at uvena.de
> http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.geany.org/pipermail/devel/attachments/20100403/8f04a99d/attachment.html>


More information about the Devel mailing list