2
/* GVFS gphoto2 file system driver
4
* Copyright (C) 2007-2008 Red Hat, Inc.
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2 of the License, or (at your option) any later version.
11
* This 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
* Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General
17
* Public License along with this library; if not, write to the
18
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19
* Boston, MA 02111-1307, USA.
21
* Author: David Zeuthen <davidz@redhat.com>
26
#include <sys/types.h>
34
#include <glib/gstdio.h>
35
#include <glib/gi18n.h>
39
#include <gudev/gudev.h>
40
#elif defined(HAVE_HAL)
42
#include <dbus/dbus.h>
44
#error Needs hal or gudev
48
#include "gvfsbackendgphoto2.h"
49
#include "gvfsjobopenforread.h"
50
#include "gvfsjobopeniconforread.h"
51
#include "gvfsjobread.h"
52
#include "gvfsjobseekread.h"
53
#include "gvfsjobqueryinfo.h"
54
#include "gvfsjobenumerate.h"
55
#include "gvfsjobsetdisplayname.h"
56
#include "gvfsjobopenforwrite.h"
57
#include "gvfsjobwrite.h"
58
#include "gvfsjobclosewrite.h"
59
#include "gvfsjobcreatemonitor.h"
60
#include "gvfsjobunmount.h"
61
#include "gvfsmonitor.h"
62
#include "gvfsjobseekwrite.h"
65
/* showing debug traces */
67
#define DEBUG_SHOW_TRACES 1
70
/* showing libgphoto2 output */
72
#define DEBUG_SHOW_LIBGPHOTO2_OUTPUT 1
75
/* use this to disable caching */
77
#define DEBUG_NO_CACHING 1
80
/*--------------------------------------------------------------------------------------------------------------*/
85
* - it's in; we support writing. yay.
86
* - though there's no way to rename an non-empty folder yet
87
* - there's an assumption, for caching, that the device won't
88
* be able to put files while we're using it. May have to
89
* revisit that if such devices exist.
90
* - one solution: make cache items valid for only five seconds or something
92
* - Note that most PTP devices (e.g. digital cameras) don't support writing
93
* - Most MTP devices (e.g. digital audio players) do
95
* - However, some MTP devices are just busted when using ~ backup
96
* style; see below. This is with my (davidz) Sandisk Sansa
97
* e250. This is probably a firmware bug; when investigating
98
* libgphoto2 reports everything as peachy.
101
* /home/davidz/.gvfs/gphoto2 mount on usb%3A001,051/foo
106
* -rw------- 1 davidz davidz 2 2008-03-02 13:22 a
107
* -rw------- 1 davidz davidz 2 2008-03-02 13:22 b
115
* -rw------- 1 davidz davidz 2 2008-03-02 13:22 a
120
* See, this worked fine.. Now see what happens if we
121
* use different files names
123
* $ echo a > file.txt
124
* $ echo b > file.txt~
127
* -rw------- 1 davidz davidz 2 2008-03-02 13:22 file.txt
128
* -rw------- 1 davidz davidz 2 2008-03-02 13:22 file.txt~
133
* $ mv file.txt~ file.txt
136
* -rw------- 1 davidz davidz 0 1969-12-31 18:59 file.txt
140
* Awesome. I hate hardware.
142
* - This is a bit bad as it affects most text editors (vim, emacs,
143
* gedit) and it actually results in data loss. However, there's
144
* little we can do about it.
146
* - Would be nice to test this on other MTP devices to verify
147
* it's indeed a firmware bug in the Sansa Sandisk e250.
149
* - This shouldn't affect stuff like Banshee or Rhythmbox using
150
* this backend for MTP support though; despite this bug basic
151
* file operations works nicely.
152
* - http://bugzilla.gnome.org/show_bug.cgi?id=520121
154
* - Need to test this with a native gio version of gedit that should
155
* use replace() directly instead of fooling around with ~-style
158
* - adding a payload cache don't make much sense as libgphoto2 has a LRU cache already
159
* - (see comment in the do_close_write() function)
161
* - Support PTP/IP devices nicely
162
* - Need hardware for testing
163
* - Should actually work out of the box; just try mounting e.g.
164
* gphoto2://[ptpip:<something]/ from either Nautilus or via
166
* - Need to automatically unmount when the device stops answering
167
* - May need authentication bits
168
* - Need integration into network://
169
* - does such devices use DNS-SD or UPNP?
173
struct _GVfsBackendGphoto2
175
GVfsBackend parent_instance;
177
/* a gphoto2 specific identifier for the gphoto2 camera such as usb:001,041 */
182
/* see comment in ensure_ignore_prefix() */
186
GUdevClient *gudev_client;
187
GUdevDevice *udev_device;
188
#elif defined(HAVE_HAL)
189
DBusConnection *dbus_connection;
190
LibHalContext *hal_ctx;
196
/* whether we can write to the device */
198
/* whether we can delete files from to the device */
201
/* This lock protects all members in this class that are not
202
* used both on the main thread and on the IO thread.
204
* It is used, among other places, in the try_* functions to return
205
* already cached data quickly (to e.g. enumerate and get file info
206
* while we're reading or writing a file from the device).
208
* Must only be held for very short amounts of time (e.g. no IO).
214
/* free_space is set to -1 if we don't know or have modified the
215
* device since last time we read it. If -1 we can't do
216
* try_query_fs_info() and will fall back to do_query_fs_info().
221
/* fully qualified path -> GFileInfo */
222
GHashTable *info_cache;
224
/* dir name -> CameraList of (sub-) directory names in given directory */
225
GHashTable *dir_name_cache;
227
/* dir name -> CameraList of file names in given directory */
228
GHashTable *file_name_cache;
230
/* monitors (only used on the IO thread) */
231
GList *dir_monitor_proxies;
232
GList *file_monitor_proxies;
234
/* list of open read handles (only used on the IO thread) */
235
GList *open_read_handles;
237
/* list of open write handles (only used on the IO thread) */
238
GList *open_write_handles;
241
G_DEFINE_TYPE (GVfsBackendGphoto2, g_vfs_backend_gphoto2, G_VFS_TYPE_BACKEND);
243
/* ------------------------------------------------------------------------------------------------- */
246
/* this is the path of the dir/file including ignore_prefix */
248
GVfsMonitor *vfs_monitor;
252
monitor_proxy_free (MonitorProxy *proxy)
254
g_free (proxy->path);
255
/* vfs_monitor is owned by the gvfs core; see the functions
256
* vfs_dir_monitor_destroyed() and do_create_monitor()
260
/* ------------------------------------------------------------------------------------------------- */
263
/* filename as given from the vfs without ignore prefix e.g. /foo.txt */
266
/* filename with ignore prefix splitted into dir and name; e.g. "/store_00010001/" and "foo.txt" */
271
unsigned long int size;
272
unsigned long int cursor;
273
unsigned long int allocated_size;
275
gboolean job_is_replace;
276
gboolean job_is_append_to;
278
gboolean delete_before;
283
/* how much more memory to ask for when using g_realloc() when writing a file */
284
#define WRITE_INCREMENT 4096
290
unsigned long int size;
291
unsigned long int cursor;
294
/* ------------------------------------------------------------------------------------------------- */
297
DEBUG (const gchar *message, ...)
299
#ifdef DEBUG_SHOW_TRACES
301
va_start (args, message);
302
g_vfprintf (stderr, message, args);
304
g_fprintf (stderr, "\n");
309
/* ------------------------------------------------------------------------------------------------- */
311
static int commit_write_handle (GVfsBackendGphoto2 *gphoto2_backend, WriteHandle *write_handle);
314
write_handle_free (WriteHandle *write_handle)
316
g_free (write_handle->filename);
317
g_free (write_handle->dir);
318
g_free (write_handle->name);
319
g_free (write_handle->data);
320
g_free (write_handle);
323
/* This must be called before reading from the device to ensure that
324
* all pending writes are written to the device.
326
* Must only be called on the IO thread.
329
ensure_not_dirty (GVfsBackendGphoto2 *gphoto2_backend)
333
for (l = gphoto2_backend->open_write_handles; l != NULL; l = l->next)
335
WriteHandle *write_handle = l->data;
337
DEBUG ("ensure_not_dirty: looking at handle for '%s", write_handle->filename);
339
if (write_handle->is_dirty)
340
commit_write_handle (gphoto2_backend, write_handle);
344
/* ------------------------------------------------------------------------------------------------- */
346
/* used when gphoto2 will take ownership of this data for it's LRU cache - and will use free(3) to free it */
348
dup_for_gphoto2 (char *gmem, unsigned long int size)
352
memcpy (mem, gmem, size);
356
/* ------------------------------------------------------------------------------------------------- */
359
monitors_emit_internal (GVfsBackendGphoto2 *gphoto2_backend,
362
GFileMonitorEvent event,
363
const char *event_name)
368
g_return_if_fail (g_str_has_prefix (dir, gphoto2_backend->ignore_prefix));
370
DEBUG ("monitors_emit_internal() %s for '%s' '%s'", event_name, dir, name);
372
for (l = gphoto2_backend->dir_monitor_proxies; l != NULL; l = l->next)
374
MonitorProxy *proxy = l->data;
375
if (strcmp (proxy->path, dir) == 0)
378
path = g_build_filename (dir + strlen (gphoto2_backend->ignore_prefix), name, NULL);
379
g_vfs_monitor_emit_event (proxy->vfs_monitor, event, path, NULL);
380
DEBUG (" emitted %s for '%s' on dir monitor for '%s'", event_name, path, dir);
385
filepath = g_build_filename (dir, name, NULL);
386
for (l = gphoto2_backend->file_monitor_proxies; l != NULL; l = l->next)
388
MonitorProxy *proxy = l->data;
389
if (strcmp (proxy->path, filepath) == 0)
391
const char *path = filepath + strlen (gphoto2_backend->ignore_prefix);
392
g_vfs_monitor_emit_event (proxy->vfs_monitor, event, path, NULL);
393
DEBUG (" emitted %s for '%s' on file monitor", event_name, path);
399
/* ------------------------------------------------------------------------------------------------- */
401
/* call this when a file/directory have been added to a directory */
403
monitors_emit_created (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
405
DEBUG ("monitors_emit_created(): '%s' '%s'", dir, name);
406
monitors_emit_internal (gphoto2_backend, dir, name, G_FILE_MONITOR_EVENT_CREATED, "CREATED");
409
/* ------------------------------------------------------------------------------------------------- */
411
/* call this when a file/directory have been deleted from a directory */
413
monitors_emit_deleted (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
415
DEBUG ("monitors_emit_deleted(): '%s' '%s'", dir, name);
416
monitors_emit_internal (gphoto2_backend, dir, name, G_FILE_MONITOR_EVENT_DELETED, "DELETED");
419
/* ------------------------------------------------------------------------------------------------- */
421
/* call this when a file/directory have been changed in a directory */
423
monitors_emit_changed (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
425
DEBUG ("monitors_emit_changed(): '%s' '%s'", dir, name);
426
monitors_emit_internal (gphoto2_backend, dir, name, G_FILE_MONITOR_EVENT_CHANGED, "CHANGED");
429
/* ------------------------------------------------------------------------------------------------- */
432
caches_invalidate_all (GVfsBackendGphoto2 *gphoto2_backend)
434
DEBUG ("caches_invalidate_all()");
436
g_mutex_lock (&gphoto2_backend->lock);
437
if (gphoto2_backend->dir_name_cache != NULL)
438
g_hash_table_remove_all (gphoto2_backend->dir_name_cache);
439
if (gphoto2_backend->file_name_cache != NULL)
440
g_hash_table_remove_all (gphoto2_backend->file_name_cache);
441
if (gphoto2_backend->info_cache != NULL)
442
g_hash_table_remove_all (gphoto2_backend->info_cache);
443
gphoto2_backend->capacity = -1;
444
gphoto2_backend->free_space = -1;
445
g_mutex_unlock (&gphoto2_backend->lock);
448
/* ------------------------------------------------------------------------------------------------- */
451
caches_invalidate_free_space (GVfsBackendGphoto2 *gphoto2_backend)
453
g_mutex_lock (&gphoto2_backend->lock);
454
gphoto2_backend->free_space = -1;
455
g_mutex_unlock (&gphoto2_backend->lock);
458
/* ------------------------------------------------------------------------------------------------- */
461
caches_invalidate_dir (GVfsBackendGphoto2 *gphoto2_backend, const char *dir)
463
DEBUG ("caches_invalidate_dir() for '%s'", dir);
464
g_mutex_lock (&gphoto2_backend->lock);
465
g_hash_table_remove (gphoto2_backend->dir_name_cache, dir);
466
g_hash_table_remove (gphoto2_backend->file_name_cache, dir);
467
g_hash_table_remove (gphoto2_backend->info_cache, dir);
468
g_mutex_unlock (&gphoto2_backend->lock);
471
/* ------------------------------------------------------------------------------------------------- */
474
caches_invalidate_file (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
478
full_name = g_build_filename (dir, name, NULL);
480
g_mutex_lock (&gphoto2_backend->lock);
481
/* this is essentially: caches_invalidate_dir (gphoto2_backend, dir); */
482
g_hash_table_remove (gphoto2_backend->dir_name_cache, dir);
483
g_hash_table_remove (gphoto2_backend->file_name_cache, dir);
484
g_hash_table_remove (gphoto2_backend->info_cache, dir);
486
g_hash_table_remove (gphoto2_backend->info_cache, full_name);
487
g_mutex_unlock (&gphoto2_backend->lock);
489
DEBUG ("caches_invalidate_file() for '%s'", full_name);
493
/* ------------------------------------------------------------------------------------------------- */
496
get_error_from_gphoto2 (const char *message, int rc)
502
case GP_ERROR_FILE_EXISTS:
503
case GP_ERROR_DIRECTORY_EXISTS:
504
/* Translator: %s represents a more specific error message and %d the specific error code */
505
error = g_error_new (G_IO_ERROR,
506
G_IO_ERROR_EXISTS, _("%s: %d: Directory or file exists"), message, rc);
509
case GP_ERROR_FILE_NOT_FOUND:
510
case GP_ERROR_DIRECTORY_NOT_FOUND:
511
/* Translator: %s represents a more specific error message and %d the specific error code */
512
error = g_error_new (G_IO_ERROR,
513
G_IO_ERROR_NOT_FOUND, _("%s: %d: No such file or directory"), message, rc);
516
case GP_ERROR_PATH_NOT_ABSOLUTE:
517
/* Translator: %s represents a more specific error message and %d the specific error code */
518
error = g_error_new (G_IO_ERROR,
519
G_IO_ERROR_INVALID_FILENAME, _("%s: %d: Invalid filename"), message, rc);
522
case GP_ERROR_NOT_SUPPORTED:
523
/* Translator: %s represents a more specific error message and %d the specific error code */
524
error = g_error_new (G_IO_ERROR,
525
G_IO_ERROR_NOT_SUPPORTED, _("%s: %d: Not Supported"), message, rc);
529
error = g_error_new (G_IO_ERROR,
530
G_IO_ERROR_FAILED, "%s: %d: %s", message, rc, gp_result_as_string (rc));
536
/* ------------------------------------------------------------------------------------------------- */
539
release_device (GVfsBackendGphoto2 *gphoto2_backend)
543
g_free (gphoto2_backend->gphoto2_port);
544
gphoto2_backend->gphoto2_port = NULL;
546
if (gphoto2_backend->context != NULL)
548
gp_context_unref (gphoto2_backend->context);
549
gphoto2_backend->context = NULL;
552
if (gphoto2_backend->camera != NULL)
554
gp_camera_unref (gphoto2_backend->camera);
555
gphoto2_backend->camera = NULL;
559
if (gphoto2_backend->gudev_client != NULL)
560
g_object_unref (gphoto2_backend->gudev_client);
561
if (gphoto2_backend->udev_device != NULL)
562
g_object_unref (gphoto2_backend->udev_device);
564
#elif defined(HAVE_HAL)
565
if (gphoto2_backend->dbus_connection != NULL)
567
dbus_connection_close (gphoto2_backend->dbus_connection);
568
dbus_connection_unref (gphoto2_backend->dbus_connection);
569
gphoto2_backend->dbus_connection = NULL;
572
if (gphoto2_backend->hal_ctx != NULL)
574
libhal_ctx_free (gphoto2_backend->hal_ctx);
575
gphoto2_backend->hal_ctx = NULL;
578
g_free (gphoto2_backend->hal_udi);
579
gphoto2_backend->hal_udi = NULL;
580
g_free (gphoto2_backend->hal_name);
581
gphoto2_backend->hal_name = NULL;
583
g_free (gphoto2_backend->icon_name);
584
gphoto2_backend->icon_name = NULL;
586
g_free (gphoto2_backend->ignore_prefix);
587
gphoto2_backend->ignore_prefix = NULL;
589
if (gphoto2_backend->info_cache != NULL)
591
g_hash_table_unref (gphoto2_backend->info_cache);
592
gphoto2_backend->info_cache = NULL;
594
if (gphoto2_backend->dir_name_cache != NULL)
596
g_hash_table_unref (gphoto2_backend->dir_name_cache);
597
gphoto2_backend->dir_name_cache = NULL;
599
if (gphoto2_backend->file_name_cache != NULL)
601
g_hash_table_unref (gphoto2_backend->file_name_cache);
602
gphoto2_backend->file_name_cache = NULL;
605
for (l = gphoto2_backend->dir_monitor_proxies; l != NULL; l = l->next)
607
MonitorProxy *proxy = l->data;
608
monitor_proxy_free (proxy);
610
g_list_free (gphoto2_backend->dir_monitor_proxies);
611
gphoto2_backend->dir_monitor_proxies = NULL;
613
for (l = gphoto2_backend->file_monitor_proxies; l != NULL; l = l->next)
615
MonitorProxy *proxy = l->data;
616
monitor_proxy_free (proxy);
618
g_list_free (gphoto2_backend->file_monitor_proxies);
619
gphoto2_backend->file_monitor_proxies = NULL;
621
g_mutex_clear (&gphoto2_backend->lock);
622
gphoto2_backend->capacity = -1;
623
gphoto2_backend->free_space = -1;
626
/* ------------------------------------------------------------------------------------------------- */
629
g_vfs_backend_gphoto2_finalize (GObject *object)
631
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (object);
633
DEBUG ("finalizing %p", object);
635
release_device (gphoto2_backend);
637
if (G_OBJECT_CLASS (g_vfs_backend_gphoto2_parent_class)->finalize)
638
(*G_OBJECT_CLASS (g_vfs_backend_gphoto2_parent_class)->finalize) (object);
641
/* ------------------------------------------------------------------------------------------------- */
643
#ifdef DEBUG_SHOW_LIBGPHOTO2_OUTPUT
645
_gphoto2_logger_func (GPLogLevel level, const char *domain, const char *format, va_list args, void *data)
647
g_fprintf (stderr, "libgphoto2: %s: ", domain);
648
g_vfprintf (stderr, format, args);
650
g_fprintf (stderr, "\n");
655
g_vfs_backend_gphoto2_init (GVfsBackendGphoto2 *gphoto2_backend)
657
GVfsBackend *backend = G_VFS_BACKEND (gphoto2_backend);
658
GMountSpec *mount_spec;
660
DEBUG ("initing %p", gphoto2_backend);
662
g_vfs_backend_set_display_name (backend, "gphoto2");
664
mount_spec = g_mount_spec_new ("gphoto2");
665
g_vfs_backend_set_mount_spec (backend, mount_spec);
666
g_mount_spec_unref (mount_spec);
668
#ifdef DEBUG_SHOW_LIBGPHOTO2_OUTPUT
669
gp_log_add_func (GP_LOG_ALL, _gphoto2_logger_func, NULL);
673
/* ------------------------------------------------------------------------------------------------- */
676
compute_icon_name (GVfsBackendGphoto2 *gphoto2_backend)
680
if (gphoto2_backend->icon_name == NULL)
682
result = g_strdup_printf ("camera-photo");
686
result = g_strdup (gphoto2_backend->icon_name);
692
/* ------------------------------------------------------------------------------------------------- */
695
compute_display_name (GVfsBackendGphoto2 *gphoto2_backend)
702
/* the real "nice" and user-visible name is computed in the monitor; just try
703
* using the product name here */
704
if (gphoto2_backend->udev_device != NULL)
706
s = g_udev_device_get_sysfs_attr (gphoto2_backend->udev_device, "product");
708
s = g_udev_device_get_property (gphoto2_backend->udev_device, "ID_MODEL");
711
result = g_strdup (s);
715
/* Translator: %s represents the device, e.g. usb:001,042 */
716
result = g_strdup_printf (_("Digital Camera (%s)"), gphoto2_backend->gphoto2_port);
718
#elif defined(HAVE_HAL)
719
if (gphoto2_backend->hal_name == NULL)
721
/* Translator: %s represents the device, e.g. usb:001,042 */
722
result = g_strdup_printf (_("Digital Camera (%s)"), gphoto2_backend->gphoto2_port);
726
result = g_strdup (gphoto2_backend->hal_name);
733
/* ------------------------------------------------------------------------------------------------- */
737
setup_for_device (GVfsBackendGphoto2 *gphoto2_backend)
741
gboolean is_media_player = FALSE;
742
char *camera_x_content_types[] = {"x-content/image-dcf", NULL};
743
char *media_player_x_content_types[] = {"x-content/audio-player", NULL};
745
/* turn usb:001,041 string into an udev device name */
746
if (!g_str_has_prefix (gphoto2_backend->gphoto2_port, "usb:"))
748
devname = g_strconcat ("/dev/bus/usb/", gphoto2_backend->gphoto2_port+4, NULL);
749
if ((comma = strchr (devname, ',')) == NULL)
755
DEBUG ("Parsed '%s' into device name %s", gphoto2_backend->gphoto2_port, devname);
757
/* find corresponding GUdevDevice */
758
gphoto2_backend->udev_device = g_udev_client_query_by_device_file (gphoto2_backend->gudev_client, devname);
760
if (gphoto2_backend->udev_device)
762
DEBUG ("-> sysfs path %s, subsys %s, name %s", g_udev_device_get_sysfs_path (gphoto2_backend->udev_device), g_udev_device_get_subsystem (gphoto2_backend->udev_device), g_udev_device_get_name (gphoto2_backend->udev_device));
764
/* determine icon name */
765
if (g_udev_device_has_property (gphoto2_backend->udev_device, "ID_MEDIA_PLAYER_ICON_NAME"))
767
gphoto2_backend->icon_name = g_strdup (g_udev_device_get_property (gphoto2_backend->udev_device, "ID_MEDIA_PLAYER_ICON_NAME"));
768
is_media_player = TRUE;
770
else if (g_udev_device_has_property (gphoto2_backend->udev_device, "ID_MEDIA_PLAYER"))
772
gphoto2_backend->icon_name = g_strdup ("multimedia-player");
773
is_media_player = TRUE;
776
gphoto2_backend->icon_name = g_strdup ("camera-photo");
779
DEBUG ("-> did not find matching udev device");
782
g_vfs_backend_set_x_content_types (G_VFS_BACKEND (gphoto2_backend), media_player_x_content_types);
784
g_vfs_backend_set_x_content_types (G_VFS_BACKEND (gphoto2_backend), camera_x_content_types);
788
on_uevent (GUdevClient *client, gchar *action, GUdevDevice *device, gpointer user_data)
790
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (user_data);
792
DEBUG ("on_uevent action %s, device %s", action, g_udev_device_get_device_file (device));
794
if (gphoto2_backend->udev_device != NULL &&
795
g_strcmp0 (g_udev_device_get_device_file (gphoto2_backend->udev_device), g_udev_device_get_device_file (device)) == 0 &&
796
strcmp (action, "remove") == 0)
798
DEBUG ("we have been removed!");
800
/* nuke all caches so we're a bit more valgrind friendly */
801
caches_invalidate_all (gphoto2_backend);
803
/* TODO: need a cleaner way to force unmount ourselves */
808
#elif defined(HAVE_HAL)
810
find_udi_for_device (GVfsBackendGphoto2 *gphoto2_backend)
812
int num_camera_devices;
815
char **camera_devices;
823
char *camera_x_content_types[] = {"x-content/image-dcf", NULL};
824
char *music_player_x_content_types[] = {"x-content/audio-player", NULL};
826
gphoto2_backend->hal_udi = NULL;
828
/* parse the usb:001,041 string */
830
if (!g_str_has_prefix (gphoto2_backend->gphoto2_port, "usb:"))
835
tokens = g_strsplit (gphoto2_backend->gphoto2_port + 4, ",", 0);
836
if (g_strv_length (tokens) != 2)
842
usb_bus_num = strtol (tokens[0], &endp, 10);
849
usb_device_num = strtol (tokens[1], &endp, 10);
858
DEBUG ("Parsed '%s' into bus=%d device=%d", gphoto2_backend->gphoto2_port, usb_bus_num, usb_device_num);
860
camera_devices = libhal_find_device_by_capability (gphoto2_backend->hal_ctx,
864
mtp_devices = libhal_find_device_by_capability (gphoto2_backend->hal_ctx,
865
"portable_audio_player",
868
for (m = 0; m < 2 && gphoto2_backend->hal_udi == NULL; m++)
870
devices = m == 0 ? camera_devices : mtp_devices;
871
num_devices = m == 0 ? num_camera_devices : num_mtp_devices;
875
for (n = 0; n < num_devices && gphoto2_backend->hal_udi == NULL; n++)
877
char *udi = devices[n];
878
LibHalPropertySet *ps;
880
ps = libhal_device_get_all_properties (gphoto2_backend->hal_ctx, udi, NULL);
883
const char *subsystem;
885
subsystem = libhal_ps_get_string (ps, "info.subsystem");
886
if (subsystem != NULL && strcmp (subsystem, "usb") == 0)
888
int device_usb_bus_num;
889
int device_usb_device_num;
890
const char *icon_from_hal;
891
const char *name_from_hal;
893
device_usb_bus_num = libhal_ps_get_int32 (ps, "usb.bus_number");
894
device_usb_device_num = libhal_ps_get_int32 (ps, "usb.linux.device_number");
895
icon_from_hal = libhal_ps_get_string (ps, "info.desktop.icon");
896
name_from_hal = libhal_ps_get_string (ps, "info.desktop.name");
898
DEBUG ("looking at usb device '%s' with bus=%d, device=%d",
899
udi, device_usb_bus_num, device_usb_device_num);
901
if (device_usb_bus_num == usb_bus_num &&
902
device_usb_device_num == usb_device_num)
905
const char *parent_udi;
906
LibHalPropertySet *ps2;
908
DEBUG ("udi '%s' is the one!", udi);
912
* Keep this naming code in sync with
914
* hal/ghalvolume;do_update_from_hal_for_camera()
917
parent_udi = libhal_ps_get_string (ps, "info.parent");
918
if (name_from_hal != NULL)
920
name = g_strdup (name_from_hal);
922
else if (parent_udi != NULL)
924
ps2 = libhal_device_get_all_properties (gphoto2_backend->hal_ctx, parent_udi, NULL);
930
vendor = libhal_ps_get_string (ps2, "usb_device.vendor");
931
product = libhal_ps_get_string (ps2, "usb_device.product");
935
name = g_strdup (product);
940
name = g_strdup_printf ("%s %s", vendor, product);
944
/* Translator: %s is the vendor name, e.g. Panasonic */
945
name = g_strdup_printf (_("%s Camera"), vendor);
947
/* Translator: %s is the vendor name, e.g. Panasonic */
948
name = g_strdup_printf (_("%s Audio Player"), vendor);
951
libhal_free_property_set (ps2);
957
name = g_strdup (_("Camera"));
959
name = g_strdup (_("Audio Player"));
962
gphoto2_backend->hal_udi = g_strdup (udi);
963
gphoto2_backend->hal_name = name;
964
if (icon_from_hal != NULL)
966
gphoto2_backend->icon_name = g_strdup (icon_from_hal);
972
gphoto2_backend->icon_name = g_strdup ("multimedia-player");
976
gphoto2_backend->icon_name = g_strdup ("camera-photo");
980
/* TODO: should we sniff the files instead? */
983
g_vfs_backend_set_x_content_types (G_VFS_BACKEND (gphoto2_backend),
984
camera_x_content_types);
988
g_vfs_backend_set_x_content_types (G_VFS_BACKEND (gphoto2_backend),
989
music_player_x_content_types);
996
libhal_free_property_set (ps);
999
libhal_free_string_array (devices);
1004
/* ------------------------------------------------------------------------------------------------- */
1007
_hal_device_removed (LibHalContext *hal_ctx, const char *udi)
1009
GVfsBackendGphoto2 *gphoto2_backend;
1011
gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (libhal_ctx_get_user_data (hal_ctx));
1013
if (gphoto2_backend->hal_udi != NULL && strcmp (udi, gphoto2_backend->hal_udi) == 0)
1015
DEBUG ("we have been removed!");
1017
/* nuke all caches so we're a bit more valgrind friendly */
1018
caches_invalidate_all (gphoto2_backend);
1020
/* TODO: need a cleaner way to force unmount ourselves */
1026
/* ------------------------------------------------------------------------------------------------- */
1029
split_filename_with_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, const char *filename, char **dir, char **name)
1033
s = g_path_get_dirname (filename);
1035
*dir = g_strconcat (gphoto2_backend->ignore_prefix, s + 1, NULL);
1037
*dir = g_strconcat (gphoto2_backend->ignore_prefix, s, NULL);
1040
if (strcmp (filename, "/") == 0)
1041
*name = g_strdup ("");
1043
*name = g_path_get_basename (filename);
1046
if (s[strlen(s)] == '/')
1047
s[strlen(s)] = '\0';
1049
/*DEBUG ("split_filename_with_ignore_prefix: '%s' -> '%s' '%s'", filename, *dir, *name);*/
1052
/* ------------------------------------------------------------------------------------------------- */
1055
add_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, const char *filename)
1059
if (filename[0] == '/')
1060
result = g_strconcat (gphoto2_backend->ignore_prefix, filename + 1, NULL);
1062
result = g_strconcat (gphoto2_backend->ignore_prefix, filename, NULL);
1064
/*DEBUG ("add_ignore_prefix: '%s' -> '%s'", filename, result);*/
1068
/* ------------------------------------------------------------------------------------------------- */
1070
/* the passed 'dir' variable must contain ignore_prefix */
1072
file_get_info (GVfsBackendGphoto2 *gphoto2_backend,
1077
gboolean try_cache_only)
1081
CameraFileInfo gp_info;
1083
GFileInfo *cached_info;
1091
full_path = g_build_filename (dir, name, NULL);
1092
DEBUG ("file_get_info() try_cache_only=%d dir='%s', name='%s'\n"
1094
try_cache_only, dir, name, full_path, gphoto2_backend->ignore_prefix);
1097
/* first look up cache */
1098
g_mutex_lock (&gphoto2_backend->lock);
1099
cached_info = g_hash_table_lookup (gphoto2_backend->info_cache, full_path);
1100
if (cached_info != NULL)
1102
g_file_info_copy_into (cached_info, info);
1103
g_mutex_unlock (&gphoto2_backend->lock);
1104
DEBUG (" Using cached info %p for '%s'", cached_info, full_path);
1108
g_mutex_unlock (&gphoto2_backend->lock);
1113
ensure_not_dirty (gphoto2_backend);
1115
DEBUG (" No cached info for '%s'", full_path);
1117
/* Since we're caching stuff, make sure all information we store is set */
1118
g_file_info_unset_attribute_mask (info);
1120
/* handle root directory */
1121
if (strcmp (full_path, gphoto2_backend->ignore_prefix) == 0 || strcmp (full_path, "/") == 0)
1124
display_name = compute_display_name (gphoto2_backend);
1125
g_file_info_set_display_name (info, display_name);
1126
g_file_info_set_name (info, display_name);
1127
g_free (display_name);
1128
g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
1129
g_file_info_set_content_type (info, "inode/directory");
1130
g_file_info_set_size (info, 0);
1131
icon = g_themed_icon_new ("folder");
1132
g_file_info_set_icon (info, icon);
1133
g_object_unref (icon);
1134
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE);
1135
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, gphoto2_backend->can_write);
1136
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, gphoto2_backend->can_delete);
1137
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, TRUE);
1138
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
1139
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE);
1141
DEBUG (" Generating info (root folder) for '%s'", full_path);
1145
rc = gp_camera_file_get_info (gphoto2_backend->camera,
1149
gphoto2_backend->context);
1155
/* gphoto2 doesn't know about this file.. it may be a folder; try that */
1157
gp_list_new (&list);
1158
rc = gp_camera_folder_list_folders (gphoto2_backend->camera,
1161
gphoto2_backend->context);
1164
for (n = 0; n < gp_list_count (list) && !is_folder; n++)
1166
const char *folder_name;
1167
gp_list_get_name (list, n, &folder_name);
1168
if (strcmp (folder_name, name) == 0)
1174
gp_list_free (list);
1178
g_file_info_set_name (info, name);
1179
g_file_info_set_display_name (info, name);
1180
icon = g_themed_icon_new ("folder");
1181
g_file_info_set_icon (info, icon);
1182
g_object_unref (icon);
1183
g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
1184
g_file_info_set_content_type (info, "inode/directory");
1185
g_file_info_set_size (info, 0);
1186
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE);
1187
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, gphoto2_backend->can_write);
1188
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, gphoto2_backend->can_delete);
1189
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, TRUE);
1190
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
1191
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, gphoto2_backend->can_write);
1192
g_file_info_set_is_hidden (info, name != NULL && name[0] == '.');
1194
DEBUG (" Generating info (folder) for '%s'", full_path);
1198
/* nope, not a folder either.. error out.. */
1201
*error = g_error_new (G_IO_ERROR,
1202
G_IO_ERROR_NOT_FOUND,
1203
_("No such file or directory"));
1208
g_file_info_set_name (info, name);
1209
g_file_info_set_display_name (info, name);
1210
g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
1212
if (gp_info.file.fields & GP_FILE_INFO_SIZE)
1214
g_file_info_set_size (info, gp_info.file.size);
1218
/* not really sure this is the right thing to do... */
1219
g_file_info_set_size (info, 0);
1222
/* TODO: We really should sniff the file / look at file extensions
1223
* instead of relying on gp_info.file.type... but sniffing the file
1224
* is no fun since we (currently) can't do partial reads with the
1225
* libgphoto2 API :-/
1228
if (gp_info.file.fields & GP_FILE_INFO_TYPE)
1230
/* application/x-unknown is a bogus mime type return by some
1231
* devices (such as Sandisk Sansa music players) - ignore it.
1233
if (strcmp (gp_info.file.type, "application/x-unknown") != 0)
1235
mime_type = g_strdup (gp_info.file.type);
1238
if (mime_type == NULL)
1239
mime_type = g_content_type_guess (name, NULL, 0, NULL);
1240
if (mime_type == NULL)
1241
mime_type = g_strdup ("application/octet-stream");
1242
g_file_info_set_content_type (info, mime_type);
1243
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, mime_type);
1245
/* we offer thumbnails for both pics and video (see bgo #585853) */
1246
if (g_str_has_prefix (mime_type, "image") || g_str_has_prefix (mime_type, "video"))
1250
GMountSpec *mount_spec;
1252
mount_spec = g_vfs_backend_get_mount_spec (G_VFS_BACKEND (gphoto2_backend));
1253
icon_id = g_strdup_printf ("preview:%s/%s", dir + strlen (gphoto2_backend->ignore_prefix), name);
1254
icon = g_vfs_icon_new (mount_spec,
1256
g_file_info_set_attribute_object (info,
1257
G_FILE_ATTRIBUTE_PREVIEW_ICON,
1259
g_object_unref (icon);
1263
icon = g_content_type_get_icon (mime_type);
1264
DEBUG (" got icon %p for mime_type '%s'", icon, mime_type);
1267
g_file_info_set_icon (info, icon);
1268
g_object_unref (icon);
1272
if (gp_info.file.fields & GP_FILE_INFO_MTIME)
1273
mtime.tv_sec = gp_info.file.mtime;
1277
g_file_info_set_modification_time (info, &mtime);
1279
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE);
1280
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, gphoto2_backend->can_write);
1281
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, gphoto2_backend->can_delete);
1282
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, FALSE);
1283
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
1284
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, gphoto2_backend->can_write);
1285
g_file_info_set_is_hidden (info, name != NULL && name[0] == '.');
1287
if (gp_info.file.fields & GP_FILE_INFO_PERMISSIONS) {
1288
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
1289
gp_info.file.permissions & GP_FILE_PERM_DELETE);
1290
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE,
1291
gp_info.file.permissions & GP_FILE_PERM_DELETE);
1292
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME,
1293
gp_info.file.permissions & GP_FILE_PERM_DELETE);
1297
DEBUG (" Generating info (file) for '%s'", full_path);
1300
/* add this sucker to the cache */
1303
#ifndef DEBUG_NO_CACHING
1304
cached_info = g_file_info_dup (info);
1305
DEBUG (" Storing cached info %p for '%s'", cached_info, full_path);
1306
g_mutex_lock (&gphoto2_backend->lock);
1307
g_hash_table_insert (gphoto2_backend->info_cache, g_strdup (full_path), cached_info);
1308
g_mutex_unlock (&gphoto2_backend->lock);
1317
/* ------------------------------------------------------------------------------------------------- */
1320
is_directory (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
1327
info = g_file_info_new ();
1328
if (!file_get_info (gphoto2_backend, dir, name, info, NULL, FALSE))
1331
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
1335
g_object_unref (info);
1339
/* ------------------------------------------------------------------------------------------------- */
1342
is_regular (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
1349
info = g_file_info_new ();
1350
if (!file_get_info (gphoto2_backend, dir, name, info, NULL, FALSE))
1353
if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR)
1357
g_object_unref (info);
1361
/* ------------------------------------------------------------------------------------------------- */
1364
is_directory_empty (GVfsBackendGphoto2 *gphoto2_backend, const char *dir)
1372
DEBUG ("is_directory_empty begin (%s)", dir);
1374
/* TODO: use cache */
1380
gp_list_new (&list);
1381
rc = gp_camera_folder_list_files (gphoto2_backend->camera,
1384
gphoto2_backend->context);
1386
num_files = gp_list_count (list);
1387
gp_list_free (list);
1392
gp_list_new (&list);
1393
rc = gp_camera_folder_list_folders (gphoto2_backend->camera,
1396
gphoto2_backend->context);
1398
num_dirs = gp_list_count (list);
1399
gp_list_free (list);
1401
if (num_dirs == 0 && num_files == 0)
1405
DEBUG (" is_directory_empty (%s) -> %d", dir, ret);
1409
/* ------------------------------------------------------------------------------------------------- */
1411
/* If we only have a single storage head, the gphoto2 volume monitor
1412
* will not use activation roots into our mount. This is mainly to
1413
* work around buggy devices where the basedir of the storage head
1414
* changes on every camera initialization, e.g. the iPhone.
1416
* So, if we have only one storage head, do use basedir of that
1417
* head as ignore_prefix.
1419
* See also update_cameras() in ggphoto2volumemonitor.c.
1421
* This function needs to be called from do_mount().
1424
ensure_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, GVfsJob *job)
1427
CameraStorageInformation *storage_info, *head;
1428
int num_storage_info, i;
1431
if (gphoto2_backend->ignore_prefix != NULL)
1436
if (gp_camera_get_storageinfo (gphoto2_backend->camera,
1439
gphoto2_backend->context) != 0)
1443
for (i = 0; i < num_storage_info; i++)
1445
/* Ignore storage with no capacity (see bug 570888) */
1446
if ((storage_info[i].fields & GP_STORAGEINFO_MAXCAPACITY) &&
1447
storage_info[i].capacitykbytes == 0)
1450
/* Multiple heads, don't ignore */
1454
head = &storage_info[i];
1457
/* Some cameras, such as the Canon 5D, won't report the basedir */
1458
if (head->fields & GP_STORAGEINFO_BASE)
1459
prefix = g_strdup_printf ("%s/", head->basedir);
1464
gphoto2_backend->ignore_prefix = g_strdup ("/");
1466
gphoto2_backend->ignore_prefix = prefix;
1468
DEBUG ("Using ignore_prefix='%s'", gphoto2_backend->ignore_prefix);
1473
/* ------------------------------------------------------------------------------------------------- */
1476
do_mount (GVfsBackend *backend,
1478
GMountSpec *mount_spec,
1479
GMountSource *mount_source,
1480
gboolean is_automount)
1486
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
1487
GError *error = NULL;
1488
GMountSpec *gphoto2_mount_spec;
1491
GPPortInfoList *il = NULL;
1493
CameraStorageInformation *storage_info;
1494
int num_storage_info;
1496
DEBUG ("do_mount %p", gphoto2_backend);
1500
const char *subsystems[] = {"usb", NULL};
1502
gphoto2_backend->gudev_client = g_udev_client_new (subsystems);
1503
if (gphoto2_backend->gudev_client == NULL)
1505
release_device (gphoto2_backend);
1506
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot create gudev client"));
1507
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1508
g_error_free (error);
1512
g_signal_connect (gphoto2_backend->gudev_client, "uevent", G_CALLBACK (on_uevent), gphoto2_backend);
1514
#elif defined(HAVE_HAL)
1516
DBusError dbus_error;
1518
dbus_error_init (&dbus_error);
1519
gphoto2_backend->dbus_connection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &dbus_error);
1520
if (dbus_error_is_set (&dbus_error))
1522
release_device (gphoto2_backend);
1523
dbus_error_free (&dbus_error);
1524
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot connect to the system bus"));
1525
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1526
g_error_free (error);
1530
dbus_connection_set_exit_on_disconnect (gphoto2_backend->dbus_connection, FALSE);
1532
gphoto2_backend->hal_ctx = libhal_ctx_new ();
1533
if (gphoto2_backend->hal_ctx == NULL)
1535
release_device (gphoto2_backend);
1536
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot create libhal context"));
1537
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1538
g_error_free (error);
1542
_g_dbus_connection_integrate_with_main (gphoto2_backend->dbus_connection);
1543
libhal_ctx_set_dbus_connection (gphoto2_backend->hal_ctx, gphoto2_backend->dbus_connection);
1545
if (!libhal_ctx_init (gphoto2_backend->hal_ctx, &dbus_error))
1547
release_device (gphoto2_backend);
1548
dbus_error_free (&dbus_error);
1549
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot initialize libhal"));
1550
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1551
g_error_free (error);
1555
libhal_ctx_set_device_removed (gphoto2_backend->hal_ctx, _hal_device_removed);
1556
libhal_ctx_set_user_data (gphoto2_backend->hal_ctx, gphoto2_backend);
1561
host = g_mount_spec_get (mount_spec, "host");
1562
DEBUG (" host='%s'", host);
1563
if (host == NULL || strlen (host) < 3 || host[0] != '[' || host[strlen (host) - 1] != ']')
1565
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("No device specified"));
1566
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1567
g_error_free (error);
1568
release_device (gphoto2_backend);
1572
gphoto2_backend->gphoto2_port = g_strdup (host + 1);
1573
gphoto2_backend->gphoto2_port[strlen (gphoto2_backend->gphoto2_port) - 1] = '\0';
1575
DEBUG (" decoded host='%s'", gphoto2_backend->gphoto2_port);
1578
setup_for_device (gphoto2_backend);
1579
#elif defined(HAVE_HAL)
1580
find_udi_for_device (gphoto2_backend);
1583
gphoto2_backend->context = gp_context_new ();
1584
if (gphoto2_backend->context == NULL)
1586
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot create gphoto2 context"));
1587
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1588
g_error_free (error);
1589
release_device (gphoto2_backend);
1593
rc = gp_camera_new (&(gphoto2_backend->camera));
1596
error = get_error_from_gphoto2 (_("Error creating camera"), rc);
1597
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1598
g_error_free (error);
1599
release_device (gphoto2_backend);
1606
rc = gp_port_info_list_new (&il);
1609
error = get_error_from_gphoto2 (_("Error loading device information"), rc);
1610
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1611
g_error_free (error);
1612
release_device (gphoto2_backend);
1616
rc = gp_port_info_list_load (il);
1619
error = get_error_from_gphoto2 (_("Error loading device information"), rc);
1620
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1621
g_error_free (error);
1622
release_device (gphoto2_backend);
1626
DEBUG (" gphoto2_port='%s'", gphoto2_backend->gphoto2_port);
1628
n = gp_port_info_list_lookup_path (il, gphoto2_backend->gphoto2_port);
1629
if (n == GP_ERROR_UNKNOWN_PORT)
1631
error = get_error_from_gphoto2 (_("Error looking up device information"), rc);
1632
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1633
g_error_free (error);
1634
release_device (gphoto2_backend);
1638
rc = gp_port_info_list_get_info (il, n, &info);
1641
error = get_error_from_gphoto2 (_("Error getting device information"), rc);
1642
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1643
g_error_free (error);
1644
release_device (gphoto2_backend);
1648
DEBUG (" '%s' '%s' '%s'", info.name, info.path, info.library_filename);
1651
rc = gp_camera_set_port_info (gphoto2_backend->camera, info);
1654
error = get_error_from_gphoto2 (_("Error setting up camera communications port"), rc);
1655
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1656
g_error_free (error);
1657
release_device (gphoto2_backend);
1660
gp_port_info_list_free(il);
1662
rc = gp_camera_init (gphoto2_backend->camera, gphoto2_backend->context);
1665
error = get_error_from_gphoto2 (_("Error initializing camera"), rc);
1666
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1667
g_error_free (error);
1668
release_device (gphoto2_backend);
1672
if (!ensure_ignore_prefix (gphoto2_backend, G_VFS_JOB (job)))
1674
release_device (gphoto2_backend);
1678
/* Translator: %s represents the device, e.g. usb:001,042. 'gphoto2' is the name of the
1679
backend and shouldn't be translated. */
1680
fuse_name = g_strdup_printf (_("gphoto2 mount on %s"), gphoto2_backend->gphoto2_port);
1681
icon_name = compute_icon_name (gphoto2_backend);
1682
display_name = compute_display_name (gphoto2_backend);
1683
g_vfs_backend_set_stable_name (backend, fuse_name);
1684
g_vfs_backend_set_display_name (backend, display_name);
1685
g_vfs_backend_set_icon_name (backend, icon_name);
1686
g_free (display_name);
1690
gphoto2_backend->can_write = FALSE;
1691
gphoto2_backend->can_delete = FALSE;
1692
rc = gp_camera_get_storageinfo (gphoto2_backend->camera, &storage_info, &num_storage_info, gphoto2_backend->context);
1695
if (num_storage_info >= 1)
1697
if (storage_info[0].fields & GP_STORAGEINFO_ACCESS && storage_info[0].access == GP_STORAGEINFO_AC_READWRITE)
1699
gphoto2_backend->can_write = TRUE;
1700
gphoto2_backend->can_delete = TRUE;
1702
if (storage_info[0].fields & GP_STORAGEINFO_ACCESS && storage_info[0].access == GP_STORAGEINFO_AC_READONLY_WITH_DELETE)
1704
gphoto2_backend->can_delete = TRUE;
1708
DEBUG (" can_write = %d", gphoto2_backend->can_write);
1709
DEBUG (" can_delete = %d", gphoto2_backend->can_delete);
1711
g_vfs_job_succeeded (G_VFS_JOB (job));
1713
gphoto2_backend->free_space = -1;
1715
g_mutex_init (&gphoto2_backend->lock);
1717
gphoto2_mount_spec = g_mount_spec_new ("gphoto2");
1718
g_mount_spec_set (gphoto2_mount_spec, "host", host);
1719
g_vfs_backend_set_mount_spec (backend, gphoto2_mount_spec);
1720
g_mount_spec_unref (gphoto2_mount_spec);
1722
gphoto2_backend->info_cache = g_hash_table_new_full (g_str_hash,
1727
gphoto2_backend->dir_name_cache = g_hash_table_new_full (g_str_hash,
1730
(GDestroyNotify) gp_list_unref);
1732
gphoto2_backend->file_name_cache = g_hash_table_new_full (g_str_hash,
1735
(GDestroyNotify) gp_list_unref);
1737
DEBUG (" mounted %p", gphoto2_backend);
1740
/* ------------------------------------------------------------------------------------------------- */
1743
try_mount (GVfsBackend *backend,
1745
GMountSpec *mount_spec,
1746
GMountSource *mount_source,
1747
gboolean is_automount)
1750
GError *error = NULL;
1751
GMountSpec *gphoto2_mount_spec;
1753
DEBUG ("try_mount %p", backend);
1755
/* TODO: Hmm.. apparently we have to set the mount spec in
1756
* try_mount(); doing it in mount() do_won't work..
1758
host = g_mount_spec_get (mount_spec, "host");
1759
DEBUG (" host=%s", host);
1762
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("No camera specified"));
1763
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1764
g_error_free (error);
1768
gphoto2_mount_spec = g_mount_spec_new ("gphoto2");
1769
g_mount_spec_set (gphoto2_mount_spec, "host", host);
1770
g_vfs_backend_set_mount_spec (backend, gphoto2_mount_spec);
1771
g_mount_spec_unref (gphoto2_mount_spec);
1775
/* ------------------------------------------------------------------------------------------------- */
1778
free_read_handle (ReadHandle *read_handle)
1780
if (read_handle->file != NULL)
1782
gp_file_unref (read_handle->file);
1784
g_free (read_handle);
1788
do_open_for_read_real (GVfsBackend *backend,
1789
GVfsJobOpenForRead *job,
1790
const char *filename,
1791
gboolean get_preview)
1795
ReadHandle *read_handle;
1796
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
1800
ensure_not_dirty (gphoto2_backend);
1802
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
1804
if (is_directory (gphoto2_backend, dir, name))
1806
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1807
G_IO_ERROR_IS_DIRECTORY,
1808
_("Can't open directory"));
1812
if (!is_regular (gphoto2_backend, dir, name))
1814
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1815
G_IO_ERROR_NOT_FOUND,
1820
read_handle = g_new0 (ReadHandle, 1);
1821
rc = gp_file_new (&read_handle->file);
1824
error = get_error_from_gphoto2 (_("Error creating file object"), rc);
1825
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1826
g_error_free (error);
1827
free_read_handle (read_handle);
1831
rc = gp_camera_file_get (gphoto2_backend->camera,
1834
get_preview ? GP_FILE_TYPE_PREVIEW : GP_FILE_TYPE_NORMAL,
1836
gphoto2_backend->context);
1839
error = get_error_from_gphoto2 (_("Error getting file"), rc);
1840
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1841
g_error_free (error);
1842
free_read_handle (read_handle);
1846
rc = gp_file_get_data_and_size (read_handle->file, &read_handle->data, &read_handle->size);
1849
error = get_error_from_gphoto2 (_("Error getting data from file"), rc);
1850
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1851
g_error_free (error);
1852
free_read_handle (read_handle);
1856
DEBUG (" data=%p size=%ld handle=%p get_preview=%d",
1857
read_handle->data, read_handle->size, read_handle, get_preview);
1859
g_mutex_lock (&gphoto2_backend->lock);
1860
gphoto2_backend->open_read_handles = g_list_prepend (gphoto2_backend->open_read_handles, read_handle);
1861
g_mutex_unlock (&gphoto2_backend->lock);
1863
read_handle->cursor = 0;
1865
g_vfs_job_open_for_read_set_can_seek (job, TRUE);
1866
g_vfs_job_open_for_read_set_handle (job, GINT_TO_POINTER (read_handle));
1867
g_vfs_job_succeeded (G_VFS_JOB (job));
1876
do_open_for_read (GVfsBackend *backend,
1877
GVfsJobOpenForRead *job,
1878
const char *filename)
1880
DEBUG ("open_for_read (%s)", filename);
1882
do_open_for_read_real (backend,
1889
do_open_icon_for_read (GVfsBackend *backend,
1890
GVfsJobOpenIconForRead *job,
1891
const char *icon_id)
1893
DEBUG ("open_icon_for_read (%s)", icon_id);
1895
if (g_str_has_prefix (icon_id, "preview:"))
1897
do_open_for_read_real (backend,
1898
G_VFS_JOB_OPEN_FOR_READ (job),
1899
icon_id + sizeof ("preview:") - 1,
1904
g_vfs_job_failed (G_VFS_JOB (job),
1906
G_IO_ERROR_INVALID_ARGUMENT,
1907
_("Malformed icon identifier '%s'"),
1912
/* ------------------------------------------------------------------------------------------------- */
1915
try_read (GVfsBackend *backend,
1917
GVfsBackendHandle handle,
1919
gsize bytes_requested)
1921
//GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
1922
ReadHandle *read_handle = (ReadHandle *) handle;
1924
gsize bytes_to_copy;
1926
DEBUG ("do_read() %d @ %ld of %ld, handle=%p", bytes_requested, read_handle->cursor, read_handle->size, handle);
1928
if (read_handle->cursor >= read_handle->size)
1934
bytes_left = read_handle->size - read_handle->cursor;
1935
if (bytes_requested > bytes_left)
1936
bytes_to_copy = bytes_left;
1938
bytes_to_copy = bytes_requested;
1940
memcpy (buffer, read_handle->data + read_handle->cursor, bytes_to_copy);
1941
read_handle->cursor += bytes_to_copy;
1945
g_vfs_job_read_set_size (job, bytes_to_copy);
1946
g_vfs_job_succeeded (G_VFS_JOB (job));
1950
/* ------------------------------------------------------------------------------------------------- */
1953
try_seek_on_read (GVfsBackend *backend,
1954
GVfsJobSeekRead *job,
1955
GVfsBackendHandle handle,
1959
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
1960
ReadHandle *read_handle = (ReadHandle *) handle;
1963
DEBUG ("seek_on_read() offset=%d, type=%d, handle=%p", (int)offset, type, handle);
1969
new_offset = offset;
1972
new_offset = read_handle->cursor + offset;
1975
new_offset = read_handle->size + offset;
1979
if (new_offset < 0 || new_offset > read_handle->size)
1981
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1983
_("Error seeking in stream on camera %s"), gphoto2_backend->gphoto2_port);
1987
read_handle->cursor = new_offset;
1988
g_vfs_job_seek_read_set_offset (job, offset);
1989
g_vfs_job_succeeded (G_VFS_JOB (job));
1994
/* ------------------------------------------------------------------------------------------------- */
1996
/* cannot be async because we unref the CameraFile */
1998
do_close_read (GVfsBackend *backend,
1999
GVfsJobCloseRead *job,
2000
GVfsBackendHandle handle)
2002
ReadHandle *read_handle = (ReadHandle *) handle;
2003
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2005
DEBUG ("close_read() handle=%p", handle);
2007
g_mutex_lock (&gphoto2_backend->lock);
2008
gphoto2_backend->open_read_handles = g_list_remove (gphoto2_backend->open_read_handles, read_handle);
2009
g_mutex_unlock (&gphoto2_backend->lock);
2011
free_read_handle (read_handle);
2013
g_vfs_job_succeeded (G_VFS_JOB (job));
2016
/* ------------------------------------------------------------------------------------------------- */
2019
do_query_info (GVfsBackend *backend,
2020
GVfsJobQueryInfo *job,
2021
const char *filename,
2022
GFileQueryInfoFlags flags,
2024
GFileAttributeMatcher *matcher)
2026
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2031
DEBUG ("query_info (%s)", filename);
2033
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2036
if (!file_get_info (gphoto2_backend, dir, name, info, &error, FALSE))
2038
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2039
g_error_free (error);
2043
g_vfs_job_succeeded (G_VFS_JOB (job));
2050
/* ------------------------------------------------------------------------------------------------- */
2053
try_query_info (GVfsBackend *backend,
2054
GVfsJobQueryInfo *job,
2055
const char *filename,
2056
GFileQueryInfoFlags flags,
2058
GFileAttributeMatcher *matcher)
2060
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2065
DEBUG ("try_query_info (%s)", filename);
2069
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2071
if (!file_get_info (gphoto2_backend, dir, name, info, NULL, TRUE))
2073
DEBUG (" BUU no info from cache for try_query_info (%s)", filename);
2076
DEBUG (" YAY got info from cache for try_query_info (%s)", filename);
2078
g_vfs_job_succeeded (G_VFS_JOB (job));
2087
/* ------------------------------------------------------------------------------------------------- */
2090
do_enumerate (GVfsBackend *backend,
2091
GVfsJobEnumerate *job,
2092
const char *given_filename,
2093
GFileAttributeMatcher *matcher,
2094
GFileQueryInfoFlags flags)
2096
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2104
gboolean using_cached_dir_list;
2105
gboolean using_cached_file_list;
2110
using_cached_dir_list = FALSE;
2111
using_cached_file_list = FALSE;
2113
filename = add_ignore_prefix (gphoto2_backend, given_filename);
2114
DEBUG ("enumerate ('%s', with_prefix='%s')", given_filename, filename);
2116
split_filename_with_ignore_prefix (gphoto2_backend, given_filename, &as_dir, &as_name);
2117
if (!is_directory (gphoto2_backend, as_dir, as_name))
2119
if (is_regular (gphoto2_backend, as_dir, as_name))
2121
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2122
G_IO_ERROR_NOT_DIRECTORY,
2123
_("Not a directory"));
2127
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2128
G_IO_ERROR_NOT_FOUND,
2129
_("No such file or directory"));
2138
/* first, list the folders */
2139
g_mutex_lock (&gphoto2_backend->lock);
2140
list = g_hash_table_lookup (gphoto2_backend->dir_name_cache, filename);
2143
g_mutex_unlock (&gphoto2_backend->lock);
2145
ensure_not_dirty (gphoto2_backend);
2147
DEBUG (" Generating dir list for dir '%s'", filename);
2149
gp_list_new (&list);
2150
rc = gp_camera_folder_list_folders (gphoto2_backend->camera,
2153
gphoto2_backend->context);
2156
error = get_error_from_gphoto2 (_("Failed to get folder list"), rc);
2157
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2158
g_error_free (error);
2165
DEBUG (" Using cached dir list for dir '%s'", filename);
2166
using_cached_dir_list = TRUE;
2168
g_mutex_unlock (&gphoto2_backend->lock);
2170
for (n = 0; n < gp_list_count (list); n++)
2174
gp_list_get_name (list, n, &name);
2175
DEBUG (" enum folder '%s'", name);
2176
info = g_file_info_new ();
2178
if (!file_get_info (gphoto2_backend, filename, name, info, &error, FALSE))
2180
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2181
g_error_free (error);
2182
g_list_foreach (l, (GFunc) g_object_unref, NULL);
2184
gp_list_free (list);
2187
l = g_list_append (l, info);
2189
if (!using_cached_dir_list)
2191
#ifndef DEBUG_NO_CACHING
2192
g_mutex_lock (&gphoto2_backend->lock);
2193
g_hash_table_insert (gphoto2_backend->dir_name_cache, g_strdup (filename), list);
2194
g_mutex_unlock (&gphoto2_backend->lock);
2199
g_mutex_lock (&gphoto2_backend->lock);
2200
gp_list_unref (list);
2201
g_mutex_unlock (&gphoto2_backend->lock);
2205
/* then list the files in each folder */
2206
g_mutex_lock (&gphoto2_backend->lock);
2207
list = g_hash_table_lookup (gphoto2_backend->file_name_cache, filename);
2210
g_mutex_unlock (&gphoto2_backend->lock);
2211
ensure_not_dirty (gphoto2_backend);
2213
DEBUG (" Generating file list for dir '%s'", filename);
2215
gp_list_new (&list);
2216
rc = gp_camera_folder_list_files (gphoto2_backend->camera,
2219
gphoto2_backend->context);
2222
error = get_error_from_gphoto2 (_("Failed to get file list"), rc);
2223
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2224
g_error_free (error);
2231
DEBUG (" Using cached file list for dir '%s'", filename);
2232
using_cached_file_list = TRUE;
2234
g_mutex_unlock (&gphoto2_backend->lock);
2236
for (n = 0; n < gp_list_count (list); n++)
2240
gp_list_get_name (list, n, &name);
2241
DEBUG (" enum file '%s'", name);
2243
info = g_file_info_new ();
2245
if (!file_get_info (gphoto2_backend, filename, name, info, &error, FALSE))
2247
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2248
g_error_free (error);
2249
g_list_foreach (l, (GFunc) g_object_unref, NULL);
2251
gp_list_free (list);
2254
l = g_list_append (l, info);
2256
if (!using_cached_file_list)
2258
#ifndef DEBUG_NO_CACHING
2259
g_mutex_lock (&gphoto2_backend->lock);
2260
g_hash_table_insert (gphoto2_backend->file_name_cache, g_strdup (filename), list);
2261
g_mutex_unlock (&gphoto2_backend->lock);
2266
g_mutex_lock (&gphoto2_backend->lock);
2267
gp_list_unref (list);
2268
g_mutex_unlock (&gphoto2_backend->lock);
2271
/* and we're done */
2273
g_vfs_job_succeeded (G_VFS_JOB (job));
2274
g_vfs_job_enumerate_add_infos (job, l);
2275
g_list_foreach (l, (GFunc) g_object_unref, NULL);
2277
g_vfs_job_enumerate_done (job);
2282
/* ------------------------------------------------------------------------------------------------- */
2285
try_enumerate (GVfsBackend *backend,
2286
GVfsJobEnumerate *job,
2287
const char *given_filename,
2288
GFileAttributeMatcher *matcher,
2289
GFileQueryInfoFlags flags)
2291
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2302
filename = add_ignore_prefix (gphoto2_backend, given_filename);
2303
DEBUG ("try_enumerate (%s)", given_filename);
2305
/* first, list the folders */
2306
g_mutex_lock (&gphoto2_backend->lock);
2307
list = g_hash_table_lookup (gphoto2_backend->dir_name_cache, filename);
2310
g_mutex_unlock (&gphoto2_backend->lock);
2311
goto error_not_cached;
2314
g_mutex_unlock (&gphoto2_backend->lock);
2315
for (n = 0; n < gp_list_count (list); n++)
2317
gp_list_get_name (list, n, &name);
2318
DEBUG (" try_enum folder '%s'", name);
2319
info = g_file_info_new ();
2320
if (!file_get_info (gphoto2_backend, filename, name, info, &error, TRUE))
2322
g_mutex_lock (&gphoto2_backend->lock);
2323
gp_list_unref (list);
2324
g_mutex_unlock (&gphoto2_backend->lock);
2325
goto error_not_cached;
2327
l = g_list_append (l, info);
2329
g_mutex_lock (&gphoto2_backend->lock);
2330
gp_list_unref (list);
2331
g_mutex_unlock (&gphoto2_backend->lock);
2333
/* then list the files in each folder */
2334
g_mutex_lock (&gphoto2_backend->lock);
2335
list = g_hash_table_lookup (gphoto2_backend->file_name_cache, filename);
2338
g_mutex_unlock (&gphoto2_backend->lock);
2339
goto error_not_cached;
2342
g_mutex_unlock (&gphoto2_backend->lock);
2343
for (n = 0; n < gp_list_count (list); n++)
2345
gp_list_get_name (list, n, &name);
2346
DEBUG (" try_enum file '%s'", name);
2348
info = g_file_info_new ();
2349
if (!file_get_info (gphoto2_backend, filename, name, info, &error, TRUE))
2351
g_mutex_lock (&gphoto2_backend->lock);
2352
gp_list_unref (list);
2353
g_mutex_unlock (&gphoto2_backend->lock);
2354
goto error_not_cached;
2356
l = g_list_append (l, info);
2358
g_mutex_lock (&gphoto2_backend->lock);
2359
gp_list_unref (list);
2360
g_mutex_unlock (&gphoto2_backend->lock);
2362
/* and we're done */
2364
g_vfs_job_succeeded (G_VFS_JOB (job));
2365
g_vfs_job_enumerate_add_infos (job, l);
2366
g_list_foreach (l, (GFunc) g_object_unref, NULL);
2368
g_vfs_job_enumerate_done (job);
2371
DEBUG (" YAY got info from cache for try_enumerate (%s)", given_filename);
2375
g_list_foreach (l, (GFunc) g_object_unref, NULL);
2379
DEBUG (" BUU no info from cache for try_enumerate (%s)", given_filename);
2383
/* ------------------------------------------------------------------------------------------------- */
2386
do_query_fs_info (GVfsBackend *backend,
2387
GVfsJobQueryFsInfo *job,
2388
const char *filename,
2390
GFileAttributeMatcher *attribute_matcher)
2393
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2394
CameraStorageInformation *storage_info;
2395
int num_storage_info;
2397
DEBUG ("query_fs_info (%s)", filename);
2399
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "gphoto2");
2400
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL);
2401
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, !gphoto2_backend->can_write);
2403
rc = gp_camera_get_storageinfo (gphoto2_backend->camera, &storage_info, &num_storage_info, gphoto2_backend->context);
2406
if (num_storage_info >= 1)
2408
/* for now we only support a single storage head */
2409
if (storage_info[0].fields & GP_STORAGEINFO_MAXCAPACITY)
2411
g_mutex_lock (&gphoto2_backend->lock);
2412
gphoto2_backend->capacity = storage_info[0].capacitykbytes * 1024;
2413
g_mutex_unlock (&gphoto2_backend->lock);
2414
g_file_info_set_attribute_uint64 (info,
2415
G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,
2416
(guint64) gphoto2_backend->capacity);
2419
if (storage_info[0].fields & GP_STORAGEINFO_FREESPACEKBYTES)
2421
g_mutex_lock (&gphoto2_backend->lock);
2422
gphoto2_backend->free_space = storage_info[0].freekbytes * 1024;
2423
g_mutex_unlock (&gphoto2_backend->lock);
2424
g_file_info_set_attribute_uint64 (info,
2425
G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
2426
(guint64) gphoto2_backend->free_space);
2429
DEBUG (" got %d storage_info objects", num_storage_info);
2432
g_vfs_job_succeeded (G_VFS_JOB (job));
2435
/* ------------------------------------------------------------------------------------------------- */
2438
try_query_fs_info (GVfsBackend *backend,
2439
GVfsJobQueryFsInfo *job,
2440
const char *filename,
2442
GFileAttributeMatcher *attribute_matcher)
2444
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2449
DEBUG ("try_query_fs_info (%s)", filename);
2453
g_mutex_lock (&gphoto2_backend->lock);
2454
free_space = gphoto2_backend->free_space;
2455
capacity = gphoto2_backend->capacity;
2456
g_mutex_unlock (&gphoto2_backend->lock);
2458
if (free_space == -1 || capacity == -1)
2460
DEBUG (" BUU no info from cache for try_query_fs_info (%s)", filename);
2463
DEBUG (" YAY got info from cache for try_query_fs_info (%s)", filename);
2465
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "gphoto2");
2466
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL);
2467
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, !gphoto2_backend->can_write);
2468
g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, (guint64) capacity);
2469
g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, (guint64) free_space);
2470
g_vfs_job_succeeded (G_VFS_JOB (job));
2477
/* ------------------------------------------------------------------------------------------------- */
2480
do_make_directory (GVfsBackend *backend,
2481
GVfsJobMakeDirectory *job,
2482
const char *filename)
2484
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2490
DEBUG ("make_directory (%s)", filename);
2492
ensure_not_dirty (gphoto2_backend);
2498
if (!gphoto2_backend->can_write)
2500
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2501
G_IO_ERROR_NOT_SUPPORTED,
2502
_("Not supported"));
2506
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2508
rc = gp_camera_folder_make_dir (gphoto2_backend->camera,
2511
gphoto2_backend->context);
2514
error = get_error_from_gphoto2 (_("Error creating directory"), rc);
2515
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2516
g_error_free (error);
2520
caches_invalidate_dir (gphoto2_backend, dir);
2521
caches_invalidate_free_space (gphoto2_backend);
2522
monitors_emit_created (gphoto2_backend, dir, name);
2524
g_vfs_job_succeeded (G_VFS_JOB (job));
2531
/* ------------------------------------------------------------------------------------------------- */
2534
do_slow_file_rename_in_same_dir (GVfsBackendGphoto2 *gphoto2_backend,
2537
const char *new_name,
2538
gboolean allow_overwrite)
2542
CameraFile *file_dest;
2544
unsigned long int size;
2549
DEBUG ("do_slow_file_rename_in_same_dir() '%s' '%s' -> '%s'", dir, name, new_name);
2551
rc = gp_file_new (&file);
2555
rc = gp_camera_file_get (gphoto2_backend->camera,
2558
GP_FILE_TYPE_NORMAL,
2560
gphoto2_backend->context);
2564
rc = gp_file_get_data_and_size (file, &data, &size);
2568
rc = gp_file_new (&file_dest);
2572
rc = gp_file_copy (file_dest, file);
2576
rc = gp_file_set_name (file_dest, new_name);
2580
if (allow_overwrite)
2582
gp_camera_file_delete (gphoto2_backend->camera,
2585
gphoto2_backend->context);
2588
DEBUG (" file delete failed as part of slow rename rc=%d", rc);
2593
rc = gp_camera_folder_put_file (gphoto2_backend->camera, dir, file_dest, gphoto2_backend->context);
2597
rc = gp_camera_file_delete (gphoto2_backend->camera,
2600
gphoto2_backend->context);
2603
/* at least try to clean up the newly created file... */
2604
gp_camera_file_delete (gphoto2_backend->camera,
2607
gphoto2_backend->context);
2613
gp_file_unref (file);
2614
if (file_dest != NULL)
2615
gp_file_unref (file_dest);
2619
/* ------------------------------------------------------------------------------------------------- */
2622
do_file_rename_in_same_dir (GVfsBackendGphoto2 *gphoto2_backend,
2625
const char *new_name,
2626
gboolean allow_overwrite)
2628
/* TODO: The libgphoto2 API speaks of just using
2629
* gp_camera_file_set_info() to achieve this. However this
2630
* fails on the devices that I own. So fall back to the slow
2631
* method for now. Patches welcome for someone with a device
2632
* where the above mentioned trick works.
2634
return do_slow_file_rename_in_same_dir (gphoto2_backend, dir, name, new_name, allow_overwrite);
2637
/* ------------------------------------------------------------------------------------------------- */
2640
do_dir_rename_in_same_dir (GVfsBackendGphoto2 *gphoto2_backend,
2643
const char *new_name)
2648
dir_name = g_build_filename (dir, name, NULL);
2650
DEBUG ("do_dir_rename_in_same_dir() '%s' '%s' -> '%s' ('%s')", dir, name, new_name, dir_name);
2652
/* TODO: Support non-empty folders by recursively renaming stuff.
2653
* Or that might be too dangerous as it's not exactly atomic.
2654
* And renaming files may be slow; see do_file_rename_in_same_dir() above.
2656
if (is_directory_empty (gphoto2_backend, dir_name))
2658
rc = gp_camera_folder_make_dir (gphoto2_backend->camera,
2661
gphoto2_backend->context);
2665
rc = gp_camera_folder_remove_dir (gphoto2_backend->camera,
2668
gphoto2_backend->context);
2674
rc = GP_ERROR_NOT_SUPPORTED;
2682
/* ------------------------------------------------------------------------------------------------- */
2685
do_set_display_name (GVfsBackend *backend,
2686
GVfsJobSetDisplayName *job,
2687
const char *filename,
2688
const char *display_name)
2690
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2698
ensure_not_dirty (gphoto2_backend);
2700
DEBUG ("set_display_name() '%s' -> '%s'", filename, display_name);
2707
if (!gphoto2_backend->can_write)
2709
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2710
G_IO_ERROR_NOT_SUPPORTED,
2711
_("Not supported"));
2715
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2717
/* refuse is desired name is already taken */
2718
if (is_directory (gphoto2_backend, dir, display_name) ||
2719
is_regular (gphoto2_backend, dir, display_name))
2721
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2723
_("Name already exists"));
2727
/* ensure name is not too long - otherwise it might screw up enumerating
2728
* the folder on some devices
2730
if (strlen (display_name) > 63)
2732
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2733
G_IO_ERROR_NOT_SUPPORTED,
2734
_("New name too long"));
2738
if (is_directory (gphoto2_backend, dir, name))
2741
rc = do_dir_rename_in_same_dir (gphoto2_backend, dir, name, display_name);
2744
error = get_error_from_gphoto2 (_("Error renaming directory"), rc);
2745
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2746
g_error_free (error);
2749
caches_invalidate_file (gphoto2_backend, dir, name);
2754
rc = do_file_rename_in_same_dir (gphoto2_backend, dir, name, display_name, FALSE);
2757
error = get_error_from_gphoto2 (_("Error renaming file"), rc);
2758
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2759
g_error_free (error);
2762
caches_invalidate_file (gphoto2_backend, dir, name);
2766
/* emit on monitor */
2767
monitors_emit_deleted (gphoto2_backend, dir, name);
2768
monitors_emit_created (gphoto2_backend, dir, display_name);
2770
new_name = g_build_filename (dir + strlen (gphoto2_backend->ignore_prefix), display_name, NULL);
2771
g_vfs_job_set_display_name_set_new_path (job, new_name);
2773
g_vfs_job_succeeded (G_VFS_JOB (job));
2782
/* ------------------------------------------------------------------------------------------------- */
2785
do_delete (GVfsBackend *backend,
2787
const char *filename)
2789
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2796
ensure_not_dirty (gphoto2_backend);
2798
DEBUG ("delete() '%s'", filename);
2804
if (!gphoto2_backend->can_delete)
2806
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2807
G_IO_ERROR_NOT_SUPPORTED,
2808
_("Not supported"));
2812
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2814
if (is_directory (gphoto2_backend, dir, name))
2816
dir_name = add_ignore_prefix (gphoto2_backend, filename);
2817
if (!is_directory_empty (gphoto2_backend, dir_name))
2819
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2820
G_IO_ERROR_NOT_EMPTY,
2821
_("Directory '%s' is not empty"), filename);
2826
rc = gp_camera_folder_remove_dir (gphoto2_backend->camera,
2829
gphoto2_backend->context);
2832
error = get_error_from_gphoto2 (_("Error deleting directory"), rc);
2833
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2834
g_error_free (error);
2837
caches_invalidate_file (gphoto2_backend, dir, name);
2838
caches_invalidate_free_space (gphoto2_backend);
2839
monitors_emit_deleted (gphoto2_backend, dir, name);
2844
if (!is_regular (gphoto2_backend, dir, name))
2846
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2847
G_IO_ERROR_NOT_FOUND,
2848
_("No such file or directory"));
2852
rc = gp_camera_file_delete (gphoto2_backend->camera,
2855
gphoto2_backend->context);
2858
error = get_error_from_gphoto2 (_("Error deleting file"), rc);
2859
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2860
g_error_free (error);
2864
caches_invalidate_file (gphoto2_backend, dir, name);
2865
caches_invalidate_free_space (gphoto2_backend);
2866
monitors_emit_deleted (gphoto2_backend, dir, name);
2869
g_vfs_job_succeeded (G_VFS_JOB (job));
2877
/* ------------------------------------------------------------------------------------------------- */
2880
do_create_internal (GVfsBackend *backend,
2881
GVfsJobOpenForWrite *job,
2882
const char *filename,
2883
GFileCreateFlags flags,
2884
gboolean job_is_replace,
2885
gboolean job_is_append_to)
2887
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2888
WriteHandle *handle;
2892
ensure_not_dirty (gphoto2_backend);
2897
if (!gphoto2_backend->can_write)
2899
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2900
G_IO_ERROR_NOT_SUPPORTED,
2901
_("Not supported"));
2905
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2907
if (is_directory (gphoto2_backend, dir, name))
2909
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2910
G_IO_ERROR_IS_DIRECTORY,
2911
_("Can't write to directory"));
2915
/* unless we're replacing or appending.. error out if file already exists */
2916
if (is_regular (gphoto2_backend, dir, name))
2918
if (! (job_is_replace || job_is_append_to))
2920
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2928
if (job_is_replace || job_is_append_to)
2930
/* so we're not really replacing or appending; dont fail these
2931
* operations; just turn them into create instead...
2933
job_is_replace = FALSE;
2934
job_is_append_to = FALSE;
2938
handle = g_new0 (WriteHandle, 1);
2939
handle->filename = g_strdup (filename);
2940
handle->dir = g_strdup (dir);
2941
handle->name = g_strdup (name);
2942
handle->job_is_replace = job_is_replace;
2943
handle->job_is_append_to = job_is_append_to;
2944
handle->is_dirty = TRUE;
2946
/* if we're appending to a file read in all of the file to memory */
2947
if (job_is_append_to)
2953
unsigned long int size;
2955
rc = gp_file_new (&file);
2958
error = get_error_from_gphoto2 (_("Cannot allocate new file to append to"), rc);
2959
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2960
g_error_free (error);
2961
write_handle_free (handle);
2965
rc = gp_camera_file_get (gphoto2_backend->camera,
2968
GP_FILE_TYPE_NORMAL,
2970
gphoto2_backend->context);
2973
error = get_error_from_gphoto2 (_("Cannot read file to append to"), rc);
2974
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2975
g_error_free (error);
2976
write_handle_free (handle);
2977
gp_file_unref (file);
2981
rc = gp_file_get_data_and_size (file, &data, &size);
2984
error = get_error_from_gphoto2 (_("Cannot get data of file to append to"), rc);
2985
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2986
g_error_free (error);
2987
write_handle_free (handle);
2988
gp_file_unref (file);
2992
handle->data = g_malloc (size + WRITE_INCREMENT);
2993
handle->allocated_size = size + WRITE_INCREMENT;
2994
handle->size = size;
2995
handle->cursor = size;
2996
memcpy (handle->data, data, size);
2997
gp_file_unref (file);
3002
handle->data = g_malloc (WRITE_INCREMENT);
3003
handle->allocated_size = WRITE_INCREMENT;
3006
g_vfs_job_open_for_write_set_handle (job, handle);
3007
g_vfs_job_open_for_write_set_can_seek (job, TRUE);
3009
gphoto2_backend->open_write_handles = g_list_prepend (gphoto2_backend->open_write_handles, handle);
3011
DEBUG (" handle=%p", handle);
3013
/* make sure we invalidate the dir and the file */
3014
caches_invalidate_file (gphoto2_backend, dir, name);
3016
/* emit on the monitor - hopefully some client won't need info
3017
* about this (to avoid committing dirty bits midwrite) before
3018
* the write is done...
3020
if (job_is_replace || job_is_append_to)
3021
monitors_emit_changed (gphoto2_backend, dir, name);
3023
monitors_emit_created (gphoto2_backend, dir, name);
3025
g_vfs_job_succeeded (G_VFS_JOB (job));
3032
/* ------------------------------------------------------------------------------------------------- */
3035
do_create (GVfsBackend *backend,
3036
GVfsJobOpenForWrite *job,
3037
const char *filename,
3038
GFileCreateFlags flags)
3040
DEBUG ("create() '%s' flags=0x%04x", filename, flags);
3042
return do_create_internal (backend, job, filename, flags, FALSE, FALSE);
3045
/* ------------------------------------------------------------------------------------------------- */
3048
do_replace (GVfsBackend *backend,
3049
GVfsJobOpenForWrite *job,
3050
const char *filename,
3052
gboolean make_backup,
3053
GFileCreateFlags flags)
3055
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3059
DEBUG ("replace() '%s' etag='%s' make_backup=%d flags=0x%04x", filename, etag, make_backup, flags);
3063
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
3066
* - will delete the existing one when done in do_close_write()
3068
do_create_internal (backend, job, filename, flags, TRUE, FALSE);
3074
/* ------------------------------------------------------------------------------------------------- */
3077
do_append_to (GVfsBackend *backend,
3078
GVfsJobOpenForWrite *job,
3079
const char *filename,
3080
GFileCreateFlags flags)
3082
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3086
DEBUG ("append_to() '%s' flags=0x%04x", filename, flags);
3090
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
3093
* - will read existing data in do_create_internal
3094
* - will delete the existing one when done in do_close_write()
3096
do_create_internal (backend, job, filename, flags, FALSE, TRUE);
3102
/* ------------------------------------------------------------------------------------------------- */
3105
do_write (GVfsBackend *backend,
3107
GVfsBackendHandle _handle,
3111
WriteHandle *handle = _handle;
3113
DEBUG ("write() %p, '%s', %d bytes", handle, handle->filename, buffer_size);
3115
/* ensure we have enough room */
3116
if (handle->cursor + buffer_size > handle->allocated_size)
3118
unsigned long int new_allocated_size;
3119
new_allocated_size = ((handle->cursor + buffer_size) / WRITE_INCREMENT + 1) * WRITE_INCREMENT;
3120
handle->data = g_realloc (handle->data, new_allocated_size);
3121
handle->allocated_size = new_allocated_size;
3122
DEBUG (" allocated_size is now %ld bytes)", handle->allocated_size);
3126
memcpy (handle->data + handle->cursor, buffer, buffer_size);
3127
handle->cursor += buffer_size;
3129
if (handle->cursor > handle->size)
3130
handle->size = handle->cursor;
3132
/* this will make us dirty */
3133
handle->is_dirty = TRUE;
3135
g_vfs_job_write_set_written_size (job, buffer_size);
3136
g_vfs_job_succeeded (G_VFS_JOB (job));
3139
/* ------------------------------------------------------------------------------------------------- */
3142
do_seek_on_write (GVfsBackend *backend,
3143
GVfsJobSeekWrite *job,
3144
GVfsBackendHandle handle,
3148
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3149
WriteHandle *write_handle = handle;
3152
DEBUG ("seek_on_write() %p '%s' offset=%d type=%d cursor=%ld size=%ld", write_handle, write_handle->filename, (int)offset, type, write_handle->cursor, write_handle->size);
3158
new_offset = offset;
3161
new_offset = write_handle->cursor + offset;
3164
new_offset = write_handle->size + offset;
3168
if (new_offset < 0 || new_offset > write_handle->size)
3170
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
3172
_("Error seeking in stream on camera %s"), gphoto2_backend->gphoto2_port);
3176
write_handle->cursor = new_offset;
3177
g_vfs_job_seek_write_set_offset (job, offset);
3178
g_vfs_job_succeeded (G_VFS_JOB (job));
3182
/* ------------------------------------------------------------------------------------------------- */
3184
/* this functions updates the device with the data currently in write_handle */
3186
commit_write_handle (GVfsBackendGphoto2 *gphoto2_backend, WriteHandle *write_handle)
3191
DEBUG ("commit_write_handle() '%s' of size %ld", write_handle->filename, write_handle->size);
3193
/* no need to write as we're not dirty */
3194
if (!write_handle->is_dirty)
3196
DEBUG (" not dirty => not writing");
3200
if (write_handle->delete_before ||
3201
(write_handle->job_is_replace || write_handle->job_is_append_to))
3203
/* OK, so this is not atomic. But there's no way we can make it
3204
* atomic until rename works properly - see comments in
3205
* do_set_display_name() and why have do_slow_rename()...
3207
* So first delete the existing file...
3209
rc = gp_camera_file_delete (gphoto2_backend->camera,
3212
gphoto2_backend->context);
3216
DEBUG (" deleted '%s' '%s' for delete_before=%d, job_is_replace=%d, job_is_append_to=%d",
3217
write_handle->dir, write_handle->name,
3218
write_handle->delete_before, write_handle->job_is_replace, write_handle->job_is_append_to);
3221
rc = gp_file_new (&file);
3225
gp_file_set_type (file, GP_FILE_TYPE_NORMAL);
3226
gp_file_set_name (file, write_handle->name);
3227
gp_file_set_mtime (file, time (NULL));
3228
gp_file_set_data_and_size (file,
3229
dup_for_gphoto2 (write_handle->data, write_handle->size),
3230
write_handle->size);
3232
rc = gp_camera_folder_put_file (gphoto2_backend->camera, write_handle->dir, file, gphoto2_backend->context);
3235
gp_file_unref (file);
3239
DEBUG (" successfully wrote '%s' of %ld bytes", write_handle->filename, write_handle->size);
3240
monitors_emit_changed (gphoto2_backend, write_handle->dir, write_handle->name);
3242
gp_file_unref (file);
3245
write_handle->is_dirty = FALSE;
3246
write_handle->delete_before = TRUE;
3248
caches_invalidate_file (gphoto2_backend, write_handle->dir, write_handle->name);
3249
caches_invalidate_free_space (gphoto2_backend);
3254
/* ------------------------------------------------------------------------------------------------- */
3257
do_close_write (GVfsBackend *backend,
3258
GVfsJobCloseWrite *job,
3259
GVfsBackendHandle handle)
3261
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3262
WriteHandle *write_handle = handle;
3266
DEBUG ("close_write() %p '%s' %ld bytes total", write_handle, write_handle->filename, write_handle->size);
3268
rc = commit_write_handle (gphoto2_backend, write_handle);
3271
error = get_error_from_gphoto2 (_("Error writing file"), rc);
3272
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
3273
g_error_free (error);
3277
monitors_emit_changed (gphoto2_backend, write_handle->dir, write_handle->name);
3279
g_vfs_job_succeeded (G_VFS_JOB (job));
3282
write_handle_free (write_handle);
3283
gphoto2_backend->open_write_handles = g_list_remove (gphoto2_backend->open_write_handles, write_handle);
3286
/* ------------------------------------------------------------------------------------------------- */
3289
do_move (GVfsBackend *backend,
3292
const char *destination,
3293
GFileCopyFlags flags,
3294
GFileProgressCallback progress_callback,
3295
gpointer progress_callback_data)
3297
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3306
DEBUG ("move() '%s' -> '%s' %04x)", source, destination, flags);
3308
ensure_not_dirty (gphoto2_backend);
3310
split_filename_with_ignore_prefix (gphoto2_backend, source, &src_dir, &src_name);
3311
split_filename_with_ignore_prefix (gphoto2_backend, destination, &dst_dir, &dst_name);
3313
/* this is an limited implementation that can only move files / folders in the same directory */
3314
if (strcmp (src_dir, dst_dir) != 0)
3316
DEBUG (" not supported (not same directory)");
3317
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
3318
G_IO_ERROR_NOT_SUPPORTED,
3319
_("Not supported (not same directory)"));
3324
if (is_directory (gphoto2_backend, src_dir, src_name))
3326
if (is_directory (gphoto2_backend, dst_dir, dst_name))
3328
DEBUG (" not supported (src is dir; dst is dir)");
3329
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
3330
G_IO_ERROR_NOT_SUPPORTED,
3331
_("Not supported (the source is a directory, the destination is a directory too)"));
3334
else if (is_regular (gphoto2_backend, dst_dir, dst_name))
3336
DEBUG (" not supported (src is dir; dst is existing file)");
3337
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
3338
G_IO_ERROR_NOT_SUPPORTED,
3339
_("Not supported (the source is a directory, but the destination is an existing file)"));
3346
if (is_directory (gphoto2_backend, dst_dir, dst_name))
3348
DEBUG (" not supported (src is file; dst is dir)");
3349
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
3350
G_IO_ERROR_NOT_SUPPORTED,
3351
_("Not supported (the source is a file, but the destination is a directory)"));
3356
/* ensure name is not too long - otherwise it might screw up enumerating
3357
* the folder on some devices
3359
if (strlen (dst_name) > 63)
3361
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
3362
G_IO_ERROR_NOT_SUPPORTED,
3363
_("New name too long"));
3369
DEBUG (" renaming dir");
3370
rc = do_dir_rename_in_same_dir (gphoto2_backend, src_dir, src_name, dst_name);
3373
DEBUG (" error renaming dir");
3374
error = get_error_from_gphoto2 (_("Error renaming directory"), rc);
3375
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
3376
g_error_free (error);
3382
DEBUG (" renaming file");
3383
rc = do_file_rename_in_same_dir (gphoto2_backend, src_dir, src_name, dst_name, flags & G_FILE_COPY_OVERWRITE);
3386
DEBUG (" error renaming file");
3387
error = get_error_from_gphoto2 (_("Error renaming file"), rc);
3388
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
3389
g_error_free (error);
3394
caches_invalidate_file (gphoto2_backend, src_dir, src_name);
3395
monitors_emit_deleted (gphoto2_backend, src_dir, src_name);
3396
monitors_emit_created (gphoto2_backend, src_dir, dst_name);
3400
g_vfs_job_succeeded (G_VFS_JOB (job));
3409
/* ------------------------------------------------------------------------------------------------- */
3412
vfs_dir_monitor_destroyed (gpointer user_data, GObject *where_the_object_was)
3415
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (user_data);
3417
DEBUG ("vfs_dir_monitor_destroyed()");
3419
for (l = gphoto2_backend->dir_monitor_proxies; l != NULL; l = l->next)
3421
MonitorProxy *proxy = l->data;
3422
if (G_OBJECT (proxy->vfs_monitor) == where_the_object_was)
3424
gphoto2_backend->dir_monitor_proxies = g_list_remove (gphoto2_backend->dir_monitor_proxies, proxy);
3425
DEBUG (" Removed dead dir monitor for '%s'", proxy->path);
3426
monitor_proxy_free (proxy);
3433
do_create_dir_monitor (GVfsBackend *backend,
3434
GVfsJobCreateMonitor *job,
3435
const char *filename,
3436
GFileMonitorFlags flags)
3440
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3441
MonitorProxy *proxy;
3443
DEBUG ("create_dir_monitor (%s)", filename);
3445
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
3447
proxy = g_new0 (MonitorProxy, 1);
3448
proxy->path = add_ignore_prefix (gphoto2_backend, filename);
3449
proxy->vfs_monitor = g_vfs_monitor_new (backend);
3451
gphoto2_backend->dir_monitor_proxies = g_list_prepend (gphoto2_backend->dir_monitor_proxies, proxy);
3453
g_vfs_job_create_monitor_set_monitor (job, proxy->vfs_monitor);
3454
g_object_weak_ref (G_OBJECT (proxy->vfs_monitor), vfs_dir_monitor_destroyed, gphoto2_backend);
3455
g_object_unref (proxy->vfs_monitor);
3456
g_vfs_job_succeeded (G_VFS_JOB (job));
3459
/* ------------------------------------------------------------------------------------------------- */
3462
vfs_file_monitor_destroyed (gpointer user_data, GObject *where_the_object_was)
3465
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (user_data);
3467
DEBUG ("vfs_file_monitor_destroyed()");
3469
for (l = gphoto2_backend->file_monitor_proxies; l != NULL; l = l->next)
3471
MonitorProxy *proxy = l->data;
3472
if (G_OBJECT (proxy->vfs_monitor) == where_the_object_was)
3474
gphoto2_backend->dir_monitor_proxies = g_list_remove (gphoto2_backend->dir_monitor_proxies, proxy);
3475
DEBUG (" Removed dead file monitor for '%s'", proxy->path);
3476
monitor_proxy_free (proxy);
3483
do_create_file_monitor (GVfsBackend *backend,
3484
GVfsJobCreateMonitor *job,
3485
const char *filename,
3486
GFileMonitorFlags flags)
3490
GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3491
MonitorProxy *proxy;
3493
DEBUG ("create_file_monitor (%s)", filename);
3495
split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
3497
proxy = g_new0 (MonitorProxy, 1);
3498
proxy->path = add_ignore_prefix (gphoto2_backend, filename);
3499
proxy->vfs_monitor = g_vfs_monitor_new (backend);
3501
gphoto2_backend->file_monitor_proxies = g_list_prepend (gphoto2_backend->file_monitor_proxies, proxy);
3503
g_vfs_job_create_monitor_set_monitor (job, proxy->vfs_monitor);
3504
g_object_weak_ref (G_OBJECT (proxy->vfs_monitor), vfs_file_monitor_destroyed, gphoto2_backend);
3505
g_object_unref (proxy->vfs_monitor);
3506
g_vfs_job_succeeded (G_VFS_JOB (job));
3509
/* ------------------------------------------------------------------------------------------------- */
3512
g_vfs_backend_gphoto2_class_init (GVfsBackendGphoto2Class *klass)
3514
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3515
GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
3517
gobject_class->finalize = g_vfs_backend_gphoto2_finalize;
3519
backend_class->try_mount = try_mount;
3520
backend_class->mount = do_mount;
3521
backend_class->open_icon_for_read = do_open_icon_for_read;
3522
backend_class->open_for_read = do_open_for_read;
3523
backend_class->try_read = try_read;
3524
backend_class->try_seek_on_read = try_seek_on_read;
3525
backend_class->close_read = do_close_read;
3526
backend_class->query_info = do_query_info;
3527
backend_class->enumerate = do_enumerate;
3528
backend_class->query_fs_info = do_query_fs_info;
3529
backend_class->make_directory = do_make_directory;
3530
backend_class->set_display_name = do_set_display_name;
3531
backend_class->delete = do_delete;
3532
backend_class->create = do_create;
3533
backend_class->replace = do_replace;
3534
backend_class->append_to = do_append_to;
3535
backend_class->write = do_write;
3536
backend_class->close_write = do_close_write;
3537
backend_class->seek_on_write = do_seek_on_write;
3538
backend_class->move = do_move;
3539
backend_class->create_dir_monitor = do_create_dir_monitor;
3540
backend_class->create_file_monitor = do_create_file_monitor;
3542
/* fast sync versions that only succeed if info is in the cache */
3543
backend_class->try_query_info = try_query_info;
3544
backend_class->try_enumerate = try_enumerate;
3545
backend_class->try_query_fs_info = try_query_fs_info;