95582d5cb0b5d0c38f81284a2c16052e98260159
[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 #include "dbus-file.h"
27
28 /**
29  * Appends the contents of the given file to the string,
30  * returning error code. At the moment, won't open a file
31  * more than a megabyte in size.
32  *
33  * @param str the string to append to
34  * @param filename filename to load
35  * @param error place to set an error
36  * @returns #FALSE if error was set
37  */
38 dbus_bool_t
39 _dbus_file_get_contents (DBusString       *str,
40                          const DBusString *filename,
41                          DBusError        *error)
42 {
43   int fd;
44   struct stat sb;
45   int orig_len;
46   int total;
47   const char *filename_c;
48
49   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
50   
51   filename_c = _dbus_string_get_const_data (filename);
52   
53   /* O_BINARY useful on Cygwin */
54   fd = open (filename_c, O_RDONLY | O_BINARY);
55   if (fd < 0)
56     {
57       dbus_set_error (error, _dbus_error_from_errno (errno),
58                       "Failed to open \"%s\": %s",
59                       filename_c,
60                       _dbus_strerror (errno));
61       return FALSE;
62     }
63
64   _dbus_verbose ("file fd %d opened\n", fd);
65   
66   if (fstat (fd, &sb) < 0)
67     {
68       dbus_set_error (error, _dbus_error_from_errno (errno),
69                       "Failed to stat \"%s\": %s",
70                       filename_c,
71                       _dbus_strerror (errno));
72
73       _dbus_verbose ("fstat() failed: %s",
74                      _dbus_strerror (errno));
75       
76       _dbus_close (fd, NULL);
77       
78       return FALSE;
79     }
80
81   if (sb.st_size > _DBUS_ONE_MEGABYTE)
82     {
83       dbus_set_error (error, DBUS_ERROR_FAILED,
84                       "File size %lu of \"%s\" is too large.",
85                       (unsigned long) sb.st_size, filename_c);
86       _dbus_close (fd, NULL);
87       return FALSE;
88     }
89   
90   total = 0;
91   orig_len = _dbus_string_get_length (str);
92   if (sb.st_size > 0 && S_ISREG (sb.st_mode))
93     {
94       int bytes_read;
95
96       while (total < (int) sb.st_size)
97         {
98           bytes_read = _dbus_read (fd, str,
99                                    sb.st_size - total);
100           if (bytes_read <= 0)
101             {
102               dbus_set_error (error, _dbus_error_from_errno (errno),
103                               "Error reading \"%s\": %s",
104                               filename_c,
105                               _dbus_strerror (errno));
106
107               _dbus_verbose ("read() failed: %s",
108                              _dbus_strerror (errno));
109               
110               _dbus_close (fd, NULL);
111               _dbus_string_set_length (str, orig_len);
112               return FALSE;
113             }
114           else
115             total += bytes_read;
116         }
117
118       _dbus_close (fd, NULL);
119       return TRUE;
120     }
121   else if (sb.st_size != 0)
122     {
123       _dbus_verbose ("Can only open regular files at the moment.\n");
124       dbus_set_error (error, DBUS_ERROR_FAILED,
125                       "\"%s\" is not a regular file",
126                       filename_c);
127       _dbus_close (fd, NULL);
128       return FALSE;
129     }
130   else
131     {
132       _dbus_close (fd, NULL);
133       return TRUE;
134     }
135 }
136
137 /**
138  * Writes a string out to a file. If the file exists,
139  * it will be atomically overwritten by the new data.
140  *
141  * @param str the string to write out
142  * @param filename the file to save string to
143  * @param error error to be filled in on failure
144  * @returns #FALSE on failure
145  */
146 dbus_bool_t
147 _dbus_string_save_to_file (const DBusString *str,
148                            const DBusString *filename,
149                            DBusError        *error)
150 {
151   int fd;
152   int bytes_to_write;
153   const char *filename_c;
154   DBusString tmp_filename;
155   const char *tmp_filename_c;
156   int total;
157   dbus_bool_t need_unlink;
158   dbus_bool_t retval;
159
160   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
161   
162   fd = -1;
163   retval = FALSE;
164   need_unlink = FALSE;
165   
166   if (!_dbus_string_init (&tmp_filename))
167     {
168       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
169       return FALSE;
170     }
171
172   if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
173     {
174       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
175       _dbus_string_free (&tmp_filename);
176       return FALSE;
177     }
178   
179   if (!_dbus_string_append (&tmp_filename, "."))
180     {
181       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
182       _dbus_string_free (&tmp_filename);
183       return FALSE;
184     }
185
186 #define N_TMP_FILENAME_RANDOM_BYTES 8
187   if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
188     {
189       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
190       _dbus_string_free (&tmp_filename);
191       return FALSE;
192     }
193     
194   filename_c = _dbus_string_get_const_data (filename);
195   tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
196
197   fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
198              0600);
199   if (fd < 0)
200     {
201       dbus_set_error (error, _dbus_error_from_errno (errno),
202                       "Could not create %s: %s", tmp_filename_c,
203                       _dbus_strerror (errno));
204       goto out;
205     }
206
207   _dbus_verbose ("tmp file fd %d opened\n", fd);
208   
209   need_unlink = TRUE;
210   
211   total = 0;
212   bytes_to_write = _dbus_string_get_length (str);
213
214   while (total < bytes_to_write)
215     {
216       int bytes_written;
217
218       bytes_written = _dbus_write (fd, str, total,
219                                    bytes_to_write - total);
220
221       if (bytes_written <= 0)
222         {
223           dbus_set_error (error, _dbus_error_from_errno (errno),
224                           "Could not write to %s: %s", tmp_filename_c,
225                           _dbus_strerror (errno));
226           
227           goto out;
228         }
229
230       total += bytes_written;
231     }
232
233   if (fsync(fd))
234     {
235       dbus_set_error (error, _dbus_error_from_errno (errno),
236                       "Could not synchronize file %s: %s",
237                       tmp_filename_c, _dbus_strerror (errno));
238
239       goto out;
240   }
241
242   if (!_dbus_close (fd, NULL))
243     {
244       dbus_set_error (error, _dbus_error_from_errno (errno),
245                       "Could not close file %s: %s",
246                       tmp_filename_c, _dbus_strerror (errno));
247
248       goto out;
249     }
250
251   fd = -1;
252   
253   if (rename (tmp_filename_c, filename_c) < 0)
254     {
255       dbus_set_error (error, _dbus_error_from_errno (errno),
256                       "Could not rename %s to %s: %s",
257                       tmp_filename_c, filename_c,
258                       _dbus_strerror (errno));
259
260       goto out;
261     }
262
263   need_unlink = FALSE;
264   
265   retval = TRUE;
266   
267  out:
268   /* close first, then unlink, to prevent ".nfs34234235" garbage
269    * files
270    */
271
272   if (fd >= 0)
273     _dbus_close (fd, NULL);
274         
275   if (need_unlink && unlink (tmp_filename_c) < 0)
276     _dbus_verbose ("Failed to unlink temp file %s: %s\n",
277                    tmp_filename_c, _dbus_strerror (errno));
278
279   _dbus_string_free (&tmp_filename);
280
281   if (!retval)
282     _DBUS_ASSERT_ERROR_IS_SET (error);
283   
284   return retval;
285 }
286
287 /** Makes the file readable by every user in the system.
288  *
289  * @param filename the filename
290  * @param error error location
291  * @returns #TRUE if the file's permissions could be changed.
292  */
293 dbus_bool_t
294 _dbus_make_file_world_readable(const DBusString *filename,
295                                DBusError *error)
296 {
297   const char *filename_c;
298
299   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
300
301   filename_c = _dbus_string_get_const_data (filename);
302   if (chmod (filename_c, 0644) == -1)
303     {
304       dbus_set_error (error,
305                       DBUS_ERROR_FAILED,
306                       "Could not change permissions of file %s: %s\n",
307                       filename_c,
308                       _dbus_strerror (errno));
309       return FALSE;
310     }
311   return TRUE;
312 }
313
314 /** Creates the given file, failing if the file already exists.
315  *
316  * @param filename the filename
317  * @param error error location
318  * @returns #TRUE if we created the file and it didn't exist
319  */
320 dbus_bool_t
321 _dbus_create_file_exclusively (const DBusString *filename,
322                                DBusError        *error)
323 {
324   int fd;
325   const char *filename_c;
326
327   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
328   
329   filename_c = _dbus_string_get_const_data (filename);
330   
331   fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
332              0600);
333   if (fd < 0)
334     {
335       dbus_set_error (error,
336                       DBUS_ERROR_FAILED,
337                       "Could not create file %s: %s\n",
338                       filename_c,
339                       _dbus_strerror (errno));
340       return FALSE;
341     }
342
343   _dbus_verbose ("exclusive file fd %d opened\n", fd);
344   
345   if (!_dbus_close (fd, NULL))
346     {
347       dbus_set_error (error,
348                       DBUS_ERROR_FAILED,
349                       "Could not close file %s: %s\n",
350                       filename_c,
351                       _dbus_strerror (errno));
352       return FALSE;
353     }
354   
355   return TRUE;
356 }
357
358 /**
359  * Deletes the given file.
360  *
361  * @param filename the filename
362  * @param error error location
363  * 
364  * @returns #TRUE if unlink() succeeded
365  */
366 dbus_bool_t
367 _dbus_delete_file (const DBusString *filename,
368                    DBusError        *error)
369 {
370   const char *filename_c;
371
372   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
373   
374   filename_c = _dbus_string_get_const_data (filename);
375
376   if (unlink (filename_c) < 0)
377     {
378       dbus_set_error (error, DBUS_ERROR_FAILED,
379                       "Failed to delete file %s: %s\n",
380                       filename_c, _dbus_strerror (errno));
381       return FALSE;
382     }
383   else
384     return TRUE;
385 }