1 /* editor file locking.
3 Copyright (C) 2003 the Free Software Foundation
5 Authors: 2003 Adam Byrtek
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 #include "../src/wtools.h" /* edit_query_dialog () */
31 #define PID_BUF_SIZE 10
38 /* Locking scheme used in mcedit is based on a documentation found
39 in JED editor sources. Abstract from lock.c file (by John E. Davis):
41 The basic idea here is quite simple. Whenever a buffer is attached to
42 a file, and that buffer is modified, then attempt to lock the
43 file. Moreover, before writing to a file for any reason, lock the
44 file. The lock is really a protocol respected and not a real lock.
45 The protocol is this: If in the directory of the file is a
46 symbolic link with name ".#FILE", the FILE is considered to be locked
47 by the process specified by the link.
50 /* Build user@host.domain.pid string (need to be freed) */
52 lock_build_name (char *fname
)
54 char host
[BUF_SIZE
], *user
;
57 ((user
= getpwuid (getuid ())->pw_name
) || (user
= getenv ("USER"))
58 || (user
= getenv ("USERNAME")) || (user
= getenv ("LOGNAME"))))
61 /* TODO: Use FQDN, no clean interface, so requires lot of code */
62 if (gethostname (host
, BUF_SIZE
- 1) == -1)
65 return g_strdup_printf ("%s@%s.%d", user
, host
, getpid ());
68 /* Extract pid from user@host.domain.pid string */
69 static struct lock_s
*
70 lock_extract_info (char *str
)
74 static char pid
[PID_BUF_SIZE
], who
[BUF_SIZE
];
75 static struct lock_s lock
;
77 for (p
= str
+ strlen (str
) - 1; p
>= str
; p
--)
81 /* Everything before last '.' is user@host */
83 for (s
= str
; s
< p
&& i
< BUF_SIZE
; s
++)
87 /* Treat text between '.' and ':' or '\0' as pid */
90 p
< str
+ strlen (str
) && *p
!= ':' && i
< PID_BUF_SIZE
; p
++)
94 lock
.pid
= (pid_t
) atol (pid
);
99 /* Extract user@host.domain.pid from lock file (static string) */
101 lock_get_info (char *lockfname
)
104 static char buf
[BUF_SIZE
];
106 if ((cnt
= readlink (lockfname
, buf
, BUF_SIZE
- 1)) == -1 || !buf
114 /* Tries to raise file lock
115 Returns 1 on success, 0 on failure, -1 if abort
116 Warning: Might do screen refresh and lose edit->force */
118 edit_lock_file (char *fname
)
120 char *lockfname
, *newlock
, *msg
, *lock
;
122 struct lock_s
*lockinfo
;
124 /* Just to be sure (and don't lock new file) */
125 if (!fname
|| !*fname
)
128 /* Locking on VFS is not supported */
129 if (!vfs_file_is_local (fname
))
132 /* Check if already locked */
133 lockfname
= g_strconcat (".#", fname
, NULL
);
134 if (lstat (lockfname
, &statbuf
) == 0) {
135 lock
= lock_get_info (lockfname
);
140 lockinfo
= lock_extract_info (lock
);
142 /* Check if locking process alive, ask user if required */
144 || !(kill (lockinfo
->pid
, 0) == -1 && errno
== ESRCH
)) {
147 ("File \"%s\" is already being edited\n"
148 "User: %s\nProcess ID: %d"), fname
,
149 lockinfo
->who
, lockinfo
->pid
);
150 /* TODO: Implement "Abort" - needs to rewind undo stack */
151 switch (edit_query_dialog2
152 (_("File locked"), msg
, _("&Grab lock"),
153 _("&Ignore lock"))) {
167 /* Create lock symlink */
168 newlock
= lock_build_name (fname
);
169 if (symlink (newlock
, lockfname
) == -1) {
180 /* Lowers file lock if possible
181 Always returns 0 to make 'lock = edit_unlock_file (f)' possible */
183 edit_unlock_file (char *fname
)
185 char *lockfname
, *lock
;
188 /* Just to be sure */
189 if (!fname
|| !*fname
)
192 lockfname
= g_strconcat (".#", fname
, NULL
);
194 /* Check if lock exists */
195 if (lstat (lockfname
, &statbuf
) == -1) {
200 lock
= lock_get_info (lockfname
);
202 /* Don't touch if lock is not ours */
203 if (lock_extract_info (lock
)->pid
!= getpid ()) {