1
1

* editlock.c, editlock.h: New files. Implement file locking in

Emacs style, as documented in JED editor sources.
* Makefile.am: Add those files to build tree.

* edit-widget.c (WEdit): New property 'locked', 0 on edit_init.
* edit.c (edit_modification): Lock buffer on modification.
* editcmd.c (edit_save_cmd, edit_save_as_cmd): Handle locking
during file save.
(edit_load_file_from_filename): Unlock.  Remove 2 duplicate
lines (handled by edit_init).
(edit_quit_cmd): Unlock.
Этот коммит содержится в:
Pavel Roskin 2003-04-02 19:36:10 +00:00
родитель b190930e09
Коммит d88b75838a
7 изменённых файлов: 272 добавлений и 11 удалений

Просмотреть файл

@ -1,3 +1,17 @@
2003-04-01 Adam Byrtek <alpha@debian.org>
* editlock.c, editlock.h: New files. Implement file locking in
Emacs style, as documented in JED editor sources.
* Makefile.am: Add those files to build tree.
* edit-widget.c (WEdit): New property 'locked', 0 on edit_init.
* edit.c (edit_modification): Lock buffer on modification.
* editcmd.c (edit_save_cmd, edit_save_as_cmd): Handle locking
during file save.
(edit_load_file_from_filename): Unlock. Remove 2 duplicate
lines (handled by edit_init).
(edit_quit_cmd): Unlock.
2003-03-12 Pavel Roskin <proski@gnu.org> 2003-03-12 Pavel Roskin <proski@gnu.org>
* edit.h: Make it easier to tweak buffer size and maximal number * edit.h: Make it easier to tweak buffer size and maximal number

Просмотреть файл

@ -9,6 +9,6 @@ endif
libedit_a_SOURCES = \ libedit_a_SOURCES = \
bookmark.c edit.c editcmd.c editwidget.c editdraw.c editkeys.c \ bookmark.c edit.c editcmd.c editwidget.c editdraw.c editkeys.c \
editmenu.c editoptions.c editcmddef.h edit.h edit-widget.h \ editmenu.c editoptions.c editcmddef.h edit.h edit-widget.h \
syntax.c wordproc.c editlock.c editlock.h syntax.c wordproc.c
EXTRA_DIST = ChangeLog EXTRA_DIST = ChangeLog

Просмотреть файл

