~ubuntu-branches/ubuntu/natty/gvfs/natty

« back to all changes in this revision

Viewing changes to .pc/debian-changes-1.7.3-0ubuntu1/client/gdaemonvfs.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2011-03-22 11:11:57 UTC
  • Revision ID: james.westby@ubuntu.com-20110322111157-tn8edztqci0xr9hk
Correctly update using merge-upstream otherwise the diff will be reverted
in the diff.gz.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GIO - GLib Input, Output and Streaming Library
2
 
 * 
3
 
 * Copyright (C) 2006-2007 Red Hat, Inc.
4
 
 *
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 * Lesser General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Lesser General
16
 
 * Public License along with this library; if not, write to the
17
 
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18
 
 * Boston, MA 02111-1307, USA.
19
 
 *
20
 
 * Author: Alexander Larsson <alexl@redhat.com>
21
 
 */
22
 
 
23
 
#include <config.h>
24
 
#include <string.h>
25
 
#include <signal.h>
26
 
#include <stdlib.h>
27
 
#include <errno.h>
28
 
#include <dbus/dbus.h>
29
 
#include "gdaemonvfs.h"
30
 
#include "gvfsuriutils.h"
31
 
#include "gdaemonfile.h"
32
 
#include <gio/gio.h>
33
 
#include <gvfsdaemonprotocol.h>
34
 
#include <gmodule.h>
35
 
#include "gvfsdaemondbus.h"
36
 
#include "gvfsdbusutils.h"
37
 
#include "gmountspec.h"
38
 
#include "gvfsurimapper.h"
39
 
#include "gdaemonvolumemonitor.h"
40
 
#include "gvfsicon.h"
41
 
#include "gvfsiconloadable.h"
42
 
#include <glib/gi18n-lib.h>
43
 
#include <glib/gstdio.h>
44
 
 
45
 
typedef struct  {
46
 
  char *type;
47
 
  char *scheme;
48
 
  char **scheme_aliases;
49
 
  int default_port;
50
 
  gboolean host_is_inet;
51
 
} MountableInfo; 
52
 
 
53
 
struct _GDaemonVfs
54
 
{
55
 
  GVfs parent;
56
 
 
57
 
  DBusConnection *async_bus;
58
 
  
59
 
  GVfs *wrapped_vfs;
60
 
  GList *mount_cache;
61
 
 
62
 
  GFile *fuse_root;
63
 
  
64
 
  GHashTable *from_uri_hash;
65
 
  GHashTable *to_uri_hash;
66
 
 
67
 
  MountableInfo **mountable_info;
68
 
  char **supported_uri_schemes;
69
 
};
70
 
 
71
 
struct _GDaemonVfsClass
72
 
{
73
 
  GVfsClass parent_class;
74
 
};
75
 
 
76
 
G_DEFINE_DYNAMIC_TYPE (GDaemonVfs, g_daemon_vfs, G_TYPE_VFS)
77
 
 
78
 
static GDaemonVfs *the_vfs = NULL;
79
 
 
80
 
G_LOCK_DEFINE_STATIC(mount_cache);
81
 
 
82
 
 
83
 
static void fill_mountable_info (GDaemonVfs *vfs);
84
 
 
85
 
static void
86
 
g_daemon_vfs_finalize (GObject *object)
87
 
{
88
 
  GDaemonVfs *vfs;
89
 
 
90
 
  vfs = G_DAEMON_VFS (object);
91
 
 
92
 
  if (vfs->from_uri_hash)
93
 
    g_hash_table_destroy (vfs->from_uri_hash);
94
 
  
95
 
  if (vfs->to_uri_hash)
96
 
    g_hash_table_destroy (vfs->to_uri_hash);
97
 
 
98
 
  g_strfreev (vfs->supported_uri_schemes);
99
 
 
100
 
  if (vfs->async_bus)
101
 
    {
102
 
      dbus_connection_close (vfs->async_bus);
103
 
      dbus_connection_unref (vfs->async_bus);
104
 
    }
105
 
 
106
 
  if (vfs->wrapped_vfs)
107
 
    g_object_unref (vfs->wrapped_vfs);
108
 
  
109
 
  /* must chain up */
110
 
  G_OBJECT_CLASS (g_daemon_vfs_parent_class)->finalize (object);
111
 
}
112
 
 
113
 
static MountableInfo *
114
 
get_mountable_info_for_scheme (GDaemonVfs *vfs,
115
 
                               const char *scheme)
116
 
{
117
 
  MountableInfo *info;
118
 
  int i, j;
119
 
 
120
 
  if (vfs->mountable_info == NULL)
121
 
    return NULL;
122
 
 
123
 
  for (i = 0; vfs->mountable_info[i] != NULL; i++)
124
 
    {
125
 
      info = vfs->mountable_info[i];
126
 
      
127
 
      if (info->scheme != NULL && strcmp (info->scheme, scheme) == 0)
128
 
        return info;
129
 
 
130
 
      if (info->scheme_aliases != NULL)
131
 
        {
132
 
          for (j = 0; info->scheme_aliases[j] != NULL; j++)
133
 
            {
134
 
              if (strcmp (info->scheme_aliases[j], scheme) == 0)
135
 
                return info;
136
 
            }
137
 
        }
138
 
      
139
 
    }
140
 
  
141
 
  return NULL;
142
 
}
143
 
 
144
 
static MountableInfo *
145
 
get_mountable_info_for_type (GDaemonVfs *vfs,
146
 
                             const char *type)
147
 
{
148
 
  MountableInfo *info;
149
 
  int i;
150
 
  
151
 
  if (vfs->mountable_info == NULL)
152
 
    return NULL;
153
 
  
154
 
  for (i = 0; vfs->mountable_info[i] != NULL; i++)
155
 
    {
156
 
      info = vfs->mountable_info[i];
157
 
      
158
 
      if (strcmp (info->type, type) == 0)
159
 
        return info;
160
 
    }
161
 
  
162
 
  return NULL;
163
 
}
164
 
 
165
 
static void
166
 
str_tolower_inplace (char *str)
167
 
{
168
 
  char *p = str;
169
 
 
170
 
  while (*p != 0)
171
 
    {
172
 
      *p = g_ascii_tolower (*p);
173
 
      p++;
174
 
    }
175
 
 
176
 
}
177
 
 
178
 
static gboolean
179
 
get_mountspec_from_uri (GDaemonVfs *vfs,
180
 
                        const char *uri,
181
 
                        GMountSpec **spec_out,
182
 
                        char **path_out)
183
 
