4 >Writing Modules</TITLE
7 CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
10 TITLE="GnomeVFS - Filesystem Abstraction library"
11 HREF="index.html"><LINK
13 TITLE="Filesystem Modules"
14 HREF="modules.html"><LINK
16 TITLE="Filesystem Modules"
17 HREF="modules.html"><LINK
20 HREF="gnome-vfs-gnome-vfs-mime.html"><META
22 CONTENT="GTK-Doc V0.10 (SGML mode)"><STYLE
24 >.synopsis, .classsynopsis {
26 border: solid 1px #aaaaaa;
31 border: solid 1px #aaaaff;
40 border: solid 1px #ffaaaa;
47 .navigation a:visited {
64 SUMMARY="Navigation header"
105 >GnomeVFS - Filesystem Abstraction library</TH
109 HREF="gnome-vfs-gnome-vfs-mime.html"
121 NAME="WRITING-MODULES"
131 >Writing Modules -- basic gnome-vfs module concepts</DIV
140 >This section will introduce the basic concepts that are
141 needed for writing GNOME Virtual File System modules.</P
148 >GNOME VFS URIs (Uniform Resource Identifiers)</H3
150 >The GNOME Virtual file system uses URIs similiar to the
151 standard WWW URIs. The basic difference between a VFS URI and
152 WWW URI is that, while with WWW URIs you can only use a single
153 protocol for accessing a certain file, with GNOME VFS URIs you
154 can combine different access methods in sequence.</P
156 >For example, suppose you want to access file
164 file which is in turn accessible through FTP from a remote
165 machine. In order to access this file, you would need to:</P
172 >Connect to the FTP site.</P
203 >The GNOME Virtual File System lets you express this by
204 combining the three access methods (i.e. tar, GZIP and FTP)
205 into a single URI. Access methods are combined in the URI by
206 using the `#' character, followed by the name for the access
207 method and the subpath for that specific access method. The
208 subpath can be omitted for those storage methods that do not
209 need a path to retrieve the file. (For example, a GZIP file
210 always contains a single uncompressed file, so no path is
211 needed to locate the uncompressed file within the GZIP file.
212 But on the other hand, the TAR method requires a path to
213 locate a specific file or directory.)</P
215 >For example, in the case we outlined above, the URI would
216 look something like:</P
218 CLASS="PROGRAMLISTING"
219 > ftp://username:password@host.net/path/to/file.tar.gz#gzip#tar/path/to/hello.c</PRE
221 >Each method/subpath couple is called a <I
225 >. When URI elements are combined like this,
226 each URI element uses the previous one to access a base resource
227 into which it will look up a file, using the subpath
228 information. For this reason, we will say that each element is
232 > element for the following one.</P
234 >The first URI element, the one which has no parent, is
239 use the `#' character; instead, it uses the standard syntax of
242 CLASS="PROGRAMLISTING"
243 > method://user:password@host/path/to/file</PRE
245 >This way, normal WWW URIs can be used with the GNOME Virtual
248 >Toplevel elements are also special because they let users
249 specify user names, passwords and host names, while
250 non-toplevel elements don't.</P
263 >Within the GNOME Virtual File System library, URI elements
264 are represented by a special type,
268 >, which is meant to represent
269 user-provided URIs in a machine-optimized way. </P
275 following information:</P
281 >A reference counter</P
285 >A pointer to the parent
297 >The name of the access method.</P
304 >GnomeVFSMethod</SPAN
305 > object, describing the
306 access method (see below).</P
317 >GNOME Virtual File System access method implementation</H2
319 >In the GNOME Virtual File System, the implementations for
320 all the access methods are loaded at runtime, as shared library
321 modules. The modules are loaded during parsing of the string URI:
322 if the parser encounters an access method for which no
323 implementation is currently loaded, it retrieves the corresponding
324 library file, dynamically links it into the executable, and
327 >After initialization, the module returns a special
330 >GnomeVFSMethod</SPAN
331 > object that contains
332 pointers to the various implementation functions for that specific
333 method. By storing a pointer to this object into the
337 > type, the VFS library is then
338 able to use these functions for file access.</P
345 >How file access is performed</H3
347 >When the VFS library needs to perform some file operation,
348 it performs the following steps:</P
354 >If the URI is given in textual form (i.e. as a
355 string), it parses it and activates the necessary access method
360 >It retrieves a pointer to the lowmost
361 level URI element.</P
365 >It retrieves a pointer to the
368 >GnomeVFSMethod</SPAN
369 > object that corresponds
370 to the access method for that URI element.</P
374 >It retrieves a pointer to the implementation
375 function for that operation from the
378 >GnomeVFSMethod</SPAN
383 >It invokes that implementation function
384 passing the pointer to the lowmost level URI
389 >Combining the access methods is always done within the
390 method implementation. If the method implementation needs to do
391 some file operation on the the parent URI element, it can do so
392 by simply invoking the corresponding VFS function in, by using
393 the parent pointer in the <SPAN
399 >For example, suppose you have to read a simple URI like
402 CLASS="PROGRAMLISTING"
403 > file:/home/ettore/file.gz#gzip</PRE
405 >In this case, the GZIP method will be invoked with a
410 `gzip' part; then the GZIP method will be able to read
414 > by just invoking the corresponding
415 GNOME VFS library function on its parent, and decompress it on
425 >Implementing an access method in practice</H2
427 >Implementing a new access method is really not difficult at
428 all. This section explains how this is done.</P
435 >Using shared libraries</H3
437 >Every module must be compiled as a shared library (i.e. a
443 >The current way for accessing the right module for the
444 right method is very simple, and is based on file names. In
445 practice, a module implementing access method named
453 >. For example, the module
461 >, the module implementing
471 >This might change in the future.</P
479 >The initialization/shutdown functions</H3
481 >Every shared library module must provide two functions:</P
483 CLASS="PROGRAMLISTING"
484 > GnomeVFSMethod *vfs_module_init (void);
485 void vfs_module_shutdown (GnomeVFSMethod *method);</PRE
487 >These are the only functions that the VFS library will
488 access directly. All the other symbols (i.e. functions and
489 variables) in the module should be made static. </P
493 >vfs_module_init()</TT
495 as soon as the module is loaded in memory. It will have to
496 return a pointer to a <SPAN
498 >GnomeVFSMethod</SPAN
500 object that will contain the pointers to the method's
501 implementation functions. We will describe this later. </P
505 >vfs_module_shutdown</TT
507 is called before the module is unloaded or the program that uses
508 it dies. This functions should:</P
514 >Deallocate all the memory allocated by the
519 >Close all the file descriptors associated with
524 >Kill any external process spawned by the
529 >In general, make sure that any operation that
530 was going on before this function was called will be
531 interrupted correctly, as soon as possible and without any
544 >GnomeVFSMethod</SPAN
547 >This object is contains pointers to the module
548 implementation functions.</P
550 CLASS="PROGRAMLISTING"
551 > GnomeVFSResult (* open) (GnomeVFSMethodHandle **method_handle_return,
553 GnomeVFSOpenMode mode
554 GnomeVFSCancellation *cancellation);
556 GnomeVFSResult (* create) (GnomeVFSMethodHandle **method_handle_return,
558 GnomeVFSOpenMode mode,
561 GnomeVFSCancellation *cancellation);
563 GnomeVFSResult (* close) (GnomeVFSMethodHandle *method_handle
564 GnomeVFSCancellation *cancellation);
566 GnomeVFSResult (* read) (GnomeVFSMethodHandle *method_handle,
568 GnomeVFSFileSize num_bytes,
569 GnomeVFSFileSize *bytes_read_return
570 GnomeVFSCancellation *cancellation);
572 GnomeVFSResult (* write) (GnomeVFSMethodHandle *method_handle,
573 gconstpointer buffer,
574 GnomeVFSFileSize num_bytes,
575 GnomeVFSFileSize *bytes_written_return
576 GnomeVFSCancellation *cancellation);
578 GnomeVFSResult (* seek) (GnomeVFSMethodHandle *method_handle,
579 GnomeVFSSeekPosition whence,
580 GnomeVFSFileOffset offset
581 GnomeVFSCancellation *cancellation);
583 GnomeVFSResult (* tell) (GnomeVFSMethodHandle *method_handle,
584 GnomeVFSFileOffset *offset_return);
586 GnomeVFSResult (* truncate) (GnomeVFSMethodHandle *method_handle,
587 GnomeVFSFileSize where
588 GnomeVFSCancellation *cancellation);
590 GnomeVFSResult (* open_directory) (GnomeVFSMethodHandle **method_handle,
592 GnomeVFSFileInfoOptions options,
593 const GList *meta_keys,
594 const GnomeVFSDirectoryFilter *filter
595 GnomeVFSCancellation *cancellation);
597 GnomeVFSResult (* close_directory) (GnomeVFSMethodHandle *method_handle
598 GnomeVFSCancellation *cancellation);
600 GnomeVFSResult (* read_directory) (GnomeVFSMethodHandle *method_handle,
601 GnomeVFSFileInfo *file_info
602 GnomeVFSCancellation *cancellation);
604 GnomeVFSResult (* get_file_info) (GnomeVFSURI *uri,
605 GnomeVFSFileInfo *file_info,
606 GnomeVFSFileInfoOptions options,
607 const GList *meta_keys
608 GnomeVFSCancellation *cancellation);
610 GnomeVFSResult (* get_file_info_from_handle)
611 (GnomeVFSMethodHandle *method_handle,
612 GnomeVFSFileInfo *file_info,
613 GnomeVFSFileInfoOptions options,
614 const GList *meta_keys
615 GnomeVFSCancellation *cancellation);
617 gboolean (* is_local) (const GnomeVFSURI *uri
618 GnomeVFSCancellation *cancellation);
620 GnomeVFSResult (* rename) (GnomeVFSURI *uri, const gchar *new_name
621 GnomeVFSCancellation *cancellation);
623 GnomeVFSResult (* make_directory) (GnomeVFSURI *uri, guint perm
624 GnomeVFSCancellation *cancellation);
626 GnomeVFSResult (* remove_directory) (GnomeVFSURI *uri
627 GnomeVFSCancellation *cancellation);
629 GnomeVFSResult (* unlink) (GnomeVFSURI *uri
630 GnomeVFSCancellation *cancellation);</PRE
639 >Handling cancellation</H2
641 >As VFS operations might be very long, especially in the case
642 of transient errors (such as a network server that has gone down),
643 the GNOME Virtual File System Library provides a standard way for
644 handling cancellation of VFS operations.</P
653 >GnomeVFSCancellation</SPAN
656 >The object that encapsulates this functionality is
659 >GnomeVFSCancellation</SPAN
661 implementation functions get a pointer to such an object, and are
662 expected to use this object to recognize when an operation should
665 >The most simple way to check for a cancellation request is
666 to poll the object with
669 >gnome_vfs_cancellation_check()</TT
672 CLASS="PROGRAMLISTING"
674 gboolean gnome_vfs_cancellation_check (GnomeVFSCancellation *cancellation);</PRE
676 >This function will return a nonzero value if the current
677 operation should be cancelled.</P
679 >Notice that cancellation is an asynchronous operation that
680 might happen outside your function, in parallel with the code that
681 you are writing. For example, in the case of threads, the request
682 will be set in the master thread; in the case of slave
683 CORBA-driven processes, the request will be activated by a Unix
684 signal. So you can expect a cancellation request to happen (and
685 consequently be signalled in
688 >GnomeVFSCancellation</SPAN
691 >For this reason, you should be calling this function
692 periodically, whenever you are going to perform several
693 iterations of the same task, or execute a single expensive task.
694 When the function returns a nonzero value, the correct way to
702 >Clean things up so that the result of the
703 operations that have been performed are all
711 >GNOME_VFS_ERROR_CANCELLED</SPAN
717 >But there are some other situations in which you want to
718 be able to interrupt a I/O operation when a cancellation request
719 is performed. In such cases, polling is not a viable option.</P
724 >GnomeVFSCancellation</SPAN
726 alternative way of sending notifications, using a file
727 descriptor. To use this feature, you should use the following
730 CLASS="PROGRAMLISTING"
731 > gint gnome_vfs_cancellation_get_fd (GnomeVFSCancellation *cancellation); </PRE
733 >When this function is called, it will return an open file
734 descriptor, which is the read-side of a pipe. The pipe will be
735 given a character from the write side as soon as a cancellation
736 request is sent. For this reason, you can check for a
737 cancellation by using the <TT
745 data is available on the file descriptor, you know that a
746 cancellation is being requested.</P
748 >For example, if you are reading from a file descriptor and
749 you want to check for a pending cancellation at the same time,
753 >for checking if data
754 is available on both the cancellation file descriptor and the
755 file descriptor you are reading from.</P
768 >In order to maximize the chance of cancelling an operation
769 immediately, the GNOME Virtual File System can sends a signal to
770 the asynchronous thread or process. This does not happen on all
771 the systems and setups, though.</P
773 >The result of this is that, if a process is in the middle
774 of a Unix system call while receiving this signal, the system
775 call might be interrupted and return a <SPAN
781 >For this reason, when you receive <SPAN
785 you should check if a cancellation request is pending, using
788 >gnome_vfs_cancellation_check()</TT
792 >GnomeVFSCancellation</SPAN
794 implementation function received:</P
800 >If a cancellation is indeed pending
803 >gnome_vfs_cancellation_check()</TT
805 nonzero value), you should cancel the operation, cleaning up
806 all the effects, and return
809 >GNOME_VFS_ERROR_INTERRUPTED</SPAN
813 >GNOME_VFS_ERROR_CANCELLED</SPAN
818 >Otherwise, retry the system call as you would
830 >Basic guidelines for writing a module</H2
832 >Writing GNOME VFS modules is easy, but there are a few
833 things that you must keep in mind when hacking them:</P
839 >All of the code must be completely thread safe.
840 The reason for this is that the asynchronous GNOME VFS engine
841 will use threads when available; if you don't make sure that the
842 code is thread-safe, every kind of weird and unexpected errors
843 will happen. As debugging these problems can be very hard, it's
844 important to write the code with threads in mind right from the
852 >gnome_vfs_*_cancellable()</TT
854 instead of the standard non-cancellable ones, passing them the
857 >GnomeVFSCancellation</SPAN
859 are given, so that the operation can always be interrrupted at
864 >The code should respect the basic GNOME
865 guidelines for source code indentation and
875 >How to make the code thread safe</H3
877 >Although it might sound scary at first, making the code
878 for the modules thread safe is not complicated at all.</P
880 >First of all, make sure the amount of global variables is
881 kept to the bare minimum. If possible, you should avoid them at
884 >For those cases where globals are inevitable (such as
885 caches, connection pools or things like that), you have to make
886 sure every variable is properly associated with a mutex, and
887 that the mutex is locked before every access to this variable
888 and released afterwards. You can also use
891 >G_LOCK_DEFINE_STATIC</TT
903 >Generally speaking, if you are going to dynamically
904 allocate structures that are shared by more than one
905 operation/file, you should provide all of them with their nice
908 >Finally, make sure mutexes are used only if they are
909 available. One way to do so is to use macros like the
912 CLASS="PROGRAMLISTING"
913 > #ifdef G_THREADS_ENABLED
914 #define MUTEX_NEW() g_mutex_new ()
915 #define MUTEX_FREE(a) g_mutex_free (a)
916 #define MUTEX_LOCK(a) if ((a) != NULL) g_mutex_lock (a)
917 #define MUTEX_UNLOCK(a) if ((a) != NULL) g_mutex_unlock (a)
919 #define MUTEX_NEW() NULL
920 #define MUTEX_FREE(a)
921 #define MUTEX_LOCK(a)
922 #define MUTEX_UNLOCK(a)
927 >G_LOCK_DEFINE_STATIC</TT
936 GLib are always safe to use, as they are already defined to be
937 nothing when thread support is not available.</P
939 >(Probably it would be a good idea to have something in the
940 private GNOME VFS API that does this stuff for all the
947 SUMMARY="Navigation footer"
958 ><<< Filesystem Modules</B
965 HREF="gnome-vfs-gnome-vfs-mime.html"
967 >MIME typing >>></B