~ubuntu-branches/ubuntu/quantal/gconf/quantal

« back to all changes in this revision

Viewing changes to backends/xml-dir.c

  • Committer: Bazaar Package Importer
  • Author(s): Josselin Mouette
  • Date: 2007-11-01 18:47:26 UTC
  • mto: (7.1.1 lenny) (1.2.1) (76.1.1 oneiric-proposed)
  • mto: This revision was merged to the branch mainline in revision 7.
  • Revision ID: james.westby@ubuntu.com-20071101184726-e3e4cxfcp41tz6ui
Tags: upstream-2.20.1
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
#include <fcntl.h>
32
32
#include <unistd.h>
33
33
#include <errno.h>
34
 
#include <dirent.h>
35
34
#include <limits.h>
36
35
 
37
36
#include <gconf/gconf-internals.h>
38
 
#include "xml-entry.h"
39
37
 
40
38
/* This makes hash table safer when debugging */
41
39
#ifndef GCONF_ENABLE_DEBUG
59
57
}
60
58
#endif
61
59
 
62
 
static gchar* parent_dir(const gchar* dir);
 
60
static xmlDocPtr my_xml_parse_file (const char *filename,
 
61
                                    GError    **err);
 
62
 
 
63
static gboolean dir_rescan_subdirs (Dir* d, GError** err);
63
64
 
64
65
struct _Dir {
65
66
  gchar* key;
 
67
  gchar* parent_key;
66
68
  gchar* fs_dirname;
67
69
  gchar* xml_filename;
68
70
  guint root_dir_len;
69
71
  GTime last_access; /* so we know when to un-cache */
70
72
  xmlDocPtr doc;
71
73
  GHashTable* entry_cache; /* store key-value entries */
72
 
  GHashTable* subdir_cache; /* store subdirectories */
73
74
  guint dir_mode;
74
75
  guint file_mode;
 
76
  GSList *subdir_names;
75
77
  guint dirty : 1;
76
 
  guint deleted : 1;
 
78
  guint need_rescan_subdirs : 1;
77
79
};
78
80
 
79
81
static void
101
103
  }
102
104
#endif
103
105
  
104
 
  d->key = g_strdup(key);
 
106
  d->key = g_strdup (key);
 
107
  d->parent_key = gconf_key_directory (key);
105
108
  
106
109
  d->last_access = time(NULL);
107
110
  d->doc = NULL;
108
111
 
109
 
  d->entry_cache = g_hash_table_new(g_str_hash, g_str_equal);
 
112
  d->entry_cache = g_hash_table_new (g_str_hash, g_str_equal);
110
113
  
111
114
  d->dirty = FALSE;
112
 
  d->deleted = FALSE;
 
115
  d->need_rescan_subdirs = TRUE;
113
116
 
 
117
  d->subdir_names = NULL;
 
118
  
114
119
  d->dir_mode = 0700;
115
120
  d->file_mode = 0600;
116
121
  
118
123
}
119
124
 
120
125
Dir*
121
 
dir_new(const gchar  *keyname,
122
 
        const gchar  *xml_root_dir,
123
 
        guint dir_mode,
124
 
        guint file_mode)
 
126
dir_new (const gchar  *keyname,
 
127
         const gchar  *xml_root_dir,
 
128
         guint dir_mode,
 
129
         guint file_mode)
125
130
{
126
131
  Dir* d;
127
132
  
139
144
}
140
145
 
141
146
Dir*
142
 
dir_load        (const gchar* key, const gchar* xml_root_dir, GError** err)
 
