ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / modules / test-method.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* Test-method.c: Gnome-VFS testing method
3
4    Copyright (C) 2000 Eazel
5
6    The Gnome Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The Gnome Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20
21    Authors: Seth Nickell      (seth@eazel.com) */
22
23 /* Create a settings file and put it at PREFIX/etc/vfs/Test-conf.xml,
24  * then point gnome-vfs clients to test:<uri_minus_scheme> which will
25  * translate into the "real" method (e.g. test:///home/seth).
26  *
27  * The delay is in milliseconds.
28  *
29  * Here's a sample config file (pointing to the file method):
30  *
31  *    <?xml version="1.0"?>
32  *        <TestModule method="file">
33  *            <function name="open_directory" delay="2000"/>
34  *        </TestModule>
35  * */
36
37 #include <config.h>
38
39 #include <glib/gstrfuncs.h>
40 #include <libgnomevfs/gnome-vfs-cancellable-ops.h>
41 #include <libgnomevfs/gnome-vfs-ops.h>
42 #include <libgnomevfs/gnome-vfs-i18n.h>
43 #include <libgnomevfs/gnome-vfs-module.h>
44 #include <libxml/parser.h>
45 #include <libxml/tree.h>
46 #include <libxml/xmlmemory.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <unistd.h>
53
54 #define TEST_CONF_ENV_VARIABLE "GNOME_VFS_TEST_CONFIG_FILE"
55
56 typedef struct {
57         char *operation_name;
58         int delay;
59         gboolean skip;
60         gboolean override_result;
61         GnomeVFSResult overridden_result_value;
62 } OperationSettings;
63
64 #define NUM_RESULT_STRINGS 41
65
66 static gboolean properly_initialized;
67
68 static char *test_method_name;
69 static GList *settings_list;
70
71 static const char * const
72 result_strings[NUM_RESULT_STRINGS] = {
73         "GNOME_VFS_OK",
74         "GNOME_VFS_ERROR_NOT_FOUND",
75         "GNOME_VFS_ERROR_GENERIC",
76         "GNOME_VFS_ERROR_INTERNAL",
77         "GNOME_VFS_ERROR_BAD_PARAMETERS",
78         "GNOME_VFS_ERROR_NOT_SUPPORTED",
79         "GNOME_VFS_ERROR_IO",
80         "GNOME_VFS_ERROR_CORRUPTED_DATA",
81         "GNOME_VFS_ERROR_WRONG_FORMAT",
82         "GNOME_VFS_ERROR_BAD_FILE",
83         "GNOME_VFS_ERROR_TOO_BIG",
84         "GNOME_VFS_ERROR_NO_SPACE",
85         "GNOME_VFS_ERROR_READ_ONLY",
86         "GNOME_VFS_ERROR_INVALID_URI",
87         "GNOME_VFS_ERROR_NOT_OPEN",
88         "GNOME_VFS_ERROR_INVALID_OPEN_MODE",
89         "GNOME_VFS_ERROR_ACCESS_DENIED",
90         "GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES",
91         "GNOME_VFS_ERROR_EOF",
92         "GNOME_VFS_ERROR_NOT_A_DIRECTORY",
93         "GNOME_VFS_ERROR_IN_PROGRESS",
94         "GNOME_VFS_ERROR_INTERRUPTED",
95         "GNOME_VFS_ERROR_FILE_EXISTS",
96         "GNOME_VFS_ERROR_LOOP",
97         "GNOME_VFS_ERROR_NOT_PERMITTED",
98         "GNOME_VFS_ERROR_IS_DIRECTORY",
99         "GNOME_VFS_ERROR_NO_MEMORY",
100         "GNOME_VFS_ERROR_HOST_NOT_FOUND",
101         "GNOME_VFS_ERROR_INVALID_HOST_NAME",
102         "GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS",
103         "GNOME_VFS_ERROR_LOGIN_FAILED",
104         "GNOME_VFS_ERROR_CANCELLED",
105         "GNOME_VFS_ERROR_DIRECTORY_BUSY",
106         "GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY",
107         "GNOME_VFS_ERROR_TOO_MANY_LINKS",
108         "GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM",
109         "GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM",
110         "GNOME_VFS_ERROR_NAME_TOO_LONG",
111         "GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE",
112         "GNOME_VFS_NUM_ERRORS"
113 };
114
115 /* Module entry points. */
116 GnomeVFSMethod *vfs_module_init     (const char     *method_name,
117                                         const char     *args);
118 void            vfs_module_shutdown  (GnomeVFSMethod *method);
119
120 static GnomeVFSURI *
121 translate_uri (GnomeVFSURI *uri)
122 {
123         GnomeVFSURI *translated_uri;
124         char *uri_text;
125         char *translated_uri_text;
126         char *no_method;
127
128         uri_text = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
129         no_method = strchr (uri_text, ':');
130         
131         if (test_method_name != NULL) {
132           translated_uri_text = g_strconcat (test_method_name, 
133                                              no_method, NULL);
134         } else {
135           translated_uri_text = NULL;
136         }
137
138         if (translated_uri_text != NULL) {
139           translated_uri = gnome_vfs_uri_new (translated_uri_text);
140         } else {
141           translated_uri = NULL;
142         }
143
144         g_free (translated_uri_text);
145         g_free (uri_text);
146
147         return translated_uri;
148 }
149
150 /* reads the configuration file and returns TRUE if there are special options for
151    this execution of the operation.
152
153    if TRUE is returned then result will contain the result the operation should return
154    and perform_operation will be TRUE if the operation should execute the underlying
155    operation anyway
156 */
157 static const OperationSettings *
158 get_operation_settings (const char *function_identifier)
159 {
160         static OperationSettings empty_settings;
161         GList *node;
162         OperationSettings *settings;
163
164         for (node = settings_list; node != NULL; node = node->next) {
165                 settings = node->data;
166                 if (g_ascii_strcasecmp (settings->operation_name, function_identifier) == 0) {
167                         return settings;
168                 }
169         }
170         
171         return &empty_settings;
172 }
173
174 static const OperationSettings *
175 start_operation (const char *name,
176                  GnomeVFSURI **uri,
177                  GnomeVFSURI **saved_uri)
178 {
179         const OperationSettings *settings;
180         struct timeval tv;
181
182         settings = get_operation_settings (name);
183
184         tv.tv_sec = settings->delay / 1000;
185         tv.tv_usec = 1000 * (settings->delay % 1000);
186         select (0, NULL, NULL, NULL, &tv);
187         
188         if (uri != NULL) {
189                 *saved_uri = *uri;
190                 *uri = translate_uri (*uri);
191         }
192         return settings;
193 }
194
195 static GnomeVFSResult
196 finish_operation (const OperationSettings *settings,
197                   GnomeVFSResult result,
198                   GnomeVFSURI **uri,
199                   GnomeVFSURI **saved_uri)
200 {
201         if (uri != NULL) {
202                 gnome_vfs_uri_unref (*uri);
203                 *uri = *saved_uri;
204         }
205
206         if (settings->override_result) {
207                 return settings->overridden_result_value;
208         }
209         return result;
210 }
211
212 #define PERFORM_OPERATION(name, operation)                      \
213 do {                                                            \
214         const OperationSettings *settings;                      \
215         GnomeVFSURI *saved_uri;                                 \
216         GnomeVFSResult result;                                  \
217                                                                 \
218         if (!properly_initialized) {                            \
219                 return GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE;   \
220         }                                                       \
221                                                                 \
222         settings = start_operation (#name, &uri, &saved_uri);   \
223         if (settings->skip) {                                   \
224                 result = GNOME_VFS_OK;                          \
225         } else {                                                \
226                 result = operation;                             \
227         }                                                       \
228         return finish_operation (settings, result,              \
229                                  &uri, &saved_uri);             \
230 } while (0)
231
232
233 #define PERFORM_OPERATION_NO_URI(name, operation)               \
234 do {                                                            \
235         const OperationSettings *settings;                      \
236         GnomeVFSResult result;                                  \
237                                                                 \
238         if (!properly_initialized) {                            \
239                 return GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE;   \
240         }                                                       \
241                                                                 \
242         settings = start_operation (#name, NULL, NULL);         \
243         if (settings->skip) {                                   \
244                 result = GNOME_VFS_OK;                          \
245         } else {                                                \
246                 result = operation;                             \
247         }                                                       \
248         return finish_operation (settings, result,              \
249                                  NULL, NULL);                   \
250 } while (0)
251
252 static gboolean
253 parse_result_text (const char *result_text,
254                    GnomeVFSResult *result_code)
255 {
256         int i;
257
258         for (i = 0; i < NUM_RESULT_STRINGS; i++) {
259                 if (g_ascii_strcasecmp (result_text, result_strings[i]) == 0) {
260                         *result_code = i;
261                         return TRUE;
262                 }
263         }
264         
265         return FALSE;
266 }
267
268 static gboolean
269 load_settings (const char *filename) 
270 {
271         xmlDocPtr doc;
272         xmlNodePtr node;
273         char *name;
274         OperationSettings *operation;
275         char *str;
276
277         doc = xmlParseFile (filename); 
278
279         if (doc == NULL
280             || doc->xmlRootNode == NULL
281             || doc->xmlRootNode->name == NULL
282             || g_ascii_strcasecmp (doc->xmlRootNode->name, "testmodule") != 0) {
283                 xmlFreeDoc(doc);
284                 return FALSE;
285         }
286
287         test_method_name = xmlGetProp (doc->xmlRootNode, "method");
288         
289         for (node = doc->xmlRootNode->xmlChildrenNode; node != NULL; node = node->next) {
290                 name = xmlGetProp (node, "name");
291                 if (name == NULL) {
292                         continue;
293                 }
294
295                 operation = g_new0 (OperationSettings, 1);
296                 operation->operation_name = name;
297
298                 str = xmlGetProp (node, "delay");
299                 if (str != NULL) {
300                         sscanf (str, "%d", &operation->delay);
301                 }
302                 xmlFree (str);
303
304                 str = xmlGetProp(node, "execute_operation");
305                 if (str != NULL && g_ascii_strcasecmp (str, "FALSE") == 0) {
306                         operation->skip = TRUE;
307                 }
308                 xmlFree (str);
309
310                 str = xmlGetProp (node, "result");
311                 if (str != NULL) {
312                         operation->override_result = parse_result_text
313                                 (str, &operation->overridden_result_value);
314                 }
315                 xmlFree (str);
316                 
317                 settings_list = g_list_prepend (settings_list, operation);
318         }
319         return TRUE;
320 }
321
322 static GnomeVFSResult
323 do_open (GnomeVFSMethod *method,
324          GnomeVFSMethodHandle **method_handle,
325          GnomeVFSURI *uri,
326          GnomeVFSOpenMode mode,
327          GnomeVFSContext *context)
328 {       
329         PERFORM_OPERATION (open, gnome_vfs_open_uri_cancellable ((GnomeVFSHandle **) method_handle, uri, mode, context));
330 }
331
332 static GnomeVFSResult
333 do_create (GnomeVFSMethod *method,
334            GnomeVFSMethodHandle **method_handle,
335            GnomeVFSURI *uri,
336            GnomeVFSOpenMode mode,
337            gboolean exclusive,
338            guint perm,
339            GnomeVFSContext *context)
340 {
341         /* FIXME bugzilla.eazel.com 3837: Not implemented. */
342         return GNOME_VFS_ERROR_INTERNAL;
343 }
344
345 static GnomeVFSResult
346 do_close (GnomeVFSMethod *method,
347           GnomeVFSMethodHandle *method_handle,
348           GnomeVFSContext *context)
349 {
350         PERFORM_OPERATION_NO_URI (close, gnome_vfs_close_cancellable ((GnomeVFSHandle *) method_handle, context));
351 }
352
353 static GnomeVFSResult
354 do_read (GnomeVFSMethod *method,
355          GnomeVFSMethodHandle *method_handle,
356          gpointer buffer,
357          GnomeVFSFileSize num_bytes,
358          GnomeVFSFileSize *bytes_read,
359          GnomeVFSContext *context)
360 {
361         PERFORM_OPERATION_NO_URI (read, gnome_vfs_read_cancellable ((GnomeVFSHandle *) method_handle, buffer, num_bytes, bytes_read, context));
362 }
363
364 static GnomeVFSResult
365 do_write (GnomeVFSMethod *method,
366           GnomeVFSMethodHandle *method_handle,
367           gconstpointer buffer,
368           GnomeVFSFileSize num_bytes,
369           GnomeVFSFileSize *bytes_written,
370           GnomeVFSContext *context)
371 {
372         PERFORM_OPERATION_NO_URI (write, gnome_vfs_write_cancellable((GnomeVFSHandle *) method_handle, buffer, num_bytes, bytes_written, context));
373 }
374
375 static GnomeVFSResult
376 do_seek (GnomeVFSMethod *method,
377          GnomeVFSMethodHandle *method_handle,
378          GnomeVFSSeekPosition whence,
379          GnomeVFSFileOffset offset,
380          GnomeVFSContext *context)
381 {
382         PERFORM_OPERATION_NO_URI (seek, gnome_vfs_seek_cancellable ((GnomeVFSHandle *) method_handle, whence, offset, context));
383 }
384
385 static GnomeVFSResult
386 do_tell (GnomeVFSMethod *method,
387          GnomeVFSMethodHandle *method_handle,
388          GnomeVFSFileOffset *offset_return)
389 {
390         PERFORM_OPERATION_NO_URI (tell, gnome_vfs_tell ((GnomeVFSHandle *) method_handle, offset_return));
391 }
392
393
394 static GnomeVFSResult
395 do_open_directory (GnomeVFSMethod *method,
396                    GnomeVFSMethodHandle **method_handle,
397                    GnomeVFSURI *uri,
398                    GnomeVFSFileInfoOptions options,
399                    GnomeVFSContext *context)
400 {
401         PERFORM_OPERATION (open_directory, gnome_vfs_directory_open_from_uri ((GnomeVFSDirectoryHandle **) method_handle, uri, options));
402 }
403
404 static GnomeVFSResult
405 do_close_directory (GnomeVFSMethod *method,
406                     GnomeVFSMethodHandle *method_handle,
407                     GnomeVFSContext *context)
408 {
409         PERFORM_OPERATION_NO_URI (close_directory, gnome_vfs_directory_close ((GnomeVFSDirectoryHandle *) method_handle));
410 }
411
412 static GnomeVFSResult
413 do_read_directory (GnomeVFSMethod *method,
414                    GnomeVFSMethodHandle *method_handle,
415                    GnomeVFSFileInfo *file_info,
416                    GnomeVFSContext *context)
417 {
418         PERFORM_OPERATION_NO_URI (read_directory, gnome_vfs_directory_read_next ((GnomeVFSDirectoryHandle *) method_handle, file_info));
419 }
420
421 static GnomeVFSResult
422 do_get_file_info (GnomeVFSMethod *method,
423                   GnomeVFSURI *uri,
424                   GnomeVFSFileInfo *file_info,
425                   GnomeVFSFileInfoOptions options,
426                   GnomeVFSContext *context)
427 {
428         PERFORM_OPERATION (get_file_info, gnome_vfs_get_file_info_uri_cancellable (uri, file_info, options, context));
429 }
430
431 static GnomeVFSResult
432 do_get_file_info_from_handle (GnomeVFSMethod *method,
433                               GnomeVFSMethodHandle *method_handle,
434                               GnomeVFSFileInfo *file_info,
435                               GnomeVFSFileInfoOptions options,
436                               GnomeVFSContext *context)
437 {
438         PERFORM_OPERATION_NO_URI (get_file_info_from_handle, gnome_vfs_get_file_info_from_handle_cancellable ((GnomeVFSHandle *) method_handle, file_info, options, context));
439 }
440
441 static gboolean
442 do_is_local (GnomeVFSMethod *method,
443              const GnomeVFSURI *uri)
444 {
445         /* FIXME bugzilla.eazel.com 3837: Not implemented. */
446         return TRUE;
447 }
448
449 static GnomeVFSResult
450 do_make_directory (GnomeVFSMethod *method,
451                    GnomeVFSURI *uri,
452                    guint perm,
453                    GnomeVFSContext *context)
454 {
455         PERFORM_OPERATION (make_directory, gnome_vfs_make_directory_for_uri_cancellable (uri, perm, context));
456 }
457
458 static GnomeVFSResult
459 do_remove_directory (GnomeVFSMethod *method,
460                      GnomeVFSURI *uri,
461                      GnomeVFSContext *context)
462 {
463         PERFORM_OPERATION (remove_directory, gnome_vfs_remove_directory_from_uri_cancellable (uri, context));
464 }
465
466 static GnomeVFSResult
467 do_move (GnomeVFSMethod *method,
468          GnomeVFSURI *old_uri,
469          GnomeVFSURI *new_uri,
470          gboolean force_replace,
471          GnomeVFSContext *context)
472 {
473         /* FIXME bugzilla.eazel.com 3837: Not implemented. */
474         return gnome_vfs_move_uri_cancellable (old_uri, new_uri, force_replace, context);
475 }
476
477 static GnomeVFSResult
478 do_unlink (GnomeVFSMethod *method,
479            GnomeVFSURI *uri,
480            GnomeVFSContext *context)
481 {
482         PERFORM_OPERATION (unlink, gnome_vfs_unlink_from_uri_cancellable (uri, context));
483 }
484
485 static GnomeVFSResult
486 do_check_same_fs (GnomeVFSMethod *method,
487                   GnomeVFSURI *a,
488                   GnomeVFSURI *b,
489                   gboolean *same_fs_return,
490                   GnomeVFSContext *context)
491 {
492         /* FIXME bugzilla.eazel.com 3837: Not implemented. */
493         return gnome_vfs_check_same_fs_uris_cancellable (a, b, same_fs_return, context);
494 }
495
496 static GnomeVFSResult
497 do_set_file_info (GnomeVFSMethod *method,
498                   GnomeVFSURI *uri,
499                   const GnomeVFSFileInfo *info,
500                   GnomeVFSSetFileInfoMask mask,
501                   GnomeVFSContext *context)
502 {       
503         PERFORM_OPERATION (set_file_info, gnome_vfs_set_file_info_cancellable (uri, info, mask, context));
504 }
505
506 static GnomeVFSResult
507 do_truncate (GnomeVFSMethod *method,
508              GnomeVFSURI *uri,
509              GnomeVFSFileSize where,
510              GnomeVFSContext *context)
511 {
512         PERFORM_OPERATION (truncate, gnome_vfs_truncate_uri_cancellable (uri, where, context));
513 }
514
515 static GnomeVFSResult
516 do_truncate_handle (GnomeVFSMethod *method,
517                     GnomeVFSMethodHandle *method_handle,
518                     GnomeVFSFileSize where,
519                     GnomeVFSContext *context)
520 {
521         PERFORM_OPERATION_NO_URI (truncate_handle, gnome_vfs_truncate_handle_cancellable ((GnomeVFSHandle *) method_handle, where, context));
522 }
523
524 static GnomeVFSResult
525 do_find_directory (GnomeVFSMethod *method,
526                    GnomeVFSURI *uri,
527                    GnomeVFSFindDirectoryKind kind,
528                    GnomeVFSURI **result_uri,
529                    gboolean create_if_needed,
530                    gboolean find_if_needed,
531                    guint permissions,
532                    GnomeVFSContext *context)
533 {
534         PERFORM_OPERATION (find_directory, gnome_vfs_find_directory_cancellable (uri, kind, result_uri, create_if_needed, find_if_needed, permissions, context));
535 }
536
537 static GnomeVFSResult
538 do_create_symbolic_link (GnomeVFSMethod *method,
539                          GnomeVFSURI *uri,
540                          const char *target_reference,
541                          GnomeVFSContext *context)
542 {
543         PERFORM_OPERATION (create_symbolic_link, gnome_vfs_create_symbolic_link_cancellable (uri, target_reference, context));
544 }
545
546 static GnomeVFSMethod method = {
547         sizeof (GnomeVFSMethod),
548         do_open,
549         do_create,
550         do_close,
551         do_read,
552         do_write,
553         do_seek,
554         do_tell,
555         do_truncate_handle,
556         do_open_directory,
557         do_close_directory,
558         do_read_directory,
559         do_get_file_info,
560         do_get_file_info_from_handle,
561         do_is_local,
562         do_make_directory,
563         do_remove_directory,
564         do_move,
565         do_unlink,
566         do_check_same_fs,
567         do_set_file_info,
568         do_truncate,
569         do_find_directory,
570         do_create_symbolic_link
571 };
572
573
574 GnomeVFSMethod *
575 vfs_module_init (const char *method_name, const char *args)
576 {
577         char *conf_file;
578
579         LIBXML_TEST_VERSION
580         
581         conf_file = getenv (TEST_CONF_ENV_VARIABLE);
582
583         if (conf_file == NULL) {
584                 conf_file = PREFIX "/etc/vfs/Test-conf.xml";
585         }
586
587         if (load_settings (conf_file) == FALSE) {
588
589           // FIXME: we probably shouldn't use printf to output the message
590           printf (_("Didn't find a valid settings file at %s\n"), 
591                   conf_file);
592           printf (_("Use the %s environment variable to specify a different location.\n"),
593                   TEST_CONF_ENV_VARIABLE);
594           properly_initialized = FALSE;
595         } else {
596           properly_initialized = TRUE;
597         }
598
599         return &method;
600 }
601
602 void
603 vfs_module_shutdown (GnomeVFSMethod *method)
604 {
605         GList *node;
606         OperationSettings *settings;
607
608         for (node = settings_list; node != NULL; node = node->next) {
609                 settings = node->data;
610                 xmlFree (settings->operation_name);
611                 g_free (settings);
612         }
613         g_list_free (settings_list);
614         xmlFree (test_method_name);
615 }