1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /*
2 gnome-vfs-job.c - Jobs for asynchronous operation of the GNOME Virtual File
3 System (version for POSIX threads).
5 Copyright (C) 1999 Free Software Foundation
6 Copyright (C) 2000 Eazel
8 The Gnome Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
13 The Gnome Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public
19 License along with the Gnome Library; see the file COPYING.LIB. If not,
20 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
24 Ettore Perazzoli <ettore@gnu.org>
25 Pavel Cisler <pavel@eazel.com>
26 Darin Adler <darin@eazel.com>
31 #include "gnome-vfs-job.h"
33 #include "gnome-vfs-async-job-map.h"
34 #include "gnome-vfs-job-slave.h"
35 #include "gnome-vfs-job-queue.h"
38 #include <glib/gmessages.h>
39 #include <glib/gstrfuncs.h>
40 #include <libgnomevfs/gnome-vfs-cancellable-ops.h>
41 #include <libgnomevfs/gnome-vfs-context.h>
42 #include <libgnomevfs/gnome-vfs-i18n.h>
43 #include <libgnomevfs/gnome-vfs-backend.h>
47 static GStaticPrivate job_private = G_STATIC_PRIVATE_INIT;
49 #if GNOME_VFS_JOB_DEBUG
51 char *job_debug_types[] = {
52 "open", "open as channel",
53 "create", "create symbolic link",
54 "create as channel", "close",
55 "read", "write", "read write done",
56 "load directory", "find directory",
57 "xfer", "get file info", "set file info",
58 "module callback", "file control",
62 /* FIXME bugzilla.eazel.com 1130
63 * - this is should use the correct static mutex initialization macro.
64 * However glibconfig.h is broken and the supplied macro gives a warning.
65 * Since this id debug only, just use what the macro should be here.
66 * even though it is not portable.
68 GStaticMutex debug_mutex = G_STATIC_MUTEX_INIT;
71 static int job_count = 0;
73 static void gnome_vfs_op_destroy (GnomeVFSOp *op);
74 static void _gnome_vfs_job_destroy_notify_result (GnomeVFSNotifyResult *notify_result);
75 static gboolean dispatch_job_callback (gpointer data);
76 static gboolean dispatch_sync_job_callback (gpointer data);
78 static void clear_current_job (void);
79 static void set_current_job (GnomeVFSJob *context);
82 set_fl (int fd, int flags)
86 val = fcntl (fd, F_GETFL, 0);
88 g_warning ("fcntl() F_GETFL failed: %s", strerror (errno));
94 val = fcntl (fd, F_SETFL, val);
96 g_warning ("fcntl() F_SETFL failed: %s", strerror (errno));
102 clr_fl (int fd, int flags)
106 val = fcntl (fd, F_GETFL, 0);
108 g_warning ("fcntl() F_GETFL failed: %s", strerror (errno));
114 val = fcntl (fd, F_SETFL, val);
116 g_warning ("fcntl() F_SETFL failed: %s", strerror (errno));
122 * Find out whether or not a given job should be left in
123 * the job map, preserving it's open VFS handle, since we
124 * can do more operations on it later.
127 _gnome_vfs_job_complete (GnomeVFSJob *job)
129 g_assert (job->op != NULL);
131 switch (job->op->type) {
132 case GNOME_VFS_OP_OPEN:
133 case GNOME_VFS_OP_OPEN_AS_CHANNEL:
134 case GNOME_VFS_OP_CREATE:
135 case GNOME_VFS_OP_CREATE_AS_CHANNEL:
136 case GNOME_VFS_OP_CREATE_SYMBOLIC_LINK:
137 /* if job got cancelled, no close expected */
138 return job->cancelled || job->failed;
140 case GNOME_VFS_OP_READ:
141 case GNOME_VFS_OP_WRITE:
142 g_assert_not_reached();
144 case GNOME_VFS_OP_READ_WRITE_DONE:
145 case GNOME_VFS_OP_FILE_CONTROL:
153 /* This notifies the master thread asynchronously, without waiting for an
157 job_oneway_notify (GnomeVFSJob *job, GnomeVFSNotifyResult *notify_result)
159 if (_gnome_vfs_async_job_add_callback (job, notify_result)) {
160 JOB_DEBUG (("job %u, callback %u type '%s'",
161 GPOINTER_TO_UINT (notify_result->job_handle),
162 notify_result->callback_id,
163 JOB_DEBUG_TYPE (job->op->type)));
165 g_idle_add (dispatch_job_callback, notify_result);
167 JOB_DEBUG (("Barfing on oneway cancel %u (%d) type '%s'",
168 GPOINTER_TO_UINT (notify_result->job_handle),
169 job->op->type, JOB_DEBUG_TYPE (job->op->type)));
170 _gnome_vfs_job_destroy_notify_result (notify_result);
174 /* This notifies the master threads, waiting until it acknowledges the
177 job_notify (GnomeVFSJob *job, GnomeVFSNotifyResult *notify_result)
179 if (!_gnome_vfs_async_job_add_callback (job, notify_result)) {
180 JOB_DEBUG (("Barfing on sync cancel %u (%d)",
181 GPOINTER_TO_UINT (notify_result->job_handle),
183 _gnome_vfs_job_destroy_notify_result (notify_result);
187 /* Send the notification. This will wake up the master thread, which
188 * will in turn signal the notify condition.
190 g_idle_add (dispatch_sync_job_callback, notify_result);
192 JOB_DEBUG (("Wait notify condition %u", GPOINTER_TO_UINT (notify_result->job_handle)));
193 /* Wait for the notify condition. */
194 g_cond_wait (job->notify_ack_condition, job->job_lock);
196 JOB_DEBUG (("Got notify ack condition %u", GPOINTER_TO_UINT (notify_result->job_handle)));
200 dispatch_open_callback (GnomeVFSNotifyResult *notify_result)
202 (* notify_result->specifics.open.callback) (notify_result->job_handle,
203 notify_result->specifics.open.result,
204 notify_result->specifics.open.callback_data);
208 dispatch_create_callback (GnomeVFSNotifyResult *notify_result)
210 (* notify_result->specifics.create.callback) (notify_result->job_handle,
211 notify_result->specifics.create.result,
212 notify_result->specifics.create.callback_data);
216 dispatch_open_as_channel_callback (GnomeVFSNotifyResult *notify_result)
218 (* notify_result->specifics.open_as_channel.callback) (notify_result->job_handle,
219 notify_result->specifics.open_as_channel.channel,
220 notify_result->specifics.open_as_channel.result,
221 notify_result->specifics.open_as_channel.callback_data);
225 dispatch_create_as_channel_callback (GnomeVFSNotifyResult *notify_result)
227 (* notify_result->specifics.create_as_channel.callback) (notify_result->job_handle,
228 notify_result->specifics.create_as_channel.channel,
229 notify_result->specifics.create_as_channel.result,
230 notify_result->specifics.create_as_channel.callback_data);
234 dispatch_close_callback (GnomeVFSNotifyResult *notify_result)
236 (* notify_result->specifics.close.callback) (notify_result->job_handle,
237 notify_result->specifics.close.result,
238 notify_result->specifics.close.callback_data);
242 dispatch_read_callback (GnomeVFSNotifyResult *notify_result)
244 (* notify_result->specifics.read.callback) (notify_result->job_handle,
245 notify_result->specifics.read.result,
246 notify_result->specifics.read.buffer,
247 notify_result->specifics.read.num_bytes,
248 notify_result->specifics.read.bytes_read,
249 notify_result->specifics.read.callback_data);
253 dispatch_write_callback (GnomeVFSNotifyResult *notify_result)
255 (* notify_result->specifics.write.callback) (notify_result->job_handle,
256 notify_result->specifics.write.result,
257 notify_result->specifics.write.buffer,
258 notify_result->specifics.write.num_bytes,
259 notify_result->specifics.write.bytes_written,
260 notify_result->specifics.write.callback_data);
264 dispatch_load_directory_callback (GnomeVFSNotifyResult *notify_result)
266 (* notify_result->specifics.load_directory.callback) (notify_result->job_handle,
267 notify_result->specifics.load_directory.result,
268 notify_result->specifics.load_directory.list,
269 notify_result->specifics.load_directory.entries_read,
270 notify_result->specifics.load_directory.callback_data);
274 dispatch_get_file_info_callback (GnomeVFSNotifyResult *notify_result)
276 (* notify_result->specifics.get_file_info.callback) (notify_result->job_handle,
277 notify_result->specifics.get_file_info.result_list,
278 notify_result->specifics.get_file_info.callback_data);
282 dispatch_find_directory_callback (GnomeVFSNotifyResult *notify_result)
284 (* notify_result->specifics.find_directory.callback) (notify_result->job_handle,
285 notify_result->specifics.find_directory.result_list,
286 notify_result->specifics.find_directory.callback_data);
290 dispatch_set_file_info_callback (GnomeVFSNotifyResult *notify_result)
292 gboolean new_info_is_valid;
294 new_info_is_valid = notify_result->specifics.set_file_info.set_file_info_result == GNOME_VFS_OK
295 && notify_result->specifics.set_file_info.get_file_info_result == GNOME_VFS_OK;
297 (* notify_result->specifics.set_file_info.callback) (notify_result->job_handle,
298 notify_result->specifics.set_file_info.set_file_info_result,
299 new_info_is_valid ? notify_result->specifics.set_file_info.info : NULL,
300 notify_result->specifics.set_file_info.callback_data);
304 dispatch_xfer_callback (GnomeVFSNotifyResult *notify_result, gboolean cancelled)
307 /* make the xfer operation stop */
308 notify_result->specifics.xfer.reply = 0;
312 notify_result->specifics.xfer.reply = (* notify_result->specifics.xfer.callback) (
313 notify_result->job_handle,
314 notify_result->specifics.xfer.progress_info,
315 notify_result->specifics.xfer.callback_data);
319 dispatch_module_callback (GnomeVFSNotifyResult *notify_result)
321 notify_result->specifics.callback.callback (notify_result->specifics.callback.in,
322 notify_result->specifics.callback.in_size,
323 notify_result->specifics.callback.out,
324 notify_result->specifics.callback.out_size,
325 notify_result->specifics.callback.user_data,
326 notify_result->specifics.callback.response,
327 notify_result->specifics.callback.response_data);
331 dispatch_file_control_callback (GnomeVFSNotifyResult *notify_result)
333 notify_result->specifics.file_control.callback (notify_result->job_handle,
334 notify_result->specifics.file_control.result,
335 notify_result->specifics.file_control.operation_data,
336 notify_result->specifics.file_control.callback_data);
340 empty_close_callback (GnomeVFSAsyncHandle *handle,
341 GnomeVFSResult result,
342 gpointer callback_data)
347 handle_cancelled_open (GnomeVFSJob *job)
349 /* schedule a silent close to make sure the handle does not leak */
350 _gnome_vfs_job_set (job, GNOME_VFS_OP_CLOSE,
351 (GFunc) empty_close_callback, NULL);
352 _gnome_vfs_job_go (job);
356 free_get_file_info_notify_result (GnomeVFSGetFileInfoOpResult *notify_result)
359 GnomeVFSGetFileInfoResult *result_item;
361 for (p = notify_result->result_list; p != NULL; p = p->next) {
362 result_item = p->data;
364 gnome_vfs_uri_unref (result_item->uri);
365 gnome_vfs_file_info_unref (result_item->file_info);
366 g_free (result_item);
368 g_list_free (notify_result->result_list);
372 free_find_directory_notify_result (GnomeVFSFindDirectoryOpResult *notify_result)
375 GnomeVFSFindDirectoryResult *result_item;
377 for (p = notify_result->result_list; p != NULL; p = p->next) {
378 result_item = p->data;
380 if (result_item->uri != NULL) {
381 gnome_vfs_uri_unref (result_item->uri);
383 g_free (result_item);
385 g_list_free (notify_result->result_list);
389 _gnome_vfs_job_destroy_notify_result (GnomeVFSNotifyResult *notify_result)
391 JOB_DEBUG (("%u", notify_result->callback_id));
393 switch (notify_result->type) {
394 case GNOME_VFS_OP_CLOSE:
395 case GNOME_VFS_OP_CREATE:
396 case GNOME_VFS_OP_CREATE_AS_CHANNEL:
397 case GNOME_VFS_OP_CREATE_SYMBOLIC_LINK:
398 case GNOME_VFS_OP_WRITE:
399 case GNOME_VFS_OP_OPEN:
400 case GNOME_VFS_OP_OPEN_AS_CHANNEL:
401 case GNOME_VFS_OP_READ:
402 g_free (notify_result);
405 case GNOME_VFS_OP_FILE_CONTROL:
406 if (notify_result->specifics.file_control.operation_data_destroy_func) {
407 notify_result->specifics.file_control.operation_data_destroy_func (
408 notify_result->specifics.file_control.operation_data);
410 g_free (notify_result);
413 case GNOME_VFS_OP_FIND_DIRECTORY:
414 free_find_directory_notify_result (¬ify_result->specifics.find_directory);
415 g_free (notify_result);
418 case GNOME_VFS_OP_GET_FILE_INFO:
419 free_get_file_info_notify_result (¬ify_result->specifics.get_file_info);
420 g_free (notify_result);
423 case GNOME_VFS_OP_SET_FILE_INFO:
424 gnome_vfs_file_info_unref (notify_result->specifics.set_file_info.info);
425 g_free (notify_result);
428 case GNOME_VFS_OP_LOAD_DIRECTORY:
429 gnome_vfs_file_info_list_free (notify_result->specifics.load_directory.list);
430 g_free (notify_result);
433 case GNOME_VFS_OP_XFER:
434 /* the XFER result is allocated on the stack */
437 case GNOME_VFS_OP_MODULE_CALLBACK:
438 /* the MODULE_CALLBACK result is allocated on the stack */
442 g_assert_not_reached ();
447 /* Entry point for sync notification callback */
449 dispatch_sync_job_callback (gpointer data)
451 GnomeVFSNotifyResult *notify_result;
456 notify_result = (GnomeVFSNotifyResult *) data;
458 _gnome_vfs_async_job_callback_valid (notify_result->callback_id, &valid, &cancelled);
460 /* Even though the notify result is owned by the async thread and persists
461 * all through the notification, we still keep it in the job map to
462 * make cancellation easier.
464 _gnome_vfs_async_job_remove_callback (notify_result->callback_id);
468 switch (notify_result->type) {
469 case GNOME_VFS_OP_CREATE_AS_CHANNEL:
470 dispatch_create_as_channel_callback (notify_result);
472 case GNOME_VFS_OP_OPEN_AS_CHANNEL:
473 dispatch_open_as_channel_callback (notify_result);
475 case GNOME_VFS_OP_XFER:
476 dispatch_xfer_callback (notify_result, cancelled);
478 case GNOME_VFS_OP_MODULE_CALLBACK:
479 dispatch_module_callback (notify_result);
482 g_assert_not_reached ();
486 _gnome_vfs_async_job_map_lock ();
487 job = _gnome_vfs_async_job_map_get_job (notify_result->job_handle);
488 g_mutex_lock (job->job_lock);
489 _gnome_vfs_async_job_map_unlock ();
491 g_assert (job != NULL);
493 JOB_DEBUG (("signalling %u", GPOINTER_TO_UINT (notify_result->job_handle)));
495 /* Signal the async thread that we are done with the notification. */
496 g_cond_signal (job->notify_ack_condition);
497 g_mutex_unlock (job->job_lock);
502 /* Entry point for async notification callback */
504 dispatch_job_callback (gpointer data)
507 GnomeVFSNotifyResult *notify_result;
512 notify_result = (GnomeVFSNotifyResult *) data;
514 JOB_DEBUG (("%u type '%s'", GPOINTER_TO_UINT (notify_result->job_handle),
515 JOB_DEBUG_TYPE (notify_result->type)));
517 _gnome_vfs_async_job_callback_valid (notify_result->callback_id, &valid, &cancelled);
518 _gnome_vfs_async_job_remove_callback (notify_result->callback_id);
521 /* this can happen when gnome vfs is shutting down */
522 JOB_DEBUG (("shutting down: callback %u no longer valid",
523 notify_result->callback_id));
524 _gnome_vfs_job_destroy_notify_result (notify_result);
529 /* cancel the job in progress */
530 JOB_DEBUG (("cancelling job %u %u",
531 GPOINTER_TO_UINT (notify_result->job_handle),
532 notify_result->callback_id));
534 _gnome_vfs_async_job_map_lock ();
536 job = _gnome_vfs_async_job_map_get_job (notify_result->job_handle);
539 g_mutex_lock (job->job_lock);
541 switch (job->op->type) {
542 case GNOME_VFS_OP_OPEN:
543 case GNOME_VFS_OP_OPEN_AS_CHANNEL:
544 case GNOME_VFS_OP_CREATE:
545 case GNOME_VFS_OP_CREATE_AS_CHANNEL:
546 case GNOME_VFS_OP_CREATE_SYMBOLIC_LINK:
548 g_mutex_unlock (job->job_lock);
549 handle_cancelled_open (job);
550 JOB_DEBUG (("handle cancel open job %u",
551 GPOINTER_TO_UINT (notify_result->job_handle)));
553 } /* else drop through */
555 /* Remove job from the job map. */
556 _gnome_vfs_async_job_map_remove_job (job);
557 g_mutex_unlock (job->job_lock);
562 _gnome_vfs_async_job_map_unlock ();
563 _gnome_vfs_job_destroy_notify_result (notify_result);
568 JOB_DEBUG (("executing callback %u", GPOINTER_TO_UINT (notify_result->job_handle)));
570 switch (notify_result->type) {
571 case GNOME_VFS_OP_CLOSE:
572 dispatch_close_callback (notify_result);
574 case GNOME_VFS_OP_CREATE:
575 dispatch_create_callback (notify_result);
577 case GNOME_VFS_OP_CREATE_AS_CHANNEL:
578 dispatch_create_as_channel_callback (notify_result);
580 case GNOME_VFS_OP_CREATE_SYMBOLIC_LINK:
581 dispatch_create_callback (notify_result);
583 case GNOME_VFS_OP_FIND_DIRECTORY:
584 dispatch_find_directory_callback (notify_result);
586 case GNOME_VFS_OP_GET_FILE_INFO:
587 dispatch_get_file_info_callback (notify_result);
589 case GNOME_VFS_OP_LOAD_DIRECTORY:
590 dispatch_load_directory_callback (notify_result);
592 case GNOME_VFS_OP_OPEN:
593 dispatch_open_callback (notify_result);
595 case GNOME_VFS_OP_OPEN_AS_CHANNEL:
596 dispatch_open_as_channel_callback (notify_result);
598 case GNOME_VFS_OP_READ:
599 dispatch_read_callback (notify_result);
601 case GNOME_VFS_OP_SET_FILE_INFO:
602 dispatch_set_file_info_callback (notify_result);
604 case GNOME_VFS_OP_WRITE:
605 dispatch_write_callback (notify_result);
607 case GNOME_VFS_OP_FILE_CONTROL:
608 dispatch_file_control_callback (notify_result);
611 g_assert_not_reached ();
615 JOB_DEBUG (("dispatch callback - done %u", GPOINTER_TO_UINT (notify_result->job_handle)));
616 _gnome_vfs_job_destroy_notify_result (notify_result);
622 _gnome_vfs_job_set (GnomeVFSJob *job,
625 gpointer callback_data)
629 op = g_new (GnomeVFSOp, 1);
631 op->callback = callback;
632 op->callback_data = callback_data;
633 op->context = gnome_vfs_context_new ();
634 op->stack_info = _gnome_vfs_module_callback_get_stack_info ();
636 g_assert (gnome_vfs_context_get_cancellation (op->context) != NULL);
638 JOB_DEBUG (("locking access lock %u, op %d", GPOINTER_TO_UINT (job->job_handle), type));
640 g_mutex_lock (job->job_lock);
642 gnome_vfs_op_destroy (job->op);
644 job->cancelled = FALSE;
646 g_mutex_unlock (job->job_lock);
648 JOB_DEBUG (("%u op type %d, op %p", GPOINTER_TO_UINT (job->job_handle),
649 job->op->type, job->op));
653 _gnome_vfs_job_new (GnomeVFSOpType type, int priority, GFunc callback, gpointer callback_data)
655 GnomeVFSJob *new_job;
657 new_job = g_new0 (GnomeVFSJob, 1);
659 new_job->job_lock = g_mutex_new ();
660 new_job->notify_ack_condition = g_cond_new ();
661 new_job->priority = priority;
663 /* Add the new job into the job hash table. This also assigns
664 * the job a unique id
666 _gnome_vfs_async_job_map_add_job (new_job);
667 _gnome_vfs_job_set (new_job, type, callback, callback_data);
675 _gnome_vfs_job_destroy (GnomeVFSJob *job)
677 JOB_DEBUG (("destroying job %u", GPOINTER_TO_UINT (job->job_handle)));
679 gnome_vfs_op_destroy (job->op);
681 g_mutex_free (job->job_lock);
682 g_cond_free (job->notify_ack_condition);
684 memset (job, 0xaa, sizeof (GnomeVFSJob));
689 JOB_DEBUG (("job %u terminated cleanly", GPOINTER_TO_UINT (job->job_handle)));
693 gnome_vfs_job_get_count (void)
699 gnome_vfs_op_destroy (GnomeVFSOp *op)
706 case GNOME_VFS_OP_CREATE:
707 if (op->specifics.create.uri != NULL) {
708 gnome_vfs_uri_unref (op->specifics.create.uri);
711 case GNOME_VFS_OP_CREATE_AS_CHANNEL:
712 if (op->specifics.create_as_channel.uri != NULL) {
713 gnome_vfs_uri_unref (op->specifics.create_as_channel.uri);
716 case GNOME_VFS_OP_CREATE_SYMBOLIC_LINK:
717 gnome_vfs_uri_unref (op->specifics.create_symbolic_link.uri);
718 g_free (op->specifics.create_symbolic_link.uri_reference);
720 case GNOME_VFS_OP_FIND_DIRECTORY:
721 gnome_vfs_uri_list_free (op->specifics.find_directory.uris);
723 case GNOME_VFS_OP_GET_FILE_INFO:
724 gnome_vfs_uri_list_free (op->specifics.get_file_info.uris);
726 case GNOME_VFS_OP_LOAD_DIRECTORY:
727 if (op->specifics.load_directory.uri != NULL) {
728 gnome_vfs_uri_unref (op->specifics.load_directory.uri);
731 case GNOME_VFS_OP_OPEN:
732 if (op->specifics.open.uri != NULL) {
733 gnome_vfs_uri_unref (op->specifics.open.uri);
736 case GNOME_VFS_OP_OPEN_AS_CHANNEL:
737 if (op->specifics.open_as_channel.uri != NULL) {
738 gnome_vfs_uri_unref (op->specifics.open_as_channel.uri);
741 case GNOME_VFS_OP_SET_FILE_INFO:
742 gnome_vfs_uri_unref (op->specifics.set_file_info.uri);
743 gnome_vfs_file_info_unref (op->specifics.set_file_info.info);
745 case GNOME_VFS_OP_XFER:
746 gnome_vfs_uri_list_free (op->specifics.xfer.source_uri_list);
747 gnome_vfs_uri_list_free (op->specifics.xfer.target_uri_list);
749 case GNOME_VFS_OP_READ:
750 case GNOME_VFS_OP_WRITE:
751 case GNOME_VFS_OP_CLOSE:
752 case GNOME_VFS_OP_READ_WRITE_DONE:
754 case GNOME_VFS_OP_FILE_CONTROL:
755 g_free (op->specifics.file_control.operation);
758 g_warning (_("Unknown op type %u"), op->type);
761 g_assert (gnome_vfs_context_get_cancellation (op->context) != NULL);
763 gnome_vfs_context_free (op->context);
764 _gnome_vfs_module_callback_free_stack_info (op->stack_info);
770 _gnome_vfs_job_go (GnomeVFSJob *job)
772 JOB_DEBUG (("new job %u, op %d, type '%s' unlocking job lock",
773 GPOINTER_TO_UINT (job->job_handle), job->op->type,
774 JOB_DEBUG_TYPE (job->op->type)));
776 /* Fire up the async job thread. */
777 if (!_gnome_vfs_job_schedule (job)) {
778 g_warning ("Cannot schedule this job.");
779 _gnome_vfs_job_destroy (job);
784 #define DEFAULT_BUFFER_SIZE 16384
787 serve_channel_read (GnomeVFSHandle *handle,
788 GIOChannel *channel_in,
789 GIOChannel *channel_out,
790 gulong advised_block_size,
791 GnomeVFSContext *context)
794 guint filled_bytes_in_buffer;
795 guint written_bytes_in_buffer;
796 guint current_buffer_size;
798 if (advised_block_size == 0) {
799 advised_block_size = DEFAULT_BUFFER_SIZE;
802 current_buffer_size = advised_block_size;
803 buffer = g_malloc(current_buffer_size);
804 filled_bytes_in_buffer = 0;
805 written_bytes_in_buffer = 0;
808 GnomeVFSResult result;
810 GnomeVFSFileSize bytes_read;
812 restart_toplevel_loop:
814 g_assert(filled_bytes_in_buffer <= current_buffer_size);
815 g_assert(written_bytes_in_buffer == 0);
817 result = gnome_vfs_read_cancellable (handle,
818 (char *) buffer + filled_bytes_in_buffer,
819 MIN (advised_block_size, (current_buffer_size
820 - filled_bytes_in_buffer)),
821 &bytes_read, context);
823 if (result == GNOME_VFS_ERROR_INTERRUPTED) {
825 } else if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) {
829 filled_bytes_in_buffer += bytes_read;
831 if (filled_bytes_in_buffer == 0) {
835 g_assert(written_bytes_in_buffer <= filled_bytes_in_buffer);
837 if (gnome_vfs_context_check_cancellation(context)) {
841 while (written_bytes_in_buffer < filled_bytes_in_buffer) {
844 /* channel_out is nonblocking; if we get
845 EAGAIN (G_IO_STATUS_AGAIN) then we tried to
846 write but the pipe was full. In this case, we
847 want to enlarge our buffer and go back to
848 reading for one iteration, so we can keep
849 collecting data while the main thread is
852 io_result = g_io_channel_write_chars
854 (char *) buffer + written_bytes_in_buffer,
855 filled_bytes_in_buffer - written_bytes_in_buffer,
856 &bytes_written, NULL);
858 written_bytes_in_buffer += bytes_written;
860 if (gnome_vfs_context_check_cancellation(context)) {
864 if (io_result == G_IO_STATUS_AGAIN) {
865 /* if bytes_read == 0 then we reached
866 EOF so there's no point reading
867 again. So turn off nonblocking and
868 do a blocking write next time through. */
869 if (bytes_read == 0) {
872 fd = g_io_channel_unix_get_fd (channel_out);
874 clr_fl (fd, O_NONBLOCK);
876 if (written_bytes_in_buffer > 0) {
877 /* Need to shift the unwritten bytes
878 to the start of the buffer */
880 (char *) buffer + written_bytes_in_buffer,
881 filled_bytes_in_buffer - written_bytes_in_buffer);
882 filled_bytes_in_buffer =
883 filled_bytes_in_buffer - written_bytes_in_buffer;
885 written_bytes_in_buffer = 0;
888 /* If the buffer is more than half
889 full, double its size */
890 if (filled_bytes_in_buffer * 2 > current_buffer_size) {
891 current_buffer_size *= 2;
892 buffer = g_realloc(buffer, current_buffer_size);
895 /* Leave this loop, start reading again */
896 goto restart_toplevel_loop;
898 } /* end of else (bytes_read != 0) */
900 } else if (io_result != G_IO_STATUS_NORMAL || bytes_written == 0) {
905 g_assert(written_bytes_in_buffer == filled_bytes_in_buffer);
907 /* Reset, we wrote everything */
908 written_bytes_in_buffer = 0;
909 filled_bytes_in_buffer = 0;
914 g_io_channel_shutdown (channel_out, TRUE, NULL);
915 g_io_channel_unref (channel_out);
916 g_io_channel_unref (channel_in);
920 serve_channel_write (GnomeVFSHandle *handle,
921 GIOChannel *channel_in,
922 GIOChannel *channel_out,
923 GnomeVFSContext *context)
925 gchar buffer[DEFAULT_BUFFER_SIZE];
928 buffer_size = DEFAULT_BUFFER_SIZE;
931 GnomeVFSResult result;
934 gsize bytes_to_write;
935 GnomeVFSFileSize bytes_written;
938 io_result = g_io_channel_read_chars (channel_in, buffer, buffer_size,
941 if (io_result == G_IO_STATUS_AGAIN)
943 if (io_result != G_IO_STATUS_NORMAL || bytes_read == 0)
947 bytes_to_write = bytes_read;
948 while (bytes_to_write > 0) {
949 result = gnome_vfs_write_cancellable (handle,
954 if (result == GNOME_VFS_ERROR_INTERRUPTED) {
958 if (result != GNOME_VFS_OK || bytes_written == 0) {
963 bytes_to_write -= bytes_written;
968 g_io_channel_shutdown (channel_in, TRUE, NULL);
969 g_io_channel_unref (channel_in);
970 g_io_channel_unref (channel_out);
973 /* Job execution. This is performed by the slave thread. */
976 execute_open (GnomeVFSJob *job)
978 GnomeVFSResult result;
979 GnomeVFSHandle *handle;
980 GnomeVFSOpenOp *open_op;
981 GnomeVFSNotifyResult *notify_result;
983 open_op = &job->op->specifics.open;
985 if (open_op->uri == NULL) {
986 result = GNOME_VFS_ERROR_INVALID_URI;
988 result = gnome_vfs_open_uri_cancellable (&handle, open_op->uri,
991 job->handle = handle;
994 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
995 notify_result->job_handle = job->job_handle;
996 notify_result->type = job->op->type;
997 notify_result->specifics.open.result = result;
998 notify_result->specifics.open.callback = (GnomeVFSAsyncOpenCallback) job->op->callback;
999 notify_result->specifics.open.callback_data = job->op->callback_data;
1001 if (result != GNOME_VFS_OK) {
1002 /* if the open failed, just drop the job */
1006 job_oneway_notify (job, notify_result);
1010 execute_open_as_channel (GnomeVFSJob *job)
1012 GnomeVFSResult result;
1013 GnomeVFSHandle *handle;
1014 GnomeVFSOpenAsChannelOp *open_as_channel_op;
1015 GnomeVFSOpenMode open_mode;
1016 GIOChannel *channel_in, *channel_out;
1018 GnomeVFSNotifyResult *notify_result;
1020 open_as_channel_op = &job->op->specifics.open_as_channel;
1022 if (open_as_channel_op->uri == NULL) {
1023 result = GNOME_VFS_ERROR_INVALID_URI;
1025 result = gnome_vfs_open_uri_cancellable
1027 open_as_channel_op->uri,
1028 open_as_channel_op->open_mode,
1032 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1033 notify_result->job_handle = job->job_handle;
1034 notify_result->type = job->op->type;
1035 notify_result->specifics.open_as_channel.result = result;
1036 notify_result->specifics.open_as_channel.callback =
1037 (GnomeVFSAsyncOpenAsChannelCallback) job->op->callback;
1038 notify_result->specifics.open_as_channel.callback_data = job->op->callback_data;
1040 if (result != GNOME_VFS_OK) {
1041 /* if the open failed, just drop the job */
1043 job_oneway_notify (job, notify_result);
1047 if (pipe (pipefd) < 0) {
1048 g_warning (_("Cannot create pipe for open GIOChannel: %s"),
1049 g_strerror (errno));
1050 notify_result->specifics.open_as_channel.result = GNOME_VFS_ERROR_INTERNAL;
1051 /* if the open failed, just drop the job */
1053 job_oneway_notify (job, notify_result);
1057 /* Set up the pipe for nonblocking writes, so if the main
1058 * thread is blocking for some reason the slave can keep
1061 set_fl (pipefd[1], O_NONBLOCK);
1063 channel_in = g_io_channel_unix_new (pipefd[0]);
1064 channel_out = g_io_channel_unix_new (pipefd[1]);
1066 open_mode = open_as_channel_op->open_mode;
1068 if (open_mode & GNOME_VFS_OPEN_READ) {
1069 notify_result->specifics.open_as_channel.channel = channel_in;
1071 notify_result->specifics.open_as_channel.channel = channel_out;
1074 notify_result->specifics.open_as_channel.result = GNOME_VFS_OK;
1076 job_notify (job, notify_result);
1078 if (open_mode & GNOME_VFS_OPEN_READ) {
1079 serve_channel_read (handle, channel_in, channel_out,
1080 open_as_channel_op->advised_block_size,
1083 serve_channel_write (handle, channel_in, channel_out,
1089 execute_create (GnomeVFSJob *job)
1091 GnomeVFSResult result;
1092 GnomeVFSHandle *handle;
1093 GnomeVFSCreateOp *create_op;
1094 GnomeVFSNotifyResult *notify_result;
1096 create_op = &job->op->specifics.create;
1098 if (create_op->uri == NULL) {
1099 result = GNOME_VFS_ERROR_INVALID_URI;
1101 result = gnome_vfs_create_uri_cancellable
1104 create_op->open_mode,
1105 create_op->exclusive,
1109 job->handle = handle;
1112 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1113 notify_result->job_handle = job->job_handle;
1114 notify_result->type = job->op->type;
1115 notify_result->specifics.create.result = result;
1116 notify_result->specifics.create.callback = (GnomeVFSAsyncCreateCallback) job->op->callback;
1117 notify_result->specifics.create.callback_data = job->op->callback_data;
1119 if (result != GNOME_VFS_OK) {
1120 /* if the open failed, just drop the job */
1124 job_oneway_notify (job, notify_result);
1128 execute_create_symbolic_link (GnomeVFSJob *job)
1130 GnomeVFSResult result;
1131 GnomeVFSCreateLinkOp *create_op;
1132 GnomeVFSNotifyResult *notify_result;
1134 create_op = &job->op->specifics.create_symbolic_link;
1136 result = gnome_vfs_create_symbolic_link_cancellable
1138 create_op->uri_reference,
1141 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1142 notify_result->job_handle = job->job_handle;
1143 notify_result->type = job->op->type;
1144 notify_result->specifics.create.result = result;
1145 notify_result->specifics.create.callback = (GnomeVFSAsyncCreateCallback) job->op->callback;
1146 notify_result->specifics.create.callback_data = job->op->callback_data;
1148 if (result != GNOME_VFS_OK) {
1149 /* if the open failed, just drop the job */
1153 job_oneway_notify (job, notify_result);
1157 execute_create_as_channel (GnomeVFSJob *job)
1159 GnomeVFSResult result;
1160 GnomeVFSHandle *handle;
1161 GnomeVFSCreateAsChannelOp *create_as_channel_op;
1162 GIOChannel *channel_in, *channel_out;
1164 GnomeVFSNotifyResult *notify_result;
1166 create_as_channel_op = &job->op->specifics.create_as_channel;
1168 if (create_as_channel_op->uri == NULL) {
1169 result = GNOME_VFS_ERROR_INVALID_URI;
1171 result = gnome_vfs_open_uri_cancellable
1173 create_as_channel_op->uri,
1174 create_as_channel_op->open_mode,
1178 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1179 notify_result->job_handle = job->job_handle;
1180 notify_result->type = job->op->type;
1181 notify_result->specifics.create_as_channel.result = result;
1182 notify_result->specifics.create_as_channel.callback = (GnomeVFSAsyncCreateAsChannelCallback) job->op->callback;
1183 notify_result->specifics.create_as_channel.callback_data = job->op->callback_data;
1185 if (result != GNOME_VFS_OK) {
1186 /* if the open failed, just drop the job */
1188 job_oneway_notify (job, notify_result);
1192 if (pipe (pipefd) < 0) {
1193 g_warning (_("Cannot create pipe for open GIOChannel: %s"),
1194 g_strerror (errno));
1195 notify_result->specifics.create_as_channel.result = GNOME_VFS_ERROR_INTERNAL;
1196 /* if the open failed, just drop the job */
1198 job_oneway_notify (job, notify_result);
1202 channel_in = g_io_channel_unix_new (pipefd[0]);
1203 channel_out = g_io_channel_unix_new (pipefd[1]);
1205 notify_result->specifics.create_as_channel.channel = channel_out;
1207 job_notify (job, notify_result);
1209 serve_channel_write (handle, channel_in, channel_out, job->op->context);
1213 execute_close (GnomeVFSJob *job)
1215 GnomeVFSCloseOp *close_op;
1216 GnomeVFSNotifyResult *notify_result;
1218 close_op = &job->op->specifics.close;
1220 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1221 notify_result->job_handle = job->job_handle;
1222 notify_result->type = job->op->type;
1223 notify_result->specifics.close.callback = (GnomeVFSAsyncCloseCallback) job->op->callback;
1224 notify_result->specifics.close.callback_data = job->op->callback_data;
1225 notify_result->specifics.close.result
1226 = gnome_vfs_close_cancellable (job->handle, job->op->context);
1228 job_oneway_notify (job, notify_result);
1232 execute_read (GnomeVFSJob *job)
1234 GnomeVFSReadOp *read_op;
1235 GnomeVFSNotifyResult *notify_result;
1237 read_op = &job->op->specifics.read;
1239 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1240 notify_result->job_handle = job->job_handle;
1241 notify_result->type = job->op->type;
1242 notify_result->specifics.read.callback = (GnomeVFSAsyncReadCallback) job->op->callback;
1243 notify_result->specifics.read.callback_data = job->op->callback_data;
1244 notify_result->specifics.read.buffer = read_op->buffer;
1245 notify_result->specifics.read.num_bytes = read_op->num_bytes;
1247 notify_result->specifics.read.result = gnome_vfs_read_cancellable (job->handle,
1250 ¬ify_result->specifics.read.bytes_read,
1253 job->op->type = GNOME_VFS_OP_READ_WRITE_DONE;
1255 job_oneway_notify (job, notify_result);
1259 execute_write (GnomeVFSJob *job)
1261 GnomeVFSWriteOp *write_op;
1262 GnomeVFSNotifyResult *notify_result;
1264 write_op = &job->op->specifics.write;
1266 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1267 notify_result->job_handle = job->job_handle;
1268 notify_result->type = job->op->type;
1269 notify_result->specifics.write.callback = (GnomeVFSAsyncWriteCallback) job->op->callback;
1270 notify_result->specifics.write.callback_data = job->op->callback_data;
1271 notify_result->specifics.write.buffer = write_op->buffer;
1272 notify_result->specifics.write.num_bytes = write_op->num_bytes;
1274 notify_result->specifics.write.result = gnome_vfs_write_cancellable (job->handle,
1276 write_op->num_bytes,
1277 ¬ify_result->specifics.write.bytes_written,
1280 job->op->type = GNOME_VFS_OP_READ_WRITE_DONE;
1282 job_oneway_notify (job, notify_result);
1286 execute_get_file_info (GnomeVFSJob *job)
1288 GnomeVFSGetFileInfoOp *get_file_info_op;
1290 GnomeVFSGetFileInfoResult *result_item;
1291 GnomeVFSNotifyResult *notify_result;
1293 get_file_info_op = &job->op->specifics.get_file_info;
1295 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1296 notify_result->job_handle = job->job_handle;
1297 notify_result->type = job->op->type;
1298 notify_result->specifics.get_file_info.callback =
1299 (GnomeVFSAsyncGetFileInfoCallback) job->op->callback;
1300 notify_result->specifics.get_file_info.callback_data = job->op->callback_data;
1302 for (p = get_file_info_op->uris; p != NULL; p = p->next) {
1303 result_item = g_new (GnomeVFSGetFileInfoResult, 1);
1305 result_item->uri = gnome_vfs_uri_ref (p->data);
1306 result_item->file_info = gnome_vfs_file_info_new ();
1308 result_item->result = gnome_vfs_get_file_info_uri_cancellable
1310 result_item->file_info,
1311 get_file_info_op->options,
1314 notify_result->specifics.get_file_info.result_list =
1315 g_list_prepend (notify_result->specifics.get_file_info.result_list, result_item);
1317 notify_result->specifics.get_file_info.result_list =
1318 g_list_reverse (notify_result->specifics.get_file_info.result_list);
1320 job_oneway_notify (job, notify_result);
1324 execute_set_file_info (GnomeVFSJob *job)
1326 GnomeVFSSetFileInfoOp *set_file_info_op;
1327 GnomeVFSURI *parent_uri, *uri_after;
1328 GnomeVFSNotifyResult *notify_result;
1330 set_file_info_op = &job->op->specifics.set_file_info;
1332 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1333 notify_result->job_handle = job->job_handle;
1334 notify_result->type = job->op->type;
1335 notify_result->specifics.set_file_info.callback =
1336 (GnomeVFSAsyncSetFileInfoCallback) job->op->callback;
1337 notify_result->specifics.set_file_info.callback_data =
1338 job->op->callback_data;
1340 notify_result->specifics.set_file_info.set_file_info_result =
1341 gnome_vfs_set_file_info_cancellable (set_file_info_op->uri,
1342 set_file_info_op->info, set_file_info_op->mask,
1345 /* Get the new URI after the set_file_info. The name may have
1349 if (notify_result->specifics.set_file_info.set_file_info_result == GNOME_VFS_OK
1350 && (set_file_info_op->mask & GNOME_VFS_SET_FILE_INFO_NAME) != 0) {
1351 parent_uri = gnome_vfs_uri_get_parent (set_file_info_op->uri);
1352 if (parent_uri != NULL) {
1353 uri_after = gnome_vfs_uri_append_file_name
1354 (parent_uri, set_file_info_op->info->name);
1355 gnome_vfs_uri_unref (parent_uri);
1358 if (uri_after == NULL) {
1359 uri_after = set_file_info_op->uri;
1360 gnome_vfs_uri_ref (uri_after);
1363 notify_result->specifics.set_file_info.info = gnome_vfs_file_info_new ();
1364 if (uri_after == NULL) {
1365 notify_result->specifics.set_file_info.get_file_info_result
1366 = GNOME_VFS_ERROR_INVALID_URI;
1368 notify_result->specifics.set_file_info.get_file_info_result
1369 = gnome_vfs_get_file_info_uri_cancellable
1371 notify_result->specifics.set_file_info.info,
1372 set_file_info_op->options,
1374 gnome_vfs_uri_unref (uri_after);
1377 job_oneway_notify (job, notify_result);
1381 execute_find_directory (GnomeVFSJob *job)
1383 GnomeVFSFindDirectoryOp *find_directory_op;
1385 GnomeVFSFindDirectoryResult *result_item;
1386 GnomeVFSNotifyResult *notify_result;
1388 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1389 notify_result->job_handle = job->job_handle;
1390 notify_result->type = job->op->type;
1391 notify_result->specifics.find_directory.callback
1392 = (GnomeVFSAsyncFindDirectoryCallback) job->op->callback;
1393 notify_result->specifics.find_directory.callback_data = job->op->callback_data;
1395 find_directory_op = &job->op->specifics.find_directory;
1396 for (p = find_directory_op->uris; p != NULL; p = p->next) {
1397 result_item = g_new0 (GnomeVFSFindDirectoryResult, 1);
1399 result_item->result = gnome_vfs_find_directory_cancellable
1400 ((GnomeVFSURI *) p->data,
1401 find_directory_op->kind,
1403 find_directory_op->create_if_needed,
1404 find_directory_op->find_if_needed,
1405 find_directory_op->permissions,
1407 notify_result->specifics.find_directory.result_list =
1408 g_list_prepend (notify_result->specifics.find_directory.result_list, result_item);
1411 notify_result->specifics.find_directory.result_list =
1412 g_list_reverse (notify_result->specifics.find_directory.result_list);
1414 job_oneway_notify (job, notify_result);
1418 load_directory_details (GnomeVFSJob *job)
1420 GnomeVFSLoadDirectoryOp *load_directory_op;
1421 GnomeVFSDirectoryHandle *handle;
1422 GList *directory_list;
1423 GnomeVFSFileInfo *info;
1424 GnomeVFSResult result;
1426 GnomeVFSNotifyResult *notify_result;
1428 JOB_DEBUG (("%u", GPOINTER_TO_UINT (job->job_handle)));
1429 load_directory_op = &job->op->specifics.load_directory;
1431 if (load_directory_op->uri == NULL) {
1432 result = GNOME_VFS_ERROR_INVALID_URI;
1434 result = gnome_vfs_directory_open_from_uri_cancellable
1436 load_directory_op->uri,
1437 load_directory_op->options,
1441 if (result != GNOME_VFS_OK) {
1442 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1443 notify_result->job_handle = job->job_handle;
1444 notify_result->type = job->op->type;
1445 notify_result->specifics.load_directory.result = result;
1446 notify_result->specifics.load_directory.callback =
1447 (GnomeVFSAsyncDirectoryLoadCallback) job->op->callback;
1448 notify_result->specifics.load_directory.callback_data = job->op->callback_data;
1449 job_oneway_notify (job, notify_result);
1453 directory_list = NULL;
1457 if (gnome_vfs_context_check_cancellation (job->op->context)) {
1458 JOB_DEBUG (("cancelled, bailing %u",
1459 GPOINTER_TO_UINT (job->job_handle)));
1460 gnome_vfs_file_info_list_free (directory_list);
1461 directory_list = NULL;
1462 result = GNOME_VFS_ERROR_CANCELLED;
1466 info = gnome_vfs_file_info_new ();
1468 result = gnome_vfs_directory_read_next_cancellable
1469 (handle, info, job->op->context);
1471 if (result == GNOME_VFS_OK) {
1472 directory_list = g_list_prepend (directory_list, info);
1475 gnome_vfs_file_info_unref (info);
1478 if (count == load_directory_op->items_per_notification
1479 || result != GNOME_VFS_OK) {
1481 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1482 notify_result->job_handle = job->job_handle;
1483 notify_result->type = job->op->type;
1484 notify_result->specifics.load_directory.result = result;
1485 notify_result->specifics.load_directory.entries_read = count;
1486 notify_result->specifics.load_directory.list =
1487 g_list_reverse (directory_list);
1488 notify_result->specifics.load_directory.callback =
1489 (GnomeVFSAsyncDirectoryLoadCallback) job->op->callback;
1490 notify_result->specifics.load_directory.callback_data =
1491 job->op->callback_data;
1493 job_oneway_notify (job, notify_result);
1496 directory_list = NULL;
1498 if (result != GNOME_VFS_OK) {
1504 g_assert (directory_list == NULL);
1505 gnome_vfs_directory_close (handle);
1509 execute_load_directory (GnomeVFSJob *job)
1511 GnomeVFSLoadDirectoryOp *load_directory_op;
1513 load_directory_op = &job->op->specifics.load_directory;
1515 load_directory_details (job);
1519 xfer_callback (GnomeVFSXferProgressInfo *info,
1523 GnomeVFSNotifyResult notify_result;
1525 job = (GnomeVFSJob *) data;
1527 /* xfer is fully synchronous, just allocate the notify result struct on the stack */
1528 notify_result.job_handle = job->job_handle;
1529 notify_result.callback_id = 0;
1530 notify_result.cancelled = FALSE;
1531 notify_result.type = job->op->type;
1532 notify_result.specifics.xfer.progress_info = info;
1533 notify_result.specifics.xfer.callback = (GnomeVFSAsyncXferProgressCallback) job->op->callback;
1534 notify_result.specifics.xfer.callback_data = job->op->callback_data;
1536 job_notify (job, ¬ify_result);
1538 /* Pass the value returned from the callback in the master thread. */
1539 return notify_result.specifics.xfer.reply;
1543 execute_xfer (GnomeVFSJob *job)
1545 GnomeVFSXferOp *xfer_op;
1546 GnomeVFSResult result;
1547 GnomeVFSXferProgressInfo info;
1548 GnomeVFSNotifyResult notify_result;
1550 xfer_op = &job->op->specifics.xfer;
1552 result = _gnome_vfs_xfer_private (xfer_op->source_uri_list,
1553 xfer_op->target_uri_list,
1554 xfer_op->xfer_options,
1555 xfer_op->error_mode,
1556 xfer_op->overwrite_mode,
1559 xfer_op->progress_sync_callback,
1560 xfer_op->sync_callback_data);
1562 /* If the xfer functions returns an error now, something really bad
1563 * must have happened.
1565 if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_INTERRUPTED) {
1567 info.status = GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR;
1568 info.vfs_status = result;
1569 info.phase = GNOME_VFS_XFER_PHASE_INITIAL;
1570 info.source_name = NULL;
1571 info.target_name = NULL;
1572 info.file_index = 0;
1573 info.files_total = 0;
1574 info.bytes_total = 0;
1576 info.bytes_copied = 0;
1577 info.total_bytes_copied = 0;
1579 notify_result.job_handle = job->job_handle;
1580 notify_result.callback_id = 0;
1581 notify_result.cancelled = FALSE;
1582 notify_result.type = job->op->type;
1583 notify_result.specifics.xfer.progress_info = &info;
1584 notify_result.specifics.xfer.callback = (GnomeVFSAsyncXferProgressCallback) job->op->callback;
1585 notify_result.specifics.xfer.callback_data = job->op->callback_data;
1587 job_notify (job, ¬ify_result);
1592 execute_file_control (GnomeVFSJob *job)
1594 GnomeVFSFileControlOp *file_control_op;
1595 GnomeVFSNotifyResult *notify_result;
1597 file_control_op = &job->op->specifics.file_control;
1599 notify_result = g_new0 (GnomeVFSNotifyResult, 1);
1600 notify_result->job_handle = job->job_handle;
1601 notify_result->type = job->op->type;
1602 notify_result->specifics.file_control.callback = (GnomeVFSAsyncFileControlCallback) job->op->callback;
1603 notify_result->specifics.file_control.callback_data = job->op->callback_data;
1604 notify_result->specifics.file_control.operation_data = file_control_op->operation_data;
1605 notify_result->specifics.file_control.operation_data_destroy_func = file_control_op->operation_data_destroy_func;
1607 notify_result->specifics.file_control.result = gnome_vfs_file_control_cancellable (job->handle,
1608 file_control_op->operation,
1609 file_control_op->operation_data,
1612 job->op->type = GNOME_VFS_OP_FILE_CONTROL;
1614 job_oneway_notify (job, notify_result);
1619 * _gnome_vfs_job_execute:
1620 * @job: the job to execute
1622 * This function is called by the slave thread to execute
1623 * the job - all work performed by a thread starts here.
1626 _gnome_vfs_job_execute (GnomeVFSJob *job)
1630 id = GPOINTER_TO_UINT (job->job_handle);
1632 JOB_DEBUG (("exec job %u", id));
1634 if (!job->cancelled) {
1635 set_current_job (job);
1637 JOB_DEBUG (("executing %u %d type %s", id, job->op->type,
1638 JOB_DEBUG_TYPE (job->op->type)));
1640 switch (job->op->type) {
1641 case GNOME_VFS_OP_OPEN:
1644 case GNOME_VFS_OP_OPEN_AS_CHANNEL:
1645 execute_open_as_channel (job);
1647 case GNOME_VFS_OP_CREATE:
1648 execute_create (job);
1650 case GNOME_VFS_OP_CREATE_AS_CHANNEL:
1651 execute_create_as_channel (job);
1653 case GNOME_VFS_OP_CREATE_SYMBOLIC_LINK:
1654 execute_create_symbolic_link (job);
1656 case GNOME_VFS_OP_CLOSE:
1657 execute_close (job);
1659 case GNOME_VFS_OP_READ:
1662 case GNOME_VFS_OP_WRITE:
1663 execute_write (job);
1665 case GNOME_VFS_OP_LOAD_DIRECTORY:
1666 execute_load_directory (job);
1668 case GNOME_VFS_OP_FIND_DIRECTORY:
1669 execute_find_directory (job);
1671 case GNOME_VFS_OP_XFER:
1674 case GNOME_VFS_OP_GET_FILE_INFO:
1675 execute_get_file_info (job);
1677 case GNOME_VFS_OP_SET_FILE_INFO:
1678 execute_set_file_info (job);
1680 case GNOME_VFS_OP_FILE_CONTROL:
1681 execute_file_control (job);
1684 g_warning (_("Unknown job kind %u"), job->op->type);
1687 /* NB. 'job' is quite probably invalid now */
1688 clear_current_job ();
1690 switch (job->op->type) {
1691 case GNOME_VFS_OP_READ:
1692 case GNOME_VFS_OP_WRITE:
1693 job->op->type = GNOME_VFS_OP_READ_WRITE_DONE;
1700 JOB_DEBUG (("done job %u", id));
1704 _gnome_vfs_job_module_cancel (GnomeVFSJob *job)
1706 GnomeVFSCancellation *cancellation;
1708 JOB_DEBUG (("%u", GPOINTER_TO_UINT (job->job_handle)));
1710 cancellation = gnome_vfs_context_get_cancellation (job->op->context);
1711 if (cancellation != NULL) {
1712 JOB_DEBUG (("cancelling %u", GPOINTER_TO_UINT (job->job_handle)));
1713 gnome_vfs_cancellation_cancel (cancellation);
1716 #ifdef OLD_CONTEXT_DEPRECATED
1717 gnome_vfs_context_emit_message (job->op->context, _("Operation stopped"));
1718 #endif /* OLD_CONTEXT_DEPRECATED */
1720 /* Since we are cancelling, we won't have anyone respond to notifications;
1721 * set the expectations right.
1723 JOB_DEBUG (("done %u", GPOINTER_TO_UINT (job->job_handle)));
1727 set_current_job (GnomeVFSJob *job)
1729 /* There shouldn't have been anything here. */
1730 g_assert (g_static_private_get (&job_private) == NULL);
1732 g_static_private_set (&job_private, job, NULL);
1734 _gnome_vfs_module_callback_use_stack_info (job->op->stack_info);
1735 _gnome_vfs_module_callback_set_in_async_thread (TRUE);
1739 clear_current_job (void)
1741 g_static_private_set (&job_private, NULL, NULL);
1743 _gnome_vfs_module_callback_clear_stacks ();
1747 _gnome_vfs_get_current_context (GnomeVFSContext **context)
1751 g_return_if_fail (context != NULL);
1753 job = g_static_private_get (&job_private);
1756 *context = job->op->context;
1763 _gnome_vfs_dispatch_module_callback (GnomeVFSAsyncModuleCallback callback,
1764 gconstpointer in, gsize in_size,
1765 gpointer out, gsize out_size,
1767 GnomeVFSModuleCallbackResponse response,
1768 gpointer response_data)
1771 GnomeVFSNotifyResult notify_result;
1773 job = g_static_private_get (&job_private);
1775 g_return_if_fail (job != NULL);
1777 memset (¬ify_result, 0, sizeof (notify_result));
1779 notify_result.job_handle = job->job_handle;
1781 notify_result.type = GNOME_VFS_OP_MODULE_CALLBACK;
1783 notify_result.specifics.callback.callback = callback;
1784 notify_result.specifics.callback.user_data = user_data;
1785 notify_result.specifics.callback.in = in;
1786 notify_result.specifics.callback.in_size = in_size;
1787 notify_result.specifics.callback.out = out;
1788 notify_result.specifics.callback.out_size = out_size;
1789 notify_result.specifics.callback.out = out;
1790 notify_result.specifics.callback.out_size = out_size;
1791 notify_result.specifics.callback.response = response;
1792 notify_result.specifics.callback.response_data = response_data;
1794 job_notify (job, ¬ify_result);