~ubuntu-branches/ubuntu/oneiric/gimp/oneiric-security

1.1.4 by Daniel Holbach
Import upstream version 2.3.16
1
/* LIBGIMP - The GIMP Library
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
 *
4
 * GimpConfigWriter
5
 * Copyright (C) 2003  Sven Neumann <sven@gimp.org>
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Library General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the
19
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
 * Boston, MA 02111-1307, USA.
21
 */
22
23
#include "config.h"
24
25
#include <errno.h>
26
#include <fcntl.h>
27
#include <string.h>
28
29
#ifdef HAVE_UNISTD_H
30
#include <unistd.h>
31
#endif
32
33
#include <sys/types.h>
34
35
#include <glib-object.h>
36
#include <glib/gstdio.h>
37
38
#ifdef G_OS_WIN32
39
#include <io.h>
40
#endif
41
42
#include "libgimpbase/gimpbase.h"
43
44
#include "gimpconfigtypes.h"
45
46
#include "gimpconfigwriter.h"
47
#include "gimpconfig-iface.h"
48
#include "gimpconfig-error.h"
49
#include "gimpconfig-serialize.h"
50
#include "gimpconfig-utils.h"
51
52
#include "libgimp/libgimp-intl.h"
53
54
55
struct _GimpConfigWriter
56
{
57
  gint      fd;
58
  gchar    *filename;
59
  gchar    *tmpname;
60
  GError   *error;
61
  GString  *buffer;
62
  gboolean  comment;
63
  gint      depth;
64
  gint      marker;
65
};
66
67
68
static inline void  gimp_config_writer_flush      (GimpConfigWriter  *writer);
69
static inline void  gimp_config_writer_newline    (GimpConfigWriter  *writer);
70
static gboolean     gimp_config_writer_close_file (GimpConfigWriter  *writer,
71
                                                   GError           **error);
72
73
static inline void
74
gimp_config_writer_flush (GimpConfigWriter *writer)
75
{
76
  if (write (writer->fd, writer->buffer->str, writer->buffer->len) < 0)
77
    g_set_error (&writer->error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_WRITE,
1.1.6 by Steve Kowalik
Import upstream version 2.4.0~rc2
78
                 _("Error writing to '%s': %s"),
79
                 gimp_filename_to_utf8 (writer->filename), g_strerror (errno));
1.1.4 by Daniel Holbach
Import upstream version 2.3.16
80
81
  g_string_truncate (writer->buffer, 0);
82
}
83
84
static inline void
85
gimp_config_writer_newline (GimpConfigWriter *writer)
86
{
87
  gint i;
88
89
  g_string_append_c (writer->buffer, '\n');
90
91
  if (writer->comment)
92
    g_string_append_len (writer->buffer, "# ", 2);
93
94
  for (i = 0; i < writer->depth; i++)
95
    g_string_append_len (writer->buffer, "    ", 4);
96
}
97
98
/**
99
 * gimp_config_writer_new_file:
100
 * @filename: a filename
101
 * @atomic: if %TRUE the file is written atomically
102
 * @header: text to include as comment at the top of the file
103
 * @error: return location for errors
104
 *
105
 * Creates a new #GimpConfigWriter and sets it up to write to
106
 * @filename. If @atomic is %TRUE, a temporary file is used to avoid
107
 * possible race conditions. The temporary file is then moved to
108
 * @filename when the writer is closed.
109
 *
110
 * Return value: a new #GimpConfigWriter or %NULL in case of an error
111
 *
112
 * Since: GIMP 2.4
113
 **/
114
GimpConfigWriter *
115
gimp_config_writer_new_file (const gchar  *filename,
116
                             gboolean      atomic,
117
                             const gchar  *header,
118
                             GError      **error)
119
{
120
  GimpConfigWriter *writer;
121
  gchar            *tmpname = NULL;
122
  gint              fd;
123
124
  g_return_val_if_fail (filename != NULL, NULL);
125
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
126
127
  if (atomic)
128
    {
129
      tmpname = g_strconcat (filename, "XXXXXX", NULL);
130
131
      fd = g_mkstemp (tmpname);
132
133
      if (fd == -1)
134
        {
135
          g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_WRITE,
136
                       _("Could not create temporary file for '%s': %s"),
137
                       gimp_filename_to_utf8 (filename), g_strerror (errno));
138
          g_free (tmpname);
139
          return NULL;
140
        }
141
    }
