Re: [PATCH] Editor locking update



On Thu, Mar 25, 2004 at 11:10:39PM +0100, Adam Byrtek / alpha wrote:
> Hi. I'm attaching a patch to the editor locking scheme. First of all

I'm attaching a patch which you might consider an update to the
previous one. Initially I wanted to separate them into two different
patches, but they depend heavily on each other, so I joined them
together.

This update implements mtime check to discover if the file was
modified by some other process during the current editor session (it
is a problem that locking didn't solve).

You might want to consult mailing list archives, especially:
http://mail.gnome.org/archives/mc-devel/2004-February/msg00001.html

I have also posted this patch to the Savannah PTS.

Regards
Adam

PS. I don't know if Cooledit author reads this list, but he might
consider using this patch in his own project.

-- 
  __ _
 / _` |   Adam Byrtek -*- jid alpha.jabber.lfa.pl -*- pgp 0xB25952C0
 \__,_|   "Każdy ideał w ciele jest trywialny" - prawdy algebraiczne

Index: ChangeLog
===================================================================
RCS file: /cvsroot/mc/mc/edit/ChangeLog,v
retrieving revision 1.188
diff -u -p -r1.188 ChangeLog
--- ChangeLog	4 Feb 2004 23:09:22 -0000	1.188
+++ ChangeLog	26 Mar 2004 17:07:54 -0000
@@ -1,3 +1,27 @@
+2004-03-25  Adam Byrtek  <alpha debian org>
+
+        * edit-widget.h (strruct WEdit): New flag rewind. New property
+	load_time.
+	* edit.c (edit_init): Initialize rewind with 0, load_time with
+	current time. (edit_modification): Change rewind flag to 1
+	when lock encountered and user aborts or file modified on disk
+	during editor session and user aborts.
+	(edit_execute_key_command): Rewind last keypress undo
+	information if rewind flag 1.
+	* editcmd.c (edit_save_as_cmd): Check if lock still valid
+	before save. Abort when lock encountered and user aborts. On
+	success update load_time to current time. (edit_save_cmd): The
+	same as above.
+	* editlock.c: Spelling fixes. Sanity check in every function.
+	(edit_lock_file): New dialog option 'Abort'. 'Ignore lock'
+	rephrased to 'Proceed'. (edit_unlock_file): Parts moved to new
+	function edit_lock_check. (edit_lock_check): New function.
+	Check if lock is still valid (eg. not grabbed by sb else).
+	(edit_check_mtime): New function, check if file was modified
+	on disk during current editor session.
+	* editlock.h: New prototypes edit_lock_check,
+	edit_check_mtime.
+
 2004-02-04  Pavel Roskin  <proski gnu org>
 
 	* editcmddef.h: Split CK_No_Command into CK_Insert_Char and
Index: edit-widget.h
===================================================================
RCS file: /cvsroot/mc/mc/edit/edit-widget.h,v
retrieving revision 1.23
diff -u -p -r1.23 edit-widget.h
--- edit-widget.h	29 Oct 2003 08:54:47 -0000	1.23
+++ edit-widget.h	26 Mar 2004 17:07:54 -0000
@@ -55,7 +55,6 @@ struct WEdit {
     int overwrite:1;		/* Overwrite on type mode (as opposed to insert) */
     int modified:1;		/* File has been modified and needs saving */
     int loading_done:1;		/* File has been loaded into the editor */
-    int locked:1;		/* We hold lock on current file */
     int screen_modified:1;	/* File has been changed since the last screen draw */
     int delete_file:1;		/* New file, needs to be deleted unless modified */
     int highlight:1;		/* There is a selected block */
@@ -64,6 +63,11 @@ struct WEdit {
     long curs_line;		/* line number of the cursor. */
     long start_line;		/* line number of the top of the page */
 
+    /* file integrity infomation */
+    int locked:1;		/* We hold lock on current file */
+    int rewind:1;		/* Rewind changes on abort */
+    int load_time;              /* Time the file was loaded */
+    
     /* file info */
     long total_lines;		/* total lines in the file */
     long mark1;			/* position of highlight start */
Index: edit.c
===================================================================
RCS file: /cvsroot/mc/mc/edit/edit.c,v
retrieving revision 1.87
diff -u -p -r1.87 edit.c
--- edit.c	4 Feb 2004 22:27:58 -0000	1.87
+++ edit.c	26 Mar 2004 17:07:57 -0000
@@ -551,6 +551,8 @@ edit_init (WEdit *edit, int lines, int c
     edit->loading_done = 1;
     edit->modified = 0;
     edit->locked = 0;
+    edit->rewind = 0;
+    edit->load_time = time (NULL);
     edit_load_syntax (edit, 0, 0);
     {
 	int color;
@@ -816,12 +818,31 @@ pop_action (WEdit * edit)
 /* is called whenever a modification is made by one of the four routines below */
 static inline void edit_modification (WEdit * edit)
 {
+    int lock;
+    
     edit->caches_valid = 0;
     edit->screen_modified = 1;
     
-    /* raise lock when file modified */
-    if (!edit->modified && !edit->delete_file)
-	edit->locked = edit_lock_file (edit->filename);
+    if (!edit->modified && !edit->delete_file) {
+	/* Check file mtime, rewind if user aborted */
+	if (!edit_check_mtime (edit->filename, edit->load_time)) {
+	    edit->rewind = 1;
+	    edit->modified = 1;
+	    return;
+	}
+	
+	/* Try to fetch lock */
+	lock = edit_lock_file (edit->filename);
+	
+	/* User aborted on lock, rewind */
+	if (lock == -1) {
+	    edit->rewind = 1;
+	    edit->locked = 0;
+	} else {
+	    edit->locked = lock;
+	}
+    }
+    
     edit->modified = 1;
 }
 
@@ -2125,6 +2146,15 @@ void edit_execute_key_command (WEdit *ed
 	edit_push_key_press (edit);
 
     edit_execute_cmd (edit, command, char_for_insertion);
+    
+    /* User aborted (eg. because file is locked), rewind the stack */
+    if (edit->rewind) {
+	edit_do_undo (edit);
+	edit->rewind = 0;
+	/* TODO: Should be done by edit_do_undo */
+	edit->modified = 0;
+    }
+	
     if (column_highlighting)
 	edit->force |= REDRAW_PAGE;
 }
Index: editcmd.c
===================================================================
RCS file: /cvsroot/mc/mc/edit/editcmd.c,v
retrieving revision 1.102
diff -u -p -r1.102 editcmd.c
--- editcmd.c	27 Nov 2003 10:23:50 -0000	1.102
+++ editcmd.c	26 Mar 2004 17:08:03 -0000
@@ -465,6 +465,9 @@ edit_save_as_cmd (WEdit *edit)
     exp = edit_get_save_file (edit->filename, _(" Save As "));
     edit_push_action (edit, KEY_PRESS + edit->start_display);
 
+    /* Check if lock still valid */
+    edit->locked = edit_lock_check (edit->filename);
+    
     if (exp) {
 	if (!*exp) {
 	    g_free (exp);
@@ -475,7 +478,7 @@ edit_save_as_cmd (WEdit *edit)
 		int file;
 		different_filename = 1;
 		if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
-		    /* the file exists */
+		    /* The file exists */
 		    mc_close (file);
 		    /* Overwrite the current file or cancel the operation */
 		    if (edit_query_dialog2
@@ -488,10 +491,21 @@ edit_save_as_cmd (WEdit *edit)
 		    }
 		}
 		save_lock = edit_lock_file (exp);
+		/* User aborted */
+		if (save_lock == -1) {
+		    g_free (exp);
+		    return 0;
+		}
 	    } else {
-		/* filenames equal, check if already locked */
-		if (!edit->locked && !edit->delete_file)
+		/* Filenames equal, raise lock if not already raised */
+		if (!edit->locked && !edit->delete_file) {
 		    save_lock = edit_lock_file (exp);
+		    /* User aborted */
+		    if (save_lock == -1) {
+			g_free (exp);
+			return 0;
+		    }
+		}
 	    }
 		
 	    if (edit_save_file (edit, exp)) {
@@ -510,12 +524,13 @@ edit_save_as_cmd (WEdit *edit)
 		g_free (exp);
 		edit->modified = 0;
 		edit->delete_file = 0;
+		edit->load_time = time (NULL);
 		if (different_filename)
 		    edit_load_syntax (edit, 0, 0);
 		edit->force |= REDRAW_COMPLETELY;
 		return 1;
 	    } else {
-		/* Failed, so maintain modify (not save) lock */
+		/* On failure maintain lock if locked before */
 		if (strcmp (edit->filename, exp) && save_lock)
 		    edit_unlock_file (exp);
 		if (save_lock)
@@ -778,20 +793,30 @@ edit_save_cmd (WEdit *edit)
 {
     int res, save_lock = 0;
     
-    if (!edit->locked && !edit->delete_file)
+    /* Check if lock is still valid */
+    edit->locked = edit_lock_check (edit->filename);
+    
+    /* Try to fetch lock otherwise */
+    if (!edit->locked && !edit->delete_file) {
 	save_lock = edit_lock_file (edit->filename);
+	/* User aborted */
+	if (save_lock == -1)
+	    return 0;
+    }
+
     res = edit_save_file (edit, edit->filename);
     
-    /* Maintain modify (not save) lock on failure */
+    /* On failure maintain lock if locked before */
     if ((res && edit->locked) || save_lock)
 	edit->locked = edit_unlock_file (edit->filename);
     
     /* On failure try 'save as', it does locking on its own */
-    if (!res) 
+    if (!res)
 	return edit_save_as_cmd (edit);
     edit->force |= REDRAW_COMPLETELY;
     edit->delete_file = 0;
     edit->modified = 0;
+    edit->load_time = time (NULL);
 
     return 1;
 }
Index: editlock.c
===================================================================
RCS file: /cvsroot/mc/mc/edit/editlock.c,v
retrieving revision 1.6
diff -u -p -r1.6 editlock.c
--- editlock.c	21 Nov 2003 03:17:18 -0000	1.6
+++ editlock.c	26 Mar 2004 17:08:03 -0000
@@ -1,4 +1,4 @@
-/* editor file locking.
+/* Editor file locking and mtime check.
 
    Copyright (C) 2003 the Free Software Foundation
 
@@ -66,7 +66,7 @@ lock_build_name (char *fname)
     return g_strdup_printf ("%s %s %d", user, host, getpid ());
 }
 
-/* Extract pid from user host domain pid string */
+/* Extract info from user host domain pid string */
 static struct lock_s *
 lock_extract_info (char *str)
 {
@@ -112,9 +112,9 @@ lock_get_info (char *lockfname)
 }
 
 
-/* Tries to raise file lock
-   Returns 1 on success,  0 on failure, -1 if abort 
-   Warning: Might do screen refresh and lose edit->force */
+/* Try to raise file lock
+   Return 1 if lock raised,  0 if lock ignored, -1 on abort
+   Note: Might do screen refresh and lose edit->force */
 int
 edit_lock_file (char *fname)
 {
@@ -122,12 +122,8 @@ edit_lock_file (char *fname)
     struct stat statbuf;
     struct lock_s *lockinfo;
 
-    /* Just to be sure (and don't lock new file) */
-    if (!fname || !*fname)
-	return 0;
-
-    /* Locking on VFS is not supported */
-    if (!vfs_file_is_local (fname))
+    /* Some sanity checks */
+    if (!fname || !*fname || !vfs_file_is_local (fname))
 	return 0;
 
     /* Check if already locked */
@@ -148,17 +144,19 @@ edit_lock_file (char *fname)
 				 ("File \"%s\" is already being edited\n"
 				  "User: %s\nProcess ID: %d"), fname,
 				 lockinfo->who, lockinfo->pid);
-	    /* TODO: Implement "Abort" - needs to rewind undo stack */
-	    switch (edit_query_dialog2
+	    switch (edit_query_dialog3
 		    (_("File locked"), msg, _("&Grab lock"),
-		     _("&Ignore lock"))) {
+		     _("&Proceed"), _("&Abort"))) {
 	    case 0:
 		break;
 	    case 1:
-	    case -1:
 		g_free (lockfname);
 		g_free (msg);
 		return 0;
+	    case 2: case -1:
+		g_free (lockfname);
+		g_free (msg);
+		return -1;
 	    }
 	    g_free (msg);
 	}
@@ -178,37 +176,77 @@ edit_lock_file (char *fname)
     return 1;
 }
 
-/* Lowers file lock if possible 
-   Always returns 0 to make 'lock = edit_unlock_file (f)' possible */
+/* Lower file lock if possible 
+   Always return 0 to make 'lock = edit_unlock_file (f)' possible */
 int
 edit_unlock_file (char *fname)
 {
+    char *lockfname;
+
+    /* Some sanity checks */
+    if (!fname || !*fname || !vfs_file_is_local (fname))
+	return 0;
+
+    /* If lock is ours, remove it */
+    if (edit_lock_check (fname)) {
+	lockfname = g_strconcat (".#", fname, NULL);
+	unlink (lockfname);
+	g_free (lockfname);
+    }
+    return 0;
+}
+
+/* Check if lock is still valid
+   Return 1 if lock is valid, 0 if no lock or lock grabbed */
+int
+edit_lock_check (char *fname)
+{
     char *lockfname, *lock;
     struct stat statbuf;
 
-    /* Just to be sure */
-    if (!fname || !*fname)
+    /* Some sanity checks */
+    if (!fname || !*fname || !vfs_file_is_local (fname))
 	return 0;
 
-    lockfname = g_strconcat (".#", fname, NULL);
-
     /* Check if lock exists */
+    lockfname = g_strconcat (".#", fname, NULL);
     if (lstat (lockfname, &statbuf) == -1) {
 	g_free (lockfname);
 	return 0;
     }
 
     lock = lock_get_info (lockfname);
-    if (lock) {
-	/* Don't touch if lock is not ours */
-	if (lock_extract_info (lock)->pid != getpid ()) {
-	    g_free (lockfname);
-	    return 0;
-	}
-    }
-
-    /* Remove lock */
-    unlink (lockfname);
     g_free (lockfname);
-    return 0;
+
+    /* Check if lock is ours */
+    if (strcmp (lock_build_name (fname), lock) != 0)
+	return 0;
+    return 1;
+}
+
+/* Check if file modified on disk during current session
+   Return 1 if ok or user accepted, 0 on abort */
+int
+edit_check_mtime (char *fname, time_t load_time)
+{
+    char *msg;
+    struct stat statbuf;
+    
+    if (stat (fname, &statbuf) == 0)
+	if (statbuf.st_mtime > load_time) {
+	    msg = g_strdup_printf (_
+				   ("File \"%s\" changed on disk.\n"
+				    "Do you really want to edit?"), fname);
+	    switch (edit_query_dialog2
+		    (_("File changed"), msg, _("&Proceed"),
+		     _("&Abort"))) {
+	    case 0 :
+		g_free (msg);
+		return 1;
+	    case 1 : case -1 :
+		g_free (msg);
+		return 0;
+	    }
+	}
+    return 1;
 }
Index: editlock.h
===================================================================
RCS file: /cvsroot/mc/mc/edit/editlock.h,v
retrieving revision 1.1
diff -u -p -r1.1 editlock.h
--- editlock.h	2 Apr 2003 19:36:10 -0000	1.1
+++ editlock.h	26 Mar 2004 17:08:03 -0000
@@ -3,5 +3,7 @@
 
 int edit_lock_file (char *fname);
 int edit_unlock_file (char *fname);
+int edit_lock_check (char *fname);
+int edit_check_mtime (char *fname, time_t load_time);
 
 #endif				/* !__EDIT_LOCK_H */


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