{
184
 
  GMountSpec *spec;
185
 
  char *path;
186
 
  GVfsUriMapper *mapper;
187
 
  char *scheme;
188
 
  GVfsUriMountInfo *info;
189
 
  
190
 
  scheme = g_uri_parse_scheme (uri);
191
 
  if (scheme == NULL)
192
 
    return FALSE;
193
 
 
194
 
  /* convert the scheme to lower case since g_uri_parse_scheme
195
 
   * doesn't do that and we compare with g_str_equal */
196
 
  str_tolower_inplace (scheme);
197
 
  
198
 
  spec = NULL;
199
 
  path = NULL;
200
 
  
201
 
  mapper = g_hash_table_lookup (vfs->from_uri_hash, scheme);
202
 
  
203
 
  if (mapper)
204
 
    {
205
 
      info = g_vfs_uri_mapper_from_uri (mapper, uri);
206
 
      if (info != NULL)
207
 
        {
208
 
          spec = g_mount_spec_new_from_data (info->keys, NULL);
209
 
          path = info->path;
210
 
          /* We took over ownership of info parts, custom free: */
211
 
          g_free (info);
212
 
        }
213
 
    }
214
 
  
215
 
  if (spec == NULL)
216
 
    {
217
 
      GDecodedUri *decoded;
218
 
      MountableInfo *mountable;
219
 
      char *type;
220
 
      int l;
221
 
 
222
 
      decoded = g_vfs_decode_uri (uri);
223
 
      if (decoded)
224
 
        {       
225
 
          mountable = get_mountable_info_for_scheme (vfs, decoded->scheme);
226
 
      
227
 
          if (mountable)
228
 
            type = mountable->type;
229
 
          else
230
 
            type = decoded->scheme;
231
 
          
232
 
          spec = g_mount_spec_new (type);
233
 
          
234
 
          if (decoded->host && *decoded->host)
235
 
            {
236
 
              if (mountable && mountable->host_is_inet)
237
 
                {
238
 
                  /* Convert hostname to lower case */
239
 
                  str_tolower_inplace (decoded->host);
240
 
                  
241
 
                  /* Remove brackets aroung ipv6 addresses */
242
 
                  l = strlen (decoded->host);
243
 
                  if (decoded->host[0] == '[' &&
244
 
                      decoded->host[l - 1] == ']')
245
 
                    g_mount_spec_set_with_len (spec, "host", decoded->host+1, l - 2);
246
 
                  else
247
 
                    g_mount_spec_set (spec, "host", decoded->host);
248
 
                }
249
 
              else
250
 
                g_mount_spec_set (spec, "host", decoded->host);
251
 
            }
252
 
          
253
 
          if (decoded->userinfo && *decoded->userinfo)
254
 
            g_mount_spec_set (spec, "user", decoded->userinfo);
255
 
          
256
 
          if (decoded->port != -1 &&
257
 
              (mountable == NULL ||
258
 
               mountable->default_port == 0 ||
259
 
               mountable->default_port != decoded->port))
260
 
            {
261
 
              char *port = g_strdup_printf ("%d", decoded->port);
262
 
              g_mount_spec_set (spec, "port", port);
263
 
              g_free (port);
264
 
            }
265
 
 
266
 
          if (decoded->query && *decoded->query)
267
 
            g_mount_spec_set (spec, "query", decoded->query);
268
 
          if (decoded->fragment && *decoded->fragment)
269
 
            g_mount_spec_set (spec, "fragment", decoded->fragment);
270
 
          
271
 
          path = g_strdup (decoded->path);
272
 
          
273
 
          g_vfs_decoded_uri_free (decoded);
274
 
        }
275
 
    }
276
 
  
277
 
  g_free (scheme);
278
 
  
279
 
  if (spec == NULL)
280
 
    return FALSE;
281
 
 
282
 
  *spec_out = spec;
283
 
  *path_out = path;
284
 
  
285
 
  return TRUE;
286
 
}
287
 
 
288
 
static void
289
 
g_daemon_vfs_init (GDaemonVfs *vfs)
290
 
{
291
 
  GType *mappers;
292
 
  guint n_mappers;
293
 
  const char * const *schemes, * const *mount_types;
294
 
  GVfsUriMapper *mapper;
295
 
  GList *modules;
296
 
  char *file;
297
 
  int i;
298
 
 
299
 
  bindtextdomain (GETTEXT_PACKAGE, GVFS_LOCALEDIR);
300
 
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
301
 
  
302
 
  if (g_thread_supported ())
303
 
    dbus_threads_init_default ();
304
 
 
305
 
  vfs->async_bus = dbus_bus_get_private (DBUS_BUS_SESSION, NULL);
306
 
 
307
 
  if (vfs->async_bus == NULL)
308
 
    return; /* Not supported, return here and return false in vfs_is_active() */
309
 
 
310
 
  g_assert (the_vfs == NULL);
311
 
  the_vfs = vfs;
312
 
 
313
 
  /* We disable SIGPIPE globally. This is sort of bad
314
 
     for s library to do since its a global resource.
315
 
     However, without this there is no way to be able
316
 
     to handle mount daemons dying without client apps
317
 
     crashing, which is much worse.
318
 
 
319
 
     I blame Unix, there really should be a portable
320
 
     way to do this on all unixes, but there isn't,
321
 
     even for somewhat modern ones like solaris.
322
 
  */
323
 
  signal (SIGPIPE, SIG_IGN);
324
 
 
325
 
  fill_mountable_info (vfs);
326
 
  
327
 
  vfs->wrapped_vfs = g_vfs_get_local ();
328
 
 
329
 
  file = g_build_filename (g_get_home_dir(), ".gvfs", NULL);
330
 
  vfs->fuse_root = g_vfs_get_file_for_path (vfs->wrapped_vfs, file);
331
 
  g_free (file);
332
 
  
333
 
  dbus_connection_set_exit_on_disconnect (vfs->async_bus, FALSE);
334
 
 
335
 
  _g_dbus_connection_integrate_with_main (vfs->async_bus);
336
 
 
337
 
  modules = g_io_modules_load_all_in_directory (GVFS_MODULE_DIR);
338
 
 
339
 
  vfs->from_uri_hash = g_hash_table_new (g_str_hash, g_str_equal);
340
 
  vfs->to_uri_hash = g_hash_table_new (g_str_hash, g_str_equal);
341
 
  
342
 
  mappers = g_type_children (G_VFS_TYPE_URI_MAPPER, &n_mappers);
343
 
 
344
 
  for (i = 0; i < n_mappers; i++)
345
 
    {
346
 
      int j;
347
 
      mapper = g_object_new (mappers[i], NULL);
348
 
 
349
 
      schemes = g_vfs_uri_mapper_get_handled_schemes (mapper);
350
 
 
351
 
      for (j = 0; schemes != NULL && schemes[j] != NULL; j++)
352
 
        g_hash_table_insert (vfs->from_uri_hash, (char *)schemes[j], mapper);
353
 
      
354
 
      mount_types = g_vfs_uri_mapper_get_handled_mount_types (mapper);
355
 
      for (j = 0; mount_types != NULL && mount_types[j] != NULL; j++)
356
 
        g_hash_table_insert (vfs->to_uri_hash, (char *)mount_types[j], mapper);
357
 
    }
358
 
 
359
 
  /* The above should have ref:ed the modules anyway */
360
 
  g_list_foreach (modules, (GFunc)g_type_module_unuse, NULL);
361
 
  g_list_free (modules);
362
 
  g_free (mappers);
363
 
}
364
 
 
365
 
GDaemonVfs *
366
 
g_daemon_vfs_new (void)
367
 
{
368
 
  return g_object_new (G_TYPE_DAEMON_VFS, NULL);
369
 
}
370
 
 
371
 
/* This unrefs file if its changed */
372
 
static GFile *
373
 
convert_fuse_path (GVfs     *vfs,
374
 
                   GFile    *file)
375
 
{
376
 
  GFile *fuse_root;
377
 
  char *fuse_path, *mount_path;
378
 
  GMountInfo *mount_info;
379
 
 
380
 
  fuse_root = ((GDaemonVfs *)vfs)->fuse_root;
381
 
  if (g_file_has_prefix (file, fuse_root))
382
 
    {
383
 
      fuse_path = g_file_get_path (file);
384
 
      mount_info = _g_daemon_vfs_get_mount_info_by_fuse_sync (fuse_path, &mount_path);
385
 
      g_free (fuse_path);
386
 
      if (mount_info)
387
 
        {
388
 
          g_object_unref (file);
389
 
          file = g_daemon_file_new (mount_info->mount_spec, mount_path);
390
 
          g_free (mount_path);
391
 
          g_mount_info_unref (mount_info);
392
 
        }
393
 
    }
394
 
  return file;
395
 
}
396
 
 
397
 
static GFile *
398
 
g_daemon_vfs_get_file_for_path (GVfs       *vfs,
399
 
                                const char *path)
400
 
{
401
 
  GFile *file;
402
 
  
403
 
  file = g_vfs_get_file_for_path (G_DAEMON_VFS (vfs)->wrapped_vfs, path);
404
 
  file = convert_fuse_path (vfs, file);
405
 
  return file;
406
 
}
407
 
 
408
 
static GFile *
409
 
g_daemon_vfs_get_file_for_uri (GVfs       *vfs,
410
 
                               const char *uri)
411
 
