~ubuntu-branches/ubuntu/precise/gvfs/precise-proposed

« back to all changes in this revision

Viewing changes to .pc/07_gphoto2_mutex_init.patch/daemon/gvfsbackendgphoto2.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2012-04-16 22:23:43 UTC
  • mfrom: (1.1.83)
  • Revision ID: package-import@ubuntu.com-20120416222343-v6omfnmfg1go4b3e
Tags: 1.12.1-0ubuntu1
* New upstream release: 
  - udisks2: Fix some memory leaks (not relevant for Ubuntu)
  - gphoto2: Initialize mutex early enough
  - afc: Fix building against libimobiledevice-1.1.2
  - afp: Prevent redefinition of GVfsAfpServer
  - Translation updates
* Drop 07_gphoto2_mutex_init.patch, upstream now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
/* GVFS gphoto2 file system driver
3
 
 * 
4
 
 * Copyright (C) 2007-2008 Red Hat, Inc.
5
 
 *
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.
10
 
 *
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.
15
 
 *
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.
20
 
 *
21
 
 * Author: David Zeuthen <davidz@redhat.com>
22
 
 */
23
 
 
24
 
#include <config.h>
25
 
 
26
 
#include <sys/types.h>
27
 
#include <sys/stat.h>
28
 
#include <errno.h>
29
 
#include <unistd.h>
30
 
#include <fcntl.h>
31
 
#include <string.h>
32
 
#include <stdlib.h>
33
 
 
34
 
#include <glib/gstdio.h>
35
 
#include <glib/gi18n.h>
36
 
#include <gio/gio.h>
37
 
#include <gphoto2.h>
38
 
#ifdef HAVE_GUDEV
39
 
  #include <gudev/gudev.h>
40
 
#elif defined(HAVE_HAL)
41
 
  #include <libhal.h>
42
 
  #include <dbus/dbus.h>
43
 
#else
44
 
  #error Needs hal or gudev
45
 
#endif
46
 
#include <sys/time.h>
47
 
 
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"
63
 
#include "gvfsicon.h"
64
 
 
65
 
/* showing debug traces */
66
 
#if 1
67
 
#define DEBUG_SHOW_TRACES 1
68
 
#endif
69
 
 
70
 
/* showing libgphoto2 output */
71
 
#if 0
72
 
#define DEBUG_SHOW_LIBGPHOTO2_OUTPUT 1
73
 
#endif
74
 
 
75
 
/* use this to disable caching */
76
 
#if 0
77
 
#define DEBUG_NO_CACHING 1
78
 
#endif
79
 
 
80
 
/*--------------------------------------------------------------------------------------------------------------*/
81
 
 
82
 
/* TODO:
83
 
 *
84
 
 *  - write support
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
91
 
 *
92
 
 *    - Note that most PTP devices (e.g. digital cameras) don't support writing
93
 
 *      - Most MTP devices (e.g. digital audio players) do
94
 
 *
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.
99
 
 *
100
 
 *         $ pwd
101
 
 *         /home/davidz/.gvfs/gphoto2 mount on usb%3A001,051/foo
102
 
 *         $ echo a > a
103
 
 *         $ echo b > b
104
 
 *         $ ls -l
105
 
 *         total 0
106
 
 *         -rw------- 1 davidz davidz 2 2008-03-02 13:22 a
107
 
 *         -rw------- 1 davidz davidz 2 2008-03-02 13:22 b
108
 
 *         $ cat a
109
 
 *         a
110
 
 *         $ cat b
111
 
 *         b
112
 
 *         $ mv b a
113
 
 *         $ ls -l
114
 
 *         total 0
115
 
 *         -rw------- 1 davidz davidz 2 2008-03-02 13:22 a
116
 
 *         $ cat a
117
 
 *         b
118
 
 *         $ rm a
119
 
 *
120
 
 *      See, this worked fine.. Now see what happens if we
121
 
 *      use different files names
122
 
 *
123
 
 *         $ echo a > file.txt
124
 
 *         $ echo b > file.txt~
125
 
 *         $ ls -l
126
 
 *         total 0
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~
129
 
 *         $ cat file.txt
130
 
 *         a
131
 
 *         $ cat file.txt~
132
 
 *         b
133
 
 *         $ mv file.txt~ file.txt
134
 
 *         $ ls -l
135
 
 *         total 0
136
 
 *         -rw------- 1 davidz davidz 0 1969-12-31 18:59 file.txt
137
 
 *         $ cat file.txt 
138
 
 *         $
139
 
 *
140
 
 *      Awesome. I hate hardware.
141
 
 *
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.
145
 
 *
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.
148
 
 *
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
153
 
 *
154
 
 *      - Need to test this with a native gio version of gedit that should
155
 
 *        use replace() directly instead of fooling around with ~-style
156
 
 *        backup files
157
 
 *
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)
160
 
 *
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
165
 
 *      gvfs-mount(1).
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?
170
 
 *    
171
 
 */
172
 
 
173
 
struct _GVfsBackendGphoto2
174
 
{
175
 
  GVfsBackend parent_instance;
176
 
 
177
 
  /* a gphoto2 specific identifier for the gphoto2 camera such as usb:001,041 */
178
 
  char *gphoto2_port;
179
 
  GPContext *context;
180
 
  Camera *camera;
181
 
 
182
 
  /* see comment in ensure_ignore_prefix() */
183
 
  char *ignore_prefix;
184
 
 
185
 
#ifdef HAVE_GUDEV
186
 
  GUdevClient *gudev_client;
187
 
  GUdevDevice *udev_device;
188
 
#elif defined(HAVE_HAL)
189
 
  DBusConnection *dbus_connection;
190
 
  LibHalContext *hal_ctx;
191
 
  char *hal_udi;
192
 
  char *hal_name;
193
 
#endif
194
 
  char *icon_name;
195
 
 
196
 
  /* whether we can write to the device */
197
 
  gboolean can_write;
198
 
  /* whether we can delete files from to the device */
199
 
  gboolean can_delete;
200
 
 
201
 
  /* This lock protects all members in this class that are not
202
 
   * used both on the main thread and on the IO thread. 
203
 
   *
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).
207
 
   *
208
 
   * Must only be held for very short amounts of time (e.g. no IO).
209
 
   */
210
 
  GMutex lock;
211
 
 
212
 
  /* CACHES */
213
 
 
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().
217
 
   */
218
 
  gint64 free_space;
219
 
  gint64 capacity;
220
 
 
221
 
  /* fully qualified path -> GFileInfo */
222
 
  GHashTable *info_cache;
223
 
 
224
 
  /* dir name -> CameraList of (sub-) directory names in given directory */
225
 
  GHashTable *dir_name_cache;
226
 
 
227
 
  /* dir name -> CameraList of file names in given directory */
228
 
  GHashTable *file_name_cache;
229
 
 
230
 
  /* monitors (only used on the IO thread) */
231
 
  GList *dir_monitor_proxies;
232
 
  GList *file_monitor_proxies;
233
 
 
234
 
  /* list of open read handles (only used on the IO thread) */
235
 
  GList *open_read_handles;
236
 
 
237
 
  /* list of open write handles (only used on the IO thread) */
238
 
  GList *open_write_handles;
239
 
};
240
 
 
241
 
G_DEFINE_TYPE (GVfsBackendGphoto2, g_vfs_backend_gphoto2, G_VFS_TYPE_BACKEND);
242
 
 
243
 
/* ------------------------------------------------------------------------------------------------- */
244
 
 
245
 
typedef struct {
246
 
  /* this is the path of the dir/file including ignore_prefix */
247
 
  char *path;
248
 
  GVfsMonitor *vfs_monitor;
249
 
} MonitorProxy;
250
 
 
251
 
static void
252
 
monitor_proxy_free (MonitorProxy *proxy)
253
 
{
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()
257
 
   */
258
 
}
259
 
 
260
 
/* ------------------------------------------------------------------------------------------------- */
261
 
 
262
 
typedef struct {
263
 
  /* filename as given from the vfs without ignore prefix e.g. /foo.txt */
264
 
  char *filename;
265
 
 
266
 
  /* filename with ignore prefix splitted into dir and name; e.g. "/store_00010001/" and "foo.txt" */
267
 
  char *dir;
268
 
  char *name;
269
 
 
270
 
  char *data;
271
 
  unsigned long int size;
272
 
  unsigned long int cursor;
273
 
  unsigned long int allocated_size;
274
 
 
275
 
  gboolean job_is_replace;
276
 
  gboolean job_is_append_to;
277
 
 
278
 
  gboolean delete_before;
279
 
 
280
 
  gboolean is_dirty;
281
 
} WriteHandle;
282
 
 
283
 
/* how much more memory to ask for when using g_realloc() when writing a file */
284
 
#define WRITE_INCREMENT 4096
285
 
 
286
 
typedef struct {
287
 
  CameraFile *file;
288
 
 
289
 
  const char *data;
290
 
  unsigned long int size;
291
 
  unsigned long int cursor;
292
 
} ReadHandle;
293
 
 
294
 
/* ------------------------------------------------------------------------------------------------- */
295
 
 
296
 
static void
297
 
DEBUG (const gchar *message, ...)
298
 
{
299
 
#ifdef DEBUG_SHOW_TRACES
300
 
  va_list args;
301
 
  va_start (args, message);
302
 
  g_vfprintf (stderr, message, args);
303
 
  va_end (args);
304
 
  g_fprintf (stderr, "\n");
305
 
  fflush (stderr);
306
 
#endif
307
 
}
308
 
 
309
 
/* ------------------------------------------------------------------------------------------------- */
310
 
 
311
 
static int commit_write_handle (GVfsBackendGphoto2 *gphoto2_backend, WriteHandle *write_handle);
312
 
 
313
 
static void
314
 
write_handle_free (WriteHandle *write_handle)
315
 
{
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);
321
 
}
322
 
 
323
 
/* This must be called before reading from the device to ensure that
324
 
 * all pending writes are written to the device.
325
 
 *
326
 
 * Must only be called on the IO thread.
327
 
 */
328
 
static void
329
 
ensure_not_dirty (GVfsBackendGphoto2 *gphoto2_backend)
330
 
{
331
 
  GList *l;
332
 
 
333
 
  for (l = gphoto2_backend->open_write_handles; l != NULL; l = l->next)
334
 
    {
335
 
      WriteHandle *write_handle = l->data;
336
 
 
337
 
      DEBUG ("ensure_not_dirty: looking at handle for '%s", write_handle->filename);
338
 
 
339
 
      if (write_handle->is_dirty)
340
 
        commit_write_handle (gphoto2_backend, write_handle);
341
 
    }
342
 
}
343
 
 
344
 
/* ------------------------------------------------------------------------------------------------- */
345
 
 
346
 
/* used when gphoto2 will take ownership of this data for it's LRU cache - and will use free(3) to free it */
347
 
static char *
348
 
dup_for_gphoto2 (char *gmem, unsigned long int size)
349
 
{
350
 
  char *mem;
351
 
  mem = malloc (size);
352
 
  memcpy (mem, gmem, size);
353
 
  return mem;
354
 
}
355
 
 
356
 
/* ------------------------------------------------------------------------------------------------- */
357
 
 
358
 
static void
359
 
monitors_emit_internal (GVfsBackendGphoto2 *gphoto2_backend, 
360
 
                        const char *dir, 
361
 
                        const char *name, 
362
 
                        GFileMonitorEvent event,
363
 
                        const char *event_name)
364
 
{
365
 
  GList *l;
366
 
  char *filepath;
367
 
 
368
 
  g_return_if_fail (g_str_has_prefix (dir, gphoto2_backend->ignore_prefix));
369
 
 
370
 
  DEBUG ("monitors_emit_internal() %s for '%s' '%s'", event_name, dir, name);
371
 
 
372
 
  for (l = gphoto2_backend->dir_monitor_proxies; l != NULL; l = l->next)
373
 
    {
374
 
      MonitorProxy *proxy = l->data;
375
 
      if (strcmp (proxy->path, dir) == 0)
376
 
        {
377
 
          char *path;
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);
381
 
          g_free (path);
382
 
        }
383
 
    }
384
 
 
385
 
  filepath = g_build_filename (dir, name, NULL);
386
 
  for (l = gphoto2_backend->file_monitor_proxies; l != NULL; l = l->next)
387
 
    {
388
 
      MonitorProxy *proxy = l->data;
389
 
      if (strcmp (proxy->path, filepath) == 0)
390
 
        {
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);
394
 
        }
395
 
    }
396
 
  g_free (filepath);
397
 
}
398
 
 
399
 
/* ------------------------------------------------------------------------------------------------- */
400
 
 
401
 
/* call this when a file/directory have been added to a directory */
402
 
static void
403
 
monitors_emit_created (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
404
 
{
405
 
  DEBUG ("monitors_emit_created(): '%s' '%s'", dir, name);
406
 
  monitors_emit_internal (gphoto2_backend, dir, name, G_FILE_MONITOR_EVENT_CREATED, "CREATED");
407
 
}
408
 
 
409
 
/* ------------------------------------------------------------------------------------------------- */
410
 
 
411
 
/* call this when a file/directory have been deleted from a directory */
412
 
static void
413
 
monitors_emit_deleted (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
414
 
{
415
 
  DEBUG ("monitors_emit_deleted(): '%s' '%s'", dir, name);
416
 
  monitors_emit_internal (gphoto2_backend, dir, name, G_FILE_MONITOR_EVENT_DELETED, "DELETED");
417
 
}
418
 
 
419
 
/* ------------------------------------------------------------------------------------------------- */
420
 
 
421
 
/* call this when a file/directory have been changed in a directory */
422
 
static void
423
 
monitors_emit_changed (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
424
 
{
425
 
  DEBUG ("monitors_emit_changed(): '%s' '%s'", dir, name);
426
 
  monitors_emit_internal (gphoto2_backend, dir, name, G_FILE_MONITOR_EVENT_CHANGED, "CHANGED");
427
 
}
428
 
 
429
 
/* ------------------------------------------------------------------------------------------------- */
430
 
 
431
 
static void
432
 
caches_invalidate_all (GVfsBackendGphoto2 *gphoto2_backend)
433
 
{
434
 
  DEBUG ("caches_invalidate_all()");
435
 
 
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);
446
 
}
447
 
 
448
 
/* ------------------------------------------------------------------------------------------------- */
449
 
 
450
 
static void
451
 
caches_invalidate_free_space (GVfsBackendGphoto2 *gphoto2_backend)
452
 
{
453
 
  g_mutex_lock (&gphoto2_backend->lock);
454
 
  gphoto2_backend->free_space = -1;  
455
 
  g_mutex_unlock (&gphoto2_backend->lock);
456
 
}
457
 
 
458
 
/* ------------------------------------------------------------------------------------------------- */
459
 
 
460
 
static void
461
 
caches_invalidate_dir (GVfsBackendGphoto2 *gphoto2_backend, const char *dir)
462
 
{
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);
469
 
}
470
 
 
471
 
/* ------------------------------------------------------------------------------------------------- */
472
 
 
473
 
static void
474
 
caches_invalidate_file (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
475
 
{
476
 
  char *full_name;
477
 
 
478
 
  full_name = g_build_filename (dir, name, NULL);
479
 
 
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);
485
 
 
486
 
  g_hash_table_remove (gphoto2_backend->info_cache, full_name);
487
 
  g_mutex_unlock (&gphoto2_backend->lock);
488
 
 
489
 
  DEBUG ("caches_invalidate_file() for '%s'", full_name);
490
 
  g_free (full_name);
491
 
}
492
 
 
493
 
/* ------------------------------------------------------------------------------------------------- */
494
 
 
495
 
static GError *
496
 
get_error_from_gphoto2 (const char *message, int rc)
497
 
{
498
 
  GError *error;
499
 
 
500
 
  switch (rc)
501
 
    {
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);
507
 
      break;
508
 
 
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);
514
 
      break;
515
 
 
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);
520
 
      break;