142
  else
143
    {
144
      fd = g_creat (filename, 0644);
145
146
      if (fd == -1)
147
        {
148
          g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_WRITE,
149
                       _("Could not open '%s' for writing: %s"),
150
                       gimp_filename_to_utf8 (filename), g_strerror (errno));
151
          return NULL;
152
        }
153
    }
154
1.1.5 by Daniel Holbach
Import upstream version 2.3.18
155
  writer = g_slice_new0 (GimpConfigWriter);
1.1.4 by Daniel Holbach
Import upstream version 2.3.16
156
157
  writer->fd       = fd;
158
  writer->filename = g_strdup (filename);
159
  writer->tmpname  = tmpname;
160
  writer->buffer   = g_string_new (NULL);
161
162
  if (header)
163
    {
164
      gimp_config_writer_comment (writer, header);
165
      gimp_config_writer_linefeed (writer);
166
    }
167
168
  return writer;
169
}
170
171
/**
172
 * gimp_config_writer_new_fd:
173
 * @fd:
174
 *
175
 * Return value: a new #GimpConfigWriter or %NULL in case of an error
176
 *
177
 * Since: GIMP 2.4
178
 **/
179
GimpConfigWriter *
180
gimp_config_writer_new_fd (gint fd)
181
{
182
  GimpConfigWriter *writer;
183
184
  g_return_val_if_fail (fd > 0, NULL);
185
1.1.5 by Daniel Holbach
Import upstream version 2.3.18
186
  writer = g_slice_new0 (GimpConfigWriter);
1.1.4 by Daniel Holbach
Import upstream version 2.3.16
187
188
  writer->fd     = fd;
189
  writer->buffer = g_string_new (NULL);
190
191
  return writer;
192
}
193
194
/**
195
 * gimp_config_writer_new_string:
196
 * @string:
197
 *
198
 * Return value: a new #GimpConfigWriter or %NULL in case of an error
199
 *
200
 * Since: GIMP 2.4
201
 **/
202
GimpConfigWriter *
203
gimp_config_writer_new_string (GString *string)
204
{
205
  GimpConfigWriter *writer;
206
207
  g_return_val_if_fail (string != NULL, NULL);
208
1.1.5 by Daniel Holbach
Import upstream version 2.3.18
209
  writer = g_slice_new0 (GimpConfigWriter);
1.1.4 by Daniel Holbach
Import upstream version 2.3.16
210
211
  writer->buffer = string;
212
213
  return writer;
214
}
215
216
/**
217
 * gimp_config_writer_comment_mode:
218
 * @writer: a #GimpConfigWriter
219
 * @enable: %TRUE to enable comment mode, %FALSE to disable it
220
 *
221
 * This function toggles whether the @writer should create commented
222
 * or uncommented output. This feature is used to generate the
223
 * system-wide installed gimprc that documents the default settings.
224
 *
225
 * Since comments have to start at the beginning of a line, this
226
 * funtion will insert a newline if necessary.
227
 *
228
 * Since: GIMP 2.4
229
 **/
230
void
231
gimp_config_writer_comment_mode (GimpConfigWriter *writer,
232
                                 gboolean          enable)
233
{
234
  g_return_if_fail (writer != NULL);
235
236
  if (writer->error)
237
    return;
238
239
  enable = (enable ? TRUE : FALSE);
240
241
  if (writer->comment == enable)
242
    return;
243
244
  writer->comment = enable;
245
246
  if (enable)
247
    {
248
     if (writer->buffer->len == 0)
249
       g_string_append_len (writer->buffer, "# ", 2);
250
     else
251
       gimp_config_writer_newline (writer);
252
    }
253
}
254
255
256
/**
257
 * gimp_config_writer_open:
258
 * @writer: a #GimpConfigWriter
259
 * @name: name of the element to open
260
 *
261
 * This function writes the opening parenthese followed by @name.
262
 * It also increases the indentation level and sets a mark that
263
 * can be used by gimp_config_writer_revert().
264
 *
265
 * Since: GIMP 2.4
266
 **/
267
void
268
gimp_config_writer_open (GimpConfigWriter *writer,
269
                         const gchar      *name)