{
412
 
  GDaemonVfs *daemon_vfs;
413
 
  GFile *file;
414
 
  GMountSpec *spec;
415
 
  char *path;
416
 
 
417
 
  daemon_vfs = G_DAEMON_VFS (vfs);
418
 
 
419
 
  if (g_ascii_strncasecmp (uri, "file:", 5) == 0)
420
 
    {
421
 
      path = g_filename_from_uri (uri, NULL, NULL);
422
 
 
423
 
      if (path == NULL)
424
 
        /* Dummy file */
425
 
        return g_vfs_get_file_for_uri (G_DAEMON_VFS (vfs)->wrapped_vfs, uri);
426
 
      
427
 
      file = g_daemon_vfs_get_file_for_path (vfs, path);
428
 
      g_free (path);
429
 
      return file;
430
 
    }
431
 
  
432
 
  if (get_mountspec_from_uri (daemon_vfs, uri, &spec, &path))
433
 
    {
434
 
      file = g_daemon_file_new (spec, path);
435
 
      g_mount_spec_unref (spec);
436
 
      g_free (path);
437
 
      return file;
438
 
    }
439
 
 
440
 
  /* Dummy file */
441
 
  return g_vfs_get_file_for_uri (G_DAEMON_VFS (vfs)->wrapped_vfs, uri);
442
 
}
443
 
 
444
 
GMountSpec *
445
 
_g_daemon_vfs_get_mount_spec_for_path (GMountSpec *spec,
446
 
                                       const char *path,
447
 
                                       const char *new_path)
448
 
{
449
 
  const char *type;
450
 
  GVfsUriMapper *mapper;
451
 
  GMountSpec *new_spec;
452
 
 
453
 
  type = g_mount_spec_get_type (spec);
454
 
 
455
 
  if (type == NULL)
456
 
    return g_mount_spec_ref (spec);
457
 
  
458
 
  new_spec = NULL;
459
 
  mapper = g_hash_table_lookup (the_vfs->to_uri_hash, type);
460
 
  if (mapper)
461
 
    {
462
 
      GVfsUriMountInfo info, *new_info;
463
 
      info.keys = spec->items;
464
 
      info.path = (char *)path;
465
 
      new_info = g_vfs_uri_mapper_get_mount_info_for_path (mapper, &info, new_path);
466
 
      if (new_info != NULL)
467
 
        {
468
 
          new_spec = g_mount_spec_new_from_data (new_info->keys, NULL);
469
 
          /* We took over ownership of parts of new_info, custom free: */
470
 
          g_free (new_info->path);
471
 
          g_free (new_info);
472
 
        }
473
 
    }
474
 
 
475
 
  if (new_spec == NULL)
476
 
    new_spec = g_mount_spec_ref (spec);
477
 
 
478
 
  return new_spec;
479
 
}
480
 
 
481
 
char *
482
 
_g_daemon_vfs_get_uri_for_mountspec (GMountSpec *spec,
483
 
                                     char *path,
484
 
                                     gboolean allow_utf8)
485
 
{
486
 
  char *uri;
487
 
  const char *type;
488
 
  GVfsUriMapper *mapper;
489
 
 
490
 
  type = g_mount_spec_get_type (spec);
491
 
  if (type == NULL)
492
 
    {
493
 
      GString *string = g_string_new ("unknown://");
494
 
      if (path)
495
 
        g_string_append_uri_escaped (string,
496
 
                                     path,
497
 
                                     "!$&'()*+,;=:@/",
498
 
                                     allow_utf8);
499
 
      
500
 
      return g_string_free (string, FALSE);
501
 
    }
502
 
 
503
 
  uri = NULL;
504
 
  mapper = g_hash_table_lookup (the_vfs->to_uri_hash, type);
505
 
  if (mapper)
506
 
    {
507
 
      GVfsUriMountInfo info;
508
 
      info.keys = spec->items;
509
 
      info.path = path;
510
 
      uri = g_vfs_uri_mapper_to_uri (mapper, &info, allow_utf8);
511
 
    }
512
 
 
513
 
  if (uri == NULL)
514
 
    {
515
 
      GDecodedUri decoded;
516
 
      MountableInfo *mountable;
517
 
      const char *port;
518
 
      gboolean free_host;
519
 
 
520
 
      memset (&decoded, 0, sizeof (decoded));
521
 
      decoded.port = -1;
522
 
 
523
 
      mountable = get_mountable_info_for_type (the_vfs, type);
524
 
 
525
 
      if (mountable)
526
 
        decoded.scheme = mountable->scheme;
527
 
      else
528
 
        decoded.scheme = (char *)type;
529
 
      decoded.host = (char *)g_mount_spec_get (spec, "host");
530
 
      free_host = FALSE;
531
 
      if (mountable && mountable->host_is_inet && decoded.host != NULL && strchr (decoded.host, ':') != NULL)
532
 
        {
533
 
          free_host = TRUE;
534
 
          decoded.host = g_strconcat ("[", decoded.host, "]", NULL);
535
 
        }
536
 
      
537
 
      decoded.userinfo = (char *)g_mount_spec_get (spec, "user");
538
 
      port = g_mount_spec_get (spec, "port");
539
 
      if (port != NULL)
540
 
        decoded.port = atoi (port);
541
 
      
542
 
      if (path == NULL)
543
 
        decoded.path = "/";
544
 
      else
545
 
        decoded.path = path;
546
 
 
547
 
      decoded.query = (char *)g_mount_spec_get (spec, "query");
548
 
      decoded.fragment = (char *)g_mount_spec_get (spec, "fragment");
549
 
      
550
 
      uri = g_vfs_encode_uri (&decoded, FALSE);
551
 
      
552
 
      if (free_host)
553
 
        g_free (decoded.host);
554
 
    }
555
 
  
556
 
  return uri;
557
 
}
558
 
 
559
 
const char *
560
 
_g_daemon_vfs_mountspec_get_uri_scheme (GMountSpec *spec)
561
 
{
562
 
  const char *type, *scheme;
563
 
  GVfsUriMapper *mapper;
564
 
  MountableInfo *mountable;
565
 
 
566
 
  type = g_mount_spec_get_type (spec);
567
 
  mapper = g_hash_table_lookup (the_vfs->to_uri_hash, type);
568
 
 
569
 
  scheme = NULL;
570
 
  if (mapper)
571
 
    {
572
 
      GVfsUriMountInfo info;
573
 
      
574
 
      info.keys = spec->items;
575
 
      info.path = "/";
576
 
      
577
 
      scheme = g_vfs_uri_mapper_to_uri_scheme (mapper, &info);
578
 
    }
579
 
  
580
 
  if (scheme == NULL)
581
 
    {
582
 
      mountable = get_mountable_info_for_type (the_vfs, type);
583
 
      if (mountable)
584
 
        scheme = mountable->scheme;
585
 
      else
586
 
        scheme = type;
587
 
    }
588
 
  
589
 
  return scheme;
590
 
}
591
 
 
592
 
static int
593
 
find_string (GPtrArray *array, const char *find_me)
594
 
{
595
 
  int i;
596
 
  
597
 
  g_return_val_if_fail (find_me != NULL, -1);
598
 
  
599
 
  for (i = 0; i < array->len; ++i)
600
 
    {
601
 
      if (strcmp (g_ptr_array_index (array, i), find_me) == 0)
602
 
        return i;
603
 
    }
604
 
  
605
 
  return -1;
606
 
}
607
 
 
608
 
 
609
 
static void
610
 
fill_mountable_info (GDaemonVfs *vfs)
611
 
{
612
 
  DBusMessage *message, *reply;
613
 
  DBusError error;
614
 
  DBusMessageIter iter, array_iter, struct_iter;
615
 
  MountableInfo *info;
616
 
  GPtrArray *infos, *uri_schemes;
617
 
  gint i;
618
 
 
619
 
  message = dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
620
 
                                          G_VFS_DBUS_MOUNTTRACKER_PATH,
621
 
                                          G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
622
 
                                          G_VFS_DBUS_MOUNTTRACKER_OP_LIST_MOUNTABLE_INFO);