521
 
 
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);
526
 
      break;
527
 
 
528
 
    default:
529
 
      error = g_error_new (G_IO_ERROR, 
530
 
                           G_IO_ERROR_FAILED, "%s: %d: %s", message, rc, gp_result_as_string (rc));
531
 
      break;
532
 
    }
533
 
  return error;
534
 
}
535
 
 
536
 
/* ------------------------------------------------------------------------------------------------- */
537
 
 
538
 
static void
539
 
release_device (GVfsBackendGphoto2 *gphoto2_backend)
540
 
{
541
 
  GList *l;
542
 
 
543
 
  g_free (gphoto2_backend->gphoto2_port);
544
 
  gphoto2_backend->gphoto2_port = NULL;
545
 
 
546
 
  if (gphoto2_backend->context != NULL)
547
 
    {
548
 
      gp_context_unref (gphoto2_backend->context);
549
 
      gphoto2_backend->context = NULL;
550
 
    }
551
 
 
552
 
  if (gphoto2_backend->camera != NULL)
553
 
    {
554
 
      gp_camera_unref (gphoto2_backend->camera);
555
 
      gphoto2_backend->camera = NULL;
556
 
    }
557
 
 
558
 
#ifdef HAVE_GUDEV
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);
563
 
 
564
 
#elif defined(HAVE_HAL)
565
 
  if (gphoto2_backend->dbus_connection != NULL)
566
 
    {
567
 
      dbus_connection_close (gphoto2_backend->dbus_connection);
568
 
      dbus_connection_unref (gphoto2_backend->dbus_connection);
569
 
      gphoto2_backend->dbus_connection = NULL;
570
 
    }
571
 
 
572
 
  if (gphoto2_backend->hal_ctx != NULL)
573
 
    {
574
 
      libhal_ctx_free (gphoto2_backend->hal_ctx);
575
 
      gphoto2_backend->hal_ctx = NULL;
576
 
 
577
 
    }
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;
582
 
#endif
583
 
  g_free (gphoto2_backend->icon_name);
584
 
  gphoto2_backend->icon_name = NULL;
585
 
 
586
 
  g_free (gphoto2_backend->ignore_prefix);
587
 
  gphoto2_backend->ignore_prefix = NULL;
588
 
 
589
 
  if (gphoto2_backend->info_cache != NULL)
590
 
    {
591
 
      g_hash_table_unref (gphoto2_backend->info_cache);
592
 
      gphoto2_backend->info_cache = NULL;
593
 
    }
594
 
  if (gphoto2_backend->dir_name_cache != NULL)
595
 
    {
596
 
      g_hash_table_unref (gphoto2_backend->dir_name_cache);
597
 
      gphoto2_backend->dir_name_cache = NULL;
598
 
    }
599
 
  if (gphoto2_backend->file_name_cache != NULL)
600
 
    {
601
 
      g_hash_table_unref (gphoto2_backend->file_name_cache);
602
 
      gphoto2_backend->file_name_cache = NULL;
603
 
    }
604
 
 
605
 
  for (l = gphoto2_backend->dir_monitor_proxies; l != NULL; l = l->next)
606
 
    {
607
 
      MonitorProxy *proxy = l->data;
608
 
      monitor_proxy_free (proxy);
609
 
    }
610
 
  g_list_free (gphoto2_backend->dir_monitor_proxies);
611
 
  gphoto2_backend->dir_monitor_proxies = NULL;
612
 
 
613
 
  for (l = gphoto2_backend->file_monitor_proxies; l != NULL; l = l->next)
614
 
    {
615
 
      MonitorProxy *proxy = l->data;
616
 
      monitor_proxy_free (proxy);
617
 
    }
618
 
  g_list_free (gphoto2_backend->file_monitor_proxies);
619
 
  gphoto2_backend->file_monitor_proxies = NULL;
620
 
 
621
 
  g_mutex_clear (&gphoto2_backend->lock);
622
 
  gphoto2_backend->capacity = -1;
623
 
  gphoto2_backend->free_space = -1;
624
 
}
625
 
 
626
 
/* ------------------------------------------------------------------------------------------------- */
627
 
 
628
 
static void
629
 
g_vfs_backend_gphoto2_finalize (GObject *object)
630
 
{
631
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (object);
632
 
 
633
 
  DEBUG ("finalizing %p", object);
634
 
 
635
 
  release_device (gphoto2_backend);
636
 
 
637
 
  if (G_OBJECT_CLASS (g_vfs_backend_gphoto2_parent_class)->finalize)
638
 
    (*G_OBJECT_CLASS (g_vfs_backend_gphoto2_parent_class)->finalize) (object);
639
 
}
640
 
 
641
 
/* ------------------------------------------------------------------------------------------------- */
642
 
 
643
 
#ifdef DEBUG_SHOW_LIBGPHOTO2_OUTPUT
644
 
static void
645
 
_gphoto2_logger_func (GPLogLevel level, const char *domain, const char *format, va_list args, void *data)
646
 
{
647
 
  g_fprintf (stderr, "libgphoto2: %s: ", domain);
648
 
  g_vfprintf (stderr, format, args);
649
 
  va_end (args);
650
 
  g_fprintf (stderr, "\n");
651
 
}
652
 
#endif
653
 
 
654
 
static void
655
 
g_vfs_backend_gphoto2_init (GVfsBackendGphoto2 *gphoto2_backend)
656
 
{
657
 
  GVfsBackend *backend = G_VFS_BACKEND (gphoto2_backend);
658
 
  GMountSpec *mount_spec;
659
 
 
660
 
  DEBUG ("initing %p", gphoto2_backend);
661
 
 
662
 
  g_vfs_backend_set_display_name (backend, "gphoto2");
663
 
 
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);
667
 
 
668
 
#ifdef DEBUG_SHOW_LIBGPHOTO2_OUTPUT
669
 
  gp_log_add_func (GP_LOG_ALL, _gphoto2_logger_func, NULL);
670
 
#endif
671
 
}
672
 
 
673
 
/* ------------------------------------------------------------------------------------------------- */
674
 
 
675
 
static char *
676
 
compute_icon_name (GVfsBackendGphoto2 *gphoto2_backend)
677
 
{
678
 
  char *result;
679
 
 
680
 
  if (gphoto2_backend->icon_name == NULL)
681
 
    {
682
 
      result = g_strdup_printf ("camera-photo");
683
 
    }
684
 
  else
685
 
    {
686
 
      result = g_strdup (gphoto2_backend->icon_name);
687
 
    }
688
 
 
689
 
  return result;
690
 
}
691
 
 
692
 
/* ------------------------------------------------------------------------------------------------- */
693
 
 
694
 
static char *
695
 
compute_display_name (GVfsBackendGphoto2 *gphoto2_backend)
696
 
{
697
 
  char *result = NULL;
698
 
 
699
 
#ifdef HAVE_GUDEV
700
 
  const char *s;
701
 
 
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)
705
 
    {
706
 
      s = g_udev_device_get_sysfs_attr (gphoto2_backend->udev_device, "product");
707
 
      if (s == NULL)
708
 
        s = g_udev_device_get_property (gphoto2_backend->udev_device, "ID_MODEL");
709
 
 
710
 
      if (s != NULL)
711
 
        result = g_strdup (s);
712
 
    }
713
 
  if (result == NULL )
714
 
    {
715
 
      /* Translator: %s represents the device, e.g. usb:001,042  */
716
 
      result = g_strdup_printf (_("Digital Camera (%s)"), gphoto2_backend->gphoto2_port);
717
 
    }
718
 
#elif defined(HAVE_HAL)
719
 
  if (gphoto2_backend->hal_name == NULL)
720
 
    {
721
 
      /* Translator: %s represents the device, e.g. usb:001,042  */
722
 
      result = g_strdup_printf (_("Digital Camera (%s)"), gphoto2_backend->gphoto2_port);
723
 
    }
724
 
  else
725
 
    {
726
 
      result = g_strdup (gphoto2_backend->hal_name);
727
 
    }
728
 
#endif
729
 
 
730
 
  return result;
731
 
}
732
 
 
733
 
/* ------------------------------------------------------------------------------------------------- */
734
 
 
735
 
#ifdef HAVE_GUDEV
736
 
static void
737
 
setup_for_device (GVfsBackendGphoto2 *gphoto2_backend)
738
 
{
739
 
  gchar *devname;
740
 
  char *comma;
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};
744
 
 
745
 
  /* turn usb:001,041 string into an udev device name */
746
 
  if (!g_str_has_prefix (gphoto2_backend->gphoto2_port, "usb:"))
747
 
    return;
748
 
  devname = g_strconcat ("/dev/bus/usb/", gphoto2_backend->gphoto2_port+4, NULL);
749
 
  if ((comma = strchr (devname, ',')) == NULL)
750
 
    {
751
 
      g_free (devname);
752
 
      return;
753
 
    }
754
 
  *comma = '/';
755
 
  DEBUG ("Parsed '%s' into device name %s", gphoto2_backend->gphoto2_port, devname);
756
 
 
757
 
  /* find corresponding GUdevDevice */
758
 
  gphoto2_backend->udev_device = g_udev_client_query_by_device_file (gphoto2_backend->gudev_client, devname);
759
 
  g_free (devname);
760
 
  if (gphoto2_backend->udev_device)
761
 
    {
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));
763
 
 
764
 
      /* determine icon name */
765
 
      if (g_udev_device_has_property (gphoto2_backend->udev_device, "ID_MEDIA_PLAYER_ICON_NAME"))
766
 
        {
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;
769
 
        }
770
 
      else if (g_udev_device_has_property (gphoto2_backend->udev_device, "ID_MEDIA_PLAYER"))
771
 
        {
772
 
          gphoto2_backend->icon_name = g_strdup ("multimedia-player");
773
 
          is_media_player = TRUE;
774
 
        }
775
 
      else
776
 
          gphoto2_backend->icon_name = g_strdup ("camera-photo");
777
 
    }
778
 
  else
779
 
      DEBUG ("-> did not find matching udev device");
780
 
 
781
 
  if (is_media_player)
782
 
      g_vfs_backend_set_x_content_types (G_VFS_BACKEND (gphoto2_backend), media_player_x_content_types);
783
 
  else
784
 
      g_vfs_backend_set_x_content_types (G_VFS_BACKEND (gphoto2_backend), camera_x_content_types);
785
 
}
786
 
 
787
 
static void
788
 
on_uevent (GUdevClient *client, gchar *action, GUdevDevice *device, gpointer user_data)
789
 
{
790
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (user_data);
791
 
 
792
 
  DEBUG ("on_uevent action %s, device %s", action, g_udev_device_get_device_file (device));
793
 
 
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)
797
 
    {
798
 
      DEBUG ("we have been removed!");
799
 
 
800
 
      /* nuke all caches so we're a bit more valgrind friendly */
801
 
      caches_invalidate_all (gphoto2_backend);
802
 
 
803
 
      /* TODO: need a cleaner way to force unmount ourselves */
804
 
      exit (1);
805
 
    }
806
 
}
807
 
 
808
 
#elif defined(HAVE_HAL)
809
 
static void
810
 
find_udi_for_device (GVfsBackendGphoto2 *gphoto2_backend)
811
 