147
dir_load (const gchar* key, const gchar* xml_root_dir, GError** err)
143
148
{
144
149
  Dir* d;
145
150
  gchar* fs_dirname;
156
161
    struct stat s;
157
162
    gboolean notfound = FALSE;
158
163
    
159
 
    if (stat(xml_filename, &s) != 0)
 
164
    if (g_stat(xml_filename, &s) != 0)
160
165
      {
161
166
        if (errno != ENOENT)
162
167
          {
163
 
            gconf_set_error(err, GCONF_ERROR_FAILED,
164
 
                            _("Could not stat `%s': %s"),
165
 
                            xml_filename, strerror(errno));
 
168
            gconf_set_error (err, GCONF_ERROR_FAILED,
 
169
                             _("Could not stat `%s': %s"),
 
170
                             xml_filename, g_strerror(errno));
166
171
 
167
172
          }
168
173
        
170
175
      }
171
176
    else if (S_ISDIR(s.st_mode))
172
177
      {
173
 
        gconf_set_error(err, GCONF_ERROR_FAILED,
 
178
        gconf_set_error (err, GCONF_ERROR_FAILED,
174
179
                         _("XML filename `%s' is a directory"),
175
180
                         xml_filename);
176
181
        notfound = TRUE;
186
191
    else
187
192
      {
188
193
        /* Take directory mode from the xml_root_dir, if possible */
189
 
        if (stat (xml_root_dir, &s) == 0)
 
194
        if (g_stat (xml_root_dir, &s) == 0)
190
195
          {
191
 
            dir_mode = mode_t_to_mode(s.st_mode);
 
196
            dir_mode = _gconf_mode_t_to_mode (s.st_mode);
192
197
          }
193
198
        
194
199
        file_mode = dir_mode & ~0111; /* turn off search bits */
205
210
  d->dir_mode = dir_mode;
206
211
  d->file_mode = file_mode;
207
212
  
208
 
  gconf_log(GCL_DEBUG, "loaded dir %s", fs_dirname);
 
213
  gconf_log (GCL_DEBUG, "loaded dir %s", fs_dirname);
209
214
  
210
215
  return d;
211
216
}
214
219
static void
215
220
entry_destroy_foreach(const gchar* name, Entry* e, gpointer data)
216
221
{
217
 
  entry_destroy(e);
 
222
  entry_destroy (e);
218
223
}
219
224
 
220
225
void
221
226
dir_destroy(Dir* d)
222
227
{
223
 
  g_free(d->key);
224
 
  g_free(d->fs_dirname);
225
 
  g_free(d->xml_filename);
226
 
  
227
 
  g_hash_table_foreach(d->entry_cache, (GHFunc)entry_destroy_foreach,
228
 
                       NULL);
229
 
  
230
 
  g_hash_table_destroy(d->entry_cache);
 
228
  g_free (d->key);
 
229
  g_free (d->parent_key);
 
230
  g_free (d->fs_dirname);
 
231
  g_free (d->xml_filename);
 
232
 
 
233
  g_slist_foreach (d->subdir_names, (GFunc) g_free, NULL);
 
234
  g_slist_free (d->subdir_names);
 
235
  
 
236
  g_hash_table_foreach (d->entry_cache, (GHFunc)entry_destroy_foreach,
 
237
                        NULL);
 
238
  
 
239
  g_hash_table_destroy (d->entry_cache);
231
240
 
232
241
  if (d->doc != NULL)
233
 
    xmlFreeDoc(d->doc);
 
242
    xmlFreeDoc (d->doc);
234
243
  
235
 
  g_free(d);
 
244
  g_free (d);
236
245
}
237
246
 
238
247
static gboolean
268
277
}
269
278
 
270
279
gboolean
271
 
dir_sync_pending    (Dir          *d)
 
280
dir_sync_pending (Dir *d)
272
281
{
273
282
  return d->dirty;
274
283
}
275
284
 
 
285
void
 
286
dir_child_removed (Dir        *d,
 
287
                   const char *child_name)
 
288
{
 
289
  GSList *tmp;
 
290
  
 
291
  /* dirty because we need to consider removing
 
292
   * this directory, it may have become empty.
 
293
   */
 
294
  d->dirty = TRUE;
 
295
  
 
296
  if (d->need_rescan_subdirs)
 
297
    return; /* subdir_names is totally invalid anyhow */
 
298
 
 
299
  tmp = d->subdir_names;
 
300
  while (tmp != NULL)
 
301
    {
 
302
      if (strcmp (tmp->data, child_name) == 0)
 
303
        {
 
304
          char *tofree = tmp->data;
 
305
          
 
306
          d->subdir_names = g_slist_remove (d->subdir_names,
 
307
                                            tofree);
 
308
          g_free (tofree);
 
309
 
 
310
          break;
 
311
        }
 
312
      
 
313
      tmp = tmp->next;
 
314
    }
 
315
}
 
316
 
 
317
void
 
318
dir_child_added (Dir        *d,
 
319
                 const char *child_name)
 
320
{
 
321
  if (d->need_rescan_subdirs)
 
322
    return;
 
323
 
 
324
  if (g_slist_find_custom (d->subdir_names,
 
325
                           child_name,
 
326
                           (GCompareFunc) strcmp) == NULL)
 
327
    d->subdir_names = g_slist_prepend (d->subdir_names,
 
328
                                       g_strdup (child_name));
 
329
}
 
330
 
 
331
/* directories auto-disappear when they're empty */
 
332
static gboolean
 
333
dir_useless (Dir *d)
 
334
{
 
335
  if (d->doc == NULL)
 
336
    dir_load_doc (d, NULL);
 
337
 
 
338
  if (d->need_rescan_subdirs)
 
339
    dir_rescan_subdirs (d, NULL);
 
340
  
 
341
  return
 
342
    d->subdir_names == NULL &&
 
343
    g_hash_table_size (d->entry_cache) == 0;
 
344
}
 
345
 
 
346
/* for info on why this is used rather than xmlDocDump or xmlSaveFile
 
347
 * and friends, see http://bugzilla.gnome.org/show_bug.cgi?id=108329 */
 
348
static int
 
349
gconf_xml_doc_dump (FILE *fp, xmlDocPtr doc)
 
350
{
 
351
  char *xmlbuf;
 
352
  int fd, n;
 
353
  
 
354
  xmlDocDumpFormatMemory (doc, (xmlChar **) &xmlbuf, &n, TRUE);
 
355
  if (n <= 0)
 
356
    {
 
357
      errno = ENOMEM;
 
358
      return -1;
 
359
    }
 
360
  
 
361
  if (fwrite (xmlbuf, sizeof (xmlChar), n, fp) < n)
 
362
    {
 
363
      xmlFree (xmlbuf);
 
364
      return -1;
 
365
    }
 
366
  
 
367
  xmlFree (xmlbuf);
 
368
  
 
369
  /* From the fflush(3) man page:
 
370
   *
 
371
   * Note that fflush() only flushes the user space buffers provided by the
 
372
   * C library. To ensure that the data is physically stored on disk the
 
373
   * kernel buffers must be flushed too, e.g. with sync(2) or fsync(2).
 
374
   */
 
375
  
 
376
  /* flush user-space buffers */
 
377
  if (fflush (fp) != 0)
 
378
    return -1;
 
379
  
 
380
  if ((fd = fileno (fp)) == -1)
 
381
    return -1;
 
382
  
 
383
#ifdef HAVE_FSYNC
 
384
  /* sync kernel-space buffers to disk */
 
385
  if (fsync (fd) == -1)
 
386
    return -1;
 
387
#endif
 
388
 
 
389
  return 0;
 
390
}
 
391
 
276
392
gboolean
277
 
dir_sync        (Dir* d, GError** err)
 
393
dir_sync (Dir      *d,
 
394
          gboolean *deleted,
 
395
          GError  **err)
278
396
{
279
397
  gboolean retval = TRUE;
280
 
  
281
 
  /* note that if we are deleted but already
282
 
     synced, this returns now, making the
283
 
     dircache's recursive delete tactic reasonably
284
 
     efficient
285
 
  */
 
398
 
 
399
  if (deleted)
 
400
    *deleted = FALSE;  
 
401
 
286
402
  if (!d->dirty)
287
403
    return TRUE; 
288
404
 
289
 
  /* We should have a doc if dirty is TRUE */
290
 
  g_assert(d->doc != NULL);
291
 
 
292
 
  d->last_access = time(NULL);
293
 
  
294
 
  if (d->deleted)
 
405
  gconf_log (GCL_DEBUG, "Syncing dir \"%s\"", d->key);
 
406
  
 
407
  d->last_access = time (NULL);
 
408
  
 
409
  if (dir_useless (d))
295
410
    {
296
 
      if (unlink(d->xml_filename) != 0)
297
 
        {
298
 
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to delete `%s': %s"),
299
 
                          d->xml_filename, strerror(errno));
300
 
          return FALSE;
301
 
        }
302
 
 
303
 
      if (rmdir(d->fs_dirname) != 0)
304
 
        {
305
 
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to delete `%s': %s"),
306
 
                          d->fs_dirname, strerror(errno));
307
 
          return FALSE;
308
 
        }
 
411
      gconf_log (GCL_DEBUG, "Deleting useless dir \"%s\"",
 
412
                 d->key);
 
413
      
 
414
      if (g_unlink (d->xml_filename) != 0)
 
415
        {
 
416
          gconf_set_error (err, GCONF_ERROR_FAILED, _("Failed to delete \"%s\": %s"),
 
417
                           d->xml_filename, g_strerror (errno));
 
418
          return FALSE;
 
419
        }
 
420
 
 
421
      if (strcmp (d->key, "/") != 0) /* don't delete root dir */
 
422
        {
 
423
          if (g_rmdir (d->fs_dirname) != 0)
 
424
            {
 
425
              gconf_set_error (err, GCONF_ERROR_FAILED, _("Failed to delete \"%s\": %s"),
 
426
                               d->fs_dirname, g_strerror (errno));
 
427
              return FALSE;
 
428
            }
 
429
        }
 
430
 
 
431
      if (deleted)
 
432
        *deleted = TRUE;
309
433
    }
310
434
  else
311
435
    {
312
436
      gboolean old_existed = FALSE;
313
437
      gchar* tmp_filename;
314
438
      gchar* old_filename;
 
439
      FILE* outfile;
 
440
 
 
441
      /* We should have a doc if deleted is FALSE */
 
442
      g_assert(d->doc != NULL);
315
443
      
316
444
      /* First make sure entry values are synced to their
317
445
         XML nodes */
320
448
      tmp_filename = g_strconcat(d->fs_dirname, "/%gconf.xml.tmp", NULL);
321
449
      old_filename = g_strconcat(d->fs_dirname, "/%gconf.xml.old", NULL);
322
450
 
323
 
      if (xmlSaveFile(tmp_filename, d->doc) < 0)
 
451
      outfile = g_fopen (tmp_filename, "w");
 
452
 
 
453
      if (outfile == NULL)
324
454
        {
325
 
          gboolean recovered = FALSE;
326
 
          
327
455
          /* Try to solve the problem by creating the FS dir */
328
 
          if (!gconf_file_exists(d->fs_dirname))
 
456
          if (!g_file_test (d->fs_dirname, G_FILE_TEST_EXISTS))
329
457
            {
330
458
              if (create_fs_dir(d->fs_dirname, d->xml_filename,
331
459
                                d->root_dir_len,
332
460
                                d->dir_mode, d->file_mode,
333
461
                                err))
334
 
                {
335
 
                  if (xmlSaveFile(tmp_filename, d->doc) >= 0)
336
 
                    recovered = TRUE;
337
 
                }
 
462
                outfile = g_fopen (tmp_filename, "w");
338
463
            }
339
464
 
340
 
          if (!recovered)
 
465
          if (outfile == NULL)
341
466
            {
342
 
              /* I think libxml may mangle errno, but we might as well 
343
 
                 try. Don't set error if it's already set by some
344
 
                 earlier failure. */
 
467
              /* Don't set error if it's already set by some
 
468
               * earlier failure.
 
469
               */
345
470
              if (err && *err == NULL)
346
471
                gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to write file `%s': %s"), 
347
 
                                tmp_filename, strerror(errno));
 
472
                                tmp_filename, g_strerror(errno));
348
473
              
349
474
              retval = FALSE;
350
475
              
352
477
            }
353
478
        }
354
479
 
 
480
#ifdef HAVE_FCHMOD
 
481
      /* Set permissions on the new file */
 
482
      if (fchmod (fileno (outfile), d->file_mode) != 0)
 
483
        {
 
484
          gconf_set_error(err, GCONF_ERROR_FAILED, 
 
485
                          _("Failed to set mode on `%s': %s"),
 
486
                          tmp_filename, g_strerror(errno));
 
487
          
 
488
          retval = FALSE;
 
489
          goto failed_end_of_sync;
 
490
        }
 
491
#endif
 
492
 
 
493
      if (gconf_xml_doc_dump (outfile, d->doc) < 0)
 
494
        {
 
495
          gconf_set_error (err, GCONF_ERROR_FAILED, 
 
496
                           _("Failed to write XML data to `%s': %s"),
 
497
                           tmp_filename, g_strerror (errno));
 
498
          
 
499
          retval = FALSE;
 
500
          goto failed_end_of_sync;
 
501
        }
 
502
 
 
503
      if (fclose (outfile) < 0)
 
504
        {
 
505
          gconf_set_error (err, GCONF_ERROR_FAILED, 
 
506
                           _("Failed to close file `%s': %s"),
 
507
                           tmp_filename, g_strerror (errno));
 
508
          
 
509
          retval = FALSE;
 
510
          outfile = NULL;
 
511
          goto failed_end_of_sync;
 
512
        }
 
513
 
 
514
      outfile = NULL;
 
515
      
 
516
#ifndef HAVE_FCHMOD
355
517
      /* Set permissions on the new file */
356
518
      if (chmod (tmp_filename, d->file_mode) != 0)
357
519
        {
358
520
          gconf_set_error(err, GCONF_ERROR_FAILED, 
359
521
                          _("Failed to set mode on `%s': %s"),
360
 
                          tmp_filename, strerror(errno));
 
522
                          tmp_filename, g_strerror(errno));
361
523
          
362
524
          retval = FALSE;
363
525
          goto failed_end_of_sync;
364
526
        }
365
 
      
366
 
      old_existed = gconf_file_exists(d->xml_filename);
 
527
#endif
 
528
 
 
529
      old_existed = g_file_test (d->xml_filename, G_FILE_TEST_EXISTS);
367
530
 
368
531
      if (old_existed)
369
532
        {
370
 
          if (rename(d->xml_filename, old_filename) < 0)
 
533
          if (g_rename(d->xml_filename, old_filename) < 0)
371
534
            {
372
535
              gconf_set_error(err, GCONF_ERROR_FAILED, 
373
536
                              _("Failed to rename `%s' to `%s': %s"),
374
 
                              d->xml_filename, old_filename, strerror(errno));
 
537
                              d->xml_filename, old_filename, g_strerror(errno));
375
538
 
376
539
              retval = FALSE;
377
540
              goto failed_end_of_sync;
378
541
            }
379
542
        }
380
543
 
381
 
      if (rename(tmp_filename, d->xml_filename) < 0)
 
544
      if (g_rename(tmp_filename, d->xml_filename) < 0)
382
545
        {
383
546
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to rename `%s' to `%s': %s"),
384
 
                          tmp_filename, d->xml_filename, strerror(errno));
 
547
                          tmp_filename, d->xml_filename, g_strerror(errno));
