Patch to write config to temporary file and then 'atomicaly' move it
to proper place. 

Moreover it is a fix for following nasty bug which happend when no
~/.mc/ini is found:

open("/usr/local/share/mc/mc.ini",
O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = -1 EACCES (Permission
denied)

We should not try to write to public files, so profile_name should be
used only for reading... But dump_profile still wants to save file
(even unmodified), so we check and save only in home_dir.

Regards
Patch attached and in BTS

Adam

-- 

  _.|._ |_  _.   :  Adam Byrtek /alpha/
 (_|||_)| |(_|   :  email  alpha@(irc.pl|debian.org)
     |           :  jabber alpha.pl(at)jabber.org, pgp 0xB25952C0
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/mc/src/ChangeLog,v
retrieving revision 1.1145
diff -u -r1.1145 ChangeLog
--- ChangeLog   19 Mar 2003 13:39:48 -0000      1.1145
+++ ChangeLog   20 Mar 2003 22:54:26 -0000
@@ -1,0 +1,12 @@
+2003-03-20  Adam Byrtek  <[EMAIL PROTECTED]>
+
+       * profile.c (dump_profile): When saving config files, write to
+       a copy, then replace the file. Retain file mode.
+       * hotlist.c (save hotlist): Likewise.
+       
+       * setup.c (dump_profile), setup.c (profile_name), hotlist.c
+       (profile_name), learn.c (profile_name), panelize.c
+       (profile_name): Avoid writing config files outside home
+       directory (happend when no .mc/ini existed). Use profile_name
+       only for reading.
+
Index: hotlist.c
===================================================================
RCS file: /cvs/gnome/mc/src/hotlist.c,v
retrieving revision 1.44
diff -u -r1.44 hotlist.c
--- hotlist.c   21 Dec 2002 08:43:15 -0000      1.44
+++ hotlist.c   20 Mar 2003 22:54:26 -0000
@@ -1328,23 +1328,26 @@
 static void
 clean_up_hotlist_groups (char *section)
 {
-    char       *grp_section;
+    char       *profile, *grp_section;
     void       *profile_keys;
     char       *key, *value;
 
+    profile = concat_dir_and_file (home_dir, PROFILE_NAME);
+
     grp_section = g_strconcat (section, ".Group", NULL);
-    if (profile_has_section (section, profile_name))
-       profile_clean_section (section, profile_name);
-    if (profile_has_section (grp_section, profile_name)) {
-       profile_keys = profile_init_iterator (grp_section, profile_name);
+    if (profile_has_section (section, profile))
+       profile_clean_section (section, profile);
+    if (profile_has_section (grp_section, profile)) {
+       profile_keys = profile_init_iterator (grp_section, profile);
 
        while (profile_keys) {
            profile_keys = profile_iterator_next (profile_keys, &key, &value);
            clean_up_hotlist_groups (key);
        }
-       profile_clean_section (grp_section, profile_name);
+       profile_clean_section (grp_section, profile);
     }
     g_free (grp_section);
+    g_free (profile);
 }
 
 
@@ -1416,16 +1419,17 @@
 save_group (struct hotlist *grp)
 {
     struct hotlist *current = grp->head;
-    char           *group_section;
+    char           *group_section, *profile;
 
+    profile = concat_dir_and_file (home_dir, PROFILE_NAME);
     group_section = find_group_section (grp);
     
-    profile_clean_section (group_section, profile_name);
+    profile_clean_section (group_section, profile);
     for (;current && current->type == HL_TYPE_GROUP; current = current->next){
        WritePrivateProfileString (group_section,
                                   current->directory,
                                   current->label,
-                                  profile_name);
+                                  profile);
     }
     g_free (group_section);
 
@@ -1434,13 +1438,14 @@
         current = current->next)
         save_group (current);
     
-    profile_clean_section (grp->directory, profile_name);
+    profile_clean_section (grp->directory, profile);
     for (;current; current = current->next){
        WritePrivateProfileString (grp->directory,
                                   current->directory,
                                   current->label,
-                                  profile_name);
+                                  profile);
     }
+    g_free (profile);
 }
 
 static int  list_level = 0;
