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 }