Neil Williams: Porting a C package from libgnomevfs to GIO and GVfs.
(Note: this is a long post)Package: deb-gview
Use of GnomeVFS: "Individual package files or packages referenced in a changes file can be viewed from local or remote filesystems using GNOME VFS."
Main changes: src/dvarchive.c but also src/main.c.
Port Status: Complete and tested.
Prerequisites
Do not run any code before completing this step
You must ensure that gvfs, gvfs-bin and gvfs-backends are all installed and operational before running any of your modified code. Thereby hangs another tale. The application itself probably needs to depend on both gvfs and gvfs-backends. gvfs-bin provides test binaries like gvfs-info.
You need to ensure that the following command operates correctly:
$ gvfs-info http://www.google.com
display name: /
edit name: /
type: unknown
size: 0
attributes:
standard::display-name: /
standard::edit-name: /
standard::content-type: text/html
id::filesystem: type='http',uri='http://www.google.com',mount_prefix='/'
Note that this is run as the normal user, not under sudo and not as root. - that just complicates things. If you find that this works with sudo but not without, read the bug report against gvfsd.
If you get this output:
$ gvfs-info http://www.google.com
Error getting info: The specified location is not supported
read the bug report, find and kill the borked
gvfsd process and ensure that gvfs-backends is installed before attempting any other gvfs* commands (including via your modified source code).Starting
- Online copy of the GIO docs. online copies of the GVfs docs. I mainly use Anjuta where both sets of the docs are available via libglib2.0-doc >= 2.16.1 and devhelp or via your localhost using dwww.
#include <gio/gio.h>to replace#include <libgnomevfs/gnome-vfs.h>.
(May sound obvious now but examples are not that frequent in the GIO docs as part of libglib2.0-0.)- The GIO docs do give some info on porting variables:
GnomeVFSHandle * vfshandle;becameGFile * ghandle; GInputStream * stream;in deb-gview- Extra variables needed for deb-gview:
GVfs * vfs; GError * result; GFile * gfile; GFileInfo * ginfo;.GErroritself is not new but it can catch you out in the port because so many GIO/GVfs functions can use it and you find yourself usingg_clear_error(&error)a lot or GLib will complain about trying to replace data in a GError.
- Separate path and URI handling - GIO and GVfs have separate filename/path handling for paths on a local filesystem and paths on remote filesystems and the two cannot be mixed. This was a big source of bugs during the port (it may be a UTF-8 issue) and in the end I went for a gboolean flag in the context that this particular viewer was handling a file from a remote filesystem (e.g. http://localhost/incoming/deb-gview_0.2.0_amd64.changes, http://ftp.debian.org/debian/pool/main/e/emdebian-tools/emdebian-rootfs_0.9.1_all.deb or http://incoming.debian.org/foo_version.changes) and not from a local path (e.g. /opt/debian/deb-gview/deb-gview_0.2.0_amd64.changes or ../../debian/deb-gview/deb-gview_0.2.0_amd64.deb). Personally, I found
g_file_is_nativeto be unsuitable for this purpose and as I had a "user-entered" path available, I simply useif ((g_str_has_prefix (path, "..")) (g_str_has_prefix (path, "/")))but YMMV, depending on how you obtain the path itself.
Keep track of the type of input file when handling GFile -g_file_get_pathwill fail if passed a GFile that needsg_file_get_uriand vice-versa. These failures output messages to the console so they are relatively easy to track but not only will the call fail but the GFile itself is likely to get corrupted, leading to other bugs and messages to the console.g_vfs_get_file_for_path(vfs, path)andg_vfs_get_file_for_uri(vfs, path)(which obtain the GFile from GVfs in the first place) also fail if passed the wrong type of path.
In some situations,g_file_get_parse_namecan be used to get a "normal" char* representation of the path to the GFile but I was only able to use this in specific circumstances and only when the path and URI handling flag was implemented.
This all complicates the port becausegnome_vfs_make_uri_from_inputdid not have this separation issue. - Checking if a file exists -
if (!g_file_query_exists (gfile, NULL))may seem easy but unless issues with the URI and path are handled cleanly, this simple check will fail even though the file exists. The problem arises because GFile appears to mangle a URI with a path function and vice-versa. The GFile ends up with an invalid path and hence there is no valid file to check so the query fails - but without indicating that it's actually an internal error in GFile rather than a valid path that simply does not exist. - Reading files in one go -
vfsresult = gnome_vfs_read_entire_file (vfstext, &changes_size, &contents);gets replaced withg_file_load_contents (cfile, NULL, &contents, &changes_size, NULL, &result);(note the order swap between the size and the buffer to use). Once read, the buffer can be handled as before. This is one of the easier changes in the port, once the above issues are all cleared up. On the other hand, GIO and GVfs do appear to handle relative paths more easily than GnomeVFS. - Checking VFS is active -
vfs = g_vfs_get_default ();
if (g_vfs_is_active(vfs)) - Reading files as a stream -
result = gnome_vfs_read (vfshandle, readbuffer, skip, &bytesread);becomesbytesread = g_input_stream_read (stream, readbuffer, skip, NULL, &result);. Fairly straightforward as long as you use:
if (result)
(or something equivalent to get the error message to the user), every time you use &result.
g_warning("Error: %s", result->message);
g_clear_error (&result);
vfs_uri = gnome_vfs_uri_new (gnome_vfs_make_uri_from_shell_arg (filename));becomesfilestream = g_file_read (deb->ghandle, NULL, &result);(there's that &result again). - Checking the stream remains open.
stream = (GInputStream*)filestream;
if (g_input_stream_is_closed (stream))
return FALSE; - Seeking inside the stream - YMMV but seek never appeared to work well for me in VFS so I had to read into a dump instead.
gpointer dump;
dump = g_new0(gchar, seek);
result = gnome_vfs_read (deb->vfshandle, dump, seek, &bytesread);
g_free (dump);
In GIO, seek is much easier:g_input_stream_skip (stream, seek, NULL, &result);- just handle that &result again.
- Closing the stream -
gnome_vfs_close (vfshandle);becomesg_input_stream_close (stream, NULL, &result);. - Getting information on files -
if ((vfsinfo->type != GNOME_VFS_FILE_TYPE_REGULAR) (vfsinfo->size == 0))becomes
ginfo = g_file_query_info (ghandle, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, &result);
if (0 == g_file_info_get_attribute_uint64 (ginfo, G_FILE_ATTRIBUTE_STANDARD_SIZE))
dv_show_error (DV_ERR_NO_FILE, parent);
return;
(dv_show_error is a user-facing error report func) and, yes, there is ag_clear_error(&result);later.
Summary
This took me quite a bit of time and the bug in gvfsd was a significant hindrance so ensure that you test with gvfs-info before thinking there is a bug in your code. (Also remember that if you are reading files from http://incoming.debian.org/ then those files will disappear once each day when the cron job moves them into the pool.
The GIO docs are relatively thin (especially for GVfs) and that is not just because GIO is still new. Starting a new application using GIO and having a working GIO/GVfs setup in place already would be much easier so new applications will work. As ever, the problems really show up when trying to port an application that has already worked around the various GnomeVFS bugs and now has to both remove those workarounds and implement one or two other changes for GIO.
Ensure your application has
Depends: gvfs-backends - until the bug in gvfsd is fixed, it would be unwise to put gvfs-backends in Recommends: because that will almost inevitably result in any user without Recommends: enabled passing a call to GVfs at least once without an available backend, resulting in a broken gvfsd process and a completely broken application until the user either kills the process or logs out and logs back in. Even identifying that issue in a bug report is not straightforward - hopefully the bug report and this post will help. (Yes, depending on how you configure the ported application, it is entirely possible for this broken gvfsd process to break all file operations in your application, even local ones.) Unfortunately, there is no call (currently) to take down GVfs - you can only test to see if it is already active and that check is not sufficiently intelligent to detect the broken gvfsd process.Subjectively, GIO does appear smoother than GnomeVFS and maybe faster. Now I need to get on and try to port other applications to GIO.....
That time of the release process now came where I will rant about uncoordinated introduction of debconf templates.
Given the release timeframe, I started the very same work I did for etch: 
I am trying to add some order to the mess that is the Launchpad translation repository. Problem is, strings translated just once through Launchpad stick around forever, even if you change them in upstream later. In effect, a lot of translation bugfixes were not reaching Ubuntu users. I
In contrast to chess, there is very little free software for bridge players.
Some
Coincidentally, the screenshot shows a board from last week's club
championships. East can beat 3NT by returning a Spade, but at my table they
didn't and so the board became my first squeeze hand :)
Many artists use the problems of current society for inspiration. I am
therefore optimistic in the sense that if artists are seeing freedom as a
serious problem in the post 9/11 world, others outside of tech-oriented circles
will finally notice as well. Bruce Schneier pointed out 
Some people expressed some concerns about the fact that we currently have about ~440 bugs in testing, but still hold to our plan of releasing in september 2008. The development of the RC bug graph as seen
Debian is part of the
I'm moving to London in a bit over a week, which means disposing of some quantity of junk, moving some more to London and hiding the rest (anyone got any recommendations for storage? I don't need regular access, but life would be immeasurably easier if they can pick stuff up and take it away). It also means the end of almost 10 years of living in Cambridge, and as a consequence there will be a party in the usual location on Friday the 28th. And possibly also on Saturday the 29th, depending on how much alcohol there still is lying around.
Today I spent a while fixing some more segfault bugs. I guess that this work qualifies as either fixing RC bugs, or potential security bugs.
Anyway I did an NMU of
There seem to be a number of competing products available at the
moment, and it seems they are all based on the
Last week, while I was already busier than I like, the cpu fan of my pegasos powerpc server blew off, and the resulting heat then killed the CPU. Which was quite a pain, as I used powerpc vservers on it, for which I had no replacement hardware. Or so I thought.