{
812
 
  int num_camera_devices;
813
 
  int num_mtp_devices;
814
 
  int num_devices;
815
 
  char **camera_devices;
816
 
  char **mtp_devices;
817
 
  char **devices;
818
 
  int n, m;
819
 
  int usb_bus_num;
820
 
  int usb_device_num;
821
 
  char **tokens;
822
 
  char *endp;
823
 
  char *camera_x_content_types[] = {"x-content/image-dcf", NULL};
824
 
  char *music_player_x_content_types[] = {"x-content/audio-player", NULL};
825
 
 
826
 
  gphoto2_backend->hal_udi = NULL;
827
 
 
828
 
  /* parse the usb:001,041 string */
829
 
 
830
 
  if (!g_str_has_prefix (gphoto2_backend->gphoto2_port, "usb:"))
831
 
    {
832
 
      return;
833
 
    }
834
 
 
835
 
  tokens = g_strsplit (gphoto2_backend->gphoto2_port + 4, ",", 0);
836
 
  if (g_strv_length (tokens) != 2)
837
 
    {
838
 
      g_strfreev (tokens);
839
 
      return;
840
 
    }
841
 
 
842
 
  usb_bus_num = strtol (tokens[0], &endp, 10);
843
 
  if (*endp != '\0')
844
 
    {
845
 
      g_strfreev (tokens);
846
 
      return;
847
 
    }
848
 
 
849
 
  usb_device_num = strtol (tokens[1], &endp, 10);
850
 
  if (*endp != '\0')
851
 
    {
852
 
      g_strfreev (tokens);
853
 
      return;
854
 
    }
855
 
 
856
 
  g_strfreev (tokens);
857
 
 
858
 
  DEBUG ("Parsed '%s' into bus=%d device=%d", gphoto2_backend->gphoto2_port, usb_bus_num, usb_device_num);
859
 
 
860
 
  camera_devices = libhal_find_device_by_capability (gphoto2_backend->hal_ctx,
861
 
                                                     "camera",
862
 
                                                     &num_camera_devices,
863
 
                                                     NULL);
864
 
  mtp_devices = libhal_find_device_by_capability (gphoto2_backend->hal_ctx,
865
 
                                                  "portable_audio_player",
866
 
                                                  &num_mtp_devices,
867
 
                                                  NULL);
868
 
  for (m = 0; m < 2 && gphoto2_backend->hal_udi == NULL; m++)
869
 
    {
870
 
      devices = m == 0 ? camera_devices : mtp_devices;
871
 
      num_devices = m == 0 ? num_camera_devices : num_mtp_devices;
872
 
 
873
 
      if (devices != NULL)
874
 
        {
875
 
          for (n = 0; n < num_devices && gphoto2_backend->hal_udi == NULL; n++)
876
 
            {
877
 
              char *udi = devices[n];
878
 
              LibHalPropertySet *ps;
879
 
              
880
 
              ps = libhal_device_get_all_properties (gphoto2_backend->hal_ctx, udi, NULL);
881
 
              if (ps != NULL)
882
 
                {
883
 
                  const char *subsystem;
884
 
              
885
 
                  subsystem = libhal_ps_get_string (ps, "info.subsystem");
886
 
                  if (subsystem != NULL && strcmp (subsystem, "usb") == 0)
887
 
                    {
888
 
                      int device_usb_bus_num;
889
 
                      int device_usb_device_num;
890
 
                      const char *icon_from_hal;
891
 
                      const char *name_from_hal;
892
 
                      
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");
897
 
                      
898
 
                      DEBUG ("looking at usb device '%s' with bus=%d, device=%d", 
899
 
                             udi, device_usb_bus_num, device_usb_device_num);
900
 
                      
901
 
                      if (device_usb_bus_num == usb_bus_num && 
902
 
                          device_usb_device_num == usb_device_num)
903
 
                        {
904
 
                          char *name;
905
 
                          const char *parent_udi;
906
 
                          LibHalPropertySet *ps2;
907
 
 
908
 
                          DEBUG ("udi '%s' is the one!", udi);
909
 
                          
910
 
                          /* IMPORTANT: 
911
 
                           * 
912
 
                           * Keep this naming code in sync with
913
 
                           *
914
 
                           *   hal/ghalvolume;do_update_from_hal_for_camera() 
915
 
                           */
916
 
                          name = NULL;
917
 
                          parent_udi = libhal_ps_get_string (ps, "info.parent");
918
 
                          if (name_from_hal != NULL)
919
 
                            {
920
 
                              name = g_strdup (name_from_hal);
921
 
                            }
922
 
                          else if (parent_udi != NULL)
923
 
                            {
924
 
                              ps2 = libhal_device_get_all_properties (gphoto2_backend->hal_ctx, parent_udi, NULL);
925
 
                              if (ps2 != NULL)
926
 
                                {
927
 
                                  const char *vendor;
928
 
                                  const char *product;
929
 
                                  
930
 
                                  vendor = libhal_ps_get_string (ps2, "usb_device.vendor");
931
 
                                  product = libhal_ps_get_string (ps2, "usb_device.product");
932
 
                                  if (vendor == NULL)
933
 
                                    {
934
 
                                      if (product != NULL)
935
 
                                        name = g_strdup (product);
936
 
                                    }
937
 
                                  else
938
 
                                    {
939
 
                                      if (product != NULL)
940
 
                                        name = g_strdup_printf ("%s %s", vendor, product);
941
 
                                      else
942
 
                                        {
943
 
                                          if (m == 0)
944
 
                                            /* Translator: %s is the vendor name, e.g. Panasonic */
945
 
                                            name = g_strdup_printf (_("%s Camera"), vendor);
946
 
                                          else
947
 
                                            /* Translator: %s is the vendor name, e.g. Panasonic */
948
 
                                            name = g_strdup_printf (_("%s Audio Player"), vendor);
949
 
                                        }
950
 
                                    }
951
 
                                  libhal_free_property_set (ps2);
952
 
                                }
953
 
                            }
954
 
                          if (name == NULL)
955
 
                            {
956
 
                              if (m == 0)
957
 
                                name = g_strdup (_("Camera"));
958
 
                              else
959
 
                                name = g_strdup (_("Audio Player"));
960
 
                            }
961
 
                          
962
 
                          gphoto2_backend->hal_udi = g_strdup (udi);
963
 
                          gphoto2_backend->hal_name = name;
964
 
                          if (icon_from_hal != NULL)
965
 
                            {
966
 
                              gphoto2_backend->icon_name = g_strdup (icon_from_hal);
967
 
                            }
968
 
                          else
969
 
                            {
970
 
                              if (m == 1)
971
 
                                {
972
 
                                  gphoto2_backend->icon_name = g_strdup ("multimedia-player");
973
 
                                }
974
 
                              else
975
 
                                {
976
 
                                  gphoto2_backend->icon_name = g_strdup ("camera-photo");
977
 
                                }
978
 
                            }
979
 
 
980
 
                          /* TODO: should we sniff the files instead? */
981
 
                          if (m == 0)
982
 
                            {
983
 
                              g_vfs_backend_set_x_content_types (G_VFS_BACKEND (gphoto2_backend),
984
 
                                                                 camera_x_content_types);
985
 
                            }
986
 
                          else
987
 
                            {
988
 
                              g_vfs_backend_set_x_content_types (G_VFS_BACKEND (gphoto2_backend),
989
 
                                                                 music_player_x_content_types);
990
 
                            }
991
 
 
992
 
                        }
993
 
                      
994
 
                    }
995
 
                  
996
 
                  libhal_free_property_set (ps);
997
 
                }
998
 
            }
999
 
          libhal_free_string_array (devices);
1000
 
        }
1001
 
    }
1002
 
}
1003
 
 
1004
 
/* ------------------------------------------------------------------------------------------------- */
1005
 
 
1006
 
static void
1007
 
_hal_device_removed (LibHalContext *hal_ctx, const char *udi)
1008
 
{
1009
 
  GVfsBackendGphoto2 *gphoto2_backend;
1010
 
 
1011
 
  gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (libhal_ctx_get_user_data (hal_ctx));
1012
 
 
1013
 
  if (gphoto2_backend->hal_udi != NULL && strcmp (udi, gphoto2_backend->hal_udi) == 0)
1014
 
    {
1015
 
      DEBUG ("we have been removed!");
1016
 
 
1017
 
      /* nuke all caches so we're a bit more valgrind friendly */
1018
 
      caches_invalidate_all (gphoto2_backend);
1019
 
 
1020
 
      /* TODO: need a cleaner way to force unmount ourselves */
1021
 
      exit (1);
1022
 
    }
1023
 
}
1024
 
#endif
1025
 
 
1026
 
/* ------------------------------------------------------------------------------------------------- */
1027
 
 
1028
 
static void
1029
 
split_filename_with_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, const char *filename, char **dir, char **name)
1030
 
{
1031
 
  char *s;
1032
 
 
1033
 
  s = g_path_get_dirname (filename);
1034
 
  if (s[0] == '/')
1035
 
    *dir = g_strconcat (gphoto2_backend->ignore_prefix, s + 1, NULL);
1036
 
  else
1037
 
    *dir = g_strconcat (gphoto2_backend->ignore_prefix, s, NULL);
1038
 
  g_free (s);
1039
 
 
1040
 
  if (strcmp (filename, "/") == 0)
1041
 
    *name = g_strdup ("");
1042
 
  else
1043
 
    *name = g_path_get_basename (filename);
1044
 
 
1045
 
  s = *dir;
1046
 
  if (s[strlen(s)] == '/')
1047
 
    s[strlen(s)] = '\0';
1048
 
 
1049
 
  /*DEBUG ("split_filename_with_ignore_prefix: '%s' -> '%s' '%s'", filename, *dir, *name);*/
1050
 
}
1051
 
 
1052
 
/* ------------------------------------------------------------------------------------------------- */
1053
 
 
1054
 
static char *
1055
 
add_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, const char *filename)
1056
 
{
1057
 
  char *result;
1058
 
 
1059
 
  if (filename[0] == '/')
1060
 
    result = g_strconcat (gphoto2_backend->ignore_prefix, filename + 1, NULL);
1061
 
  else
1062
 
    result = g_strconcat (gphoto2_backend->ignore_prefix, filename, NULL);
1063
 
 
1064
 
  /*DEBUG ("add_ignore_prefix: '%s' -> '%s'", filename, result);*/
1065
 
  return result;
1066
 
}
1067
 
 
1068
 
/* ------------------------------------------------------------------------------------------------- */
1069
 
 
1070
 
/* the passed 'dir' variable must contain ignore_prefix */
1071
 
static gboolean
1072
 
file_get_info (GVfsBackendGphoto2 *gphoto2_backend, 
1073
 
               const char *dir, 
1074
 
               const char *name, 
1075
 
               GFileInfo *info, 
1076
 
               GError **error,
1077
 
               gboolean try_cache_only)
1078
 
{
1079
 
  int rc;
1080
 
  gboolean ret;
1081
 
  CameraFileInfo gp_info;
1082
 
  char *full_path;
1083
 
  GFileInfo *cached_info;
1084
 
  GTimeVal mtime;
1085
 
  char *mime_type;
1086
 
  GIcon *icon;
1087
 
  unsigned int n;
1088
 
 
1089
 
  ret = FALSE;
1090
 
 
1091
 
  full_path = g_build_filename (dir, name, NULL);
1092
 
  DEBUG ("file_get_info() try_cache_only=%d dir='%s', name='%s'\n"
1093
 
         "                full_path='%s'", 
1094
 
         try_cache_only, dir, name, full_path, gphoto2_backend->ignore_prefix);
1095
 
 
1096
 
 
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)
1101
 
    {
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);
1105
 
      ret = TRUE;
1106
 
      goto out;
1107
 
    }
1108
 
  g_mutex_unlock (&gphoto2_backend->lock);
1109
 
 
1110
 
  if (try_cache_only)
1111
 
    goto out;
1112
 
 
1113
 
  ensure_not_dirty (gphoto2_backend);
1114
 
 
1115
 
  DEBUG ("  No cached info for '%s'", full_path);
1116
 
 
1117
 
  /* Since we're caching stuff, make sure all information we store is set */
1118
 
  g_file_info_unset_attribute_mask (info);
1119
 
 
1120
 
  /* handle root directory */
1121
 
  if (strcmp (full_path, gphoto2_backend->ignore_prefix) == 0 || strcmp (full_path, "/") == 0)
1122
 
    {
1123
 
      char *display_name;
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); 
1140
 
      ret = TRUE;
1141
 
      DEBUG ("  Generating info (root folder) for '%s'", full_path);
1142
 
      goto add_to_cache;
1143
 
    }
1144
 
 
1145
 
  rc = gp_camera_file_get_info (gphoto2_backend->camera,
1146
 
                                dir,
1147
 
                                name,
1148
 
                                &gp_info,
1149
 
                                gphoto2_backend->context);
1150
 
  if (rc != 0)
1151
 
    {
1152
 
      CameraList *list;
1153
 
      gboolean is_folder;
1154
 
 
1155
 
      /* gphoto2 doesn't know about this file.. it may be a folder; try that */
1156
 
      is_folder = FALSE;
1157
 
      gp_list_new (&list);
1158
 
      rc = gp_camera_folder_list_folders (gphoto2_backend->camera, 
1159
 
                                        dir, 
1160
 
                                        list, 
1161
 
                                        gphoto2_backend->context);
1162
 
      if (rc == 0)
1163
 
        {
1164
 
          for (n = 0; n < gp_list_count (list) && !is_folder; n++)
1165
 
            {
1166
 
              const char *folder_name;
1167
 
              gp_list_get_name (list, n, &folder_name);
1168
 
              if (strcmp (folder_name, name) == 0)
1169
 
                {
1170
 
                  is_folder = TRUE;
1171
 
                }
1172
 
            }
1173
 
        }
1174
 
      gp_list_free (list);
1175
 
 
1176
 
      if (is_folder)
1177
 
        {
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] == '.');
1193
 
          ret = TRUE;
1194
 
          DEBUG ("  Generating info (folder) for '%s'", full_path);
1195
 
          goto add_to_cache;
1196
 
        }
1197
 
 
1198
 
      /* nope, not a folder either.. error out.. */
1199
 
      if (error != NULL)
1200
 
        {
1201
 
          *error = g_error_new (G_IO_ERROR,
1202
 
                                G_IO_ERROR_NOT_FOUND,
1203
 
                                _("No such file or directory"));
1204
 
        }
1205
 
      goto out;
1206
 
    }
1207
 
 
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);
1211
 
 
1212
 
  if (gp_info.file.fields & GP_FILE_INFO_SIZE)
1213
 
    {
1214
 
      g_file_info_set_size (info, gp_info.file.size);
1215
 
    }
1216
 
  else
1217
 
    {
1218
 
      /* not really sure this is the right thing to do... */
1219
 
      g_file_info_set_size (info, 0);
1220
 
    }
1221
 
 
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 :-/
1226
 
   */
1227
 
  mime_type = NULL;
1228
 
  if (gp_info.file.fields & GP_FILE_INFO_TYPE)
1229
 
    {
1230
 
      /* application/x-unknown is a bogus mime type return by some
1231
 
       * devices (such as Sandisk Sansa music players) - ignore it.
1232
 
       */
1233
 
      if (strcmp (gp_info.file.type, "application/x-unknown") != 0)
1234
 
        {
1235
 
          mime_type = g_strdup (gp_info.file.type);
1236
 
        }
1237
 
    }
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);
1244
 
 
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"))
1247
 
    {
1248
 
      char *icon_id;
1249
 
      GIcon *icon;
1250
 
      GMountSpec *mount_spec;
1251
 
 
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,
1255
 
                             icon_id);
1256
 
      g_file_info_set_attribute_object (info,
1257
 
                                        G_FILE_ATTRIBUTE_PREVIEW_ICON,
1258
 
                                        G_OBJECT (icon));
1259
 
      g_object_unref (icon);
1260
 
      g_free (icon_id);
1261
 
    }
1262
 
 
1263
 
  icon = g_content_type_get_icon (mime_type);
1264
 
  DEBUG ("  got icon %p for mime_type '%s'", icon, mime_type);
1265
 
  if (icon != NULL)
1266
 
    {
1267
 
      g_file_info_set_icon (info, icon);
1268
 
      g_object_unref (icon);
1269
 
    }