385
548
 
386
549
          /* Put the original file back, so this isn't a total disaster. */
387
 
          if (rename(old_filename, d->xml_filename) < 0)
 
550
          if (g_rename(old_filename, d->xml_filename) < 0)
388
551
            {
389
552
              gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to restore `%s' from `%s': %s"),
390
 
                              d->xml_filename, old_filename, strerror(errno));
 
553
                              d->xml_filename, old_filename, g_strerror(errno));
391
554
            }
392
555
 
393
556
          retval = FALSE;
396
559
 
397
560
      if (old_existed)
398
561
        {
399
 
          if (unlink(old_filename) < 0)
 
562
          if (g_unlink(old_filename) < 0)
400
563
            {
401
564
              gconf_log(GCL_WARNING, _("Failed to delete old file `%s': %s"),
402
 
                         old_filename, strerror(errno));
 
565
                         old_filename, g_strerror(errno));
403
566
              /* Not a failure, just leaves cruft around. */
404
567
            }
405
568
        }
408
571
      
409
572
      g_free(old_filename);
410
573
      g_free(tmp_filename);
 
574
      if (outfile)
 
575
        fclose (outfile);
411
576
    }
412
577
 
413
578
  if (retval)
417
582
}
418
583
 
419
584
void
420
 
dir_set_value   (Dir* d, const gchar* relative_key,
421
 
                 GConfValue* value, GError** err)
 