@@ -1510,23 +1515,23 @@
     struct      stat stat_buf;
     
     if (!hotlist_state.readonly && hotlist_state.modified && hotlist_file_name) {
-       char    *fbak = g_strconcat (hotlist_file_name, ".bak", NULL);
+       char    *ftmp = g_strconcat (hotlist_file_name, ".tmp", NULL);
 
-       rename (hotlist_file_name, fbak);
-       if ((hotlist_file = fopen (hotlist_file_name, "w")) != 0) {
-           if (stat (fbak, &stat_buf) == 0)
-               chmod (hotlist_file_name, stat_buf.st_mode);
+       if ((hotlist_file = fopen (ftmp, "w")) != 0) {
+           if (stat (hotlist_file_name, &stat_buf) == 0)
+               chmod (ftmp, stat_buf.st_mode);
            else
-               chmod (hotlist_file_name, S_IRUSR | S_IWUSR);
+               chmod (ftmp, S_IRUSR | S_IWUSR);
            hot_save_group (hotlist);
            fclose (hotlist_file);
-           stat (hotlist_file_name, &stat_buf);
-           hotlist_file_mtime = stat_buf.st_mtime;
-           saved = 1;
-           hotlist_state.modified = 0;
-       } else
-           rename (fbak, hotlist_file_name);
-       g_free (fbak);
+           if (rename (ftmp, hotlist_file_name) == 0) {
+               stat (hotlist_file_name, &stat_buf);
+               hotlist_file_mtime = stat_buf.st_mtime;
+               saved = 1;
+               hotlist_state.modified = 0;
+           }
+       }
+       g_free (ftmp);
     }
 
     return saved;
Index: learn.c
===================================================================
RCS file: /cvs/gnome/mc/src/learn.c,v
retrieving revision 1.19
diff -u -r1.19 learn.c
--- learn.c     21 Oct 2002 22:54:21 -0000      1.19
+++ learn.c     20 Mar 2003 22:54:26 -0000
@@ -310,12 +310,15 @@
     int i;
     int profile_changed = 0;
     char *section = g_strconcat ("terminal:", getenv ("TERM"), NULL);
+    char *profile;
 
+    profile = concat_dir_and_file (home_dir, PROFILE_NAME);
+    
     for (i = 0; i < learn_total; i++) {
        if (learnkeys [i].sequence != NULL) {
            profile_changed = 1;
            WritePrivateProfileString (section, key_name_conv_tab [i].name,
-               learnkeys [i].sequence, profile_name);
+               learnkeys [i].sequence, profile);
        }
     }
 
@@ -329,6 +332,7 @@
        sync_profiles ();
 
     g_free (section);
+    g_free (profile);
 }
 
 void learn_keys (void)
Index: panelize.c
===================================================================
RCS file: /cvs/gnome/mc/src/panelize.c,v
retrieving revision 1.33
diff -u -r1.33 panelize.c
--- panelize.c  8 Dec 2002 04:16:30 -0000       1.33
+++ panelize.c  20 Mar 2003 22:54:26 -0000
@@ -327,16 +327,20 @@
 void save_panelize (void)
 {
     struct panelize *current = panelize;
+    char *profile;
     
-    profile_clean_section (panelize_section, profile_name);
+    profile = concat_dir_and_file (home_dir, PROFILE_NAME);
+    
+    profile_clean_section (panelize_section, profile);
     for (;current; current = current->next){
        if (strcmp (current->label, _("Other command")))
            WritePrivateProfileString (panelize_section,
                                       current->label,
                                       current->command,
-                                      profile_name);
+                                      profile);
     }
     sync_profiles ();
+    g_free(profile);
 }
 
 void done_panelize (void)
Index: profile.c
===================================================================
RCS file: /cvs/gnome/mc/src/profile.c,v
retrieving revision 1.10
diff -u -r1.10 profile.c
--- profile.c   3 Mar 2003 07:59:11 -0000       1.10
+++ profile.c   20 Mar 2003 22:54:26 -0000
@@ -395,16 +395,32 @@
 static void dump_profile (TProfile *p)
 {
     FILE *profile;
+    struct stat stat_buf;
+    char *tmpFileName;
     
     if (!p)
        return;
     dump_profile (p->link);
     /* .ado: p->FileName can be empty, it's better to jump over */
-    if (p->FileName[0] != (char) 0)
-      if ((profile = fopen (p->FileName, "w")) != NULL){
+    if (p->FileName[0] == (char) 0)
+       return;
+    
+    /* write files in home dir only */
+    if (strncmp (p->FileName, home_dir, sizeof(home_dir)) != 0)
+       return;
+    
+    /* save to temporary file, 'atomic' rename after completion */
+    tmpFileName = g_strconcat (p->FileName, ".tmp", NULL);
+    
+    if ((profile = fopen (tmpFileName, "w")) != NULL){
+       if (stat (p->FileName, &stat_buf) == 0)
+           chmod (tmpFileName, stat_buf.st_mode);
+       else
+           chmod (tmpFileName, S_IRUSR | S_IWUSR);
        dump_sections (profile, p->Section);
        fclose (profile);
-      }
+       rename (tmpFileName, p->FileName);
+    }
 }
 
 /*
@@ -510,7 +526,6 @@
 
     /* We assume the user has called one of the other initialization funcs */
     if (!find_loaded (file, &section)){
-       fprintf (stderr,"Warning: profile_clean_section called before init\n");
        return;
     }
     /* We only disable the section, so it will still be freed, but it */