1270
 
  g_free (mime_type);
1271
 
 
1272
 
  if (gp_info.file.fields & GP_FILE_INFO_MTIME)
1273
 
    mtime.tv_sec = gp_info.file.mtime;
1274
 
  else
1275
 
    mtime.tv_sec = 0;
1276
 
  mtime.tv_usec = 0;
1277
 
  g_file_info_set_modification_time (info, &mtime);
1278
 
 
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] == '.');
1286
 
 
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);
1294
 
  }
1295
 
 
1296
 
  ret = TRUE;
1297
 
  DEBUG ("  Generating info (file) for '%s'", full_path);
1298
 
 
1299
 
 add_to_cache:
1300
 
  /* add this sucker to the cache */
1301
 
  if (ret == TRUE)
1302
 
    {
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);
1309
 
#endif
1310
 
    }
1311
 
 
1312
 
 out:
1313
 
  g_free (full_path);
1314
 
  return ret;
1315
 
}
1316
 
 
1317
 
/* ------------------------------------------------------------------------------------------------- */
1318
 
 
1319
 
static gboolean
1320
 
is_directory (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
1321
 
{
1322
 
  GFileInfo *info;
1323
 
  gboolean ret;
1324
 
 
1325
 
  ret = FALSE;
1326
 
 
1327
 
  info = g_file_info_new ();
1328
 
  if (!file_get_info (gphoto2_backend, dir, name, info, NULL, FALSE))
1329
 
    goto out;
1330
 
 
1331
 
  if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
1332
 
    ret = TRUE;
1333
 
 
1334
 
 out:
1335
 
  g_object_unref (info);
1336
 
  return ret;
1337
 
}
1338
 
 
1339
 
/* ------------------------------------------------------------------------------------------------- */
1340
 
 
1341
 
static gboolean 
1342
 
is_regular (GVfsBackendGphoto2 *gphoto2_backend, const char *dir, const char *name)
1343
 
{
1344
 
  GFileInfo *info;
1345
 
  gboolean ret;
1346
 
 
1347
 
  ret = FALSE;
1348
 
 
1349
 
  info = g_file_info_new ();
1350
 
  if (!file_get_info (gphoto2_backend, dir, name, info, NULL, FALSE))
1351
 
    goto out;
1352
 
 
1353
 
  if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR)
1354
 
    ret = TRUE;
1355
 
 
1356
 
 out:
1357
 
  g_object_unref (info);
1358
 
  return ret;
1359
 
}
1360
 
 
1361
 
/* ------------------------------------------------------------------------------------------------- */
1362
 
 
1363
 
static gboolean
1364
 
is_directory_empty (GVfsBackendGphoto2 *gphoto2_backend, const char *dir)
1365
 
{
1366
 
  CameraList *list;
1367
 
  gboolean ret;
1368
 
  int rc;
1369
 
  int num_dirs;
1370
 
  int num_files;
1371
 
  
1372
 
  DEBUG ("is_directory_empty begin (%s)", dir);
1373
 
  
1374
 
  /* TODO: use cache */
1375
 
  
1376
 
  ret = FALSE;
1377
 
  num_dirs = 0;
1378
 
  num_files = 0;
1379
 
  
1380
 
  gp_list_new (&list);
1381
 
  rc = gp_camera_folder_list_files (gphoto2_backend->camera, 
1382
 
                                    dir, 
1383
 
                                    list, 
1384
 
                                    gphoto2_backend->context);
1385
 
  if (rc == 0)
1386
 
    num_files = gp_list_count (list);
1387
 
  gp_list_free (list);
1388
 
  
1389
 
  if (num_files > 0)
1390
 
    goto out;
1391
 
  
1392
 
  gp_list_new (&list);
1393
 
  rc = gp_camera_folder_list_folders (gphoto2_backend->camera, 
1394
 
                                      dir, 
1395
 
                                      list, 
1396
 
                                      gphoto2_backend->context);
1397
 
  if (rc == 0)
1398
 
    num_dirs = gp_list_count (list);
1399
 
  gp_list_free (list);
1400
 
  
1401
 
  if (num_dirs == 0 && num_files == 0)
1402
 
    ret = TRUE;
1403
 
  
1404
 
 out:
1405
 
  DEBUG ("  is_directory_empty (%s) -> %d", dir, ret);
1406
 
  return ret;
1407
 
}
1408
 
 
1409
 
/* ------------------------------------------------------------------------------------------------- */
1410
 
 
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.
1415
 
 *
1416
 
 * So, if we have only one storage head, do use basedir of that
1417
 
 * head as ignore_prefix.
1418
 
 *
1419
 
 * See also update_cameras() in ggphoto2volumemonitor.c.
1420
 
 *
1421
 
 * This function needs to be called from do_mount().
1422
 
 */
1423
 
static gboolean
1424
 
ensure_ignore_prefix (GVfsBackendGphoto2 *gphoto2_backend, GVfsJob *job)
1425
 
{
1426
 
  gchar *prefix;
1427
 
  CameraStorageInformation *storage_info, *head;
1428
 
  int num_storage_info, i;
1429
 
 
1430
 
  /* already set */
1431
 
  if (gphoto2_backend->ignore_prefix != NULL)
1432
 
    return TRUE;
1433
 
 
1434
 
  prefix = NULL;
1435
 
 
1436
 
  if (gp_camera_get_storageinfo (gphoto2_backend->camera,
1437
 
                                 &storage_info,
1438
 
                                 &num_storage_info,
1439
 
                                 gphoto2_backend->context) != 0)
1440
 
    goto out;
1441
 
 
1442
 
  head = NULL;
1443
 
  for (i = 0; i < num_storage_info; i++)
1444
 
    {
1445
 
      /* Ignore storage with no capacity (see bug 570888) */
1446
 
      if ((storage_info[i].fields & GP_STORAGEINFO_MAXCAPACITY) &&
1447
 
          storage_info[i].capacitykbytes == 0)
1448
 
        continue;
1449
 
      
1450
 
      /* Multiple heads, don't ignore */
1451
 
      if (head != NULL)
1452
 
        goto out;
1453
 
        
1454
 
      head = &storage_info[i];
1455
 
    }
1456
 
 
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);
1460
 
 
1461
 
 out:
1462
 
 
1463
 
  if (prefix == NULL)
1464
 
    gphoto2_backend->ignore_prefix = g_strdup ("/");
1465
 
  else
1466
 
    gphoto2_backend->ignore_prefix = prefix;
1467
 
 
1468
 
  DEBUG ("Using ignore_prefix='%s'", gphoto2_backend->ignore_prefix);
1469
 
 
1470
 
  return TRUE;
1471
 
}
1472
 
 
1473
 
/* ------------------------------------------------------------------------------------------------- */
1474
 
 
1475
 
static void
1476
 
do_mount (GVfsBackend *backend,
1477
 
          GVfsJobMount *job,
1478
 
          GMountSpec *mount_spec,
1479
 
          GMountSource *mount_source,
1480
 
          gboolean is_automount)
1481
 
{
1482
 
  char *fuse_name;
1483
 
  char *display_name;
1484
 
  char *icon_name;
1485
 
  const char *host;
1486
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
1487
 
  GError *error = NULL;
1488
 
  GMountSpec *gphoto2_mount_spec;
1489
 
  int rc;
1490
 
  GPPortInfo info;
1491
 
  GPPortInfoList *il = NULL;
1492
 
  int n;
1493
 
  CameraStorageInformation *storage_info;
1494
 
  int num_storage_info;
1495
 
 
1496
 
  DEBUG ("do_mount %p", gphoto2_backend);
1497
 
 
1498
 
#ifdef HAVE_GUDEV
1499
 
  /* setup gudev */
1500
 
  const char *subsystems[] = {"usb", NULL};
1501
 
 
1502
 
  gphoto2_backend->gudev_client = g_udev_client_new (subsystems);
1503
 
  if (gphoto2_backend->gudev_client == NULL)
1504
 
    {
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);
1509
 
      return;
1510
 
    }
1511
 
 
1512
 
  g_signal_connect (gphoto2_backend->gudev_client, "uevent", G_CALLBACK (on_uevent), gphoto2_backend);
1513
 
 
1514
 
#elif defined(HAVE_HAL)
1515
 
  /* setup libhal */
1516
 
  DBusError dbus_error;
1517
 
 
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))
1521
 
    {
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);
1527
 
      return;
1528
 
    }
1529
 
  
1530
 
  dbus_connection_set_exit_on_disconnect (gphoto2_backend->dbus_connection, FALSE);
1531
 
 
1532
 
  gphoto2_backend->hal_ctx = libhal_ctx_new ();
1533
 
  if (gphoto2_backend->hal_ctx == NULL)
1534
 
    {
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);
1539
 
      return;
1540
 
    }
1541
 
 
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);
1544
 
  
1545
 
  if (!libhal_ctx_init (gphoto2_backend->hal_ctx, &dbus_error))
1546
 
    {
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);
1552
 
      return;
1553
 
    }
1554
 
 
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);
1557
 
#endif
1558
 
 
1559
 
  /* setup gphoto2 */
1560
 
 
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] != ']')
1564
 
    {
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);
1569
 
      return;
1570
 
    }
1571
 
 
1572
 
  gphoto2_backend->gphoto2_port = g_strdup (host + 1);
1573
 
  gphoto2_backend->gphoto2_port[strlen (gphoto2_backend->gphoto2_port) - 1] = '\0';
1574
 
 
1575
 
  DEBUG ("  decoded host='%s'", gphoto2_backend->gphoto2_port);
1576
 
 
1577
 
#ifdef HAVE_GUDEV
1578
 
  setup_for_device (gphoto2_backend);
1579
 
#elif defined(HAVE_HAL)
1580
 
  find_udi_for_device (gphoto2_backend);
1581
 
#endif
1582
 
 
1583
 
  gphoto2_backend->context = gp_context_new ();
1584
 
  if (gphoto2_backend->context == NULL)
1585
 
    {
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);
1590
 
      return;
1591
 
    }
1592
 
 
1593
 
  rc = gp_camera_new (&(gphoto2_backend->camera));
1594
 
  if (rc != 0)
1595
 
    {
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);
1600
 
      return;
1601
 
    }
1602
 
 
1603
 
 
1604
 
  il = NULL;
1605
 
  
1606
 
  rc = gp_port_info_list_new (&il);
1607
 
  if (rc != 0)
1608
 
    {
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);
1613
 
      return;
1614
 
    }
1615
 
 
1616
 
  rc = gp_port_info_list_load (il);
1617
 
  if (rc != 0)
1618
 
    {
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);
1623
 
      return;
1624
 
    }
1625
 
 
1626
 
  DEBUG ("  gphoto2_port='%s'", gphoto2_backend->gphoto2_port);
1627
 
 
1628
 
  n = gp_port_info_list_lookup_path (il, gphoto2_backend->gphoto2_port);
1629
 
  if (n == GP_ERROR_UNKNOWN_PORT)
1630
 
    {
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);
1635
 
      return;
1636
 
    }
1637
 
 
1638
 
  rc = gp_port_info_list_get_info (il, n, &info);
1639
 
  if (rc != 0)
1640
 
    {
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);
1645
 
      return;
1646
 
    }
1647
 
 
1648
 
  DEBUG ("  '%s' '%s' '%s'",  info.name, info.path, info.library_filename);
1649
 
  
1650
 
  /* set port */
1651
 
  rc = gp_camera_set_port_info (gphoto2_backend->camera, info);
1652
 
  if (rc != 0)
1653
 
    {
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);
1658
 
      return;
1659
 
    }
1660
 
  gp_port_info_list_free(il);
1661
 
 
1662
 
  rc = gp_camera_init (gphoto2_backend->camera, gphoto2_backend->context);
1663
 
  if (rc != 0)
1664
 
    {
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);
1669
 
      return;
1670
 
    }
1671
 
 
1672
 
  if (!ensure_ignore_prefix (gphoto2_backend, G_VFS_JOB (job)))
1673
 
    {
1674
 
      release_device (gphoto2_backend);
1675
 
      return;
1676
 
    }
1677
 
 
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);
1687
 
  g_free (icon_name);
1688
 
  g_free (fuse_name);
1689
 
 
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);
1693
 
  if (rc == 0)
1694
 
    {
1695
 
      if (num_storage_info >= 1)
1696
 
        {
1697
 
          if (storage_info[0].fields & GP_STORAGEINFO_ACCESS && storage_info[0].access == GP_STORAGEINFO_AC_READWRITE)
1698
 
            {
1699
 
              gphoto2_backend->can_write = TRUE;
1700
 
              gphoto2_backend->can_delete = TRUE;
1701
 
            }
1702
 
          if (storage_info[0].fields & GP_STORAGEINFO_ACCESS && storage_info[0].access == GP_STORAGEINFO_AC_READONLY_WITH_DELETE)
1703
 
            {
1704
 
              gphoto2_backend->can_delete = TRUE;
1705
 
            }
1706
 
        }
1707
 
    }
1708
 
  DEBUG ("  can_write = %d", gphoto2_backend->can_write);
1709
 
  DEBUG ("  can_delete = %d", gphoto2_backend->can_delete);
1710
 
 
1711
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
1712
 
 
1713
 
  gphoto2_backend->free_space = -1;
1714
 
 
1715
 
  g_mutex_init (&gphoto2_backend->lock);
1716
 
 
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);
1721
 
 
1722
 
  gphoto2_backend->info_cache = g_hash_table_new_full (g_str_hash,
1723
 
                                                       g_str_equal,
1724
 
                                                       g_free,
1725
 
                                                       g_object_unref);
1726
 
 
1727
 
  gphoto2_backend->dir_name_cache = g_hash_table_new_full (g_str_hash,
1728
 
                                                           g_str_equal,
1729
 
                                                           g_free,
1730
 
                                                           (GDestroyNotify) gp_list_unref);
1731
 
 
1732
 
  gphoto2_backend->file_name_cache = g_hash_table_new_full (g_str_hash,
1733
 
                                                            g_str_equal,
1734
 
                                                            g_free,
1735
 
                                                            (GDestroyNotify) gp_list_unref);
1736
 
 
1737
 
  DEBUG ("  mounted %p", gphoto2_backend);
1738
 
}
1739
 
 
1740
 
/* ------------------------------------------------------------------------------------------------- */
1741
 
 
1742
 
static gboolean
1743
 
try_mount (GVfsBackend *backend,
1744
 
           GVfsJobMount *job,
1745
 
           GMountSpec *mount_spec,
1746
 
           GMountSource *mount_source,
1747
 
           gboolean is_automount)