@ -56,6 +56,7 @@ struct WEdit {
unsigned char overwrite; unsigned char overwrite;
unsigned char modified; /* has the file been changed?: 1 if char inserted or unsigned char modified; /* has the file been changed?: 1 if char inserted or
deleted at all since last load or save */ deleted at all since last load or save */
unsigned char locked; /* 1 if lock is held on current file */
unsigned char screen_modified; /* has the file been changed since the last screen draw? */ unsigned char screen_modified; /* has the file been changed since the last screen draw? */
int delete_file; /* Has the file been created by the editor? Delete int delete_file; /* Has the file been created by the editor? Delete
it at end of editing when it hasn't been modified it at end of editing when it hasn't been modified

Просмотреть файл

@ -22,6 +22,7 @@
#include <config.h> #include <config.h>
#include "edit.h" #include "edit.h"
#include "editlock.h"
#include "edit-widget.h" #include "edit-widget.h"
#include "editcmddef.h" #include "editcmddef.h"
@ -554,6 +555,7 @@ edit_init (WEdit *edit, int lines, int columns, const char *filename,
return 0; return 0;
} }
edit->modified = 0; edit->modified = 0;
edit->locked = 0;
edit_load_syntax (edit, 0, 0); edit_load_syntax (edit, 0, 0);
{ {
int color; int color;
@ -811,8 +813,12 @@ pop_action (WEdit * edit)
static inline void edit_modification (WEdit * edit) static inline void edit_modification (WEdit * edit)
{ {
edit->caches_valid = 0; edit->caches_valid = 0;
edit->modified = 1;
edit->screen_modified = 1; edit->screen_modified = 1;
/* raise lock when file modified */
if (!edit->modified && !edit->delete_file)
edit->locked = edit_lock_file (edit->filename);
edit->modified = 1;
} }
/* /*

Просмотреть файл

@ -27,6 +27,7 @@
#include <ctype.h> #include <ctype.h>
#include "edit.h" #include "edit.h"
#include "editlock.h"
#include "editcmddef.h" #include "editcmddef.h"
#include "edit-widget.h" #include "edit-widget.h"
@ -184,9 +185,6 @@ void edit_refresh_cmd (WEdit * edit)
doupdate(); doupdate();
} }
/* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
...thanks -paul */
/* If 0 (quick save) then a) create/truncate <filename> file, /* If 0 (quick save) then a) create/truncate <filename> file,
b) save to <filename>; b) save to <filename>;
if 1 (safe save) then a) save to <tempnam>, if 1 (safe save) then a) save to <tempnam>,
@ -438,6 +436,7 @@ edit_save_as_cmd (WEdit *edit)
{ {
/* This heads the 'Save As' dialog box */ /* This heads the 'Save As' dialog box */
char *exp = 0; char *exp = 0;
int save_lock = 0;
int different_filename = 0; int different_filename = 0;
exp = edit_get_save_file (edit->filename, _(" Save As ")); exp = edit_get_save_file (edit->filename, _(" Save As "));
@ -465,8 +464,25 @@ edit_save_as_cmd (WEdit *edit)
return 0; return 0;
} }
} }
save_lock = edit_lock_file (exp);
} else {
/* filenames equal, check if already locked */
if (!edit->locked && !edit->delete_file)
save_lock = edit_lock_file (exp);
} }
if (edit_save_file (edit, exp)) { if (edit_save_file (edit, exp)) {
/* Succesful, so unlock both files */
if (strcmp (edit->filename, exp)) {
if (save_lock)
edit_unlock_file (exp);
if (edit->locked)
edit->locked = edit_unlock_file (edit->filename);
} else {
if (edit->locked || save_lock)
edit->locked = edit_unlock_file (edit->filename);
}
edit_set_filename (edit, exp); edit_set_filename (edit, exp);
g_free (exp); g_free (exp);
edit->modified = 0; edit->modified = 0;
@ -476,6 +492,11 @@ edit_save_as_cmd (WEdit *edit)
edit->force |= REDRAW_COMPLETELY; edit->force |= REDRAW_COMPLETELY;
return 1; return 1;
} else { } else {
/* Failed, so maintain modify (not save) lock */
if (strcmp (edit->filename, exp) && save_lock)
edit_unlock_file (exp);
if (save_lock)
edit->locked = edit_unlock_file (edit->filename);
g_free (exp); g_free (exp);
edit_error_dialog (_(" Save As "), edit_error_dialog (_(" Save As "),
get_sys_error (_ get_sys_error (_
@ -730,11 +751,22 @@ int edit_save_confirm_cmd (WEdit * edit)
/* returns 1 on success */ /* returns 1 on success */
int edit_save_cmd (WEdit * edit) int edit_save_cmd (WEdit * edit)
{ {
if (!edit_save_file (edit, edit->filename)) int res, save_lock = 0;
if (!edit->locked && !edit->delete_file)
save_lock = edit_lock_file (edit->filename);
res = edit_save_file (edit, edit->filename);
/* Maintain modify (not save) lock on failure */
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)
return edit_save_as_cmd (edit); return edit_save_as_cmd (edit);
edit->force |= REDRAW_COMPLETELY; edit->force |= REDRAW_COMPLETELY;
edit->modified = 0;
edit->delete_file = 0; edit->delete_file = 0;
edit->modified = 0;
return 1; return 1;
} }
@ -750,7 +782,9 @@ int edit_new_cmd (WEdit * edit)
} }
} }
edit->force |= REDRAW_COMPLETELY; edit->force |= REDRAW_COMPLETELY;
edit->modified = 0;
if (edit->locked)
edit->locked = edit_unlock_file (edit->filename);
return edit_renew (edit); /* if this gives an error, something has really screwed up */ return edit_renew (edit); /* if this gives an error, something has really screwed up */
} }
@ -758,10 +792,17 @@ int edit_new_cmd (WEdit * edit)
static int static int
edit_load_file_from_filename (WEdit * edit, char *exp) edit_load_file_from_filename (WEdit * edit, char *exp)
{ {
if (!edit_reload (edit, exp)) int prev_locked = edit->locked;
char *prev_filename = g_strdup (edit->filename);
if (!edit_reload (edit, exp)) {
g_free (prev_filename);
return 1; return 1;
edit_set_filename (edit, exp); }
edit->modified = 0;
if (prev_locked)
edit_unlock_file (prev_filename);
g_free (prev_filename);
return 0; return 0;
} }
@ -2023,6 +2064,8 @@ void edit_quit_cmd (WEdit * edit)
return; return;
break; break;
case 2: case 2:
if (edit->locked)
edit->locked = edit_unlock_file (edit->filename);
if (edit->delete_file) if (edit->delete_file)
unlink (edit->filename); unlink (edit->filename);
break; break;

190
edit/editlock.c Обычный файл
Просмотреть файл