585
dir_set_value (Dir* d, const gchar* relative_key,
 
586
               const GConfValue* value, GError** err)
422
587
{
423
588
  Entry* e;
424
589
  
460
625
                 GError** err)
461
626
{
462
627
  Entry* e;
463
 
 
 
628
  
464
629
  if (d->doc == NULL)
465
630
    dir_load_doc(d, err);
466
631
 
500
665
}
501
666
 
502
667
const gchar*
503
 
dir_get_name        (Dir          *d)
 
668
dir_get_name (Dir *d)
504
669
{
505
 
  g_return_val_if_fail(d != NULL, NULL);
 
670
  g_return_val_if_fail (d != NULL, NULL);
506
671
  return d->key;
507
672
}
508
673
 
 
674
const char*
 
675
dir_get_parent_name (Dir *d)
 
676
{
 
677
  g_return_val_if_fail (d != NULL, NULL);
 
678
  return d->parent_key;
 
679
}
 
680
 
509
681
GConfMetaInfo*
510
682
dir_get_metainfo(Dir* d, const gchar* relative_key, GError** err)
511
683
{
606
778
  entry = gconf_entry_new_nocopy (g_strdup(key),
607
779
                                  val ? gconf_value_copy(val) : NULL);
608
780
  
609
 
  if (val == NULL &&
610
 
      entry_get_schema_name (e))
 
781
  if (entry_get_schema_name (e))
611
782
    {
612
783
      gconf_entry_set_schema_name (entry, entry_get_schema_name (e));
613
784
    }
639
810
  return ld.list;
640
811
}
641
812
 
