[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