1748
 
{
1749
 
  const char *host;
1750
 
  GError *error = NULL;
1751
 
  GMountSpec *gphoto2_mount_spec;
1752
 
 
1753
 
  DEBUG ("try_mount %p", backend);
1754
 
 
1755
 
  /* TODO: Hmm.. apparently we have to set the mount spec in
1756
 
   * try_mount(); doing it in mount() do_won't work.. 
1757
 
   */
1758
 
  host = g_mount_spec_get (mount_spec, "host");
1759
 
  DEBUG ("  host=%s", host);
1760
 
  if (host == NULL)
1761
 
    {
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);
1765
 
      return TRUE;
1766
 
    }
1767
 
 
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);
1772
 
  return FALSE;
1773
 
}
1774
 
 
1775
 
/* ------------------------------------------------------------------------------------------------- */
1776
 
 
1777
 
static void
1778
 
free_read_handle (ReadHandle *read_handle)
1779
 
{
1780
 
  if (read_handle->file != NULL)
1781
 
    {
1782
 
      gp_file_unref (read_handle->file);
1783
 
    }
1784
 
  g_free (read_handle);
1785
 
}
1786
 
 
1787
 
static void
1788
 
do_open_for_read_real (GVfsBackend *backend,
1789
 
                       GVfsJobOpenForRead *job,
1790
 
                       const char *filename,
1791
 
                       gboolean get_preview)
1792
 
{
1793
 
  int rc;
1794
 
  GError *error;
1795
 
  ReadHandle *read_handle;
1796
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
1797
 
  char *dir;
1798
 
  char *name;
1799
 
 
1800
 
  ensure_not_dirty (gphoto2_backend);
1801
 
 
1802
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
1803
 
 
1804
 
  if (is_directory (gphoto2_backend, dir, name))
1805
 
    {
1806
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1807
 
                        G_IO_ERROR_IS_DIRECTORY,
1808
 
                        _("Can't open directory"));
1809
 
      goto out;
1810
 
    }
1811
 
 
1812
 
  if (!is_regular (gphoto2_backend, dir, name))
1813
 
    {
1814
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1815
 
                        G_IO_ERROR_NOT_FOUND,
1816
 
                        _("No such file"));
1817
 
      goto out;
1818
 
    }
1819
 
 
1820
 
  read_handle = g_new0 (ReadHandle, 1);
1821
 
  rc = gp_file_new (&read_handle->file);
1822
 
  if (rc != 0)
1823
 
    {
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);
1828
 
      goto out;
1829
 
    }
1830
 
 
1831
 
  rc = gp_camera_file_get (gphoto2_backend->camera,
1832
 
                           dir,
1833
 
                           name,
1834
 
                           get_preview ? GP_FILE_TYPE_PREVIEW : GP_FILE_TYPE_NORMAL,
1835
 
                           read_handle->file,
1836
 
                           gphoto2_backend->context);
1837
 
  if (rc != 0)
1838
 
    {
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);
1843
 
      goto out;
1844
 
    }
1845
 
 
1846
 
  rc = gp_file_get_data_and_size (read_handle->file, &read_handle->data, &read_handle->size);
1847
 
  if (rc != 0)
1848
 
    {
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);
1853
 
      goto out;
1854
 
    }
1855
 
 
1856
 
  DEBUG ("  data=%p size=%ld handle=%p get_preview=%d",
1857
 
         read_handle->data, read_handle->size, read_handle, get_preview);
1858
 
 
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);
1862
 
      
1863
 
  read_handle->cursor = 0;
1864
 
 
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));
1868
 
 
1869
 
 out:
1870
 
  g_free (name);
1871
 
  g_free (dir);
1872
 
}
1873
 
 
1874
 
 
1875
 
static void
1876
 
do_open_for_read (GVfsBackend *backend,
1877
 
                  GVfsJobOpenForRead *job,
1878
 
                  const char *filename)
1879
 
{
1880
 
  DEBUG ("open_for_read (%s)", filename);
1881
 
 
1882
 
  do_open_for_read_real (backend,
1883
 
                         job,
1884
 
                         filename,
1885
 
                         FALSE);
1886
 
}
1887
 
 
1888
 
static void
1889
 
do_open_icon_for_read (GVfsBackend *backend,
1890
 
                       GVfsJobOpenIconForRead *job,
1891
 
                       const char *icon_id)
1892
 
{
1893
 
  DEBUG ("open_icon_for_read (%s)", icon_id);
1894
 
 
1895
 
  if (g_str_has_prefix (icon_id, "preview:"))
1896
 
    {
1897
 
      do_open_for_read_real (backend,
1898
 
                             G_VFS_JOB_OPEN_FOR_READ (job),
1899
 
                             icon_id + sizeof ("preview:") - 1,
1900
 
                             TRUE);
1901
 
    }
1902
 
  else
1903
 
    {
1904
 
      g_vfs_job_failed (G_VFS_JOB (job),
1905
 
                        G_IO_ERROR,
1906
 
                        G_IO_ERROR_INVALID_ARGUMENT,
1907
 
                        _("Malformed icon identifier '%s'"),
1908
 
                        icon_id);
1909
 
    }
1910
 
}
1911
 
 
1912
 
/* ------------------------------------------------------------------------------------------------- */
1913
 
 
1914
 
static gboolean
1915
 
try_read (GVfsBackend *backend,
1916
 
          GVfsJobRead *job,
1917
 
          GVfsBackendHandle handle,
1918
 
          char *buffer,
1919
 
          gsize bytes_requested)
1920
 
{
1921
 
  //GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
1922
 
  ReadHandle *read_handle = (ReadHandle *) handle;
1923
 
  gsize bytes_left;
1924
 
  gsize bytes_to_copy;
1925
 
 
1926
 
  DEBUG ("do_read() %d @ %ld of %ld, handle=%p", bytes_requested, read_handle->cursor, read_handle->size, handle);
1927
 
 
1928
 
  if (read_handle->cursor >= read_handle->size)
1929
 
    {
1930
 
      bytes_to_copy = 0;
1931
 
      goto out;
1932
 
    }
1933
 
  
1934
 
  bytes_left = read_handle->size - read_handle->cursor;
1935
 
  if (bytes_requested > bytes_left)
1936
 
    bytes_to_copy = bytes_left;
1937
 
  else
1938
 
    bytes_to_copy = bytes_requested;
1939
 
 
1940
 
  memcpy (buffer, read_handle->data + read_handle->cursor, bytes_to_copy);
1941
 
  read_handle->cursor += bytes_to_copy;
1942
 
 
1943
 
 out:
1944
 
  
1945
 
  g_vfs_job_read_set_size (job, bytes_to_copy);
1946
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
1947
 
  return TRUE;
1948
 
}
1949
 
 
1950
 
/* ------------------------------------------------------------------------------------------------- */
1951
 
 
1952
 
static gboolean
1953
 
try_seek_on_read (GVfsBackend *backend,
1954
 
                  GVfsJobSeekRead *job,
1955
 
                  GVfsBackendHandle handle,
1956
 
                  goffset    offset,
1957
 
                  GSeekType  type)
1958
 
{
1959
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
1960
 
  ReadHandle *read_handle = (ReadHandle *) handle;
1961
 
  long new_offset;
1962
 
 
1963
 
  DEBUG ("seek_on_read() offset=%d, type=%d, handle=%p", (int)offset, type, handle);
1964
 
 
1965
 
  switch (type)
1966
 
    {
1967
 
    default:
1968
 
    case G_SEEK_SET:
1969
 
      new_offset = offset;
1970
 
      break;
1971
 
    case G_SEEK_CUR:
1972
 
      new_offset = read_handle->cursor + offset;
1973
 
      break;
1974
 
    case G_SEEK_END:
1975
 
      new_offset = read_handle->size + offset;
1976
 
      break;
1977
 
    }
1978
 
 
1979
 
  if (new_offset < 0 || new_offset > read_handle->size)
1980
 
    {
1981
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1982
 
                        G_IO_ERROR_FAILED,
1983
 
                        _("Error seeking in stream on camera %s"), gphoto2_backend->gphoto2_port);
1984
 
    }
1985
 
  else
1986
 
    {
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));
1990
 
    }
1991
 
  return TRUE;
1992
 
}
1993
 
 
1994
 
/* ------------------------------------------------------------------------------------------------- */
1995
 
 
1996
 
/* cannot be async because we unref the CameraFile */
1997
 
static void
1998
 
do_close_read (GVfsBackend *backend,
1999
 
                GVfsJobCloseRead *job,
2000
 
                GVfsBackendHandle handle)
2001
 
{
2002
 
  ReadHandle *read_handle = (ReadHandle *) handle;
2003
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2004
 
 
2005
 
  DEBUG ("close_read() handle=%p", handle);
2006
 
 
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);
2010
 
 
2011
 
  free_read_handle (read_handle);
2012
 
  
2013
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
2014
 
}
2015
 
 
2016
 
/* ------------------------------------------------------------------------------------------------- */
2017
 
 
2018
 
static void
2019
 
do_query_info (GVfsBackend *backend,
2020
 
               GVfsJobQueryInfo *job,
2021
 
               const char *filename,
2022
 
               GFileQueryInfoFlags flags,
2023
 
               GFileInfo *info,
2024
 
               GFileAttributeMatcher *matcher)
2025
 
{
2026
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2027
 
  GError *error;
2028
 
  char *dir;
2029
 
  char *name;
2030
 
 
2031
 
  DEBUG ("query_info (%s)", filename);
2032
 
 
2033
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2034
 
 
2035
 
  error = NULL;
2036
 
  if (!file_get_info (gphoto2_backend, dir, name, info, &error, FALSE))
2037
 
    {
2038
 
      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
2039
 
      g_error_free (error);
2040
 
    }
2041
 
  else
2042
 
    {
2043
 
      g_vfs_job_succeeded (G_VFS_JOB (job));
2044
 
    }
2045
 
  
2046
 
  g_free (name);
2047
 
  g_free (dir);
2048
 
}
2049
 
 
2050
 
/* ------------------------------------------------------------------------------------------------- */
2051
 
 
2052
 
static gboolean
2053
 
try_query_info (GVfsBackend *backend,
2054
 
                GVfsJobQueryInfo *job,
2055
 
                const char *filename,
2056
 
                GFileQueryInfoFlags flags,
2057
 
                GFileInfo *info,
2058
 
                GFileAttributeMatcher *matcher)
2059
 
{
2060
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2061
 
  char *dir;
2062
 
  char *name;
2063
 
  gboolean ret;
2064
 
 
2065
 
  DEBUG ("try_query_info (%s)", filename);
2066
 
 
2067
 
  ret = FALSE;
2068
 
 
2069
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2070
 
 
2071
 
  if (!file_get_info (gphoto2_backend, dir, name, info, NULL, TRUE))
2072
 
    {
2073
 
      DEBUG ("  BUU no info from cache for try_query_info (%s)", filename);
2074
 
      goto out;
2075
 
    }
2076
 
  DEBUG ("  YAY got info from cache for try_query_info (%s)", filename);
2077
 
 
2078
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
2079
 
  ret = TRUE;
2080
 
  
2081
 
 out:
2082
 
  g_free (name);
2083
 
  g_free (dir);
2084
 
  return ret;
2085
 
}
2086
 
 
2087
 
/* ------------------------------------------------------------------------------------------------- */
2088
 
 
2089
 
static void
2090
 
do_enumerate (GVfsBackend *backend,
2091
 
              GVfsJobEnumerate *job,
2092
 
              const char *given_filename,
2093
 
              GFileAttributeMatcher *matcher,
2094
 
              GFileQueryInfoFlags flags)
2095
 
{
2096
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2097
 
  GFileInfo *info;
2098
 
  GList *l;
2099
 
  GError *error;
2100
 
  CameraList *list;
2101
 
  int n;
2102
 
  int rc;
2103
 
  char *filename;
2104
 
  gboolean using_cached_dir_list;
2105
 
  gboolean using_cached_file_list;
2106
 
  char *as_dir;
2107
 
  char *as_name;
2108
 
 
2109
 
  l = NULL;
2110
 
  using_cached_dir_list = FALSE;
2111
 
  using_cached_file_list = FALSE;
2112
 
 
2113
 
  filename = add_ignore_prefix (gphoto2_backend, given_filename);
2114
 
  DEBUG ("enumerate ('%s', with_prefix='%s')", given_filename, filename);
2115
 
 
2116
 
  split_filename_with_ignore_prefix (gphoto2_backend, given_filename, &as_dir, &as_name);
2117
 
  if (!is_directory (gphoto2_backend, as_dir, as_name))
2118
 
    {
2119
 
      if (is_regular (gphoto2_backend, as_dir, as_name))
2120
 
        {
2121
 
          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2122
 
                            G_IO_ERROR_NOT_DIRECTORY,
2123
 
                            _("Not a directory"));
2124
 
        }
2125
 
      else
2126
 
        {
2127
 
          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2128
 
                            G_IO_ERROR_NOT_FOUND,
2129
 
                            _("No such file or directory"));
2130
 
        }
2131
 
      g_free (as_dir);
2132
 
      g_free (as_name);
2133
 
      return;
2134
 
    }
2135
 
  g_free (as_dir);
2136
 
  g_free (as_name);
2137
 
 
2138
 
  /* first, list the folders */
2139
 
  g_mutex_lock (&gphoto2_backend->lock);
2140
 
  list = g_hash_table_lookup (gphoto2_backend->dir_name_cache, filename);
2141
 
  if (list == NULL)
2142
 
    {
2143
 
      g_mutex_unlock (&gphoto2_backend->lock);
2144
 
 
2145
 
      ensure_not_dirty (gphoto2_backend);
2146
 
 
2147
 
      DEBUG ("  Generating dir list for dir '%s'", filename);
2148
 
 
2149
 
      gp_list_new (&list);
2150
 
      rc = gp_camera_folder_list_folders (gphoto2_backend->camera, 
2151
 
                                          filename, 
2152
 
                                          list, 
2153
 
                                          gphoto2_backend->context);
2154
 
      if (rc != 0)
2155
 
        {
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);
2159
 
          g_free (filename);
2160
 
          return;
2161
 
        }  
2162
 
    }
2163
 
  else
2164
 
    {
2165
 
      DEBUG ("  Using cached dir list for dir '%s'", filename);
2166
 
      using_cached_dir_list = TRUE;
2167
 
      gp_list_ref (list);
2168
 
      g_mutex_unlock (&gphoto2_backend->lock);
2169
 
    }