270
{
271
  g_return_if_fail (writer != NULL);
272
  g_return_if_fail (name != NULL);
273
274
  if (writer->error)
275
    return;
276
277
  /* store the current buffer length so we can revert to this state */
278
  writer->marker = writer->buffer->len;
279
280
  if (writer->depth > 0)
281
    gimp_config_writer_newline (writer);
282
283
  writer->depth++;
284
285
  g_string_append_printf (writer->buffer, "(%s", name);
286
}
287
288
/**
289
 * gimp_config_writer_print:
290
 * @writer: a #GimpConfigWriter
291
 * @string: a string to write
292
 * @len: number of bytes from @string or -1 if @string is NUL-terminated.
293
 *
294
 * Appends a space followed by @string to the @writer. Note that string
295
 * must not contain any special characters that might need to be escaped.
296
 *
297
 * Since: GIMP 2.4
298
 **/
299
void
300
gimp_config_writer_print (GimpConfigWriter  *writer,
301
                          const gchar       *string,
302
                          gint               len)
303
{
304
  g_return_if_fail (writer != NULL);
305
  g_return_if_fail (len == 0 || string != NULL);
306
307
  if (writer->error)
308
    return;
309
310
  if (len < 0)
311
    len = strlen (string);
312
313
  if (len)
314
    {
315
      g_string_append_c (writer->buffer, ' ');
316
      g_string_append_len (writer->buffer, string, len);
317
    }
318
}
319
320
/**
321
 * gimp_config_writer_printf:
322
 * @writer: a #GimpConfigWriter
323
 * @format: a format string as described for g_strdup_printf().
324
 * @Varargs: list of arguments according to @format
325
 *
326
 * A printf-like function for #GimpConfigWriter.
327
 *
328
 * Since: GIMP 2.4
329
 **/
330
void
331
gimp_config_writer_printf (GimpConfigWriter *writer,
332
                           const gchar      *format,
333
                           ...)
334
{
335
  gchar   *buffer;
336
  va_list  args;
337
338
  g_return_if_fail (writer != NULL);
339
  g_return_if_fail (format != NULL);
340
341
  if (writer->error)
342
    return;
343
344
  va_start (args, format);
345
  buffer = g_strdup_vprintf (format, args);
346
  va_end (args);
347
348
  g_string_append_c (writer->buffer, ' ');
349
  g_string_append (writer->buffer, buffer);
350
351
  g_free (buffer);
352
}
353
354
/**
355
 * gimp_config_writer_string:
356
 * @writer: a #GimpConfigWriter
357
 * @string: a NUL-terminated string
358
 *
359
 * Writes a string value to @writer. The @string is quoted and special
360
 * characters are escaped.
361
 *
362
 * Since: GIMP 2.4
363
 **/
364
void
365
gimp_config_writer_string (GimpConfigWriter *writer,
366
                           const gchar      *string)
367
{
368
  g_return_if_fail (writer != NULL);
369
370
  if (writer->error)
371
    return;
372
373
  g_string_append_c (writer->buffer, ' ');
374
  gimp_config_string_append_escaped (writer->buffer, string);
375
}
376
377
/**
378
 * gimp_config_writer_identifier:
379
 * @writer:     a #GimpConfigWriter
380
 * @identifier: a NUL-terminated string
381
 *
382
 * Writes an identifier to @writer. The @string is *not* quoted and special
383
 * characters are *not* escaped.
384
 *
385
 * Since: GIMP 2.4
386
 **/
387
void
388
gimp_config_writer_identifier (GimpConfigWriter *writer,
389
                               const gchar      *identifier)
390
{
391
  g_return_if_fail (writer != NULL);
392
  g_return_if_fail (identifier != NULL);
393
394
  if (writer->error)
395
    return;
396
397
  g_string_append_printf (writer->buffer, " %s", identifier);
398
}
399
400
401
/**
402
 * gimp_config_writer_data:
403
 * @writer: a #GimpConfigWriter
404
 * @length:
405
 * @data:
406
 *
407
 * Since: GIMP 2.4
408
 **/
409
void
410
gimp_config_writer_data (GimpConfigWriter *writer,
411
                         gint              length,
412
                         const guint8     *data)