623
 
 
624
 
  if (message == NULL)
625
 
    _g_dbus_oom ();
626
 
  
627
 
  dbus_message_set_auto_start (message, TRUE);
628
 
  
629
 
  dbus_error_init (&error);
630
 
  reply = dbus_connection_send_with_reply_and_block (vfs->async_bus,
631
 
                                                     message,
632
 
                                                     G_VFS_DBUS_TIMEOUT_MSECS,
633
 
                                                     &error);
634
 
  dbus_message_unref (message);
635
 
  
636
 
  if (dbus_error_is_set (&error))
637
 
    {
638
 
      dbus_error_free (&error);
639
 
      return;
640
 
    }
641
 
  
642
 
  if (reply == NULL)
643
 
    _g_dbus_oom ();
644
 
 
645
 
  dbus_message_iter_init (reply, &iter);
646
 
 
647
 
  dbus_message_iter_recurse (&iter, &array_iter);
648
 
 
649
 
  infos = g_ptr_array_new ();
650
 
  uri_schemes = g_ptr_array_new ();
651
 
  g_ptr_array_add (uri_schemes, g_strdup ("file"));
652
 
  do
653
 
    {
654
 
      char *type, *scheme, **scheme_aliases;
655
 
      int scheme_aliases_len;
656
 
      gint32 default_port;
657
 
      dbus_bool_t host_is_inet;
658
 
      
659
 
      if (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_STRUCT)
660
 
        break;
661
 
      
662
 
      dbus_message_iter_recurse (&array_iter, &struct_iter);
663
 
      
664
 
      if (!_g_dbus_message_iter_get_args (&struct_iter, NULL,
665
 
                                          DBUS_TYPE_STRING, &type,
666
 
                                          DBUS_TYPE_STRING, &scheme,
667
 
                                          DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &scheme_aliases, &scheme_aliases_len,
668
 
                                          DBUS_TYPE_INT32, &default_port,
669
 
                                          DBUS_TYPE_BOOLEAN, &host_is_inet,
670
 
                                          0))
671
 
        break;
672
 
 
673
 
      info = g_new0 (MountableInfo, 1);
674
 
      info->type = g_strdup (type);
675
 
      if (*scheme != 0)
676
 
        {
677
 
          info->scheme = g_strdup (scheme);
678
 
          if (find_string (uri_schemes, scheme) == -1)
679
 
            g_ptr_array_add (uri_schemes, g_strdup (scheme));
680
 
        }
681
 
      
682
 
      if (scheme_aliases_len > 0)
683
 
        {
684
 
          info->scheme_aliases = g_new (char *, scheme_aliases_len + 1);
685
 
          for (i = 0; i < scheme_aliases_len; i++)
686
 
            {
687
 
              info->scheme_aliases[i] = g_strdup (scheme_aliases[i]);
688
 
              if (find_string (uri_schemes, scheme_aliases[i]) == -1)
689
 
                g_ptr_array_add (uri_schemes, g_strdup (scheme_aliases[i]));
690
 
            }
691
 
          info->scheme_aliases[scheme_aliases_len] = NULL;
692
 
        }
693
 
        
694
 
      info->default_port = default_port;
695
 
      info->host_is_inet = host_is_inet;
696
 
      
697
 
      g_ptr_array_add (infos, info);
698
 
 
699
 
      g_strfreev (scheme_aliases);
700
 
    }
701
 
  while (dbus_message_iter_next (&array_iter));
702
 
 
703
 
  dbus_message_unref (reply);
704
 
 
705
 
  g_ptr_array_add (uri_schemes, NULL);
706
 
  g_ptr_array_add (infos, NULL);
707
 
  vfs->mountable_info = (MountableInfo **)g_ptr_array_free (infos, FALSE);
708
 
  vfs->supported_uri_schemes = (char **)g_ptr_array_free (uri_schemes, FALSE);
709
 
}
710
 
 
711
 
 
712
 
static const gchar * const *
713
 
g_daemon_vfs_get_supported_uri_schemes (GVfs *vfs)
714
 
{
715
 
  return (const gchar * const *) G_DAEMON_VFS (vfs)->supported_uri_schemes;
716
 
}
717
 
 
718
 
static GMountInfo *
719
 
lookup_mount_info_in_cache_locked (GMountSpec *spec,
720
 
                                   const char *path)
721
 
{
722
 
  GMountInfo *info;
723
 
  GList *l;
724
 
 
725
 
  info = NULL;
726
 
  for (l = the_vfs->mount_cache; l != NULL; l = l->next)
727
 
    {
728
 
      GMountInfo *mount_info = l->data;
729
 
 
730
 
      if (g_mount_spec_match_with_path (mount_info->mount_spec, spec, path))
731
 
        {
732
 
          info = g_mount_info_ref (mount_info);
733
 
          break;
734
 
        }
735
 
    }
736
 
  
737
 
  return info;
738
 
}
739
 
 
740
 
static GMountInfo *
741
 
lookup_mount_info_in_cache (GMountSpec *spec,
742
 
                           const char *path)
743
 
{
744
 
  GMountInfo *info;
745
 
 
746
 
  G_LOCK (mount_cache);
747
 
  info = lookup_mount_info_in_cache_locked (spec, path);
748
 
  G_UNLOCK (mount_cache);
749
 
 
750
 
  return info;
751
 
}
752
 
 
753
 
static GMountInfo *
754
 
lookup_mount_info_by_fuse_path_in_cache (const char *fuse_path,
755
 
                                         char **mount_path)
756
 
{
757
 
  GMountInfo *info;
758
 
  GList *l;
759
 
 
760
 
  G_LOCK (mount_cache);
761
 
  info = NULL;
762
 
  for (l = the_vfs->mount_cache; l != NULL; l = l->next)
763
 
    {
764
 
      GMountInfo *mount_info = l->data;
765
 
 
766
 
      if (mount_info->fuse_mountpoint != NULL &&
767
 
          g_str_has_prefix (fuse_path, mount_info->fuse_mountpoint))
768
 
        {
769
 
          int len = strlen (mount_info->fuse_mountpoint);
770
 
          if (fuse_path[len] == 0 ||
771
 
              fuse_path[len] == '/')
772
 
            {
773
 
              if (fuse_path[len] == 0)
774
 
                *mount_path = g_strdup ("/");
775
 
              else
776
 
                *mount_path = g_strdup (fuse_path + len);
777
 
              info = g_mount_info_ref (mount_info);
778
 
              break;
779
 
            }
780
 
        }
781
 
    }
782
 
  G_UNLOCK (mount_cache);
783
 
 
784
 
  return info;
785
 
}
786
 
 
787
 
 
788
 
void
789
 
_g_daemon_vfs_invalidate_dbus_id (const char *dbus_id)
790
 
{
791
 
  GList *l, *next;
792
 
 
793
 
  G_LOCK (mount_cache);
794
 
  for (l = the_vfs->mount_cache; l != NULL; l = next)
795
 
    {
796
 
      GMountInfo *mount_info = l->data;
797
 
      next = l->next;
798
 
 
799
 
      if (strcmp (mount_info->dbus_id, dbus_id) == 0)
800
 
        {
801
 
          the_vfs->mount_cache = g_list_delete_link (the_vfs->mount_cache, l);
802
 
          g_mount_info_unref (mount_info);
803
 
        }
804
 
    }
805
 
  
806
 
  G_UNLOCK (mount_cache);
807
 
}
808
 
 
809
 
 
810
 
static GMountInfo *
811
 
handler_lookup_mount_reply (DBusMessage *reply,
812
 
                            GError **error)
813
 