2170
 
  for (n = 0; n < gp_list_count (list); n++) 
2171
 
    {
2172
 
      const char *name;
2173
 
 
2174
 
      gp_list_get_name (list, n, &name);
2175
 
      DEBUG ("  enum folder '%s'", name);
2176
 
      info = g_file_info_new ();
2177
 
      error = NULL;
2178
 
      if (!file_get_info (gphoto2_backend, filename, name, info, &error, FALSE))
2179
 
        {
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);
2183
 
          g_list_free (l);
2184
 
          gp_list_free (list);
2185
 
          return;
2186
 
        }
2187
 
      l = g_list_append (l, info);
2188
 
    }
2189
 
  if (!using_cached_dir_list)
2190
 
    {
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);
2195
 
#endif
2196
 
    }
2197
 
  else
2198
 
    {
2199
 
      g_mutex_lock (&gphoto2_backend->lock);
2200
 
      gp_list_unref (list);
2201
 
      g_mutex_unlock (&gphoto2_backend->lock);
2202
 
    }
2203
 
 
2204
 
 
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);
2208
 
  if (list == NULL)
2209
 
    {
2210
 
      g_mutex_unlock (&gphoto2_backend->lock);
2211
 
      ensure_not_dirty (gphoto2_backend);
2212
 
 
2213
 
      DEBUG ("  Generating file list for dir '%s'", filename);
2214
 
 
2215
 
      gp_list_new (&list);
2216
 
      rc = gp_camera_folder_list_files (gphoto2_backend->camera, 
2217
 
                                        filename, 
2218
 
                                        list, 
2219
 
                                        gphoto2_backend->context);
2220
 
      if (rc != 0)
2221
 
        {
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);
2225
 
          g_free (filename);
2226
 
          return;
2227
 
        }
2228
 
    }
2229
 
  else
2230
 
    {
2231
 
      DEBUG ("  Using cached file list for dir '%s'", filename);
2232
 
      using_cached_file_list = TRUE;
2233
 
      gp_list_ref (list);
2234
 
      g_mutex_unlock (&gphoto2_backend->lock);
2235
 
    }
2236
 
  for (n = 0; n < gp_list_count (list); n++) 
2237
 
    {
2238
 
      const char *name;
2239
 
 
2240
 
      gp_list_get_name (list, n, &name);
2241
 
      DEBUG ("  enum file '%s'", name);
2242
 
 
2243
 
      info = g_file_info_new ();
2244
 
      error = NULL;
2245
 
      if (!file_get_info (gphoto2_backend, filename, name, info, &error, FALSE))
2246
 
        {
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);
2250
 
          g_list_free (l);
2251
 
          gp_list_free (list);
2252
 
          return;
2253
 
        }
2254
 
      l = g_list_append (l, info);
2255
 
    }
2256
 
  if (!using_cached_file_list)
2257
 
    {
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);
2262
 
#endif
2263
 
    }
2264
 
  else
2265
 
    {
2266
 
      g_mutex_lock (&gphoto2_backend->lock);
2267
 
      gp_list_unref (list);
2268
 
      g_mutex_unlock (&gphoto2_backend->lock);
2269
 
    }
2270
 
 
2271
 
  /* and we're done */
2272
 
 
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);
2276
 
  g_list_free (l);
2277
 
  g_vfs_job_enumerate_done (job);
2278
 
 
2279
 
  g_free (filename);
2280
 
}
2281
 
 
2282
 
/* ------------------------------------------------------------------------------------------------- */
2283
 
 
2284
 
static gboolean
2285
 
try_enumerate (GVfsBackend *backend,
2286
 
               GVfsJobEnumerate *job,
2287
 
               const char *given_filename,
2288
 
               GFileAttributeMatcher *matcher,
2289
 
               GFileQueryInfoFlags flags)
2290
 
{
2291
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2292
 
  GFileInfo *info;
2293
 
  GList *l;
2294
 
  GError *error;
2295
 
  CameraList *list;
2296
 
  int n;
2297
 
  char *filename;
2298
 
  const char *name;
2299
 
 
2300
 
  l = NULL;
2301
 
 
2302
 
  filename = add_ignore_prefix (gphoto2_backend, given_filename);
2303
 
  DEBUG ("try_enumerate (%s)", given_filename);
2304
 
 
2305
 
  /* first, list the folders */
2306
 
  g_mutex_lock (&gphoto2_backend->lock);
2307
 
  list = g_hash_table_lookup (gphoto2_backend->dir_name_cache, filename);
2308
 
  if (list == NULL)
2309
 
    {
2310
 
      g_mutex_unlock (&gphoto2_backend->lock);
2311
 
      goto error_not_cached;
2312
 
    }
2313
 
  gp_list_ref (list);
2314
 
  g_mutex_unlock (&gphoto2_backend->lock);
2315
 
  for (n = 0; n < gp_list_count (list); n++) 
2316
 
    {
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))
2321
 
        {
2322
 
          g_mutex_lock (&gphoto2_backend->lock);
2323
 
          gp_list_unref (list);
2324
 
          g_mutex_unlock (&gphoto2_backend->lock);
2325
 
          goto error_not_cached;
2326
 
        }
2327
 
      l = g_list_append (l, info);
2328
 
    }
2329
 
  g_mutex_lock (&gphoto2_backend->lock);
2330
 
  gp_list_unref (list);
2331
 
  g_mutex_unlock (&gphoto2_backend->lock);
2332
 
 
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);
2336
 
  if (list == NULL)
2337
 
    {
2338
 
      g_mutex_unlock (&gphoto2_backend->lock);
2339
 
      goto error_not_cached;
2340
 
    }
2341
 
  gp_list_ref (list);
2342
 
  g_mutex_unlock (&gphoto2_backend->lock);
2343
 
  for (n = 0; n < gp_list_count (list); n++) 
2344
 
    {
2345
 
      gp_list_get_name (list, n, &name);
2346
 
      DEBUG ("  try_enum file '%s'", name);
2347
 
 
2348
 
      info = g_file_info_new ();
2349
 
      if (!file_get_info (gphoto2_backend, filename, name, info, &error, TRUE))
2350
 
        {
2351
 
          g_mutex_lock (&gphoto2_backend->lock);
2352
 
          gp_list_unref (list);
2353
 
          g_mutex_unlock (&gphoto2_backend->lock);
2354
 
          goto error_not_cached;
2355
 
        }
2356
 
      l = g_list_append (l, info);
2357
 
    }
2358
 
  g_mutex_lock (&gphoto2_backend->lock);
2359
 
  gp_list_unref (list);
2360
 
  g_mutex_unlock (&gphoto2_backend->lock);
2361
 
 
2362
 
  /* and we're done */
2363
 
 
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);
2367
 
  g_list_free (l);
2368
 
  g_vfs_job_enumerate_done (job);
2369
 
 
2370
 
  g_free (filename);
2371
 
  DEBUG ("  YAY got info from cache for try_enumerate (%s)", given_filename);
2372
 
  return TRUE;
2373
 
 
2374
 
 error_not_cached:
2375
 
  g_list_foreach (l, (GFunc) g_object_unref, NULL);
2376
 
  g_list_free (l);
2377
 
 
2378
 
  g_free (filename);
2379
 
  DEBUG ("  BUU no info from cache for try_enumerate (%s)", given_filename);
2380
 
  return FALSE;
2381
 
}
2382
 
 
2383
 
/* ------------------------------------------------------------------------------------------------- */
2384
 
 
2385
 
static void
2386
 
do_query_fs_info (GVfsBackend *backend,
2387
 
                  GVfsJobQueryFsInfo *job,
2388
 
                  const char *filename,
2389
 
                  GFileInfo *info,
2390
 
                  GFileAttributeMatcher *attribute_matcher)
2391
 
{
2392
 
  int rc;
2393
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2394
 
  CameraStorageInformation *storage_info;
2395
 
  int num_storage_info;
2396
 
 
2397
 
  DEBUG ("query_fs_info (%s)", filename);
2398
 
 
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);
2402
 
 
2403
 
  rc = gp_camera_get_storageinfo (gphoto2_backend->camera, &storage_info, &num_storage_info, gphoto2_backend->context);
2404
 
  if (rc == 0)
2405
 
    {
2406
 
      if (num_storage_info >= 1)
2407
 
        {
2408
 
          /* for now we only support a single storage head */
2409
 
          if (storage_info[0].fields & GP_STORAGEINFO_MAXCAPACITY)
2410
 
            {
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);
2417
 
            }
2418
 
 
2419
 
          if (storage_info[0].fields & GP_STORAGEINFO_FREESPACEKBYTES)
2420
 
            {
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);
2427
 
            }
2428
 
        }
2429
 
      DEBUG ("  got %d storage_info objects", num_storage_info);
2430
 
    }
2431
 
  
2432
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
2433
 
}
2434
 
 
2435
 
/* ------------------------------------------------------------------------------------------------- */
2436
 
 
2437
 
static gboolean
2438
 
try_query_fs_info (GVfsBackend *backend,
2439
 
                  GVfsJobQueryFsInfo *job,
2440
 
                  const char *filename,
2441
 
                  GFileInfo *info,
2442
 
                  GFileAttributeMatcher *attribute_matcher)
2443
 
{
2444
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2445
 
  gboolean ret;
2446
 
  gint64 free_space;
2447
 
  gint64 capacity;
2448
 
 
2449
 
  DEBUG ("try_query_fs_info (%s)", filename);
2450
 
 
2451
 
  ret = FALSE;
2452
 
 
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);
2457
 
 
2458
 
  if (free_space == -1 || capacity == -1)
2459
 
    {
2460
 
      DEBUG ("  BUU no info from cache for try_query_fs_info (%s)", filename);
2461
 
      goto out;
2462
 
    }
2463
 
  DEBUG ("  YAY got info from cache for try_query_fs_info (%s)", filename);
2464
 
 
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));
2471
 
 
2472
 
  ret = TRUE;
2473
 
 out:
2474
 
  return ret;
2475
 
}
2476
 
 
2477
 
/* ------------------------------------------------------------------------------------------------- */
2478
 
 
2479
 
static void
2480
 
do_make_directory (GVfsBackend *backend,
2481
 
                   GVfsJobMakeDirectory *job,
2482
 
                   const char *filename)
2483
 
{
2484
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2485
 
  char *name;
2486
 
  char *dir;
2487
 
  int rc;
2488
 
  GError *error;
2489
 
 
2490
 
  DEBUG ("make_directory (%s)", filename);
2491
 
 
2492
 
  ensure_not_dirty (gphoto2_backend);
2493
 
 
2494
 
  dir = NULL;
2495
 
  name = NULL;
2496
 
  error = NULL;
2497
 
 
2498
 
  if (!gphoto2_backend->can_write)
2499
 
    {
2500
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2501
 
                        G_IO_ERROR_NOT_SUPPORTED,
2502
 
                        _("Not supported"));
2503
 
      goto out;
2504
 
    }
2505
 
 
2506
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2507
 
 
2508
 
  rc = gp_camera_folder_make_dir (gphoto2_backend->camera,
2509
 
                                  dir,
2510
 
                                  name,
2511
 
                                  gphoto2_backend->context);
2512
 
  if (rc != 0)
2513
 
    {
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);
2517
 
      goto out;
2518
 
    }
2519
 
 
2520
 
  caches_invalidate_dir (gphoto2_backend, dir);
2521
 
  caches_invalidate_free_space (gphoto2_backend);
2522
 
  monitors_emit_created (gphoto2_backend, dir, name);
2523
 
 
2524
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
2525
 
 
2526
 
 out:
2527
 
  g_free (dir);
2528
 
  g_free (name);
2529
 
}
2530
 
 
2531
 
/* ------------------------------------------------------------------------------------------------- */
2532
 
 
2533
 
static int
2534
 
do_slow_file_rename_in_same_dir (GVfsBackendGphoto2 *gphoto2_backend,
2535
 
                                 const char *dir,
2536
 
                                 const char *name,
2537
 
                                 const char *new_name,
2538
 
                                 gboolean allow_overwrite)
2539
 
{
2540
 
  int rc;
2541
 
  CameraFile *file;
2542
 
  CameraFile *file_dest;
2543
 
  const char *data;
2544
 
  unsigned long int size;
2545
 
 
2546
 
  file = NULL;
2547
 
  file_dest = NULL;
2548
 
 
2549
 
  DEBUG ("do_slow_file_rename_in_same_dir() '%s' '%s' -> '%s'", dir, name, new_name);
2550
 
 
2551
 
  rc = gp_file_new (&file);
2552
 
  if (rc != 0)
2553
 
    goto out;
2554
 
 
2555
 
  rc = gp_camera_file_get (gphoto2_backend->camera,
2556
 
                           dir,
2557
 
                           name,
2558
 
                           GP_FILE_TYPE_NORMAL,
2559
 
                           file,
2560
 
                           gphoto2_backend->context);
2561
 
  if (rc != 0)
2562
 
    goto out;
2563
 
 
2564
 
  rc = gp_file_get_data_and_size (file, &data, &size);
2565
 
  if (rc != 0)
2566
 
    goto out;
2567
 
 
2568
 
  rc = gp_file_new (&file_dest);
2569
 
  if (rc != 0)
2570
 
    goto out;
2571
 
 
2572
 
  rc = gp_file_copy (file_dest, file);
2573
 
  if (rc != 0)
2574
 
    goto out;
2575
 
 
2576
 
  rc = gp_file_set_name (file_dest, new_name);
2577
 
  if (rc != 0)
2578
 
    goto out;
2579
 
 
2580
 
  if (allow_overwrite)
2581
 
    {
2582
 
      gp_camera_file_delete (gphoto2_backend->camera,
2583
 
                             dir,
2584
 
                             new_name,
2585
 
                             gphoto2_backend->context);
2586
 
      if (rc != 0)
2587
 
        {
2588
 
          DEBUG ("  file delete failed as part of slow rename rc=%d", rc);
2589
 
          goto out;
2590
 
        }
2591
 
    }
2592
 
 
2593
 
  rc = gp_camera_folder_put_file (gphoto2_backend->camera, dir, file_dest, gphoto2_backend->context);
2594
 
  if (rc != 0)
2595
 
    goto out;
2596
 
 
2597
 
  rc = gp_camera_file_delete (gphoto2_backend->camera,
2598
 
                              dir,
2599
 
                              name,
2600
 
                              gphoto2_backend->context);
2601
 
  if (rc != 0)
2602
 
    {
2603
 
      /* at least try to clean up the newly created file... */
2604
 
      gp_camera_file_delete (gphoto2_backend->camera,
2605
 
                             dir,
2606
 
                             new_name,
2607
 
                             gphoto2_backend->context);
2608
 
      goto out;
2609
 
    }
2610
 
 
2611
 
 out:
2612
 
  if (file != NULL)
2613
 
    gp_file_unref (file);
2614
 
  if (file_dest != NULL)
2615
 
    gp_file_unref (file_dest);
2616
 
  return rc;
2617
 
}
2618
 
 
2619
 