413
{
414
  gint i;
415
416
  g_return_if_fail (writer != NULL);
417
  g_return_if_fail (length > 0);
418
  g_return_if_fail (data != NULL);
419
420
  if (writer->error)
421
    return;
422
423
  g_string_append (writer->buffer, " \"");
424
425
  for (i = 0; i < length; i++)
426
    {
427
      if (g_ascii_isalpha (data[i]))
428
        g_string_append_c (writer->buffer, data[i]);
429
      else
430
        g_string_append_printf (writer->buffer, "\\%o", data[i]);
431
    }
432
433
  g_string_append (writer->buffer, "\"");
434
}
435
436
/**
437
 * gimp_config_writer_revert:
438
 * @writer: a #GimpConfigWriter
439
 *
440
 * Reverts all changes to @writer that were done since the last call
441
 * to gimp_config_writer_open(). This can only work if you didn't call
442
 * gimp_config_writer_close() yet.
443
 *
444
 * Since: GIMP 2.4
445
 **/
446
void
447
gimp_config_writer_revert (GimpConfigWriter *writer)
448
{
449
  g_return_if_fail (writer != NULL);
450
451
  if (writer->error)
452
    return;
453
454
  g_return_if_fail (writer->depth > 0);
455
  g_return_if_fail (writer->marker != -1);
456
457
  g_string_truncate (writer->buffer, writer->marker);
458
459
  writer->depth--;
460
  writer->marker = -1;
461
}
462
463
/**
464
 * gimp_config_writer_close:
465
 * @writer: a #GimpConfigWriter
466
 *
467
 * Closes an element opened with gimp_config_writer_open().
468
 *
469
 * Since: GIMP 2.4
470
 **/
471
void
472
gimp_config_writer_close (GimpConfigWriter *writer)
473
{
474
  g_return_if_fail (writer != NULL);
475
476
  if (writer->error)
477
    return;
478
479
  g_return_if_fail (writer->depth > 0);
480
481
  g_string_append_c (writer->buffer, ')');
482
483
  if (--writer->depth == 0)
484
    {
485
      g_string_append_c (writer->buffer, '\n');
486
487
      if (writer->fd)
488
        gimp_config_writer_flush (writer);
489
    }
490
}
491
492
/**
493
 * gimp_config_writer_finish:
494
 * @writer: a #GimpConfigWriter
495
 * @footer: text to include as comment at the bottom of the file
496
 * @error: return location for possible errors
497
 *
498
 * This function finishes the work of @writer and frees it afterwards.
499
 * It closes all open elements, appends an optional comment and
500
 * releases all resources allocated by @writer. You must not access
501
 * the @writer afterwards.
502
 *
503
 * Return value: %TRUE if everything could be successfully written,
504
 *               %FALSE otherwise
505
 *
506
 * Since: GIMP 2.4
507
 **/
508
gboolean
509
gimp_config_writer_finish (GimpConfigWriter  *writer,
510
                           const gchar       *footer,
511
                           GError           **error)
512
{
513
  gboolean success = TRUE;
514
515
  g_return_val_if_fail (writer != NULL, FALSE);
516
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
517
518
  if (writer->depth < 0)
519
    {
520
      g_warning ("gimp_config_writer_finish: depth < 0 !!");
521
    }
522
  else
523
    {
524
      while (writer->depth)
525
        gimp_config_writer_close (writer);
526
    }
527
528
  if (footer)
529
    {
530
      gimp_config_writer_linefeed (writer);
531
      gimp_config_writer_comment (writer, footer);
532
    }
533
534
  if (writer->fd)
535
    {
536
      success = gimp_config_writer_close_file (writer, error);
537
538
      g_free (writer->filename);
539
      g_free (writer->tmpname);
540
541
      g_string_free (writer->buffer, TRUE);
542
    }
543
  else
544
    {
545
      success = TRUE;
546
    }
547
1.1.6 by Steve Kowalik
Import upstream version 2.4.0~rc2
548
  if (writer->error)
549
    {
550
      g_propagate_error (error, writer->error);
551
      success = FALSE;
552
    }
553
1.1.5 by Daniel Holbach
Import upstream version 2.3.18
554
  g_slice_free (GimpConfigWriter, writer);
1.1.4 by Daniel Holbach
Import upstream version 2.3.16
555
556
  return success;
557
}
558
559
void
560
gimp_config_writer_linefeed (GimpConfigWriter *writer)
561
{
562
  g_return_if_fail (writer != NULL);
563
564
  if (writer->error)
565
    return;
566
567
  if (writer->buffer->len == 0 && !writer->comment)
568
    {
569
      if (write (writer->fd, "\n", 1) < 0)
570
        g_set_error (&writer->error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_WRITE,
571
                     g_strerror (errno));
572
    }
573
  else
574
    {
575
      gimp_config_writer_newline (writer);
576
    }
577
}
578
579
/**
580
 * gimp_config_writer_comment:
581
 * @writer: a #GimpConfigWriter
582
 * @comment: the comment to write (ASCII only)
583
 *
584
 * Appends the @comment to @str and inserts linebreaks and hash-marks to
585
 * format it as a comment. Note that this function does not handle non-ASCII
586
 * characters.
587
 *
588
 * Since: GIMP 2.4
589
 **/