{
814
 
  DBusError derror;
815
 
  GMountInfo *info;
816
 
  DBusMessageIter iter;
817
 
  GList *l;
818
 
  gboolean in_cache;
819
 
  
820
 
 
821
 
  if (_g_error_from_message (reply, error))
822
 
    return NULL;
823
 
 
824
 
  dbus_error_init (&derror);
825
 
  dbus_message_iter_init (reply, &iter);
826
 
 
827
 
  info = g_mount_info_from_dbus (&iter);
828
 
  if (info == NULL)
829
 
    {
830
 
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
831
 
                   _("Error while getting mount info: %s"),
832
 
                   "Invalid reply");
833
 
      return NULL;
834
 
    }
835
 
 
836
 
  G_LOCK (mount_cache);
837
 
 
838
 
  in_cache = FALSE;
839
 
  /* Already in cache from other thread? */
840
 
  for (l = the_vfs->mount_cache; l != NULL; l = l->next)
841
 
    {
842
 
      GMountInfo *cached_info = l->data;
843
 
      
844
 
      if (g_mount_info_equal (info, cached_info))
845
 
        {
846
 
          in_cache = TRUE;
847
 
          g_mount_info_unref (info);
848
 
          info = g_mount_info_ref (cached_info);
849
 
          break;
850
 
        }
851
 
    }
852
 
 
853
 
  /* No, lets add it to the cache */
854
 
  if (!in_cache)
855
 
    the_vfs->mount_cache = g_list_prepend (the_vfs->mount_cache, g_mount_info_ref (info));
856
 
 
857
 
  G_UNLOCK (mount_cache);
858
 
  
859
 
  return info;
860
 
}
861
 
 
862
 
typedef struct {
863
 
  GMountInfoLookupCallback callback;
864
 
  gpointer user_data;
865
 
  GMountInfo *info;
866
 
} GetMountInfoData;
867
 
 
868
 
static void
869
 
async_get_mount_info_response (DBusMessage *reply,
870
 
                               GError *io_error,
871
 
                               void *_data)
872
 
{
873
 
  GetMountInfoData *data = _data;
874
 
  GMountInfo *info;
875
 
  GError *error;
876
 
 
877
 
  if (reply == NULL)
878
 
    data->callback (NULL, data->user_data, io_error);
879
 
  else
880
 
    {
881
 
      error = NULL;
882
 
      info = handler_lookup_mount_reply (reply, &error);
883
 
 
884
 
      data->callback (info, data->user_data, error);
885
 
 
886
 
      if (info)
887
 
        g_mount_info_unref (info);
888
 
 
889
 
      if (error)
890
 
        g_error_free (error);
891
 
    }
892
 
  
893
 
  g_free (data);
894
 
}
895
 
 
896
 
static gboolean
897
 
async_get_mount_info_cache_hit (gpointer _data)
898
 
{
899
 
  GetMountInfoData *data = _data;
900
 
  data->callback (data->info, data->user_data, NULL);
901
 
  g_mount_info_unref (data->info);
902
 
  g_free (data);
903
 
  return FALSE;
904
 
}
905
 
 
906
 
void
907
 
_g_daemon_vfs_get_mount_info_async (GMountSpec *spec,
908
 
                                    const char *path,
909
 
                                    GMountInfoLookupCallback callback,
910
 
                                    gpointer user_data)
911
 
{
912
 
  GMountInfo *info;
913
 
  GetMountInfoData *data;
914
 
  DBusMessage *message;
915
 
  DBusMessageIter iter;
916
 
 
917
 
  data = g_new0 (GetMountInfoData, 1);
918
 
  data->callback = callback;
919
 
  data->user_data = user_data;
920
 
 
921
 
  info = lookup_mount_info_in_cache (spec, path);
922
 
 
923
 
  if (info != NULL)
924
 
    {
925
 
      data->info = info;
926
 
      g_idle_add (async_get_mount_info_cache_hit, data);
927
 
      return;
928
 
    }
929
 
 
930
 
  message =
931
 
    dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
932
 
                                  G_VFS_DBUS_MOUNTTRACKER_PATH,
933
 
                                  G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
934
 
                                  G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT);
935
 
  dbus_message_set_auto_start (message, TRUE);
936
 
  
937
 
  dbus_message_iter_init_append (message, &iter);
938
 
  g_mount_spec_to_dbus_with_path (&iter, spec, path);
939
 
 
940
 
  
941
 
  _g_dbus_connection_call_async (the_vfs->async_bus, message, G_VFS_DBUS_TIMEOUT_MSECS,
942
 
                                 async_get_mount_info_response,
943
 
                                 data);
944
 
  
945
 
  dbus_message_unref (message);
946
 
}
947
 
 
948
 
 
949
 
GMountInfo *
950
 
_g_daemon_vfs_get_mount_info_sync (GMountSpec *spec,
951
 
                                   const char *path,
952
 
                                   GError **error)
953
 
{
954
 
  GMountInfo *info;
955
 
  DBusConnection *conn;
956
 
  DBusMessage *message, *reply;
957
 
  DBusMessageIter iter;
958
 
  DBusError derror;
959
 
        
960
 
  info = lookup_mount_info_in_cache (spec, path);
961
 
 
962
 
  if (info != NULL)
963
 
    return info;
964
 
  
965
 
  conn = _g_dbus_connection_get_sync (NULL, error);
966
 
  if (conn == NULL)
967
 
    return NULL;
968
 
 
969
 
  message =
970
 
    dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
971
 
                                  G_VFS_DBUS_MOUNTTRACKER_PATH,
972
 
                                  G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
973
 
                                  G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT);
974
 
  dbus_message_set_auto_start (message, TRUE);
975
 
  
976
 
  dbus_message_iter_init_append (message, &iter);
977
 
  g_mount_spec_to_dbus_with_path (&iter, spec, path);
978
 
 
979
 
  dbus_error_init (&derror);
980
 
  reply = dbus_connection_send_with_reply_and_block (conn, message, -1, &derror);
981
 
  dbus_message_unref (message);
982
 
 
983
 
  if (!reply)
984
 
    {
985
 
      _g_error_from_dbus (&derror, error);
986
 
      dbus_error_free (&derror);
987
 
      return NULL;
988
 
    }
989
 
 
990
 
  info = handler_lookup_mount_reply (reply, error);
991
 
 
992
 
  dbus_message_unref (reply);
993
 
  
994
 
  return info;
995
 
}
996
 
 
997
 
GMountInfo *
998
 
_g_daemon_vfs_get_mount_info_by_fuse_sync (const char *fuse_path,
999
 
                                           char **mount_path)
1000
 
{
1001
 
  GMountInfo *info;
1002
 
  DBusConnection *conn;
1003
 
  DBusMessage *message, *reply;
1004
 
  DBusMessageIter iter;
1005
 
  DBusError derror;
1006
 
  int len;
1007
 
  const char *mount_path_end;
1008
 
        
1009
 
  info = lookup_mount_info_by_fuse_path_in_cache (fuse_path,
1010
 
                                                  mount_path);
1011
 
  if (info != NULL)
1012
 
    return info;
1013
 
  
1014
 
  conn = _g_dbus_connection_get_sync (NULL, NULL);
1015
 
  if (conn == NULL)
1016
 
    return NULL;
1017
 
 
1018
 
  message =
1019
 
    dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME,
1020
 
                                  G_VFS_DBUS_MOUNTTRACKER_PATH,
1021
 
                                  G_VFS_DBUS_MOUNTTRACKER_INTERFACE,
1022
 
                                  G_VFS_DBUS_MOUNTTRACKER_OP_LOOKUP_MOUNT_BY_FUSE_PATH);
1023
 
  dbus_message_set_auto_start (message, TRUE);
1024
 
  
1025
 
  dbus_message_iter_init_append (message, &iter);
1026
 
  _g_dbus_message_iter_append_cstring (&iter, fuse_path);
1027
 
 
1028
 
  dbus_error_init (&derror);
1029
 
  reply = dbus_connection_send_with_reply_and_block (conn, message, -1, &derror);
1030
 
  dbus_message_unref (message);
1031
 
  if (!reply)
1032
 
    {
1033
 
      dbus_error_free (&derror);
1034
 
      return NULL;
1035
 
    }
1036
 
 
1037
 
  info = handler_lookup_mount_reply (reply, NULL);