642
 
GSList*
643
 
dir_all_subdirs (Dir* d, GError** err)
644
 
{
645
 
  DIR* dp;
646
 
  struct dirent* dent;
 
813
static GSList*
 
814
copy_string_list (GSList *src)
 
815
{
 
816
  GSList *copy;
 
817
  GSList *tmp;
 
818
  
 
819
  copy = NULL;
 
820
  tmp = src;
 
821
  while (tmp != NULL)
 
822
    {
 
823
      copy = g_slist_prepend (copy, g_strdup (tmp->data));
 
824
      tmp = tmp->next;
 
825
    }
 
826
 
 
827
  copy = g_slist_reverse (copy);
 
828
 
 
829
  return copy;
 
830
}
 
831
 
 
832
static gboolean
 
833
dir_rescan_subdirs (Dir* d, GError** err)
 
834
{
 
835
  GDir* dp;
 
836
  const char* dent;
647
837
  struct stat statbuf;
648
838
  GSList* retval = NULL;
649
839
  gchar* fullpath;
652
842
  guint subdir_len;
653
843
  
654
844
  if (d->doc == NULL)
655
 
    dir_load_doc(d, err);
 
845
    dir_load_doc (d, err);
656
846
  
657
847
  if (d->doc == NULL)
658
848
    {
659
 
      g_return_val_if_fail( (err == NULL) || (*err != NULL), NULL );
660
 
      return NULL;
 
849
      g_return_val_if_fail ((err == NULL) || (*err != NULL), FALSE);
 
850
      return FALSE;
661
851
    }
 
852
 
 
853
  if (!d->need_rescan_subdirs)
 
854
    return TRUE;
 
855
 
 
856
  g_slist_foreach (d->subdir_names, (GFunc) g_free, NULL);
 
857
  g_slist_free (d->subdir_names);
 
858
  d->subdir_names = NULL;
662
859
  
663
 
  dp = opendir(d->fs_dirname);
 
860
  dp = g_dir_open (d->fs_dirname, 0, NULL);
664
861
 
665
862
  if (dp == NULL)
666
 
    return NULL;
 
863
    {
 
864
      d->need_rescan_subdirs = FALSE;
 
865
      return TRUE;
 
866
    }
667
867
 
668
868
  len = strlen(d->fs_dirname);
669
869
  subdir_len = PATH_MAX - len;
676
876
  ++fullpath_end;
677
877
  *fullpath_end = '\0';
678
878
 
679
 
  while ((dent = readdir(dp)) != NULL)
 
879
  while ((dent = g_dir_read_name(dp)) != NULL)
680
880
    {
681
 
      /* ignore ., .., and all dot-files */
682
 
      if (dent->d_name[0] == '.')
 
881
      /* ignore all dot-files */
 
882
      if (dent[0] == '.')
683
883
        continue;
684
884
 
685
 
      len = strlen(dent->d_name);
 
885
      len = strlen(dent);
686
886
 
687
887
      if (len < subdir_len)
688
888
        {
689
 
          strcpy(fullpath_end, dent->d_name);
 
889
          strcpy(fullpath_end, dent);
690
890
          strncpy(fullpath_end+len, "/%gconf.xml", subdir_len - len);
691
891
        }
692
892
      else
693
893
        continue; /* Shouldn't ever happen since PATH_MAX is available */
694
894
      
695
 
      if (stat(fullpath, &statbuf) < 0)
 
895
      if (g_stat(fullpath, &statbuf) < 0)
696
896
        {
697
897
          /* This is some kind of cruft, not an XML directory */
698
898
          continue;
699
899
        }
700
900
      
701
 
      retval = g_slist_prepend(retval, g_strdup(dent->d_name));
 
901
      retval = g_slist_prepend (retval, g_strdup(dent));
702
902
    }
703
903
 
704
904
  /* if this fails, we really can't do a thing about it
705
 
     and it's not a meaningful error */
706
 
  closedir(dp);
 
905
   * and it's not a meaningful error
 
906
   */
 
907
  g_dir_close (dp);
707
908
 
708
909
  g_free (fullpath);
709
 
  
710
 
  return retval;
 
910
 
 
911
  d->subdir_names = retval;
 
912
  d->need_rescan_subdirs = FALSE;
 
913
 
 
914
  return TRUE;
 
915
}
 
916
 
 
917
GSList*
 
918
dir_all_subdirs (Dir* d, GError** err)
 
919
{
 
920
  if (!dir_rescan_subdirs (d, err))
 
921
    return NULL;
 
922
 
 
923
  return copy_string_list (d->subdir_names);
711
924
}
712
925
 
713
926
void
714
 
dir_set_schema  (Dir* d,
715
 
                 const gchar* relative_key,
716
 
                 const gchar* schema_key,
717
 
                 GError** err)
 
927
dir_set_schema  (Dir         *d,
 
928
                 const gchar *relative_key,
 
929
                 const gchar *schema_key,
 
930
                 GError     **err)
718
931
{
719
932
  Entry* e;
720
933
 
721
934
  if (d->doc == NULL)
722
 
    dir_load_doc(d, err);
 
935
    dir_load_doc (d, err);
723
936
 
724
937
  if (d->doc == NULL)
725
938
    {
726
 
      g_return_if_fail( (err == NULL) || (*err != NULL) );
 
939
      g_return_if_fail ((err == NULL) || (*err != NULL));
727
940
      return;
728
941
    }
729
942
  
730
943
  d->dirty = TRUE;
731
 
  d->last_access = time(NULL);
 
944
  d->last_access = time (NULL);
732
945
  
733
 
  e = g_hash_table_lookup(d->entry_cache, relative_key);
 
946
  e = g_hash_table_lookup (d->entry_cache, relative_key);
734
947
 
735
948
  if (e == NULL)
736
 
    e = dir_make_new_entry(d, relative_key);
737
 
 
738
 
  entry_set_mod_time(e, d->last_access);
739
 
 
740
 
  entry_set_schema_name(e, schema_key);
 
949
    e = dir_make_new_entry (d, relative_key);
 
950
 
 
951
  entry_set_mod_time (e, d->last_access);
 
952
 
 
953
  entry_set_schema_name (e, schema_key);
741
954
 
742
955
  if (schema_key == NULL)
743
 
    dir_forget_entry_if_useless(d, e);
744
 
}
745
 
 
746
 
void
747
 
dir_mark_deleted(Dir* d)
748
 
{
749
 
  if (d->deleted)
750
 
    return;
751
 
  
752
 
  d->deleted = TRUE;
753
 
  d->dirty = TRUE;
754
 
  
755
 
  /* go ahead and free the XML document */
756
 
 
757
 
  if (d->doc)
758
 
    xmlFreeDoc(d->doc);
759
 
  d->doc = NULL;
760
 
}
761
 
 
762
 
gboolean
763
 
dir_is_deleted     (Dir* d)
764
 
{
765
 
  return d->deleted;
 
956
    dir_forget_entry_if_useless (d, e);
766
957
}
767
958
 
768
959
GTime
793
984
          xml_already_exists = FALSE;
794
985
          break;
795
986
        case ENOTDIR:
 
987
#ifdef ELOOP
796
988
        case ELOOP:
 
989
#endif
797
990
        case EFAULT:
798
991
        case EACCES:
799
992
        case ENOMEM:
801
994
        default:
802
995
          /* These are all fatal errors */
803
996
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to stat `%s': %s"),
804
 
                          d->xml_filename, strerror(errno));
 
997
                          d->xml_filename, g_strerror(errno));
805
998
          return;
806
999
          break;
807
1000
        }
813
1006
    }
814
1007
 
815
1008
  if (xml_already_exists)
816
 
    d->doc = xmlParseFile(d->xml_filename);
817
 
 
818
 
  /* We recover from these errors instead of passing them up */
 
1009
    {
 
1010
      GError *tmp_err;
 
1011
      gboolean error_was_fatal;
 
1012
 
 
1013
      error_was_fatal = FALSE;
 
1014
      tmp_err = NULL;
 
1015
      d->doc = my_xml_parse_file (d->xml_filename, &tmp_err);
 
1016
 
 
1017
      if (tmp_err != NULL)
 
1018
        {
 
1019
          gconf_log (GCL_WARNING,
 
1020
                     "%s", tmp_err->message);
 
1021
 
 
1022
          /* file errors are assumed to be some kind of
 
1023
           * blowup, like out of file descriptors, so
 
1024
           * we play it safe and don't touch anything
 
1025
           */
 
1026
          if (tmp_err->domain == G_FILE_ERROR)
 
1027
            error_was_fatal = TRUE;
 
1028
          
 
1029
          g_error_free (tmp_err);
 
1030
        }
 
1031
 
 
1032
      if (error_was_fatal)
 
1033
        return;
 
1034
    }
 
1035
  
 
1036
  /* We recover from parse errors instead of passing them up */
819
1037
 
820
1038
  /* This has the potential to just blow away an entire corrupted
821
 
     config file; but I think that is better than the alternatives
822
 
     (disabling config for a directory because the document is mangled)
823
 
  */  
 
1039
   * config file; but I think that is better than the alternatives
 
1040
   * (disabling config for a directory because the document is mangled).
 
1041
   *
 
1042
   * Parse errors really should not happen from an XML file we created
 
1043
   * ourselves anyway...
 
1044
   */  
824
1045
 
825
1046
  /* Also we create empty %gconf.xml files when we create a new dir,
826
 
     and those return a parse error */
 
1047
   * and those return a parse error, though they should be trapped
 
1048
   * by the statbuf.st_size == 0 check above.
 
1049
   */
827
1050
  
828
1051
  if (d->doc == NULL)
829
1052
    {
830
1053
      if (xml_already_exists)
831
 
        need_backup = TRUE; /* we want to save whatever broken stuff was in the file */
 
1054
        need_backup = TRUE; /* rather uselessly save whatever broken stuff was in the file */
832
1055
          
833
1056
      /* Create a new doc */
834
1057
      
835
 
      d->doc = xmlNewDoc("1.0");
 
1058
      d->doc = xmlNewDoc((xmlChar *)"1.0");
836
1059
    }
837
1060
  
838
 
  if (d->doc->root == NULL)
 
1061
  if (d->doc->xmlRootNode == NULL)
839
1062
    {
840
1063
      /* fill it in */
841
 
      d->doc->root = xmlNewDocNode(d->doc, NULL, "gconf", NULL);
 
1064
      d->doc->xmlRootNode = xmlNewDocNode(d->doc, NULL, "gconf", NULL);
842
1065
    }
843
 
  else if (strcmp(d->doc->root->name, "gconf") != 0)
 
1066
  else if (strcmp((char*)d->doc->xmlRootNode->name, "gconf") != 0)
844
1067
    {
845
1068
      xmlFreeDoc(d->doc);
846
 
      d->doc = xmlNewDoc("1.0");
847
 
      d->doc->root = xmlNewDocNode(d->doc, NULL, "gconf", NULL);
 
1069
      d->doc = xmlNewDoc((xmlChar*)"1.0");
 
1070
      d->doc->xmlRootNode = xmlNewDocNode(d->doc, NULL, (xmlChar *)"gconf", NULL);
848
1071
      need_backup = TRUE; /* save broken stuff */
849
1072
    }
850
1073
  else
864
1087
      gchar* backup = g_strconcat(d->xml_filename, ".bak", NULL);
865
1088
      int fd;
866
1089
      
867
 
      rename(d->xml_filename, backup);
 
1090
      g_rename(d->xml_filename, backup);
868
1091
      
869
1092
      /* Recreate %gconf.xml to maintain our integrity and be sure
870
1093
         all_subdirs works */
871
1094
      /* If we failed to rename, we just give up and truncate the file */
872
 
      fd = open(d->xml_filename, O_CREAT | O_WRONLY | O_TRUNC, d->file_mode);
 
1095
      fd = g_open(d->xml_filename, O_CREAT | O_WRONLY | O_TRUNC, d->file_mode);
873
1096
      if (fd >= 0)
874
1097
        close(fd);
875
1098
      
877
1100
    }
878
1101
  
879
1102
  g_assert(d->doc != NULL);
880
 
  g_assert(d->doc->root != NULL);
 
1103
  g_assert(d->doc->xmlRootNode != NULL);
881
1104
}
882
1105
 
883
1106
static Entry*
886
1109
  Entry* e;
887
1110
 
888
1111
  g_return_val_if_fail(d->doc != NULL, NULL);
889
 
  g_return_val_if_fail(d->doc->root != NULL, NULL);
 
1112
  g_return_val_if_fail(d->doc->xmlRootNode != NULL, NULL);
890
1113
  
891
1114
  e = entry_new(relative_key);
892
1115
 
893
 
  entry_set_node(e, xmlNewChild(d->doc->root, NULL, "entry", NULL));
 
1116
  entry_set_node(e, xmlNewChild(d->doc->xmlRootNode, NULL, (xmlChar *)"entry", NULL));
894
1117
  
895
1118
  safe_g_hash_table_insert(d->entry_cache, (gchar*)entry_get_name(e), e);
896
1119
  
923
1146
  xmlNodePtr node;
924
1147
  
925
1148
  if (d->doc == NULL ||
926
 
      d->doc->root == NULL ||
927
 
      d->doc->root->childs == NULL)
 
1149
      d->doc->xmlRootNode == NULL ||
 
1150
      d->doc->xmlRootNode->xmlChildrenNode == NULL)
928
1151
    {
929
1152
      /* Empty document - just return. */
930
1153
      return;
931
1154
    }
932
1155
 
933
 
  node = d->doc->root->childs;
 
1156
  node = d->doc->xmlRootNode->xmlChildrenNode;
934
1157
 
935
1158
  while (node != NULL)
936
1159
    {
937
1160
      if (node->type == XML_ELEMENT_NODE && 
938
 
          (strcmp(node->name, "entry") == 0))
 
1161
          (strcmp((xmlChar *)node->name, "entry") == 0))
939
1162
        {
940
1163
          gchar* attr = my_xmlGetProp(node, "name");
941
1164
 
995
1218
  g_return_val_if_fail(xml_filename != NULL, FALSE);
996
1219
  
997
1220
  gconf_log(GCL_DEBUG, "Enter create_fs_dir: %s", dir);
998
 
  
999
 
  if (gconf_file_test(xml_filename, GCONF_FILE_ISFILE))
 
1221
 
 
1222
  if (g_file_test(xml_filename, G_FILE_TEST_IS_REGULAR))
1000
1223
    {
1001
1224
      gconf_log(GCL_DEBUG, "XML backend file %s already exists", xml_filename);
1002
1225
      return TRUE;
1007
1230
    {
1008
1231
      gchar* parent;
1009
1232
      
1010
 
      parent = parent_dir(dir);
 
1233
      parent = _gconf_parent_dir (dir);
1011
1234
 
1012
 
      gconf_log(GCL_DEBUG, "Parent dir is %s", parent);
 
1235
      gconf_log (GCL_DEBUG, "Parent dir is %s", parent);
1013
1236
      
1014
1237
      if (parent != NULL)
1015
1238
        {
1042
1265
 
1043
1266
  gconf_log(GCL_DEBUG, "Making directory %s", dir);
1044
1267
  
1045
 
  if (mkdir(dir, dir_mode) < 0)
 
1268
  if (g_mkdir(dir, dir_mode) < 0)
1046
1269
    {
1047
1270
      if (errno != EEXIST)
1048
1271
        {
1049
1272
          gconf_set_error(err, GCONF_ERROR_FAILED,
1050
 
                          _("Could not make directory `%s': %s"),
1051
 
                          (gchar*)dir, strerror(errno));
 
