Logo Search packages:      
Sourcecode: pan version File versions  Download package

util-file.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Pan - A Newsreader for Gtk+
 * Copyright (C) 2002  Charles Kerr <charles@rebelbase.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <config.h>

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <glib.h>

#include <pan/base/base-prefs.h>
#include <pan/base/log.h>
#include <pan/base/pan-i18n.h>
#include <pan/base/pan-glib-extensions.h>
#include <pan/base/util-file.h>

static int pan_mkdir (const char * path, gulong mode);


/***
****  TEMP FILES
***/

char *
pan_file_make_temp (FILE ** setme_fp)
{
      GError * err = NULL;
      char * retval = NULL;
      int fd = g_file_open_tmp ("pan_XXXXXX", &retval, &err);

      if (err == NULL)
            *setme_fp = fdopen (fd, "w+");
      else {
            log_add_va (LOG_ERROR, _("Could not create temporary file: %s"), err->message);
            g_error_free (err);
      }

      return retval;
}


/***
****
****  FILES
****
***/


char*
pan_file_normalize_inplace (char * filename)
{
      register char * in;
      register char * out;

      g_return_val_if_fail (is_nonempty_string(filename), filename);

      for (in=out=filename; *in; )
            if (in[0]==G_DIR_SEPARATOR && in[1]==G_DIR_SEPARATOR)
                  ++in;
            else
                  *out++ = *in++;
      *out = '\0';

      return filename;
}

char*
pan_file_normalize (const char * filename, const char * fallback_absolute_path)
{
      char * pch;

      g_return_val_if_fail (is_nonempty_string(filename), g_strdup(filename));

      /* take care of paths beginning with ~ */
      pch = filename[0]=='~' && filename[1]==G_DIR_SEPARATOR
            ? g_build_filename (pan_get_home_dir(), filename+2, NULL)
            : g_strdup (filename);

      g_strstrip (pch);

      /* make sure the filename is absolute */
      if (!g_path_is_absolute (pch))
      {
            if (fallback_absolute_path == NULL)
                  fallback_absolute_path = pan_get_home_dir ();
            replace_gstr (&pch, g_build_filename (fallback_absolute_path, pch, NULL));
      }

      /* remove any unnecessary directory characters */
      pan_file_normalize_inplace (pch);

      return pch;
}

gboolean
pan_file_exists (const char* filename)
{
      return is_nonempty_string(filename) && g_file_test (filename, G_FILE_TEST_EXISTS);
}

size_t
pan_file_get_size (const char* filename)
{
      struct stat buf;

      g_return_val_if_fail (is_nonempty_string(filename), -1);

      if (!stat(filename, &buf))
            return buf.st_size;

      return -1;
}

gboolean
pan_file_ensure_path_exists (const char *pathname)
{
      gboolean retval = TRUE;
      static GStaticMutex mutex = G_STATIC_MUTEX_INIT;

      g_return_val_if_fail (is_nonempty_string(pathname), TRUE);

      g_static_mutex_lock (&mutex);
      if (!g_file_test (pathname, G_FILE_TEST_IS_DIR))
      {
            const char * in = pathname;
            char * buf = g_newa (char, strlen(pathname)+1);
            char * out = buf;

            *out++ = *in++;
            for (;;)
            {
                  if (*in=='\0' || *in==G_DIR_SEPARATOR)
                  {
                              *out = '\0';

                        if (!g_file_test (buf, G_FILE_TEST_IS_DIR))
                        {
                              if (pan_mkdir (buf, S_IRUSR | S_IWUSR | S_IXUSR))
                              {
                                    log_add_va (LOG_ERROR, _("Couldn't create directory \"%s\": %s"),
                                                           buf, g_strerror (errno));
                                    retval = FALSE;
                                    break;
                              }
                        }
                  }

                  *out = *in;
                  if (!*in)
                        break;

                  ++out;
                  ++in;
            }
      }
      g_static_mutex_unlock (&mutex);

      return retval;
}

static int
pan_file_copy (const char * old_filename,
               const char * new_filename)
{
      FILE * in;
      FILE * out;
      int retval;
      char buf [4096];
      size_t size_read;

      /* sanity clause */
      g_return_val_if_fail (is_nonempty_string(old_filename), -1);
      g_return_val_if_fail (is_nonempty_string(new_filename), -1);
      g_return_val_if_fail (pan_file_exists (old_filename), -1);

      in = fopen (old_filename, "rb");
      if (in == NULL) {
            log_add_va (LOG_ERROR, _("Error opening file \"%s\": %s"), old_filename, g_strerror(errno));
            return -1;
      }
      out = fopen (new_filename, "wb+");
      if (out == NULL) {
            log_add_va (LOG_ERROR, _("Error opening file \"%s\": %s"), new_filename, g_strerror(errno));
            fclose (in);
            return -1;
      }

      while ((size_read = fread (buf, sizeof(char), sizeof(buf), in)))
            fwrite (buf, sizeof(char), size_read, out);

      retval = ferror(in) || ferror(out) ? 1 : 0;
      fclose (in);
      fclose (out);
      return retval;
}

