D-Bus 1.4.0
dbus-file-unix.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-file-unix.c unix related file implementation (internal to D-Bus implementation)
00003  * 
00004  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
00005  * Copyright (C) 2003 CodeFactory AB
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 
00027 #include "dbus-protocol.h"
00028 #include "dbus-errors.h"
00029 #include "dbus-file.h"
00030 #include "dbus-internals.h"
00031 #include "dbus-sysdeps.h"
00032 #include "dbus-sysdeps-unix.h"
00033 
00034 #include <sys/stat.h>
00035 #include <stdio.h>
00036 #include <fcntl.h>
00037 #include <unistd.h>
00038 #include <errno.h>
00039 
00040 #ifndef O_BINARY
00041 #define O_BINARY 0
00042 #endif
00043 
00054 dbus_bool_t
00055 _dbus_file_get_contents (DBusString       *str,
00056                          const DBusString *filename,
00057                          DBusError        *error)
00058 {
00059   int fd;
00060   struct stat sb;
00061   int orig_len;
00062   int total;
00063   const char *filename_c;
00064 
00065   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00066   
00067   filename_c = _dbus_string_get_const_data (filename);
00068   
00069   /* O_BINARY useful on Cygwin */
00070   fd = open (filename_c, O_RDONLY | O_BINARY);
00071   if (fd < 0)
00072     {
00073       dbus_set_error (error, _dbus_error_from_errno (errno),
00074                       "Failed to open \"%s\": %s",
00075                       filename_c,
00076                       _dbus_strerror (errno));
00077       return FALSE;
00078     }
00079 
00080   _dbus_verbose ("file fd %d opened\n", fd);
00081   
00082   if (fstat (fd, &sb) < 0)
00083     {
00084       dbus_set_error (error, _dbus_error_from_errno (errno),
00085                       "Failed to stat \"%s\": %s",
00086                       filename_c,
00087                       _dbus_strerror (errno));
00088 
00089       _dbus_verbose ("fstat() failed: %s",
00090                      _dbus_strerror (errno));
00091       
00092       _dbus_close (fd, NULL);
00093       
00094       return FALSE;
00095     }
00096 
00097   if (sb.st_size > _DBUS_ONE_MEGABYTE)
00098     {
00099       dbus_set_error (error, DBUS_ERROR_FAILED,
00100                       "File size %lu of \"%s\" is too large.",
00101                       (unsigned long) sb.st_size, filename_c);
00102       _dbus_close (fd, NULL);
00103       return FALSE;
00104     }
00105   
00106   total = 0;
00107   orig_len = _dbus_string_get_length (str);
00108   if (sb.st_size > 0 && S_ISREG (sb.st_mode))
00109     {
00110       int bytes_read;
00111 
00112       while (total < (int) sb.st_size)
00113         {
00114           bytes_read = _dbus_read (fd, str,
00115                                    sb.st_size - total);
00116           if (bytes_read <= 0)
00117             {
00118               dbus_set_error (error, _dbus_error_from_errno (errno),
00119                               "Error reading \"%s\": %s",
00120                               filename_c,
00121                               _dbus_strerror (errno));
00122 
00123               _dbus_verbose ("read() failed: %s",
00124                              _dbus_strerror (errno));
00125               
00126               _dbus_close (fd, NULL);
00127               _dbus_string_set_length (str, orig_len);
00128               return FALSE;
00129             }
00130           else
00131             total += bytes_read;
00132         }
00133 
00134       _dbus_close (fd, NULL);
00135       return TRUE;
00136     }
00137   else if (sb.st_size != 0)
00138     {
00139       _dbus_verbose ("Can only open regular files at the moment.\n");
00140       dbus_set_error (error, DBUS_ERROR_FAILED,
00141                       "\"%s\" is not a regular file",
00142                       filename_c);
00143       _dbus_close (fd, NULL);
00144       return FALSE;
00145     }
00146   else
00147     {
00148       _dbus_close (fd, NULL);
00149       return TRUE;
00150     }
00151 }
00152 
00163 dbus_bool_t
00164 _dbus_string_save_to_file (const DBusString *str,
00165                            const DBusString *filename,
00166                            dbus_bool_t      world_readable,
00167                            DBusError        *error)
00168 {
00169   int fd;
00170   int bytes_to_write;
00171   const char *filename_c;
00172   DBusString tmp_filename;
00173   const char *tmp_filename_c;
00174   int total;
00175   dbus_bool_t need_unlink;
00176   dbus_bool_t retval;
00177 
00178   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00179   
00180   fd = -1;
00181   retval = FALSE;
00182   need_unlink = FALSE;
00183   
00184   if (!_dbus_string_init (&tmp_filename))
00185     {
00186       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00187       return FALSE;
00188     }
00189 
00190   if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
00191     {
00192       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00193       _dbus_string_free (&tmp_filename);
00194       return FALSE;
00195     }
00196   
00197   if (!_dbus_string_append (&tmp_filename, "."))
00198     {
00199       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00200       _dbus_string_free (&tmp_filename);
00201       return FALSE;
00202     }
00203 
00204 #define N_TMP_FILENAME_RANDOM_BYTES 8
00205   if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
00206     {
00207       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00208       _dbus_string_free (&tmp_filename);
00209       return FALSE;
00210     }
00211     
00212   filename_c = _dbus_string_get_const_data (filename);
00213   tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
00214 
00215   fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
00216              world_readable ? 0644 : 0600);
00217   if (fd < 0)
00218     {
00219       dbus_set_error (error, _dbus_error_from_errno (errno),
00220                       "Could not create %s: %s", tmp_filename_c,
00221                       _dbus_strerror (errno));
00222       goto out;
00223     }
00224   if (world_readable)
00225     {
00226       /* Ensure the file is world readable even in the presence of
00227        * possibly restrictive umasks;
00228        * see http://lists.freedesktop.org/archives/dbus/2010-September/013367.html
00229        */
00230       if (fchmod (fd, 0644) < 0)
00231         {
00232           dbus_set_error (error, _dbus_error_from_errno (errno),
00233                           "Could not chmod %s: %s", tmp_filename_c,
00234                           _dbus_strerror (errno));
00235           goto out;
00236         }
00237     }
00238 
00239   _dbus_verbose ("tmp file fd %d opened\n", fd);
00240   
00241   need_unlink = TRUE;
00242   
00243   total = 0;
00244   bytes_to_write = _dbus_string_get_length (str);
00245 
00246   while (total < bytes_to_write)
00247     {
00248       int bytes_written;
00249 
00250       bytes_written = _dbus_write (fd, str, total,
00251                                    bytes_to_write - total);
00252 
00253       if (bytes_written <= 0)
00254         {
00255           dbus_set_error (error, _dbus_error_from_errno (errno),
00256                           "Could not write to %s: %s", tmp_filename_c,
00257                           _dbus_strerror (errno));
00258           
00259           goto out;
00260         }
00261 
00262       total += bytes_written;
00263     }
00264 
00265   if (fsync(fd))
00266     {
00267       dbus_set_error (error, _dbus_error_from_errno (errno),
00268                       "Could not synchronize file %s: %s",
00269                       tmp_filename_c, _dbus_strerror (errno));
00270 
00271       goto out;
00272   }
00273 
00274   if (!_dbus_close (fd, NULL))
00275     {
00276       dbus_set_error (error, _dbus_error_from_errno (errno),
00277                       "Could not close file %s: %s",
00278                       tmp_filename_c, _dbus_strerror (errno));
00279 
00280       goto out;
00281     }
00282 
00283   fd = -1;
00284   
00285   if (rename (tmp_filename_c, filename_c) < 0)
00286     {
00287       dbus_set_error (error, _dbus_error_from_errno (errno),
00288                       "Could not rename %s to %s: %s",
00289                       tmp_filename_c, filename_c,
00290                       _dbus_strerror (errno));
00291 
00292       goto out;
00293     }
00294 
00295   need_unlink = FALSE;
00296   
00297   retval = TRUE;
00298   
00299  out:
00300   /* close first, then unlink, to prevent ".nfs34234235" garbage
00301    * files
00302    */
00303 
00304   if (fd >= 0)
00305     _dbus_close (fd, NULL);
00306         
00307   if (need_unlink && unlink (tmp_filename_c) < 0)
00308     _dbus_verbose ("Failed to unlink temp file %s: %s\n",
00309                    tmp_filename_c, _dbus_strerror (errno));
00310 
00311   _dbus_string_free (&tmp_filename);
00312 
00313   if (!retval)
00314     _DBUS_ASSERT_ERROR_IS_SET (error);
00315   
00316   return retval;
00317 }
00318 
00325 dbus_bool_t
00326 _dbus_make_file_world_readable(const DBusString *filename,
00327                                DBusError *error)
00328 {
00329   const char *filename_c;
00330 
00331   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00332 
00333   filename_c = _dbus_string_get_const_data (filename);
00334   if (chmod (filename_c, 0644) == -1)
00335     {
00336       dbus_set_error (error,
00337                       DBUS_ERROR_FAILED,
00338                       "Could not change permissions of file %s: %s\n",
00339                       filename_c,
00340                       _dbus_strerror (errno));
00341       return FALSE;
00342     }
00343   return TRUE;
00344 }
00345 
00352 dbus_bool_t
00353 _dbus_create_file_exclusively (const DBusString *filename,
00354                                DBusError        *error)
00355 {
00356   int fd;
00357   const char *filename_c;
00358 
00359   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00360   
00361   filename_c = _dbus_string_get_const_data (filename);
00362   
00363   fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
00364              0600);
00365   if (fd < 0)
00366     {
00367       dbus_set_error (error,
00368                       DBUS_ERROR_FAILED,
00369                       "Could not create file %s: %s\n",
00370                       filename_c,
00371                       _dbus_strerror (errno));
00372       return FALSE;
00373     }
00374 
00375   _dbus_verbose ("exclusive file fd %d opened\n", fd);
00376   
00377   if (!_dbus_close (fd, NULL))
00378     {
00379       dbus_set_error (error,
00380                       DBUS_ERROR_FAILED,
00381                       "Could not close file %s: %s\n",
00382                       filename_c,
00383                       _dbus_strerror (errno));
00384       return FALSE;
00385     }
00386   
00387   return TRUE;
00388 }
00389 
00398 dbus_bool_t
00399 _dbus_delete_file (const DBusString *filename,
00400                    DBusError        *error)
00401 {
00402   const char *filename_c;
00403 
00404   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00405   
00406   filename_c = _dbus_string_get_const_data (filename);
00407 
00408   if (unlink (filename_c) < 0)
00409     {
00410       dbus_set_error (error, DBUS_ERROR_FAILED,
00411                       "Failed to delete file %s: %s\n",
00412                       filename_c, _dbus_strerror (errno));
00413       return FALSE;
00414     }
00415   else
00416     return TRUE;
00417 }