1273
                          _("Could not make directory \"%s\": %s"),
 
1274
                          (gchar*)dir, g_strerror(errno));
1052
1275
          return FALSE;
1053
1276
        }
1054
1277
    }
1057
1280
    {
1058
1281
      int fd;
1059
1282
      /* don't truncate the file, it may well already exist */
1060
 
      fd = open(xml_filename, O_CREAT | O_WRONLY, file_mode);
 
1283
      fd = g_open(xml_filename, O_CREAT | O_WRONLY, file_mode);
1061
1284
 
1062
1285
      gconf_log(GCL_DEBUG, "Creating XML file %s", xml_filename);
1063
1286
      
1064
1287
      if (fd < 0)
1065
1288
        {
1066
1289
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to create file `%s': %s"),
1067
 
                          xml_filename, strerror(errno));
 
1290
                          xml_filename, g_strerror(errno));
1068
1291
          
1069
1292
          return FALSE;
1070
1293
        }
1072
1295
      if (close(fd) < 0)
1073
1296
        {
1074
1297
          gconf_set_error(err, GCONF_ERROR_FAILED, _("Failed to close file `%s': %s"),
1075
 
                          xml_filename, strerror(errno));
 
1298
                          xml_filename, g_strerror(errno));
1076
1299
          
1077
1300
          return FALSE;
