talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

prefs.c (4156B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
     17  *
     18  */
     19 
     20 #include <stdio.h>
     21 #include <string.h>
     22 
     23 #include "defs.h"
     24 
     25 #include <glib.h>
     26 
     27 #include "prefs.h"
     28 #include "utils.h"
     29 
     30 static gboolean prefs_is_readonly	(const gchar 	*path);
     31 
     32 /*
     33  * Open preferences file for writing
     34  * Prefs are written to a temp file: Call prefs_file_close()
     35  * to rename this to the final filename
     36  */
     37 PrefFile *prefs_write_open(const gchar *path)
     38 {
     39 	FILE *fp;
     40 	char tmp[PATH_MAX];
     41 	strlcpy(tmp, path, sizeof(tmp));
     42 	strlcat(tmp, ".tmp", sizeof(tmp));
     43 	if ((fp = fopen(tmp, "w")) == NULL) {
     44 		char msg[PATH_MAX];
     45 		snprintf(msg, sizeof(msg), "open %s", tmp);
     46 		perror(msg);
     47 		return NULL;
     48 	}
     49 
     50 	PrefFile *pfile = g_new(PrefFile, 1);
     51 	pfile->fp = fp;
     52 	pfile->orig_fp = NULL;
     53 	pfile->path = strdup(path);
     54 	pfile->writing = TRUE;
     55 	return pfile;
     56 }
     57 
     58 /*!
     59  *\brief	Close and free preferences file
     60  *		Creates final file from temp, creates backup
     61  *
     62  *\param	pfile Preferences file struct
     63  *
     64  *\return	0 on success, -1 on failure
     65  */
     66 gint prefs_file_close(PrefFile *pfile)
     67 {
     68 	FILE *fp, *orig_fp;
     69 	gchar *path;
     70 	gchar *tmppath;
     71 	gchar *bakpath = NULL;
     72 	gchar buf[BUFFSIZE];
     73 
     74 	cm_return_val_if_fail(pfile != NULL, -1);
     75 
     76 	fp = pfile->fp;
     77 	orig_fp = pfile->orig_fp;
     78 	path = pfile->path;
     79 
     80 	if (!pfile->writing) {
     81 		fclose(fp);
     82 		g_free(pfile);
     83 		g_free(path);
     84 		return 0;
     85 	}
     86 
     87 	if (orig_fp) {
     88     		while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
     89 			/* next block */
     90 			if (buf[0] == '[') {
     91 				if (fputs(buf, fp)  == EOF) {
     92 					g_warning("failed to write configuration to file");
     93 					prefs_file_close_revert(pfile);
     94 
     95 					return -1;
     96 				}
     97 				break;
     98 			}
     99 		}
    100 
    101 		while (fgets(buf, sizeof(buf), orig_fp) != NULL)
    102 			if (fputs(buf, fp) == EOF) {
    103 				g_warning("failed to write configuration to file");
    104 				prefs_file_close_revert(pfile);
    105 
    106 				return -1;
    107 			}
    108 		fclose(orig_fp);
    109 	}
    110 
    111 	tmppath = g_strconcat(path, ".tmp", NULL);
    112 
    113 	if (fclose(fp) == EOF) {
    114 		FILE_OP_ERROR(tmppath, "fclose");
    115 		unlink(tmppath);
    116 		g_free(path);
    117 		g_free(tmppath);
    118 		return -1;
    119 	}
    120 
    121 	if (is_file_exist(path)) {
    122 		bakpath = g_strconcat(path, ".bak", NULL);
    123 		if (g_rename(path, bakpath) < 0) {
    124 			FILE_OP_ERROR(path, "rename");
    125 			unlink(tmppath);
    126 			g_free(path);
    127 			g_free(tmppath);
    128 			g_free(bakpath);
    129 			return -1;
    130 		}
    131 	}
    132 
    133 	if (g_rename(tmppath, path) < 0) {
    134 		FILE_OP_ERROR(tmppath, "rename");
    135 		unlink(tmppath);
    136 		g_free(path);
    137 		g_free(tmppath);
    138 		g_free(bakpath);
    139 		return -1;
    140 	}
    141 
    142 	g_free(pfile);
    143 	g_free(path);
    144 	g_free(tmppath);
    145 	g_free(bakpath);
    146 	return 0;
    147 }
    148 
    149 /*!
    150  *\brief	Close and free preferences file, delete temp file
    151  *
    152  *\param	pfile Preferences file struct
    153  */
    154 gint prefs_file_close_revert(PrefFile *pfile)
    155 {
    156 	gchar *tmppath = NULL;
    157 
    158 	cm_return_val_if_fail(pfile != NULL, -1);
    159 
    160 	if (pfile->orig_fp)
    161 		fclose(pfile->orig_fp);
    162 	if (pfile->writing)
    163 		tmppath = g_strconcat(pfile->path, ".tmp", NULL);
    164 	fclose(pfile->fp);
    165 	if (pfile->writing) {
    166 		if (unlink(tmppath) < 0) FILE_OP_ERROR(tmppath, "unlink");
    167 		g_free(tmppath);
    168 	}
    169 	g_free(pfile->path);
    170 	g_free(pfile);
    171 
    172 	return 0;
    173 }
    174 
    175 /*!
    176  *\brief	Check if "path" is a file and read-only
    177  */
    178 static gboolean prefs_is_readonly(const gchar * path)
    179 {
    180 	if (path == NULL)
    181 		return TRUE;
    182 
    183 	return (access(path, W_OK) != 0 && access(path, F_OK) == 0);
    184 }
    185 
    186 gboolean prefs_rc_is_readonly(const gchar * rcfile)
    187 {
    188 	char path[PATH_MAX];
    189 	snprintf(path, sizeof(path), "%s/%s", get_rc_dir(), rcfile);
    190 	return prefs_is_readonly(path);
    191 }