@ -0,0 +1,190 @@
/* editor file locking.
Copyright (C) 2003 the Free Software Foundation
Authors: 2003 Adam Byrtek
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
*/
#include <config.h>
#include "edit.h"
#include "editlock.h"
#include "src/wtools.h" /* edit_query_dialog () */
#define BUF_SIZE 255
#define PID_BUF_SIZE 10
/* Locking scheme used in mcedit is based on a documentation found
in JED editor sources. Abstract from lock.c file (by John E. Davis):
The basic idea here is quite simple. Whenever a buffer is attached to
a file, and that buffer is modified, then attempt to lock the
file. Moreover, before writing to a file for any reason, lock the
file. The lock is really a protocol respected and not a real lock.
The protocol is this: If in the directory of the file is a
symbolic link with name ".#FILE", the FILE is considered to be locked
by the process specified by the link.
*/
/* Build user@host.domain.pid string (need to be freed) */
static char *
lock_build_name (char *fname)
{
char host[BUF_SIZE], *user;
if (!
((user = getpwuid (getuid ())->pw_name) || (user = getenv ("USER"))
|| (user = getenv ("USERNAME")) || (user = getenv ("LOGNAME"))))
user = "";
/* TODO: Use FQDN, no clean interface, so requires lot of code */
if (gethostname (host, BUF_SIZE - 1) == -1)
*host = '\0';
return g_strdup_printf ("%s@%s.%d", user, host, getpid ());
}
/* Extract pid from user@host.domain.pid string */
static pid_t
lock_extract_pid (char *str)
{
int i;
char *p, pid[PID_BUF_SIZE];
/* Treat text between '.' and ':' or '\0' as pid */
for (p = str + strlen (str) - 1; p >= str; p--)
if (*p == '.')
break;
i = 0;
for (p = p + 1;
p < str + strlen (str) && *p != ':' && i < PID_BUF_SIZE; p++)
pid[i++] = *p;
pid[i] = '\0';
return (pid_t) atol (pid);
}
/* Extract user@host.domain.pid from lock file (static string) */
static char *
lock_get_info (char *lockfname)
{
int cnt;
static char buf[BUF_SIZE];
if ((cnt = readlink (lockfname, buf, BUF_SIZE - 1)) == -1 || !buf
|| !*buf)
return NULL;
buf[cnt] = '\0';
return buf;
}
/* Tries to raise file lock
Returns 1 on success, 0 on failure, -1 if abort */
int
edit_lock_file (char *fname)
{
char *lockfname, *newlock, *msg, *lock;
struct stat statbuf;
pid_t pid;
/* Just to be sure (and don't lock new file) */
if (!fname || !*fname)
return 0;
/* Check if already locked */
lockfname = g_strconcat (".#", fname, NULL);
if (lstat (lockfname, &statbuf) == 0) {
lock = lock_get_info (lockfname);
if (!lock) {
g_free (lockfname);
return 0;
}
pid = lock_extract_pid (lock);
/* Check if locking process alive, ask user if required */
if (!pid || !(kill (pid, 0) == -1 && errno == ESRCH)) {
msg =
g_strdup_printf (_("File %s is locked by lock %s"), fname,
lock);
/* TODO: Implement "Abort" - needs to rewind undo stack */
switch (edit_query_dialog2
(_("File locked"), msg, _("&Grab lock"),
_("&Ignore lock"))) {
case 0:
break;
case 1:
case -1:
g_free (lockfname);
g_free (msg);
return 0;
}
g_free (msg);
}
unlink (lockfname);
}
/* Create lock symlink */
newlock = lock_build_name (fname);
if (symlink (newlock, lockfname) == -1) {
g_free (lockfname);
g_free (newlock);
return 0;
}
g_free (lockfname);
g_free (newlock);
return 1;
}
/* Lowers file lock if possible
Always returns 0 to make 'lock = edit_unlock_file (f)' possible */
int
edit_unlock_file (char *fname)
{
char *lockfname, *lock;
struct stat statbuf;
/* Just to be sure */
if (!fname || !*fname)
return 0;
lockfname = g_strconcat (".#", fname, NULL);
/* Check if lock exists */
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_pid (lock) != getpid ()) {
g_free (lockfname);
return 0;
}
}
/* Remove lock */
unlink (lockfname);
g_free (lockfname);
return 0;
}

7
edit/editlock.h Обычный файл
Просмотреть файл

@ -0,0 +1,7 @@
#ifndef __EDIT_LOCK_H
#define __EDIT_LOCK_H
int edit_lock_file (char *fname);
int edit_unlock_file (char *fname);
#endif /* !__EDIT_LOCK_H */