1078
1301
        }
1085
1308
  return TRUE;
1086
1309
}
1087
1310
 
1088
 
static gchar* 
1089
 
parent_dir(const gchar* dir)
 
1311
gchar* 
 
1312
_gconf_parent_dir (const gchar* dir)
1090
1313
{
1091
1314
  /* We assume the dir doesn't have a trailing slash, since that's our
1092
1315
     standard canonicalization in GConf */
1119
1342
  return parent;
1120
1343
}
1121
1344
 
1122
 
 
1123
1345
/* util */
1124
1346
guint
1125
 
mode_t_to_mode(mode_t orig)
 
1347
_gconf_mode_t_to_mode(mode_t orig)
1126
1348
{
1127
1349
  /* I don't think this is portable. */
1128
1350
  guint mode = 0;
1135
1357
 
1136
1358
  return mode;
1137
1359
}
 
1360
 
 
1361
static xmlDocPtr
 
1362
my_xml_parse_file (const char *filename,
 
1363
                   GError    **err)
 
1364
{
 
1365
  char *text;
 
1366
  gsize length;
 
1367
  xmlDocPtr doc;
 
1368
  
 
1369
  text = NULL;
 
1370
  length = 0;
 
1371
  
 
1372
  if (!g_file_get_contents (filename,
 
1373
                            &text,
 
1374
                            &length,
 
1375
                            err))
 
1376
    return NULL;
 
1377
 
 
1378
 
 
1379
  doc = xmlParseMemory (text, length);
 
1380
 
 
1381
  g_free (text);
 
1382
 
 
1383
  if (doc == NULL)
 
1384
    {
 
1385
      g_set_error (err,
 
1386
                   GCONF_ERROR,
 
1387
                   GCONF_ERROR_PARSE_ERROR,
 
1388
                   _("Failed to parse XML file \"%s\""),
 
1389
                   filename);
 
1390
      return NULL;
 
1391
    }
 
1392
  
 
1393
  return doc;
 
1394
}
 
1395
 
 
1396
 
 
1397
void
 
1398
xml_test_dir (void)
 
1399
{
 
1400
#ifndef GCONF_DISABLE_TESTS
 
1401
  
 
1402
 
 
1403
 
 
1404
#endif
 
1405
}