Index: setup.c
===================================================================
RCS file: /cvs/gnome/mc/src/setup.c,v
retrieving revision 1.73
diff -u -r1.73 setup.c
--- setup.c     23 Jan 2003 14:26:22 -0000      1.73
+++ setup.c     20 Mar 2003 22:54:26 -0000
@@ -219,38 +219,42 @@
 void
 panel_save_setup (struct WPanel *panel, char *section)
 {
-    char buffer [BUF_TINY];
+    char buffer [BUF_TINY], *profile;
     int  i;
 
+    profile = concat_dir_and_file (home_dir, PROFILE_NAME);
+
     g_snprintf (buffer, sizeof (buffer), "%d", panel->reverse);
-    save_string (section, "reverse", buffer, profile_name);
+    save_string (section, "reverse", buffer, profile);
     g_snprintf (buffer, sizeof (buffer), "%d", panel->case_sensitive);
-    save_string (section, "case_sensitive", buffer, profile_name);
+    save_string (section, "case_sensitive", buffer, profile);
     for (i = 0; sort_names [i].key; i++)
        if (sort_names [i].sort_type == (sortfn *) panel->sort_type){
            save_string (section, "sort_order",
-                                      sort_names [i].key, profile_name);
+                                      sort_names [i].key, profile);
            break;
        }
 
     for (i = 0; list_types [i].key; i++)
        if (list_types [i].list_type == panel->list_type){
-           save_string (section, "list_mode", list_types [i].key, profile_name);
+           save_string (section, "list_mode", list_types [i].key, profile);
            break;
        }
 
     save_string (section, "user_format",
-                              panel->user_format, profile_name);
+                              panel->user_format, profile);
 
     for (i = 0; i < LIST_TYPES; i++){
        g_snprintf (buffer, sizeof (buffer), "user_status%d", i);
        save_string (section, buffer,
-           panel->user_status_format [i], profile_name);
+           panel->user_status_format [i], profile);
     }
 
     g_snprintf (buffer, sizeof (buffer), "%d", panel->user_mini_status);
     save_string (section, "user_mini_status", buffer,
-                              profile_name);
+                              profile);
+    
+    g_free (profile);
 }
 
 void
@@ -290,13 +294,17 @@
 panel_save_type (char *section, int type)
 {
     int i;
+    char *profile;
+
+    profile = concat_dir_and_file (home_dir, PROFILE_NAME);
 
     for (i = 0; panel_types [i].opt_name; i++)
        if (panel_types [i].opt_type == type){
            save_string (section, "display", panel_types [i].opt_name,
-                        profile_name);
+                        profile);
            break;
        }
+    g_free(profile);
 }
 
 void
@@ -347,7 +355,7 @@
 
 #ifdef HAVE_CHARSET
     save_string( "Misc", "display_codepage",
-                get_codepage_id( display_codepage ), profile_name );
+                get_codepage_id( display_codepage ), profile );
 #endif /* HAVE_CHARSET */
 
     g_free (profile);
@@ -476,7 +484,7 @@
 void
 load_setup (void)
 {
-    char *profile;
+    char *profile, *profile_writable;
     int    i;
 
     profile = setup_init ();
@@ -536,8 +544,10 @@
     /* Load the directory history */
 /*    directory_history_load (); */
     /* Remove the temporal entries */
-    profile_clean_section ("Temporal:New Left Panel", profile_name);
-    profile_clean_section ("Temporal:New Right Panel", profile_name);
+    profile_writable = concat_dir_and_file (home_dir, PROFILE_NAME);
+    profile_clean_section ("Temporal:New Left Panel", profile_writable);
+    profile_clean_section ("Temporal:New Right Panel", profile_writable);
+    g_free (profile_writable);
 #if defined(USE_VFS) && defined (USE_NETCODE)
     ftpfs_init_passwd ();
 #endif /* USE_VFS && USE_NETCODE */

Reply via email to