590
void
591
gimp_config_writer_comment (GimpConfigWriter *writer,
592
                            const gchar      *comment)
593
{
594
  const gchar *s;
595
  gboolean     comment_mode;
596
  gint         i, len, space;
597
598
#define LINE_LENGTH 75
599
600
  g_return_if_fail (writer != NULL);
601
602
  if (writer->error)
603
    return;
604
605
  g_return_if_fail (writer->depth == 0);
606
607
  if (!comment)
608
    return;
609
610
  comment_mode = writer->comment;
611
  gimp_config_writer_comment_mode (writer, TRUE);
612
613
  len = strlen (comment);
614
615
  while (len > 0)
616
    {
617
      for (s = comment, i = 0, space = 0;
618
           *s != '\n' && (i <= LINE_LENGTH || space == 0) && i < len;
619
           s++, i++)
620
        {
621
          if (g_ascii_isspace (*s))
622
            space = i;
623
        }
624
625
      if (i > LINE_LENGTH && space && *s != '\n')
626
        i = space;
627
628
      g_string_append_len (writer->buffer, comment, i);
629
630
      i++;
631
632
      comment += i;
633
      len     -= i;
634
635
      if (len > 0)
636
        gimp_config_writer_newline (writer);
637
    }
638
639
  gimp_config_writer_comment_mode (writer, comment_mode);
640
  gimp_config_writer_newline (writer);
641
642
  if (writer->depth == 0)
643
    gimp_config_writer_flush (writer);
644
645
#undef LINE_LENGTH
646
}
647
648
static gboolean
649
gimp_config_writer_close_file (GimpConfigWriter  *writer,
650
                               GError           **error)
651
{
652
  g_return_val_if_fail (writer->fd != 0, FALSE);
653
654
  if (! writer->filename)
655
    return TRUE;
656
657
  if (writer->error)
658
    {
659
      close (writer->fd);
660
661
      if (writer->tmpname)
662
        g_unlink (writer->tmpname);
663
1.1.6 by Steve Kowalik
Import upstream version 2.4.0~rc2
664
      return FALSE;
1.1.4 by Daniel Holbach
Import upstream version 2.3.16
665
    }
666
667
  if (close (writer->fd) != 0)
668
    {
669
      if (writer->tmpname)
670
        {
671
          if (g_file_test (writer->filename, G_FILE_TEST_EXISTS))
672
            {
673
              g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_WRITE,
674
                           _("Error writing to temporary file for '%s': %s\n"
675
                             "The original file has not been touched."),
676
                           gimp_filename_to_utf8 (writer->filename),
677
                           g_strerror (errno));
678
            }
679
          else
680
            {
681
              g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_WRITE,
682
                           _("Error writing to temporary file for '%s': %s\n"
683
                             "No file has been created."),
684
                           gimp_filename_to_utf8 (writer->filename),
685
                           g_strerror (errno));
686
            }
687
688
          g_unlink (writer->tmpname);
689
        }
690
      else
691
        {
692
          g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_WRITE,
693
                       _("Error writing to '%s': %s"),
694
                       gimp_filename_to_utf8 (writer->filename),
695
                       g_strerror (errno));
696
        }
697
698
      return FALSE;
699
    }
700
701
  if (writer->tmpname)
702
    {
703
#ifdef G_OS_WIN32
704
      /* win32 rename can't overwrite */
705
      g_unlink (writer->filename);
706
#endif
707
708
      if (g_rename (writer->tmpname, writer->filename) == -1)
709
        {
710
          g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_WRITE,
711
                       _("Could not create '%s': %s"),
712
                       gimp_filename_to_utf8 (writer->filename),
713
                       g_strerror (errno));
714
715
          g_unlink (writer->tmpname);
716
          return FALSE;
717
        }
718
    }
719
720
  return TRUE;
721
}