1038
 
  dbus_message_unref (reply);
1039
 
  
1040
 
  if (info)
1041
 
    {
1042
 
      if (info->fuse_mountpoint)
1043
 
        {
1044
 
          len = strlen (info->fuse_mountpoint);
1045
 
          if (fuse_path[len] == 0)
1046
 
            mount_path_end = "/";
1047
 
          else
1048
 
            mount_path_end = fuse_path + len;
1049
 
 
1050
 
          *mount_path = g_build_filename (info->mount_spec->mount_prefix,
1051
 
                                          mount_path_end, NULL);
1052
 
        }
1053
 
      else
1054
 
        {
1055
 
          /* This could happen if we race with the gvfs fuse mount
1056
 
           * at startup of gvfsd... */
1057
 
          g_mount_info_unref (info);
1058
 
          info = NULL;
1059
 
        }
1060
 
    }
1061
 
 
1062
 
  
1063
 
  return info;
1064
 
}
1065
 
 
1066
 
static GFile *
1067
 
g_daemon_vfs_parse_name (GVfs       *vfs,
1068
 
                         const char *parse_name)
1069
 
{
1070
 
  GFile *file;
1071
 
  
1072
 
  if (g_path_is_absolute (parse_name) ||
1073
 
      *parse_name == '~')
1074
 
    {
1075
 
      file = g_vfs_parse_name (G_DAEMON_VFS (vfs)->wrapped_vfs, parse_name);
1076
 
      file = convert_fuse_path (vfs, file);
1077
 
    }
1078
 
  else
1079
 
    {
1080
 
      file = g_daemon_vfs_get_file_for_uri (vfs, parse_name);
1081
 
    }
1082
 
 
1083
 
  return file;
1084
 
}
1085
 
 
1086
 
static gboolean
1087
 
enumerate_keys_callback (const char *key,
1088
 
                         MetaKeyType type,
1089
 
                         gpointer value,
1090
 
                         gpointer user_data)
1091
 
{
1092
 
  GFileInfo  *info = user_data;
1093
 
  char *attr;
1094
 
 
1095
 
  attr = g_strconcat ("metadata::", key, NULL);
1096
 
 
1097
 
  if (type == META_KEY_TYPE_STRING)
1098
 
    g_file_info_set_attribute_string (info, attr, (char *)value);
1099
 
  else
1100
 
    g_file_info_set_attribute_stringv (info, attr, (char **)value);
1101
 
 
1102
 
  g_free (attr);
1103
 
 
1104
 
  return TRUE;
1105
 
}
1106
 
 
1107
 
static void
1108
 
g_daemon_vfs_local_file_add_info (GVfs       *vfs,
1109
 
                                  const char *filename,
1110
 
                                  guint64     device,
1111
 
                                  GFileAttributeMatcher *matcher,
1112
 
                                  GFileInfo  *info,
1113
 
                                  GCancellable *cancellable,
1114
 
                                  gpointer    *extra_data,
1115
 
                                  GDestroyNotify *extra_data_free)
1116
 
{
1117
 
  MetaLookupCache *cache;
1118
 
  const char *first;
1119
 
  char *tree_path;
1120
 
  gboolean all;
1121
 
  MetaTree *tree;
1122
 
 
1123
 
  /* Filename may or may not be a symlink, but we should not follow it.
1124
 
     However, we want to follow symlinks for all parents that have the same
1125
 
     device node */
1126
 
  all = g_file_attribute_matcher_enumerate_namespace (matcher, "metadata");
1127
 
 
1128
 
  first = NULL;
1129
 
  if (!all)
1130
 
    {
1131
 
      first = g_file_attribute_matcher_enumerate_next (matcher);
1132
 
 
1133
 
      if (first == NULL)
1134
 
        return; /* No match */
1135
 
    }
1136
 
 
1137
 
  if (*extra_data == NULL)
1138
 
    {
1139
 
      *extra_data = meta_lookup_cache_new ();
1140
 
      *extra_data_free = (GDestroyNotify)meta_lookup_cache_free;
1141
 
    }
1142
 
  cache = (MetaLookupCache *)*extra_data;
1143
 
 
1144
 
  tree = meta_lookup_cache_lookup_path (cache,
1145
 
                                        filename,
1146
 
                                        device,
1147
 
                                        FALSE,
1148
 
                                        &tree_path);
1149
 
 
1150
 
  if (tree)
1151
 
    {
1152
 
      meta_tree_enumerate_keys (tree, tree_path,
1153
 
                                enumerate_keys_callback, info);
1154
 
      meta_tree_unref (tree);
1155
 
      g_free (tree_path);
1156
 
    }
1157
 
}
1158
 
 
1159
 
static void
1160
 
g_daemon_vfs_add_writable_namespaces (GVfs       *vfs,
1161
 
                                      GFileAttributeInfoList *list)
1162
 