gboolean
pan_file_rename (const char * old_filename,
                 const char * new_filename)
{
      /* sanity clause */
      g_return_val_if_fail (is_nonempty_string(old_filename), FALSE);
      g_return_val_if_fail (is_nonempty_string(new_filename), FALSE);
      g_return_val_if_fail (pan_file_exists (old_filename), FALSE);

      if (rename (old_filename, new_filename)) {
            if (!pan_file_copy (old_filename, new_filename))
                  unlink (old_filename);
            else {
                  log_add_va (LOG_ERROR,
                        _("Error renaming \"%s\" as \"%s\": %s."),
                        old_filename,
                        new_filename,
                        g_strerror(errno));
                  return FALSE;
            }
      }

      return TRUE;
}

static int
pan_mkdir (const char * path, gulong mode)
{
      int retval = 0;

      g_return_val_if_fail (is_nonempty_string(path), retval);

      if (strlen(path)==2 && isalpha((guchar)path[0]) && path[1]==':')
      {
            /* smells like a windows pathname.. skipping */
      }
      else
      {
            errno = 0;
#ifdef G_OS_WIN32
            retval = mkdir (path);
#else
            retval = mkdir (path, mode);
#endif
            if (errno == EEXIST)
                  retval = 0;
      }
      
      return retval;
}

gboolean
pan_file_swap_datafile (const char  * filename_tmp,
                        const char  * filename)
{
      gboolean ok = TRUE;
      char * filename_bak = NULL;

      /* sanity clause */
      g_return_val_if_fail (is_nonempty_string(filename), FALSE);
      g_return_val_if_fail (is_nonempty_string(filename_tmp), FALSE);
      g_return_val_if_fail (pan_file_exists (filename_tmp), FALSE);

      /* backup the old file */
      if (ok && pan_file_exists(filename)) {
            filename_bak = g_strdup_printf ("%s.bak", filename);
            ok = pan_file_rename (filename, filename_bak);
            if (!ok) {
                  log_add_va (LOG_ERROR, _("Can't backup \"%s\" as \"%s\": %s"),
                            filename, filename_bak, g_strerror(errno));
            }
      }

      /* replace the old file with the temp file */
      if (ok) {
            ok = pan_file_rename (filename_tmp, filename);
            if (!ok) {
                  log_add_va (LOG_ERROR, _("Can't backup \"%s\" as \"%s\": %s"),
                            filename, filename_bak, g_strerror(errno));
                  /* if we just made a backup in the previous paragraph,
                   * restore from that backup.  Use copy() rather than rename()
                   * so that even in the worst case we'll still have the backup. */
                  if (filename_bak != NULL)
                        pan_file_copy (filename_bak, filename);
            }
      }

      /* cleanup */
      g_free (filename_bak);

      return ok;
}

gboolean
pan_file_write_datafile (const char  * filename,
                         const char  * data,
                         gulong        data_len)
{
      char * filename_tmp;
      FILE * fp;
      gboolean ok;

      /* sanity clause */
      g_return_val_if_fail (is_nonempty_string (filename), FALSE);
      g_return_val_if_fail (data_len > 0ul, FALSE);
      g_return_val_if_fail (data != NULL, FALSE);

      /* write the data to a temporary file */
      filename_tmp = g_strdup_printf ("%s.tmp", filename);
      fp = fopen (filename_tmp, "w+");
      ok = fp != NULL;
      if (!ok) {
            log_add_va (LOG_ERROR, _("Can't write to \"%s\": %s"),
                        filename_tmp, g_strerror (errno));
      }
      else {
            const size_t written  = fwrite (data, sizeof(char), data_len, fp);
            fclose (fp);
            ok = data_len == written;
            if (!ok) {
                  log_add_va (LOG_ERROR, _("Can't write to \"%s\": %s"),
                              filename_tmp, g_strerror (errno));
            }
      }

      /* move the temp file to the datafile */
      if (ok)
            pan_file_swap_datafile (filename_tmp, filename);

      /* cleanup */
      g_free (filename_tmp);
      return ok;
}

Generated by  Doxygen 1.6.0   Back to index