Fix syslog string processing
[platform/upstream/dbus.git] / dbus / dbus-file-unix.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-file-unix.c unix related file implementation (internal to D-Bus implementation)
3  * 
4  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
5  * Copyright (C) 2003 CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #include <config.h>
26
27 #include "dbus-protocol.h"
28 #include "dbus-errors.h"
29 #include "dbus-file.h"
30 #include "dbus-internals.h"
31 #include "dbus-sysdeps.h"
32 #include "dbus-sysdeps-unix.h"
33
34 #include <sys/stat.h>
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <errno.h>
39
40 #ifndef O_BINARY
41 #define O_BINARY 0
42 #endif
43
44 /**
45  * Appends the contents of the given file to the string,
46  * returning error code. At the moment, won't open a file
47  * more than a megabyte in size.
48  *
49  * @param str the string to append to
50  * @param filename filename to load
51  * @param error place to set an error
52  * @returns #FALSE if error was set
53  */
54 dbus_bool_t
55 _dbus_file_get_contents (DBusString       *str,
56                          const DBusString *filename,
57                          DBusError        *error)
58 {
59   int fd;
60   struct stat sb;
61   int orig_len;
62   int total;
63   const char *filename_c;
64
65   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
66   
67   filename_c = _dbus_string_get_const_data (filename);
68   
69   /* O_BINARY useful on Cygwin */
70   fd = open (filename_c, O_RDONLY | O_BINARY);
71   if (fd < 0)
72     {
73       dbus_set_error (error, _dbus_error_from_errno (errno),
74                       "Failed to open \"%s\": %s",
75                       filename_c,
76                       _dbus_strerror (errno));
77       return FALSE;
78     }
79
80   _dbus_verbose ("file fd %d opened\n", fd);
81   
82   if (fstat (fd, &sb) < 0)
83     {
84       dbus_set_error (error, _dbus_error_from_errno (errno),
85                       "Failed to stat \"%s\": %s",
86                       filename_c,
87                       _dbus_strerror (errno));
88
89       _dbus_verbose ("fstat() failed: %s",
90                      _dbus_strerror (errno));
91       
92       _dbus_close (fd, NULL);
93       
94       return FALSE;
95     }
96
97   if (sb.st_size > _DBUS_ONE_MEGABYTE)
98     {
99       dbus_set_error (error, DBUS_ERROR_FAILED,
100                       "File size %lu of \"%s\" is too large.",
101                       (unsigned long) sb.st_size, filename_c);
102       _dbus_close (fd, NULL);
103       return FALSE;
104     }
105   
106   total = 0;
107   orig_len = _dbus_string_get_length (str);
108   if (sb.st_size > 0 && S_ISREG (sb.st_mode))
109     {
110       int bytes_read;
111
112       while (total < (int) sb.st_size)
113         {
114           bytes_read = _dbus_read (fd, str,
115                                    sb.st_size - total);
116           if (bytes_read <= 0)
117             {
118               dbus_set_error (error, _dbus_error_from_errno (errno),
119                               "Error reading \"%s\": %s",
120                               filename_c,
121                               _dbus_strerror (errno));
122
123               _dbus_verbose ("read() failed: %s",
124                              _dbus_strerror (errno));
125               
126               _dbus_close (fd, NULL);
127               _dbus_string_set_length (str, orig_len);
128               return FALSE;
129             }
130           else
131             total += bytes_read;
132         }
133
134       _dbus_close (fd, NULL);
135       return TRUE;
136     }
137   else if (sb.st_size != 0)
138     {
139       _dbus_verbose ("Can only open regular files at the moment.\n");
140       dbus_set_error (error, DBUS_ERROR_FAILED,
141                       "\"%s\" is not a regular file",
142                       filename_c);
143       _dbus_close (fd, NULL);
144       return FALSE;
145     }
146   else
147     {
148       _dbus_close (fd, NULL);
149       return TRUE;
150     }
151 }
152
153 /**
154  * Writes a string out to a file. If the file exists,
155  * it will be atomically overwritten by the new data.
156  *
157  * @param str the string to write out
158  * @param filename the file to save string to
159  * @param world_readable If set, ensure the file is world readable
160  * @param error error to be filled in on failure
161  * @returns #FALSE on failure
162  */
163 dbus_bool_t
164 _dbus_string_save_to_file (const DBusString *str,
165                            const DBusString *filename,
166                            dbus_bool_t      world_readable,
167                            DBusError        *error)
168 {
169   int fd;
170   int bytes_to_write;
171   const char *filename_c;
172   DBusString tmp_filename;
173   const char *tmp_filename_c;
174   int total;
175   dbus_bool_t need_unlink;
176   dbus_bool_t retval;
177
178   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
179   
180   fd = -1;
181   retval = FALSE;
182   need_unlink = FALSE;
183   
184   if (!_dbus_string_init (&tmp_filename))
185     {
186       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
187       return FALSE;
188     }
189
190   if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
191     {
192       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
193       _dbus_string_free (&tmp_filename);
194       return FALSE;
195     }
196   
197   if (!_dbus_string_append (&tmp_filename, "."))
198     {
199       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
200       _dbus_string_free (&tmp_filename);
201       return FALSE;
202     }
203
204 #define N_TMP_FILENAME_RANDOM_BYTES 8
205   if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
206     {
207       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
208       _dbus_string_free (&tmp_filename);
209       return FALSE;
210     }
211     
212   filename_c = _dbus_string_get_const_data (filename);
213   tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
214
215   fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
216              world_readable ? 0644 : 0600);
217   if (fd < 0)
218     {
219       dbus_set_error (error, _dbus_error_from_errno (errno),
220                       "Could not create %s: %s", tmp_filename_c,
221                       _dbus_strerror (errno));
222       goto out;
223     }
224   if (world_readable)
225     {
226       /* Ensure the file is world readable even in the presence of
227        * possibly restrictive umasks;
228        * see http://lists.freedesktop.org/archives/dbus/2010-September/013367.html
229        */
230       if (fchmod (fd, 0644) < 0)
231         {
232           dbus_set_error (error, _dbus_error_from_errno (errno),
233                           "Could not chmod %s: %s", tmp_filename_c,
234                           _dbus_strerror (errno));
235           goto out;
236         }
237     }
238
239   _dbus_verbose ("tmp file fd %d opened\n", fd);
240   
241   need_unlink = TRUE;
242   
243   total = 0;
244   bytes_to_write = _dbus_string_get_length (str);
245
246   while (total < bytes_to_write)
247     {
248       int bytes_written;
249
250       bytes_written = _dbus_write (fd, str, total,
251                                    bytes_to_write - total);
252
253       if (bytes_written <= 0)
254         {
255           dbus_set_error (error, _dbus_error_from_errno (errno),
256                           "Could not write to %s: %s", tmp_filename_c,
257                           _dbus_strerror (errno));
258           
259           goto out;
260         }
261
262       total += bytes_written;
263     }
264
265   if (fsync(fd))
266     {
267       dbus_set_error (error, _dbus_error_from_errno (errno),
268                       "Could not synchronize file %s: %s",
269                       tmp_filename_c, _dbus_strerror (errno));
270
271       goto out;
272   }
273
274   if (!_dbus_close (fd, NULL))
275     {
276       dbus_set_error (error, _dbus_error_from_errno (errno),
277                       "Could not close file %s: %s",
278                       tmp_filename_c, _dbus_strerror (errno));
279
280       goto out;
281     }
282
283   fd = -1;
284   
285   if (rename (tmp_filename_c, filename_c) < 0)
286     {
287       dbus_set_error (error, _dbus_error_from_errno (errno),
288                       "Could not rename %s to %s: %s",
289                       tmp_filename_c, filename_c,
290                       _dbus_strerror (errno));
291
292       goto out;
293     }
294
295   need_unlink = FALSE;
296   
297   retval = TRUE;
298   
299  out:
300   /* close first, then unlink, to prevent ".nfs34234235" garbage
301    * files
302    */
303
304   if (fd >= 0)
305     _dbus_close (fd, NULL);
306         
307   if (need_unlink && unlink (tmp_filename_c) < 0)
308     _dbus_verbose ("Failed to unlink temp file %s: %s\n",
309                    tmp_filename_c, _dbus_strerror (errno));
310
311   _dbus_string_free (&tmp_filename);
312
313   if (!retval)
314     _DBUS_ASSERT_ERROR_IS_SET (error);
315   
316   return retval;
317 }
318
319 /** Makes the file readable by every user in the system.
320  *
321  * @param filename the filename
322  * @param error error location
323  * @returns #TRUE if the file's permissions could be changed.
324  */
325 dbus_bool_t
326 _dbus_make_file_world_readable(const DBusString *filename,
327                                DBusError *error)
328 {
329   const char *filename_c;
330
331   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
332
333   filename_c = _dbus_string_get_const_data (filename);
334   if (chmod (filename_c, 0644) == -1)
335     {
336       dbus_set_error (error,
337                       DBUS_ERROR_FAILED,
338                       "Could not change permissions of file %s: %s\n",
339                       filename_c,
340                       _dbus_strerror (errno));
341       return FALSE;
342     }
343   return TRUE;
344 }
345
346 /** Creates the given file, failing if the file already exists.
347  *
348  * @param filename the filename
349  * @param error error location
350  * @returns #TRUE if we created the file and it didn't exist
351  */
352 dbus_bool_t
353 _dbus_create_file_exclusively (const DBusString *filename,
354                                DBusError        *error)
355 {
356   int fd;
357   const char *filename_c;
358
359   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
360   
361   filename_c = _dbus_string_get_const_data (filename);
362   
363   fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
364              0600);
365   if (fd < 0)
366     {
367       dbus_set_error (error,
368                       DBUS_ERROR_FAILED,
369                       "Could not create file %s: %s\n",
370                       filename_c,
371                       _dbus_strerror (errno));
372       return FALSE;
373     }
374
375   _dbus_verbose ("exclusive file fd %d opened\n", fd);
376   
377   if (!_dbus_close (fd, NULL))
378     {
379       dbus_set_error (error,
380                       DBUS_ERROR_FAILED,
381                       "Could not close file %s: %s\n",
382                       filename_c,
383                       _dbus_strerror (errno));
384       return FALSE;
385     }
386   
387   return TRUE;
388 }
389
390 /**
391  * Deletes the given file.
392  *
393  * @param filename the filename
394  * @param error error location
395  * 
396  * @returns #TRUE if unlink() succeeded
397  */
398 dbus_bool_t
399 _dbus_delete_file (const DBusString *filename,
400                    DBusError        *error)
401 {
402   const char *filename_c;
403
404   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
405   
406   filename_c = _dbus_string_get_const_data (filename);
407
408   if (unlink (filename_c) < 0)
409     {
410       dbus_set_error (error, DBUS_ERROR_FAILED,
411                       "Failed to delete file %s: %s\n",
412                       filename_c, _dbus_strerror (errno));
413       return FALSE;
414     }
415   else
416     return TRUE;
417 }