[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: CVS update: f_basic.nw



  User: cnieves 
  Date: 05/10/28 18:26:34

  Modified:    .        f_basic.nw s_page.nw s_toplevel.nw s_undo.nw
  Log:
  Added support for backup copies and autosaving. 
  
  Autosaving is done every "interval" seconds (configurable 
  
  through system-gschemrc).
  
  		  
  
  
  
  
  Revision  Changes    Path
  1.16      +180 -1    eda/geda/devel/libgeda/noweb/f_basic.nw
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: f_basic.nw
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/devel/libgeda/noweb/f_basic.nw,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -b -r1.15 -r1.16
  --- f_basic.nw	12 Mar 2005 23:28:57 -0000	1.15
  +++ f_basic.nw	28 Oct 2005 22:26:33 -0000	1.16
  @@ -16,6 +16,7 @@
   <<f_basic.c : f_save_close()>>
   <<f_basic.c : f_save()>>
   <<f_basic.c : f_normalize_filename()>>
  +<<f_basic.c : f_follow_symlinks()>>
   
   @ 
   
  @@ -54,9 +55,14 @@
   
   #include <sys/param.h>
   #include <stdlib.h>
  +#include <sys/types.h>
  +#include <sys/stat.h>
   
   #include <gtk/gtk.h>
   #include <libguile.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
   
   #include "defines.h"
   #include "struct.h"
  @@ -225,7 +231,84 @@
   int
   f_save(TOPLEVEL *w_current, const char *filename)
   {
  -  return o_save(w_current, filename);
  +  gchar *backup_filename;
  +  gchar *real_filename;
  +  gchar *only_filename;
  +  gchar *dirname;
  +  mode_t saved_umask;
  +  struct stat st;
  +
  +  /* Get the real filename and file permissions */
  +  real_filename = follow_symlinks (filename, NULL);
  +
  +  if (real_filename == NULL) {
  +    s_log_message ("Can't get the real filename of %s.", filename);
  +    fprintf (stderr, "Can't get the real filename of %s.\n", filename);
  +    return 0;
  +  }
  +  
  +  /* Get the directory in which the real filename lives */
  +  dirname = g_path_get_dirname (real_filename);
  +  only_filename = g_path_get_basename(real_filename);  
  +
  +  /* Do a backup if it's not an undo file backup and it was never saved. */
  +  if (w_current->page_current->saved_since_first_loaded == 0) {    
  +    if ( (g_file_test (real_filename, G_FILE_TEST_EXISTS)) && 
  +	 (!g_file_test(real_filename, G_FILE_TEST_IS_DIR)) )
  +    {
  +      backup_filename = g_strdup_printf("%s%c%s~", dirname, 
  +					G_DIR_SEPARATOR, only_filename);
  +      if (rename(real_filename, backup_filename) != 0) {
  +	s_log_message ("Can't save backup file: %s.", backup_filename);
  +	fprintf (stderr, "Can't save backup file: %s.", backup_filename);
  +      }
  +      g_free(backup_filename);
  +    }
  +  }
  +    /* If there is not an existing file with that name, compute the
  +     * permissions and uid/gid that we will use for the newly-created file.
  +     */
  +       
  +  if (stat (real_filename, &st) != 0)
  +  {
  +    struct stat dir_st;
  +    int result;
  +    
  +    /* Use default permissions */
  +    saved_umask = umask(0);
  +    st.st_mode = 0666 & ~saved_umask;
  +    umask(saved_umask);
  +    st.st_uid = getuid ();
  +    
  +    result = stat (dirname, &dir_st);
  +    
  +    if (result == 0 && (dir_st.st_mode & S_ISGID))
  +	  st.st_gid = dir_st.st_gid;
  +    else
  +    st.st_gid = getgid ();
  +  }
  +  g_free (dirname);
  +  g_free (only_filename);
  +  
  +  if (o_save(w_current, real_filename)) {
  +
  +    w_current->page_current->saved_since_first_loaded = 1;
  +
  +    /* Reset the last saved timer */
  +    g_get_current_time (&w_current->page_current->last_load_or_save_time);
  +    w_current->page_current->ops_since_last_backup = 0;
  +
  +    /* Restore permissions. */
  +    chmod (real_filename, st.st_mode);
  +    chown (real_filename, st.st_uid, st.st_gid);
  +
  +    g_free (real_filename);
  +    return 1;
  +  }
  +  else {
  +    g_free (real_filename);
  +    return 0;
  +  }
   }
   
   @ %def f_save
  @@ -262,3 +345,99 @@
   
   @ %def f_normalize_filename
   
  +@section Function @code{f_normalize_filename()}
  +
  +@defun f_follow_symlinks filename error
  +Does readlink() recursively until we find a real filename.
  +Taken from gedit's source code.
  +@end defun
  +
  +<<f_basic.c : f_follow_symlinks()>>=
  +
  +/* Does readlink() recursively until we find a real filename. */
  +char *
  +follow_symlinks (const gchar *filename, GError **error)
  +{
  +	gchar *followed_filename;
  +	gint link_count;
  +
  +	g_return_val_if_fail (filename != NULL, NULL);
  +	
  +	g_return_val_if_fail (strlen (filename) + 1 <= MAXPATHLEN, NULL);
  +
  +	followed_filename = g_strdup (filename);
  +	link_count = 0;
  +
  +	while (link_count < MAX_LINK_LEVEL)
  +	{
  +		struct stat st;
  +
  +		if (lstat (followed_filename, &st) != 0)
  +			/* We could not access the file, so perhaps it does not
  +			 * exist.  Return this as a real name so that we can
  +			 * attempt to create the file.
  +			 */
  +			return followed_filename;
  +
  +		if (S_ISLNK (st.st_mode))
  +		{
  +			gint len;
  +			gchar linkname[MAXPATHLEN];
  +
  +			link_count++;
  +
  +			len = readlink (followed_filename, linkname, MAXPATHLEN - 1);
  +
  +			if (len == -1)
  +			{
  +				s_log_message("Could not read symbolic link information for %s", followed_filename);
  +				fprintf(stderr, "Could not read symbolic link information for %s", followed_filename);
  +				g_free (followed_filename);
  +				return NULL;
  +			}
  +
  +			linkname[len] = '\0';
  +
  +			/* If the linkname is not an absolute path name, append
  +			 * it to the directory name of the followed filename.  E.g.
  +			 * we may have /foo/bar/baz.lnk -> eek.txt, which really
  +			 * is /foo/bar/eek.txt.
  +			 */
  +
  +			if (linkname[0] != G_DIR_SEPARATOR)
  +			{
  +				gchar *slashpos;
  +				gchar *tmp;
  +
  +				slashpos = strrchr (followed_filename, G_DIR_SEPARATOR);
  +
  +				if (slashpos)
  +					*slashpos = '\0';
  +				else
  +				{
  +					tmp = g_strconcat ("./", followed_filename, NULL);
  +					g_free (followed_filename);
  +					followed_filename = tmp;
  +				}
  +
  +				tmp = g_build_filename (followed_filename, linkname, NULL);
  +				g_free (followed_filename);
  +				followed_filename = tmp;
  +			}
  +			else
  +			{
  +				g_free (followed_filename);
  +				followed_filename = g_strdup (linkname);
  +			}
  +		} else
  +			return followed_filename;
  +	}
  +
  +	/* Too many symlinks */
  +
  +	s_log_message("The file has too many symbolic links.");
  +	fprintf(stderr, "The file has too many symbolic links.");
  +
  +	return NULL;
  +}
  +@ %def f_follow_symlinks
  
  
  
  1.14      +141 -0    eda/geda/devel/libgeda/noweb/s_page.nw
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_page.nw
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/devel/libgeda/noweb/s_page.nw,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -b -r1.13 -r1.14
  --- s_page.nw	13 Feb 2005 22:03:57 -0000	1.13
  +++ s_page.nw	28 Oct 2005 22:26:33 -0000	1.14
  @@ -27,6 +27,7 @@
   
   <<s_page.c : s_page_check_changed()>>
   <<s_page.c : s_page_clear_changed()>>
  +<<s_page.c : s_page_autosave()>>
   
   @
   
  @@ -72,7 +73,12 @@
   #endif
   
   #include <gtk/gtk.h>
  +#include <glib.h>
  +#include <glib/gstdio.h>
   #include <libguile.h>
  +#include <sys/types.h>
  +#include <sys/stat.h>
  +#include <unistd.h>
   
   #include "defines.h"
   #include "struct.h"
  @@ -175,6 +181,11 @@
                 toplevel->init_left, toplevel->init_right,
                 toplevel->init_top,  toplevel->init_bottom);
   
  +  /* Backup variables */
  +  g_get_current_time (&page->last_load_or_save_time);
  +  page->ops_since_last_backup = 0;
  +  page->saved_since_first_loaded = 0;
  +
     /* now append page to page list of toplevel */
     toplevel->page_tail->next = page;
     page->prev = toplevel->page_tail;
  @@ -203,6 +214,10 @@
   s_page_delete (TOPLEVEL *toplevel, PAGE *page)
   {
     PAGE *tmp;
  +  gchar *backup_filename;
  +  gchar *real_filename;
  +  gchar *only_filename;
  +  gchar *dirname;
     
     g_assert (page->pid != -1);
   
  @@ -217,6 +232,34 @@
       s_page_goto (toplevel, page);
     }
     
  +  /* Get the real filename and file permissions */
  +  real_filename = follow_symlinks (page->page_filename, NULL);
  +  
  +  if (real_filename == NULL) {
  +    s_log_message ("s_page_delete: Can't get the real filename of %s.", page->page_filename);
  +    fprintf (stderr, "s_page_delete: Can't get the real filename of %s.\n", page->page_filename);
  +  }
  +  else {
  +    /* Get the directory in which the real filename lives */
  +    dirname = g_path_get_dirname (real_filename);
  +    only_filename = g_path_get_basename(real_filename);  
  +    
  +    
  +    backup_filename = g_strdup_printf("%s%c#%s#", dirname, 
  +				      G_DIR_SEPARATOR, only_filename);
  +    /* Delete the backup file */
  +    if ( (g_file_test (backup_filename, G_FILE_TEST_EXISTS)) && 
  +	 (!g_file_test(backup_filename, G_FILE_TEST_IS_DIR)) )
  +    {
  +      if (g_unlink(backup_filename) != 0) {
  +	s_log_message("s_page_delete: Unable to delete backup file %s.", backup_filename);      }
  +    }
  +    g_free (dirname);
  +    g_free (only_filename);
  +    g_free (backup_filename);
  +  }
  +  g_free(real_filename);
  +
     /* first delete objects of page */
     s_delete_list_fromstart (toplevel, page->object_head);
     
  @@ -568,3 +611,101 @@
   
   
   @ %def s_page_clear_changed
  +
  +@section Function @code{s_page_autosave()}
  +
  +@defun s_page_autosave w_current
  +It is a callback of the glib g_timeout functions.
  +It is called every "interval" miliseconds and it saves a backup copy of the opened pages.
  +The argument is the toplevel structure.
  +@end defun
  +
  +<<s_page.c : s_page_autosave()>>=
  +gint 
  +s_page_autosave (TOPLEVEL *toplevel) 
  +{
  +  PAGE *p_save, *p_current;
  +  gchar *backup_filename;
  +  gchar *real_filename;
  +  gchar *only_filename;
  +  gchar *dirname;
  +  mode_t saved_umask;
  +  struct stat st;
  +
  +  g_assert (toplevel->page_head != NULL &&
  +            toplevel->page_head->pid == -1);
  +
  +  /* save current page */
  +  p_save = toplevel->page_current;
  +  
  +  for (p_current = toplevel->page_head->next;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +
  +    if (p_current->ops_since_last_backup != 0) {
  +      /* make p_current the current page of toplevel */
  +      s_page_goto (toplevel, p_current);
  +      
  +      /* Get the real filename and file permissions */
  +      real_filename = follow_symlinks (p_current->page_filename, NULL);
  +      
  +      if (real_filename == NULL) {
  +	s_log_message ("s_page_autosave: Can't get the real filename of %s.", p_current->page_filename);
  +	fprintf (stderr, "s_page_autosave: Can't get the real filename of %s.\n", p_current->page_filename);
  +      }
  +      else {
  +	/* Get the directory in which the real filename lives */
  +	dirname = g_path_get_dirname (real_filename);
  +	only_filename = g_path_get_basename(real_filename);  
  +      
  +
  +	backup_filename = g_strdup_printf("%s%c#%s#", dirname, 
  +					  G_DIR_SEPARATOR, only_filename);
  +	
  +	/* If there is not an existing file with that name, compute the
  +	 * permissions and uid/gid that we will use for the newly-created file.
  +	 */
  +	
  +	if (stat (real_filename, &st) != 0)
  +	  {
  +	    struct stat dir_st;
  +	    int result;
  +	    
  +	    /* Use default permissions */
  +	    saved_umask = umask(0);
  +	    st.st_mode = 0666 & ~saved_umask;
  +	    umask(saved_umask);
  +	    st.st_uid = getuid ();
  +	    
  +	    result = stat (dirname, &dir_st);
  +	    
  +	    if (result == 0 && (dir_st.st_mode & S_ISGID))
  +	      st.st_gid = dir_st.st_gid;
  +	    else
  +	      st.st_gid = getgid ();
  +	  }
  +	g_free (dirname);
  +	g_free (only_filename);
  +	g_free (real_filename);
  +	
  +	if (o_save (toplevel, backup_filename)) {
  +	  p_current->ops_since_last_backup = 0;
  +	} else {
  +	  s_log_message ("Could NOT save backup file [%s]\n", 
  +			 backup_filename);
  +	}
  +	g_free (backup_filename);
  +      }
  +    }
  +    
  +  }
  +
  +  /* restore current page */
  +  s_page_goto (toplevel, p_save);
  +
  +  /* Returns non-zero if we want to continue autosaving */
  +  return toplevel->auto_save_interval;
  +  
  +}
  +
  +@ %def s_page_autosave
  
  
  
  1.6       +3 -0      eda/geda/devel/libgeda/noweb/s_toplevel.nw
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_toplevel.nw
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/devel/libgeda/noweb/s_toplevel.nw,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -b -r1.5 -r1.6
  --- s_toplevel.nw	15 Aug 2005 01:26:51 -0000	1.5
  +++ s_toplevel.nw	28 Oct 2005 22:26:33 -0000	1.6
  @@ -460,6 +460,9 @@
     toplevel->hierarchy_uref_order = 0;
     toplevel->unnamed_netname = NULL;
   
  +  /* Auto-save interval */
  +  toplevel->auto_save_interval = 0;
  +
     /* set the rest of the variables */
     if (variable_set_func) {
       (*variable_set_func) (toplevel);
  
  
  
  1.6       +1 -1      eda/geda/devel/libgeda/noweb/s_undo.nw
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_undo.nw
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/devel/libgeda/noweb/s_undo.nw,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -b -r1.5 -r1.6