{
1163
 
  g_file_attribute_info_list_add (list,
1164
 
                                  "metadata",
1165
 
                                  G_FILE_ATTRIBUTE_TYPE_STRING, /* Also STRINGV, but no way express this ... */
1166
 
                                  G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
1167
 
                                  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
1168
 
}
1169
 
 
1170
 
static void
1171
 
send_message_oneway (DBusMessage *message)
1172
 
{
1173
 
  DBusConnection *connection;
1174
 
 
1175
 
  connection = _g_dbus_connection_get_sync (NULL, NULL);
1176
 
  if (connection == NULL)
1177
 
    return;
1178
 
 
1179
 
  dbus_connection_send (connection, message, NULL);
1180
 
  dbus_connection_flush (connection);
1181
 
}
1182
 
 
1183
 
/* Sends a message on the session bus and blocks for the reply,
1184
 
   using the thread local connection */
1185
 
gboolean
1186
 
_g_daemon_vfs_send_message_sync (DBusMessage *message,
1187
 
                                 GCancellable *cancellable,
1188
 
                                 GError **error)
1189
 
{
1190
 
  DBusConnection *connection;
1191
 
  DBusError derror;
1192
 
  DBusMessage *reply;
1193
 
 
1194
 
  connection = _g_dbus_connection_get_sync (NULL, NULL);
1195
 
  if (connection == NULL)
1196
 
    {
1197
 
      g_set_error (error, G_IO_ERROR,
1198
 
                   G_IO_ERROR_FAILED,
1199
 
                   _("Error setting file metadata: %s"),
1200
 
                   _("Can't contact session bus"));
1201
 
      return FALSE;
1202
 
    }
1203
 
 
1204
 
  dbus_error_init (&derror);
1205
 
  /* TODO: Handle cancellable */
1206
 
  reply = dbus_connection_send_with_reply_and_block (connection, message,
1207
 
                                                     G_VFS_DBUS_TIMEOUT_MSECS,
1208
 
                                                     &derror);
1209
 
  if (!reply)
1210
 
    {
1211
 
      _g_error_from_dbus (&derror, error);
1212
 
      dbus_error_free (&derror);
1213
 
      return FALSE;
1214
 
    }
1215
 
 
1216
 
  dbus_message_unref (reply);
1217
 
 
1218
 
  return TRUE;
1219
 
}
1220
 
 
1221
 
static gboolean
1222
 
strv_equal (char **a, char **b)
1223
 
{
1224
 
  int i;
1225
 
 
1226
 
  if (g_strv_length (a) != g_strv_length (b))
1227
 
    return FALSE;
1228
 
 
1229
 
  for (i = 0; a[i] != NULL; i++)
1230
 
    {
1231
 
      if (strcmp (a[i], b[i]) != 0)
1232
 
        return FALSE;
1233
 
    }
1234
 
  return TRUE;
1235
 
}
1236
 
 
1237
 
/* -1 => error, otherwise number of added items */
1238
 
int
1239
 
_g_daemon_vfs_append_metadata_for_set (DBusMessage *message,
1240
 
                                       MetaTree *tree,
1241
 
                                       const char *path,
1242
 
                                       const char *attribute,
1243
 
                                       GFileAttributeType type,
1244
 
                                       gpointer   value)
1245
 
{
1246
 
  const char *key;
1247
 
  int res;
1248
 
 
1249
 
  key = attribute + strlen ("metadata::");
1250
 
 
1251
 
  res = 0;
1252
 
  if (type == G_FILE_ATTRIBUTE_TYPE_STRING)
1253
 
    {
1254
 
      char *current;
1255
 
      const char *val = (char *)value;
1256
 
 
1257
 
      current = meta_tree_lookup_string (tree, path, key);
1258
 
      if (current == NULL || strcmp (current, val) != 0)
1259
 
        {
1260
 
          res = 1;
1261
 
          _g_dbus_message_append_args (message,
1262
 
                                       DBUS_TYPE_STRING, &key,
1263
 
                                       DBUS_TYPE_STRING, &val,
1264
 
                                       0);
1265
 
        }
1266
 
      g_free (current);
1267
 
    }
1268
 
  else if (type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
1269
 
    {
1270
 
      char **current;
1271
 
      char **val = (char **)value;
1272
 
      current = meta_tree_lookup_stringv (tree, path, key);
1273
 
      if (current == NULL || !strv_equal (current, val))
1274
 
        {
1275
 
          res = 1;
1276
 
          _g_dbus_message_append_args (message,
1277
 
                                       DBUS_TYPE_STRING, &key,
1278
 
                                       DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &val, g_strv_length (val),
1279
 
                                       0);
1280
 
        }
1281
 
      g_strfreev (current);
1282
 
    }
1283
 
  else if (type == G_FILE_ATTRIBUTE_TYPE_INVALID)
1284
 
    {
1285
 
      if (meta_tree_lookup_key_type (tree, path, key) != META_KEY_TYPE_NONE)
1286
 
        {
1287
 
          char c = 0;
1288
 
          res = 1;
1289
 
          /* Byte => unset */
1290
 
          _g_dbus_message_append_args (message,
1291
 
                                       DBUS_TYPE_STRING, &key,
1292
 
                                       DBUS_TYPE_BYTE, &c,
1293
 
                                       0);
1294
 
        }
1295
 
    }
1296
 
  else
1297
 
    res = -1;
1298
 
 
1299
 
  return res;
1300
 
}
1301
 
 
1302
 
static gboolean
1303
 
g_daemon_vfs_local_file_set_attributes (GVfs       *vfs,
1304
 
                                        const char *filename,
1305
 
                                        GFileInfo  *info,
1306
 
                                        GFileQueryInfoFlags flags,
1307
 
                                        GCancellable *cancellable,
1308
 
                                        GError    **error)
1309
 
{
1310
 
  GFileAttributeType type;
1311
 
  MetaLookupCache *cache;
1312
 
  const char *metatreefile;
1313
 
  struct stat statbuf;
1314
 
  char **attributes;
1315
 
  char *tree_path;
1316
 
  MetaTree *tree;
1317
 
  int errsv;
1318
 
  int i, num_set;
1319
 
  DBusMessage *message;
1320
 
  gboolean res;
1321
 
  int appended;
1322
 
  gpointer value;
1323
 
 
1324
 
  res = TRUE;
1325
 
  if (g_file_info_has_namespace (info, "metadata"))
1326
 
    {
1327
 
      attributes = g_file_info_list_attributes (info, "metadata");
1328
 
 
1329
 
      if (g_lstat (filename, &statbuf) != 0)
1330
 
        {
1331
 
          errsv = errno;
1332
 
          g_set_error (error, G_IO_ERROR,
1333
 
                       g_io_error_from_errno (errsv),
1334
 
                       _("Error setting file metadata: %s"),
1335
 
                       g_strerror (errsv));
1336
 
          error = NULL; /* Don't set further errors */
1337
 
 
1338
 
          for (i = 0; attributes[i] != NULL; i++)
1339
 
            g_file_info_set_attribute_status (info, attributes[i],
1340
 
                                              G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
1341
 
 
1342
 
          res = FALSE;
1343
 
        }
1344
 
      else
1345
 
        {
1346
 
          cache = meta_lookup_cache_new ();
1347
 
          tree = meta_lookup_cache_lookup_path (cache,
1348
 
                                                filename,
1349
 
                                                statbuf.st_dev,
1350
 
                                                FALSE,
1351
 
                                                &tree_path);
1352
 
          message =
1353
 
            dbus_message_new_method_call (G_VFS_DBUS_METADATA_NAME,
1354
 
                                          G_VFS_DBUS_METADATA_PATH,
1355
 
                                          G_VFS_DBUS_METADATA_INTERFACE,
1356
 
                                          G_VFS_DBUS_METADATA_OP_SET);
1357
 
          g_assert (message != NULL);
1358
 
          metatreefile = meta_tree_get_filename (tree);
1359
 
          _g_dbus_message_append_args (message,
1360
 
                                       G_DBUS_TYPE_CSTRING, &metatreefile,
1361
 
                                       G_DBUS_TYPE_CSTRING, &tree_path,
1362
 
                                       0);
1363
 
          meta_lookup_cache_free (cache);
1364
 
 
1365
 
          num_set = 0;
1366
 
          for (i = 0; attributes[i] != NULL; i++)
1367
 
            {
1368
 
              if (g_file_info_get_attribute_data (info, attributes[i], &type, &value, NULL))
1369
 
                {
1370
 
                  appended = _g_daemon_vfs_append_metadata_for_set (message,
1371
 
                                                                    tree,
1372
 
                                                                    tree_path,
1373
 
                                                                    attributes[i],
1374
 
                                                                    type,
1375
 
                                                                    value);
1376
 
                  if (appended != -1)
1377
 
                    {
1378
 
                      num_set += appended;
1379
 
                      g_file_info_set_attribute_status (info, attributes[i],
1380
 
                                                        G_FILE_ATTRIBUTE_STATUS_SET);
1381
 
                    }
1382
 
                  else
1383
 
                    {
1384
 
                      res = FALSE;
1385
 
                      g_set_error (error, G_IO_ERROR,
1386
 
                                   G_IO_ERROR_INVALID_ARGUMENT,
1387
 
                                   _("Error setting file metadata: %s"),
1388
 
                                   _("values must be string or list of strings"));
1389
 
                      error = NULL; /* Don't set further errors */
1390
 
                      g_file_info_set_attribute_status (info, attributes[i],
1391
 
                                                        G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
1392
 
                    }
1393
 
                }
1394
 
            }
1395
 
 
1396
 
          meta_tree_unref (tree);
1397
 
          g_free (tree_path);
1398
 
 
1399
 
          if (num_set > 0 &&
1400
 
              !_g_daemon_vfs_send_message_sync (message,
1401
 
                                                cancellable, error))
1402
 
            {
1403
 
              res = FALSE;
1404
 
              error = NULL; /* Don't set further errors */
1405
 
              for (i = 0; attributes[i] != NULL; i++)
1406
 
                g_file_info_set_attribute_status (info, attributes[i],
1407
 
                                                  G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
1408
 
            }
1409
 
 
1410
 
          dbus_message_unref (message);
1411
 
        }
1412
 
 
1413
 
      g_strfreev (attributes);
1414
 
    }
1415
 
 
1416
 
  return res;
1417
 
}
1418
 
 
1419
 
static void
1420
 
g_daemon_vfs_local_file_removed (GVfs       *vfs,
1421
 
                                 const char *filename)
1422
 
{
1423
 
  MetaLookupCache *cache;
1424
 
  DBusMessage *message;
1425
 
  const char *metatreefile;
1426
 
  MetaTree *tree;
1427
 
  char *tree_path;
1428
 
 
1429
 
  cache = meta_lookup_cache_new ();
1430
 
  tree = meta_lookup_cache_lookup_path (cache,
1431
 
                                        filename,
1432
 
                                        0,
1433
 
                                        FALSE,
1434
 
                                        &tree_path);
1435
 
  if (tree)
1436
 
    {
1437
 
      message =
1438
 
        dbus_message_new_method_call (G_VFS_DBUS_METADATA_NAME,
1439
 
                                      G_VFS_DBUS_METADATA_PATH,
1440
 
                                      G_VFS_DBUS_METADATA_INTERFACE,
1441
 
                                      G_VFS_DBUS_METADATA_OP_REMOVE);
1442
 
      g_assert (message != NULL);
1443
 
      metatreefile = meta_tree_get_filename (tree);
1444
 
      _g_dbus_message_append_args (message,
1445
 
                                   G_DBUS_TYPE_CSTRING, &metatreefile,
1446
 
                                   G_DBUS_TYPE_CSTRING, &tree_path,
1447
 
                                   0);
1448
 
      send_message_oneway (message);
1449
 
      dbus_message_unref (message);
1450
 
      meta_tree_unref (tree);
1451
 
      g_free (tree_path);
1452
 
    }
1453
 
 
1454
 
  meta_lookup_cache_free (cache);
1455
 
}
1456
 
 
1457
 
static void
1458
 
g_daemon_vfs_local_file_moved (GVfs       *vfs,
1459
 
                               const char *source,
1460
 
                               const char *dest)
1461
 
{
1462
 
  MetaLookupCache *cache;
1463
 
  DBusMessage *message;
1464
 
  const char *metatreefile;
1465
 
  MetaTree *tree1, *tree2;
1466
 
  char *tree_path1, *tree_path2;
1467
 
 
1468
 
  cache = meta_lookup_cache_new ();
1469
 
  tree1 = meta_lookup_cache_lookup_path (cache,
1470
 
                                         source,
1471
 
                                         0,
1472
 
                                         FALSE,
1473
 
                                         &tree_path1);
1474
 
  tree2 = meta_lookup_cache_lookup_path (cache,
1475
 
                                         dest,
1476
 
                                         0,
1477
 
                                         FALSE,
1478
 
                                         &tree_path2);
1479
 
  if (tree1 && tree2 && tree1 == tree2)
1480
 
    {
1481
 
      message =
1482
 
        dbus_message_new_method_call (G_VFS_DBUS_METADATA_NAME,
1483
 
                                      G_VFS_DBUS_METADATA_PATH,
1484
 
                                      G_VFS_DBUS_METADATA_INTERFACE,
1485
 
                                      G_VFS_DBUS_METADATA_OP_MOVE);
1486
 
      g_assert (message != NULL);
1487
 
      metatreefile = meta_tree_get_filename (tree1);
1488
 
      _g_dbus_message_append_args (message,
1489
 
                                   G_DBUS_TYPE_CSTRING, &metatreefile,
1490
 
                                   G_DBUS_TYPE_CSTRING, &tree_path1,
1491
 
                                   G_DBUS_TYPE_CSTRING, &tree_path2,
1492
 
                                   0);
1493
 
      send_message_oneway (message);
1494
 
      dbus_message_unref (message);
1495
 
    }
1496
 
 
1497
 
  if (tree1)
1498
 
    {
1499
 
      meta_tree_unref (tree1);
1500
 
      g_free (tree_path1);
1501
 
    }
1502
 
 
1503
 
  if (tree2)
1504
 
    {
1505
 
      meta_tree_unref (tree2);
1506
 
      g_free (tree_path2);
1507
 
    }
1508
 
 
1509
 
  meta_lookup_cache_free (cache);
1510
 
}
1511
 
 
1512
 
DBusConnection *
1513
 
_g_daemon_vfs_get_async_bus (void)
1514
 
{
1515
 
  return the_vfs->async_bus;
1516
 
}
1517
 
 
1518
 
static gboolean
1519
 
g_daemon_vfs_is_active (GVfs *vfs)
1520
 
{
1521
 
  GDaemonVfs *daemon_vfs = G_DAEMON_VFS (vfs);
1522
 
  return daemon_vfs->async_bus != NULL;
1523
 
}
1524
 
 
1525
 
static void
1526
 
g_daemon_vfs_class_finalize (GDaemonVfsClass *klass)
1527
 
{
1528
 
}
1529
 
 
1530
 
static void
1531
 
g_daemon_vfs_class_init (GDaemonVfsClass *class)
1532
 
{
1533
 
  GObjectClass *object_class;
1534
 
  GVfsClass *vfs_class;
1535
 
 
1536
 
  object_class = (GObjectClass *) class;
1537
 
 
1538
 
  g_daemon_vfs_parent_class = g_type_class_peek_parent (class);
1539
 
 
1540
 
  object_class->finalize = g_daemon_vfs_finalize;
1541
 
 
1542
 
  vfs_class = G_VFS_CLASS (class);
1543
 
 
1544
 
  vfs_class->is_active = g_daemon_vfs_is_active;
1545
 
  vfs_class->get_file_for_path = g_daemon_vfs_get_file_for_path;
1546
 
  vfs_class->get_file_for_uri = g_daemon_vfs_get_file_for_uri;
1547
 
  vfs_class->get_supported_uri_schemes = g_daemon_vfs_get_supported_uri_schemes;
1548
 
  vfs_class->parse_name = g_daemon_vfs_parse_name;
1549
 
  vfs_class->local_file_add_info = g_daemon_vfs_local_file_add_info;
1550
 
  vfs_class->add_writable_namespaces = g_daemon_vfs_add_writable_namespaces;
1551
 
  vfs_class->local_file_set_attributes = g_daemon_vfs_local_file_set_attributes;
1552
 
  vfs_class->local_file_removed = g_daemon_vfs_local_file_removed;
1553
 
  vfs_class->local_file_moved = g_daemon_vfs_local_file_moved;
1554
 
}
1555
 
 
1556
 
/* Module API */
1557
 
 
1558
 
void g_vfs_uri_mapper_smb_register (GIOModule *module);
1559
 
void g_vfs_uri_mapper_http_register (GIOModule *module);
1560
 
void g_vfs_uri_mapper_sftp_register (GIOModule *module);
1561
 
 
1562
 
void
1563
 
g_io_module_load (GIOModule *module)
1564
 
{
1565
 
  /* This is so that system daemons can use gio
1566
 
   * without spawning private dbus instances.
1567
 
   * See bug 526454.
1568
 
   */
1569
 
  if (g_getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL) 
1570
 
    return;
1571
 
 
1572
 
  /* Make this module resident so that we ground the common
1573
 
   * library. If that is unloaded we could get into all kinds
1574
 
   * of strange situations. This is safe to do even if we loaded
1575
 
   * some other common-using module first as all modules are loaded
1576
 
   * before any are freed.
1577
 
   */
1578
 
  g_type_module_use (G_TYPE_MODULE (module));
1579
 
  
1580
 
  g_daemon_vfs_register_type (G_TYPE_MODULE (module));
1581
 
  g_daemon_volume_monitor_register_types (G_TYPE_MODULE (module));
1582
 
  
1583
 
  /* We implement GLoadableIcon only on client side.
1584
 
     see comment in common/giconvfs.c */
1585
 
  _g_vfs_icon_add_loadable_interface ();
1586
 
 
1587
 
  g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME,
1588
 
                                  G_TYPE_DAEMON_VFS,
1589
 
                                  "gvfs",
1590
 
                                  10);
1591
 
  
1592
 
  g_vfs_uri_mapper_register (module);
1593
 
  g_vfs_uri_mapper_smb_register (module);
1594
 
  g_vfs_uri_mapper_http_register (module);
1595
 
}
1596
 
 
1597
 
void
1598
 
g_io_module_unload (GIOModule   *module)
1599
 
{
1600
 
}
1601
 
 
1602
 
char **
1603
 
g_io_module_query (void)
1604
 
{
1605
 
  char *eps[] = {
1606
 
    G_VFS_EXTENSION_POINT_NAME,
1607
 
    G_VOLUME_MONITOR_EXTENSION_POINT_NAME,
1608
 
    NULL
1609
 
  };
1610
 
  return g_strdupv (eps);
1611
 
}