/* ------------------------------------------------------------------------------------------------- */
2620
 
 
2621
 
static int
2622
 
do_file_rename_in_same_dir (GVfsBackendGphoto2 *gphoto2_backend,
2623
 
                            const char *dir,
2624
 
                            const char *name,
2625
 
                            const char *new_name,
2626
 
                            gboolean allow_overwrite)
2627
 
{
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.
2633
 
   */
2634
 
  return do_slow_file_rename_in_same_dir (gphoto2_backend, dir, name, new_name, allow_overwrite);
2635
 
}
2636
 
 
2637
 
/* ------------------------------------------------------------------------------------------------- */
2638
 
 
2639
 
static int
2640
 
do_dir_rename_in_same_dir (GVfsBackendGphoto2 *gphoto2_backend,
2641
 
                           const char *dir,
2642
 
                           const char *name,
2643
 
                           const char *new_name)
2644
 
{
2645
 
  int rc;
2646
 
  char *dir_name;
2647
 
 
2648
 
  dir_name = g_build_filename (dir, name, NULL);
2649
 
 
2650
 
  DEBUG ("do_dir_rename_in_same_dir() '%s' '%s' -> '%s' ('%s')", dir, name, new_name, dir_name);
2651
 
 
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.
2655
 
   */
2656
 
  if (is_directory_empty (gphoto2_backend, dir_name))
2657
 
    {
2658
 
      rc = gp_camera_folder_make_dir (gphoto2_backend->camera,
2659
 
                                      dir,
2660
 
                                      new_name,
2661
 
                                      gphoto2_backend->context);
2662
 
      if (rc != 0)
2663
 
        goto out;
2664
 
      
2665
 
      rc = gp_camera_folder_remove_dir (gphoto2_backend->camera,
2666
 
                                        dir,
2667
 
                                        name,
2668
 
                                        gphoto2_backend->context);
2669
 
      if (rc != 0)
2670
 
        goto out;
2671
 
    }
2672
 
  else
2673
 
    {
2674
 
      rc = GP_ERROR_NOT_SUPPORTED;
2675
 
    }
2676
 
  
2677
 
 out:
2678
 
  g_free (dir_name);
2679
 
  return rc;
2680
 
}
2681
 
 
2682
 
/* ------------------------------------------------------------------------------------------------- */
2683
 
 
2684
 
static void
2685
 
do_set_display_name (GVfsBackend *backend,
2686
 
                     GVfsJobSetDisplayName *job,
2687
 
                     const char *filename,
2688
 
                     const char *display_name)
2689
 
{
2690
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2691
 
  char *name;
2692
 
  char *dir;
2693
 
  int rc;
2694
 
  char *dir_name;
2695
 
  GError *error;
2696
 
  char *new_name;
2697
 
 
2698
 
  ensure_not_dirty (gphoto2_backend);
2699
 
 
2700
 
  DEBUG ("set_display_name() '%s' -> '%s'", filename, display_name);
2701
 
 
2702
 
  dir = NULL;
2703
 
  name = NULL;
2704
 
  dir_name = NULL;
2705
 
  new_name = NULL;
2706
 
 
2707
 
  if (!gphoto2_backend->can_write)
2708
 
    {
2709
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2710
 
                        G_IO_ERROR_NOT_SUPPORTED,
2711
 
                        _("Not supported"));
2712
 
      goto out;
2713
 
    }
2714
 
 
2715
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2716
 
 
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))
2720
 
    {
2721
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2722
 
                        G_IO_ERROR_EXISTS,
2723
 
                        _("Name already exists"));
2724
 
      goto out;      
2725
 
    }
2726
 
 
2727
 
  /* ensure name is not too long - otherwise it might screw up enumerating
2728
 
   * the folder on some devices 
2729
 
   */
2730
 
  if (strlen (display_name) > 63)
2731
 
    {
2732
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2733
 
                        G_IO_ERROR_NOT_SUPPORTED,
2734
 
                        _("New name too long"));
2735
 
      goto out;
2736
 
    }
2737
 
 
2738
 
  if (is_directory (gphoto2_backend, dir, name))
2739
 
    {
2740
 
      /* dir renaming */
2741
 
      rc = do_dir_rename_in_same_dir (gphoto2_backend, dir, name, display_name);
2742
 
      if (rc != 0)
2743
 
        {
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);
2747
 
          goto out;
2748
 
        }
2749
 
      caches_invalidate_file (gphoto2_backend, dir, name);
2750
 
    }
2751
 
  else
2752
 
    {
2753
 
      /* file renaming */
2754
 
      rc = do_file_rename_in_same_dir (gphoto2_backend, dir, name, display_name, FALSE);
2755
 
      if (rc != 0)
2756
 
        {
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);
2760
 
          goto out;
2761
 
        }
2762
 
      caches_invalidate_file (gphoto2_backend, dir, name);
2763
 
    }
2764
 
 
2765
 
 
2766
 
  /* emit on monitor */
2767
 
  monitors_emit_deleted (gphoto2_backend, dir, name);
2768
 
  monitors_emit_created (gphoto2_backend, dir, display_name);
2769
 
 
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);
2772
 
 
2773
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
2774
 
 
2775
 
 out:
2776
 
  g_free (dir);
2777
 
  g_free (name);
2778
 
  g_free (dir_name);
2779
 
  g_free (new_name);
2780
 
}
2781
 
 
2782
 
/* ------------------------------------------------------------------------------------------------- */
2783
 
 
2784
 
static void
2785
 
do_delete (GVfsBackend *backend,
2786
 
           GVfsJobDelete *job,
2787
 
           const char *filename)
2788
 
{
2789
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2790
 
  char *name;
2791
 
  char *dir;
2792
 
  int rc;
2793
 
  GError *error;
2794
 
  char *dir_name;
2795
 
 
2796
 
  ensure_not_dirty (gphoto2_backend);
2797
 
 
2798
 
  DEBUG ("delete() '%s'", filename);
2799
 
 
2800
 
  dir = NULL;
2801
 
  name = NULL;
2802
 
  dir_name = NULL;
2803
 
 
2804
 
  if (!gphoto2_backend->can_delete)
2805
 
    {
2806
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2807
 
                        G_IO_ERROR_NOT_SUPPORTED,
2808
 
                        _("Not supported"));
2809
 
      goto out;
2810
 
    }
2811
 
 
2812
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2813
 
 
2814
 
  if (is_directory (gphoto2_backend, dir, name))
2815
 
    {
2816
 
      dir_name = add_ignore_prefix (gphoto2_backend, filename);
2817
 
      if (!is_directory_empty (gphoto2_backend, dir_name))
2818
 
        {
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);
2822
 
          goto out;
2823
 
        }
2824
 
      else
2825
 
        {
2826
 
          rc = gp_camera_folder_remove_dir (gphoto2_backend->camera,
2827
 
                                            dir,
2828
 
                                            name,
2829
 
                                            gphoto2_backend->context);
2830
 
          if (rc != 0)
2831
 
            {
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);
2835
 
              goto out;
2836
 
            }
2837
 
          caches_invalidate_file (gphoto2_backend, dir, name);
2838
 
          caches_invalidate_free_space (gphoto2_backend);
2839
 
          monitors_emit_deleted (gphoto2_backend, dir, name);
2840
 
        }
2841
 
    }
2842
 
  else
2843
 
    {
2844
 
      if (!is_regular (gphoto2_backend, dir, name))
2845
 
        {
2846
 
          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2847
 
                            G_IO_ERROR_NOT_FOUND,
2848
 
                            _("No such file or directory"));
2849
 
          goto out;
2850
 
        }
2851
 
 
2852
 
      rc = gp_camera_file_delete (gphoto2_backend->camera,
2853
 
                                  dir,
2854
 
                                  name,
2855
 
                                  gphoto2_backend->context);
2856
 
      if (rc != 0)
2857
 
        {
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);
2861
 
          goto out;
2862
 
        }
2863
 
 
2864
 
      caches_invalidate_file (gphoto2_backend, dir, name);
2865
 
      caches_invalidate_free_space (gphoto2_backend);
2866
 
      monitors_emit_deleted (gphoto2_backend, dir, name);
2867
 
    }
2868
 
 
2869
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
2870
 
 
2871
 
 out:
2872
 
  g_free (dir);
2873
 
  g_free (name);
2874
 
  g_free (dir_name);
2875
 
}
2876
 
 
2877
 
/* ------------------------------------------------------------------------------------------------- */
2878
 
 
2879
 
static void 
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)
2886
 
{
2887
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
2888
 
  WriteHandle *handle;
2889
 
  char *dir;
2890
 
  char *name;
2891
 
 
2892
 
  ensure_not_dirty (gphoto2_backend);
2893
 
 
2894
 
  dir = NULL;
2895
 
  name = NULL;
2896
 
 
2897
 
  if (!gphoto2_backend->can_write)
2898
 
    {
2899
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2900
 
                        G_IO_ERROR_NOT_SUPPORTED,
2901
 
                        _("Not supported"));
2902
 
      goto out;
2903
 
    }
2904
 
 
2905
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
2906
 
 
2907
 
  if (is_directory (gphoto2_backend, dir, name))
2908
 
    {
2909
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2910
 
                        G_IO_ERROR_IS_DIRECTORY,
2911
 
                        _("Can't write to directory"));
2912
 
      goto out;
2913
 
    }
2914
 
 
2915
 
  /* unless we're replacing or appending.. error out if file already exists */
2916
 
  if (is_regular (gphoto2_backend, dir, name))
2917
 
    {
2918
 
      if (! (job_is_replace || job_is_append_to))
2919
 
        {
2920
 
          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
2921
 
                            G_IO_ERROR_EXISTS,
2922
 
                            _("File exists"));
2923
 
          goto out;
2924
 
        }
2925
 
    }
2926
 
  else
2927
 
    {
2928
 
      if (job_is_replace || job_is_append_to)
2929
 
        {
2930
 
          /* so we're not really replacing or appending; dont fail these
2931
 
           * operations; just turn them into create instead...
2932
 
           */
2933
 
          job_is_replace = FALSE;
2934
 
          job_is_append_to = FALSE;
2935
 
        }
2936
 
    }      
2937
 
 
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;
2945
 
 
2946
 
  /* if we're appending to a file read in all of the file to memory */
2947
 
  if (job_is_append_to)
2948
 
    {
2949
 
      int rc;
2950
 
      GError *error;
2951
 
      CameraFile *file;
2952
 
      const char *data;
2953
 
      unsigned long int size;
2954
 
      
2955
 
      rc = gp_file_new (&file);
2956
 
      if (rc != 0)
2957
 
        {
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);
2962
 
          goto out;
2963
 
        }
2964
 
 
2965
 
      rc = gp_camera_file_get (gphoto2_backend->camera,
2966
 
                               dir,
2967
 
                               name,
2968
 
                               GP_FILE_TYPE_NORMAL,
2969
 
                               file,
2970
 
                               gphoto2_backend->context);
2971
 
      if (rc != 0)
2972
 
        {
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);
2978
 
          goto out;
2979
 
        }
2980
 
 
2981
 
      rc = gp_file_get_data_and_size (file, &data, &size);
2982
 
      if (rc != 0)
2983
 
        {
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);
2989
 
          goto out;
2990
 
        }
2991
 
 
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);
2998
 
      
2999
 
    }
3000
 
  else
3001
 
    {
3002
 
      handle->data = g_malloc (WRITE_INCREMENT);
3003
 
      handle->allocated_size = WRITE_INCREMENT;
3004
 
    }
3005
 
 
3006
 
  g_vfs_job_open_for_write_set_handle (job, handle);
3007
 
  g_vfs_job_open_for_write_set_can_seek (job, TRUE);
3008
 
 
3009
 
  gphoto2_backend->open_write_handles = g_list_prepend (gphoto2_backend->open_write_handles, handle);
3010
 
 
3011
 
  DEBUG ("  handle=%p", handle);
3012
 
 
3013
 
  /* make sure we invalidate the dir and the file */
3014
 
  caches_invalidate_file (gphoto2_backend, dir, name);
3015
 
 
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...
3019
 
   */
3020
 
  if (job_is_replace || job_is_append_to)
3021
 
    monitors_emit_changed (gphoto2_backend, dir, name);
3022
 
  else
3023
 
    monitors_emit_created (gphoto2_backend, dir, name);
3024
 
 
3025
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
3026
 
 
3027
 
 out:
3028
 
  g_free (dir);
3029
 
  g_free (name);
3030
 
}
3031
 
 
3032
 
/* ------------------------------------------------------------------------------------------------- */
3033
 
 
3034
 
static void 
3035
 
do_create (GVfsBackend *backend,
3036
 
           GVfsJobOpenForWrite *job,
3037
 
           const char *filename,
3038
 
           GFileCreateFlags flags)
3039
 
{
3040
 
  DEBUG ("create() '%s' flags=0x%04x", filename, flags);
3041
 
 
3042
 
  return do_create_internal (backend, job, filename, flags, FALSE, FALSE);
3043
 
}
3044
 
 
3045
 
/* ------------------------------------------------------------------------------------------------- */
3046
 
 
3047
 
static void
3048
 
do_replace (GVfsBackend *backend,
3049
 
            GVfsJobOpenForWrite *job,
3050
 
            const char *filename,
3051
 
            const char *etag,
3052
 
            gboolean make_backup,
3053
 
            GFileCreateFlags flags)
3054
 
{
3055
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3056
 
  char *dir;
3057
 
  char *name;
3058
 
 
3059
 
  DEBUG ("replace() '%s' etag='%s' make_backup=%d flags=0x%04x", filename, etag, make_backup, flags);
3060
 
 
3061
 
  dir = NULL;
3062
 
  name = NULL;
3063
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
3064
 
  
3065
 
  /* write a new file
3066
 
   * - will delete the existing one when done in do_close_write() 
3067
 
   */
3068
 
  do_create_internal (backend, job, filename, flags, TRUE, FALSE);
3069
 
 
3070
 
  g_free (dir);
3071
 
  g_free (name);
3072
 
}
3073
 
 
3074
 
