363a278a8d236691ac56f4dcf6ac06e418ee7b5d
[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 error error to be filled in on failure
160  * @returns #FALSE on failure
161  */
162 dbus_bool_t
163 _dbus_string_save_to_file (const DBusString *str,
164                            const DBusString *filename,
165                            DBusError        *error)
166 {
167   int fd;
168   int bytes_to_write;
169   const char *filename_c;
170   DBusString tmp_filename;
171   const char *tmp_filename_c;
172   int total;
173   dbus_bool_t need_unlink;
174   dbus_bool_t retval;
175
176   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
177   
178   fd = -1;
179   retval = FALSE;
180   need_unlink = FALSE;
181   
182   if (!_dbus_string_init (&tmp_filename))
183     {
184       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
185       return FALSE;
186     }
187
188   if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
189     {
190       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
191       _dbus_string_free (&tmp_filename);
192       return FALSE;
193     }
194   
195   if (!_dbus_string_append (&tmp_filename, "."))
196     {
197       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
198       _dbus_string_free (&tmp_filename);
199       return FALSE;
200     }
201
202 #define N_TMP_FILENAME_RANDOM_BYTES 8
203   if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
204     {
205       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
206       _dbus_string_free (&tmp_filename);
207       return FALSE;
208     }
209     
210   filename_c = _dbus_string_get_const_data (filename);
211   tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
212
213   fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
214              0600);
215   if (fd < 0)
216     {
217       dbus_set_error (error, _dbus_error_from_errno (errno),
218                       "Could not create %s: %s", tmp_filename_c,
219                       _dbus_strerror (errno));
220       goto out;
221     }
222
223   _dbus_verbose ("tmp file fd %d opened\n", fd);
224   
225   need_unlink = TRUE;
226   
227   total = 0;
228   bytes_to_write = _dbus_string_get_length (str);
229
230   while (total < bytes_to_write)
231     {
232       int bytes_written;
233
234       bytes_written = _dbus_write (fd, str, total,
235                                    bytes_to_write - total);
236
237       if (bytes_written <= 0)
238         {
239           dbus_set_error (error, _dbus_error_from_errno (errno),
240                           "Could not write to %s: %s", tmp_filename_c,
241                           _dbus_strerror (errno));
242           
243           goto out;
244         }
245
246       total += bytes_written;
247     }
248
249   if (fsync(fd))
250     {
251       dbus_set_error (error, _dbus_error_from_errno (errno),
252                       "Could not synchronize file %s: %s",
253                       tmp_filename_c, _dbus_strerror (errno));
254
255       goto out;
256   }
257
258   if (!_dbus_close (fd, NULL))
259     {
260       dbus_set_error (error, _dbus_error_from_errno (errno),
261                       "Could not close file %s: %s",
262                       tmp_filename_c, _dbus_strerror (errno));
263
264       goto out;
265     }
266
267   fd = -1;
268   
269   if (rename (tmp_filename_c, filename_c) < 0)
270     {
271       dbus_set_error (error, _dbus_error_from_errno (errno),
272                       "Could not rename %s to %s: %s",
273                       tmp_filename_c, filename_c,
274                       _dbus_strerror (errno));
275
276       goto out;
277     }
278
279   need_unlink = FALSE;
280   
281   retval = TRUE;
282   
283  out:
284   /* close first, then unlink, to prevent ".nfs34234235" garbage
285    * files
286    */
287
288   if (fd >= 0)
289     _dbus_close (fd, NULL);
290         
291   if (need_unlink && unlink (tmp_filename_c) < 0)
292     _dbus_verbose ("Failed to unlink temp file %s: %s\n",
293                    tmp_filename_c, _dbus_strerror (errno));
294
295   _dbus_string_free (&tmp_filename);
296
297   if (!retval)
298     _DBUS_ASSERT_ERROR_IS_SET (error);
299   
300   return retval;
301 }
302
303 /** Makes the file readable by every user in the system.
304  *
305  * @param filename the filename
306  * @param error error location
307  * @returns #TRUE if the file's permissions could be changed.
308  */
309 dbus_bool_t
310 _dbus_make_file_world_readable(const DBusString *filename,
311                                DBusError *error)
312 {
313   const char *filename_c;
314
315   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
316
317   filename_c = _dbus_string_get_const_data (filename);
318   if (chmod (filename_c, 0644) == -1)
319     {
320       dbus_set_error (error,
321                       DBUS_ERROR_FAILED,
322                       "Could not change permissions of file %s: %s\n",
323                       filename_c,
324                       _dbus_strerror (errno));
325       return FALSE;
326     }
327   return TRUE;
328 }
329
330 /** Creates the given file, failing if the file already exists.
331  *
332  * @param filename the filename
333  * @param error error location
334  * @returns #TRUE if we created the file and it didn't exist
335  */
336 dbus_bool_t
337 _dbus_create_file_exclusively (const DBusString *filename,
338                                DBusError        *error)
339 {
340   int fd;
341   const char *filename_c;
342
343   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
344   
345   filename_c = _dbus_string_get_const_data (filename);
346   
347   fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
348              0600);
349   if (fd < 0)
350     {
351       dbus_set_error (error,
352                       DBUS_ERROR_FAILED,
353                       "Could not create file %s: %s\n",
354                       filename_c,
355                       _dbus_strerror (errno));
356       return FALSE;
357     }
358
359   _dbus_verbose ("exclusive file fd %d opened\n", fd);
360   
361   if (!_dbus_close (fd, NULL))
362     {
363       dbus_set_error (error,
364                       DBUS_ERROR_FAILED,
365                       "Could not close file %s: %s\n",
366                       filename_c,
367                       _dbus_strerror (errno));
368       return FALSE;
369     }
370   
371   return TRUE;
372 }
373
374 /**
375  * Deletes the given file.
376  *
377  * @param filename the filename
378  * @param error error location
379  * 
380  * @returns #TRUE if unlink() succeeded
381  */
382 dbus_bool_t
383 _dbus_delete_file (const DBusString *filename,
384                    DBusError        *error)
385 {
386   const char *filename_c;
387
388   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
389   
390   filename_c = _dbus_string_get_const_data (filename);
391
392   if (unlink (filename_c) < 0)
393     {
394       dbus_set_error (error, DBUS_ERROR_FAILED,
395                       "Failed to delete file %s: %s\n",
396                       filename_c, _dbus_strerror (errno));
397       return FALSE;
398     }
399   else
400     return TRUE;
401 }