/* ------------------------------------------------------------------------------------------------- */
3075
 
 
3076
 
static void
3077
 
do_append_to (GVfsBackend *backend,
3078
 
              GVfsJobOpenForWrite *job,
3079
 
              const char *filename,
3080
 
              GFileCreateFlags flags)
3081
 
{
3082
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3083
 
  char *dir;
3084
 
  char *name;
3085
 
 
3086
 
  DEBUG ("append_to() '%s' flags=0x%04x", filename, flags);
3087
 
 
3088
 
  dir = NULL;
3089
 
  name = NULL;
3090
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
3091
 
  
3092
 
  /* write a new file
3093
 
   * - will read existing data in do_create_internal
3094
 
   * - will delete the existing one when done in do_close_write() 
3095
 
   */
3096
 
  do_create_internal (backend, job, filename, flags, FALSE, TRUE);
3097
 
 
3098
 
  g_free (dir);
3099
 
  g_free (name);
3100
 
}
3101
 
 
3102
 
/* ------------------------------------------------------------------------------------------------- */
3103
 
 
3104
 
static void
3105
 
do_write (GVfsBackend *backend,
3106
 
          GVfsJobWrite *job,
3107
 
          GVfsBackendHandle _handle,
3108
 
          char *buffer,
3109
 
          gsize buffer_size)
3110
 
{
3111
 
  WriteHandle *handle = _handle;
3112
 
 
3113
 
  DEBUG ("write() %p, '%s', %d bytes", handle, handle->filename, buffer_size);
3114
 
 
3115
 
  /* ensure we have enough room */
3116
 
  if (handle->cursor + buffer_size > handle->allocated_size)
3117
 
    {
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);
3123
 
    }
3124
 
 
3125
 
 
3126
 
  memcpy (handle->data + handle->cursor, buffer, buffer_size);
3127
 
  handle->cursor += buffer_size;
3128
 
 
3129
 
  if (handle->cursor > handle->size)
3130
 
    handle->size = handle->cursor;
3131
 
 
3132
 
  /* this will make us dirty */
3133
 
  handle->is_dirty = TRUE;
3134
 
 
3135
 
  g_vfs_job_write_set_written_size (job, buffer_size);
3136
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
3137
 
}
3138
 
 
3139
 
/* ------------------------------------------------------------------------------------------------- */
3140
 
 
3141
 
static void
3142
 
do_seek_on_write (GVfsBackend *backend,
3143
 
                  GVfsJobSeekWrite *job,
3144
 
                  GVfsBackendHandle handle,
3145
 
                  goffset    offset,
3146
 
                  GSeekType  type)
3147
 
{
3148
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3149
 
  WriteHandle *write_handle = handle;
3150
 
  long new_offset;
3151
 
 
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);
3153
 
 
3154
 
  switch (type)
3155
 
    {
3156
 
    default:
3157
 
    case G_SEEK_SET:
3158
 
      new_offset = offset;
3159
 
      break;
3160
 
    case G_SEEK_CUR:
3161
 
      new_offset = write_handle->cursor + offset;
3162
 
      break;
3163
 
    case G_SEEK_END:
3164
 
      new_offset = write_handle->size + offset;
3165
 
      break;
3166
 
    }
3167
 
 
3168
 
  if (new_offset < 0 || new_offset > write_handle->size)
3169
 
    {
3170
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
3171
 
                        G_IO_ERROR_FAILED,
3172
 
                        _("Error seeking in stream on camera %s"), gphoto2_backend->gphoto2_port);
3173
 
    }
3174
 
  else
3175
 
    {
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));
3179
 
    }
3180
 
}
3181
 
 
3182
 
/* ------------------------------------------------------------------------------------------------- */
3183
 
 
3184
 
/* this functions updates the device with the data currently in write_handle */
3185
 
static int
3186
 
commit_write_handle (GVfsBackendGphoto2 *gphoto2_backend, WriteHandle *write_handle)
3187
 
{
3188
 
  int rc;
3189
 
  CameraFile *file;
3190
 
 
3191
 
  DEBUG ("commit_write_handle() '%s' of size %ld", write_handle->filename, write_handle->size);
3192
 
 
3193
 
  /* no need to write as we're not dirty */
3194
 
  if (!write_handle->is_dirty)
3195
 
    {
3196
 
      DEBUG ("  not dirty => not writing");
3197
 
      return 0;
3198
 
    }
3199
 
 
3200
 
  if (write_handle->delete_before || 
3201
 
      (write_handle->job_is_replace || write_handle->job_is_append_to))
3202
 
    {
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()...
3206
 
       *
3207
 
       * So first delete the existing file...
3208
 
       */
3209
 
      rc = gp_camera_file_delete (gphoto2_backend->camera,
3210
 
                                  write_handle->dir,
3211
 
                                  write_handle->name,
3212
 
                                  gphoto2_backend->context);
3213
 
      if (rc != 0)
3214
 
        goto out;
3215
 
 
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);
3219
 
    }
3220
 
 
3221
 
  rc = gp_file_new (&file);
3222
 
  if (rc != 0)
3223
 
    goto out;
3224
 
 
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);
3231
 
  
3232
 
  rc = gp_camera_folder_put_file (gphoto2_backend->camera, write_handle->dir, file, gphoto2_backend->context);
3233
 
  if (rc != 0)
3234
 
    {
3235
 
      gp_file_unref (file);
3236
 
      goto out;
3237
 
    }
3238
 
 
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);
3241
 
 
3242
 
  gp_file_unref (file);
3243
 
 
3244
 
 out:
3245
 
  write_handle->is_dirty = FALSE;
3246
 
  write_handle->delete_before = TRUE;
3247
 
 
3248
 
  caches_invalidate_file (gphoto2_backend, write_handle->dir, write_handle->name);
3249
 
  caches_invalidate_free_space (gphoto2_backend);
3250
 
 
3251
 
  return rc;
3252
 
}
3253
 
 
3254
 
/* ------------------------------------------------------------------------------------------------- */
3255
 
 
3256
 
static void 
3257
 
do_close_write (GVfsBackend *backend,
3258
 
                GVfsJobCloseWrite *job,
3259
 
                GVfsBackendHandle handle)
3260
 
{
3261
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3262
 
  WriteHandle *write_handle = handle;
3263
 
  GError *error;
3264
 
  int rc;
3265
 
 
3266
 
  DEBUG ("close_write() %p '%s' %ld bytes total", write_handle, write_handle->filename, write_handle->size);
3267
 
 
3268
 
  rc = commit_write_handle (gphoto2_backend, write_handle);
3269
 
  if (rc != 0)
3270
 
    {
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);
3274
 
      goto out;
3275
 
    }
3276
 
 
3277
 
  monitors_emit_changed (gphoto2_backend, write_handle->dir, write_handle->name);
3278
 
 
3279
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
3280
 
 
3281
 
 out:
3282
 
  write_handle_free (write_handle);
3283
 
  gphoto2_backend->open_write_handles = g_list_remove (gphoto2_backend->open_write_handles, write_handle);
3284
 
}
3285
 
 
3286
 
/* ------------------------------------------------------------------------------------------------- */
3287
 
 
3288
 
static void
3289
 
do_move (GVfsBackend *backend,
3290
 
         GVfsJobMove *job,
3291
 
         const char *source,
3292
 
         const char *destination,
3293
 
         GFileCopyFlags flags,
3294
 
         GFileProgressCallback progress_callback,
3295
 
         gpointer progress_callback_data)
3296
 
{
3297
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3298
 
  char *src_dir;
3299
 
  char *src_name;
3300
 
  char *dst_dir;
3301
 
  char *dst_name;
3302
 
  int rc;
3303
 
  GError *error;
3304
 
  gboolean mv_dir;
3305
 
 
3306
 
  DEBUG ("move() '%s' -> '%s' %04x)", source, destination, flags);
3307
 
 
3308
 
  ensure_not_dirty (gphoto2_backend);
3309
 
 
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);
3312
 
 
3313
 
  /* this is an limited implementation that can only move files / folders in the same directory */
3314
 
  if (strcmp (src_dir, dst_dir) != 0)
3315
 
    {
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)"));
3320
 
      goto out;
3321
 
    }
3322
 
 
3323
 
  mv_dir = FALSE;
3324
 
  if (is_directory (gphoto2_backend, src_dir, src_name))
3325
 
    {
3326
 
      if (is_directory (gphoto2_backend, dst_dir, dst_name))
3327
 
        {
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)"));
3332
 
          goto out;
3333
 
        }
3334
 
      else if (is_regular (gphoto2_backend, dst_dir, dst_name))
3335
 
        {
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)"));
3340
 
          goto out;
3341
 
        }
3342
 
      mv_dir = TRUE;
3343
 
    }
3344
 
  else
3345
 
    {
3346
 
      if (is_directory (gphoto2_backend, dst_dir, dst_name))
3347
 
        {
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)"));
3352
 
          goto out;
3353
 
        }
3354
 
    }
3355
 
 
3356
 
  /* ensure name is not too long - otherwise it might screw up enumerating
3357
 
   * the folder on some devices 
3358
 
   */
3359
 
  if (strlen (dst_name) > 63)
3360
 
    {
3361
 
      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
3362
 
                        G_IO_ERROR_NOT_SUPPORTED,
3363
 
                        _("New name too long"));
3364
 
      goto out;
3365
 
    }
3366
 
 
3367
 
  if (mv_dir)
3368
 
    {
3369
 
      DEBUG ("  renaming dir");
3370
 
      rc = do_dir_rename_in_same_dir (gphoto2_backend, src_dir, src_name, dst_name);
3371
 
      if (rc != 0)
3372
 
        {
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);
3377
 
          goto out;
3378
 
        }
3379
 
    }
3380
 
  else
3381
 
    {
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);
3384
 
      if (rc != 0)
3385
 
        {
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);
3390
 
          goto out;
3391
 
        }
3392
 
    }
3393
 
 
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);
3397
 
 
3398
 
  DEBUG ("  success");
3399
 
 
3400
 
  g_vfs_job_succeeded (G_VFS_JOB (job));
3401
 
 
3402
 
 out:
3403
 
  g_free (src_dir);
3404
 
  g_free (src_name);
3405
 
  g_free (dst_dir);
3406
 
  g_free (dst_name);
3407
 
}
3408
 
 
3409
 
/* ------------------------------------------------------------------------------------------------- */
3410
 
 
3411
 
static void
3412
 
vfs_dir_monitor_destroyed (gpointer user_data, GObject *where_the_object_was)
3413
 
{
3414
 
  GList *l;
3415
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (user_data);
3416
 
  
3417
 
  DEBUG ("vfs_dir_monitor_destroyed()");
3418
 
 
3419
 
  for (l = gphoto2_backend->dir_monitor_proxies; l != NULL; l = l->next)
3420
 
    {
3421
 
      MonitorProxy *proxy = l->data;
3422
 
      if (G_OBJECT (proxy->vfs_monitor) == where_the_object_was)
3423
 
        {
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);
3427
 
          break;
3428
 
        }
3429
 
    }  
3430
 
}
3431
 
 
3432
 
static void
3433
 
do_create_dir_monitor (GVfsBackend *backend,
3434
 
                       GVfsJobCreateMonitor *job,
3435
 
                       const char *filename,
3436
 
                       GFileMonitorFlags flags)
3437
 
{
3438
 
  char *dir;
3439
 
  char *name;
3440
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3441
 
  MonitorProxy *proxy;
3442
 
 
3443
 
  DEBUG ("create_dir_monitor (%s)", filename);
3444
 
 
3445
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
3446
 
 
3447
 
  proxy = g_new0 (MonitorProxy, 1);
3448
 
  proxy->path = add_ignore_prefix (gphoto2_backend, filename);
3449
 
  proxy->vfs_monitor = g_vfs_monitor_new (backend);
3450
 
 
3451
 
  gphoto2_backend->dir_monitor_proxies = g_list_prepend (gphoto2_backend->dir_monitor_proxies, proxy);
3452
 
 
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));
3457
 
}
3458
 
 
3459
 
/* ------------------------------------------------------------------------------------------------- */
3460
 
 
3461
 
static void
3462
 
vfs_file_monitor_destroyed (gpointer user_data, GObject *where_the_object_was)
3463
 
{
3464
 
  GList *l;
3465
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (user_data);
3466
 
  
3467
 
  DEBUG ("vfs_file_monitor_destroyed()");
3468
 
 
3469
 
  for (l = gphoto2_backend->file_monitor_proxies; l != NULL; l = l->next)
3470
 
    {
3471
 
      MonitorProxy *proxy = l->data;
3472
 
      if (G_OBJECT (proxy->vfs_monitor) == where_the_object_was)
3473
 
        {
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);
3477
 
          break;
3478
 
        }
3479
 
    }  
3480
 
}
3481
 
 
3482
 
static void
3483
 
do_create_file_monitor (GVfsBackend *backend,
3484
 
                        GVfsJobCreateMonitor *job,
3485
 
                        const char *filename,
3486
 
                        GFileMonitorFlags flags)
3487
 
{
3488
 
  char *dir;
3489
 
  char *name;
3490
 
  GVfsBackendGphoto2 *gphoto2_backend = G_VFS_BACKEND_GPHOTO2 (backend);
3491
 
  MonitorProxy *proxy;
3492
 
 
3493
 
  DEBUG ("create_file_monitor (%s)", filename);
3494
 
 
3495
 
  split_filename_with_ignore_prefix (gphoto2_backend, filename, &dir, &name);
3496
 
 
3497
 
  proxy = g_new0 (MonitorProxy, 1);
3498
 
  proxy->path = add_ignore_prefix (gphoto2_backend, filename);
3499
 
  proxy->vfs_monitor = g_vfs_monitor_new (backend);
3500
 
 
3501
 
  gphoto2_backend->file_monitor_proxies = g_list_prepend (gphoto2_backend->file_monitor_proxies, proxy);
3502
 
 
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));
3507
 
}
3508
 
 
3509
 
/* ------------------------------------------------------------------------------------------------- */
3510
 
 
3511
 
static void
3512
 
g_vfs_backend_gphoto2_class_init (GVfsBackendGphoto2Class *klass)
3513
 
{
3514
 
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3515
 
  GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
3516
 
  
3517
 
  gobject_class->finalize = g_vfs_backend_gphoto2_finalize;
3518
 
 
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;
3541
 
 
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;
3546
 
}