|
@@ -19,7 +19,7 @@
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301, USA.
|
|
02110-1301, USA.
|
|
|
|
|
|
-*/
|
|
|
|
|
|
+ */
|
|
|
|
|
|
/** \file
|
|
/** \file
|
|
* \brief Source: file locking
|
|
* \brief Source: file locking
|
|
@@ -40,7 +40,7 @@
|
|
|
|
|
|
#include <config.h>
|
|
#include <config.h>
|
|
|
|
|
|
-#include <signal.h> /* kill() */
|
|
|
|
|
|
+#include <signal.h> /* kill() */
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stdarg.h>
|
|
#include <sys/types.h>
|
|
#include <sys/types.h>
|
|
@@ -54,14 +54,16 @@
|
|
|
|
|
|
#include "lib/global.h"
|
|
#include "lib/global.h"
|
|
#include "lib/vfs/mc-vfs/vfs.h"
|
|
#include "lib/vfs/mc-vfs/vfs.h"
|
|
|
|
+#include "lib/util.h" /* tilde_expand() */
|
|
#include "lib/lock.h"
|
|
#include "lib/lock.h"
|
|
|
|
|
|
-#include "src/wtools.h" /* query_dialog() */
|
|
|
|
|
|
+#include "src/wtools.h" /* query_dialog() */
|
|
|
|
|
|
#define BUF_SIZE 255
|
|
#define BUF_SIZE 255
|
|
#define PID_BUF_SIZE 10
|
|
#define PID_BUF_SIZE 10
|
|
|
|
|
|
-struct lock_s {
|
|
|
|
|
|
+struct lock_s
|
|
|
|
+{
|
|
char *who;
|
|
char *who;
|
|
pid_t pid;
|
|
pid_t pid;
|
|
};
|
|
};
|
|
@@ -78,15 +80,20 @@ lock_build_name (void)
|
|
struct passwd *pw;
|
|
struct passwd *pw;
|
|
|
|
|
|
pw = getpwuid (getuid ());
|
|
pw = getpwuid (getuid ());
|
|
- if (pw) user = pw->pw_name;
|
|
|
|
- if (!user) user = getenv ("USER");
|
|
|
|
- if (!user) user = getenv ("USERNAME");
|
|
|
|
- if (!user) user = getenv ("LOGNAME");
|
|
|
|
- if (!user) user = "";
|
|
|
|
|
|
+ if (pw)
|
|
|
|
+ user = pw->pw_name;
|
|
|
|
+ if (!user)
|
|
|
|
+ user = getenv ("USER");
|
|
|
|
+ if (!user)
|
|
|
|
+ user = getenv ("USERNAME");
|
|
|
|
+ if (!user)
|
|
|
|
+ user = getenv ("LOGNAME");
|
|
|
|
+ if (!user)
|
|
|
|
+ user = "";
|
|
|
|
|
|
/** \todo Use FQDN, no clean interface, so requires lot of code */
|
|
/** \todo Use FQDN, no clean interface, so requires lot of code */
|
|
if (gethostname (host, BUF_SIZE - 1) == -1)
|
|
if (gethostname (host, BUF_SIZE - 1) == -1)
|
|
- *host = '\0';
|
|
|
|
|
|
+ *host = '\0';
|
|
|
|
|
|
return g_strdup_printf ("%s@%s.%d", user, host, (int) getpid ());
|
|
return g_strdup_printf ("%s@%s.%d", user, host, (int) getpid ());
|
|
}
|
|
}
|
|
@@ -98,7 +105,7 @@ lock_build_symlink_name (const char *fname)
|
|
char absolute_fname[PATH_MAX];
|
|
char absolute_fname[PATH_MAX];
|
|
|
|
|
|
if (mc_realpath (fname, absolute_fname) == NULL)
|
|
if (mc_realpath (fname, absolute_fname) == NULL)
|
|
- return NULL;
|
|
|
|
|
|
+ return NULL;
|
|
|
|
|
|
fname = x_basename (absolute_fname);
|
|
fname = x_basename (absolute_fname);
|
|
fname_copy = g_strdup (fname);
|
|
fname_copy = g_strdup (fname);
|
|
@@ -121,19 +128,19 @@ lock_extract_info (const char *str)
|
|
len = strlen (str);
|
|
len = strlen (str);
|
|
|
|
|
|
for (p = str + len - 1; p >= str; p--)
|
|
for (p = str + len - 1; p >= str; p--)
|
|
- if (*p == '.')
|
|
|
|
- break;
|
|
|
|
|
|
+ if (*p == '.')
|
|
|
|
+ break;
|
|
|
|
|
|
/* Everything before last '.' is user@host */
|
|
/* Everything before last '.' is user@host */
|
|
i = 0;
|
|
i = 0;
|
|
for (s = str; s < p && i < BUF_SIZE; s++)
|
|
for (s = str; s < p && i < BUF_SIZE; s++)
|
|
- who[i++] = *s;
|
|
|
|
|
|
+ who[i++] = *s;
|
|
who[i] = '\0';
|
|
who[i] = '\0';
|
|
|
|
|
|
/* Treat text between '.' and ':' or '\0' as pid */
|
|
/* Treat text between '.' and ':' or '\0' as pid */
|
|
i = 0;
|
|
i = 0;
|
|
for (p = p + 1; (p < str + len) && (*p != ':') && (i < PID_BUF_SIZE); p++)
|
|
for (p = p + 1; (p < str + len) && (*p != ':') && (i < PID_BUF_SIZE); p++)
|
|
- pid[i++] = *p;
|
|
|
|
|
|
+ pid[i++] = *p;
|
|
pid[i] = '\0';
|
|
pid[i] = '\0';
|
|
|
|
|
|
lock.pid = (pid_t) atol (pid);
|
|
lock.pid = (pid_t) atol (pid);
|
|
@@ -150,7 +157,7 @@ lock_get_info (const char *lockfname)
|
|
|
|
|
|
cnt = readlink (lockfname, buf, BUF_SIZE - 1);
|
|
cnt = readlink (lockfname, buf, BUF_SIZE - 1);
|
|
if (cnt == -1 || *buf == '\0')
|
|
if (cnt == -1 || *buf == '\0')
|
|
- return NULL;
|
|
|
|
|
|
+ return NULL;
|
|
buf[cnt] = '\0';
|
|
buf[cnt] = '\0';
|
|
return buf;
|
|
return buf;
|
|
}
|
|
}
|
|
@@ -165,63 +172,69 @@ lock_file (const char *fname)
|
|
char *lockfname, *newlock, *msg, *lock;
|
|
char *lockfname, *newlock, *msg, *lock;
|
|
struct stat statbuf;
|
|
struct stat statbuf;
|
|
struct lock_s *lockinfo;
|
|
struct lock_s *lockinfo;
|
|
|
|
+ gboolean symlink_ok;
|
|
|
|
|
|
/* Just to be sure (and don't lock new file) */
|
|
/* Just to be sure (and don't lock new file) */
|
|
- if (!fname || !*fname)
|
|
|
|
- return 0;
|
|
|
|
|
|
+ if (fname == NULL || *fname == '\0')
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ fname = tilde_expand (fname);
|
|
|
|
|
|
/* Locking on VFS is not supported */
|
|
/* Locking on VFS is not supported */
|
|
if (!vfs_file_is_local (fname))
|
|
if (!vfs_file_is_local (fname))
|
|
- return 0;
|
|
|
|
|
|
+ {
|
|
|
|
+ g_free (fname);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
|
|
/* Check if already locked */
|
|
/* Check if already locked */
|
|
lockfname = lock_build_symlink_name (fname);
|
|
lockfname = lock_build_symlink_name (fname);
|
|
|
|
+ g_free (fname);
|
|
if (lockfname == NULL)
|
|
if (lockfname == NULL)
|
|
- return 0;
|
|
|
|
- if (lstat (lockfname, &statbuf) == 0) {
|
|
|
|
- lock = lock_get_info (lockfname);
|
|
|
|
- if (!lock) {
|
|
|
|
- g_free (lockfname);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- lockinfo = lock_extract_info (lock);
|
|
|
|
-
|
|
|
|
- /* Check if locking process alive, ask user if required */
|
|
|
|
- if (!lockinfo->pid
|
|
|
|
- || !(kill (lockinfo->pid, 0) == -1 && errno == ESRCH)) {
|
|
|
|
- msg =
|
|
|
|
- g_strdup_printf (_
|
|
|
|
- ("File \"%s\" is already being edited.\n"
|
|
|
|
- "User: %s\nProcess ID: %d"), x_basename (lockfname) + 2,
|
|
|
|
- lockinfo->who, (int) lockinfo->pid);
|
|
|
|
- /* TODO: Implement "Abort" - needs to rewind undo stack */
|
|
|
|
- switch (query_dialog
|
|
|
|
- (_("File locked"), msg, D_NORMAL, 2, _("&Grab lock"),
|
|
|
|
- _("&Ignore lock"))) {
|
|
|
|
- case 0:
|
|
|
|
- break;
|
|
|
|
- case 1:
|
|
|
|
- case -1:
|
|
|
|
- g_free (lockfname);
|
|
|
|
- g_free (msg);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- g_free (msg);
|
|
|
|
- }
|
|
|
|
- unlink (lockfname);
|
|
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (lstat (lockfname, &statbuf) == 0)
|
|
|
|
+ {
|
|
|
|
+ lock = lock_get_info (lockfname);
|
|
|
|
+ if (lock == NULL)
|
|
|
|
+ {
|
|
|
|
+ g_free (lockfname);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ lockinfo = lock_extract_info (lock);
|
|
|
|
+
|
|
|
|
+ /* Check if locking process alive, ask user if required */
|
|
|
|
+ if (lockinfo->pid == 0 || !(kill (lockinfo->pid, 0) == -1 && errno == ESRCH))
|
|
|
|
+ {
|
|
|
|
+ msg =
|
|
|
|
+ g_strdup_printf (_
|
|
|
|
+ ("File \"%s\" is already being edited.\n"
|
|
|
|
+ "User: %s\nProcess ID: %d"), x_basename (lockfname) + 2,
|
|
|
|
+ lockinfo->who, (int) lockinfo->pid);
|
|
|
|
+ /* TODO: Implement "Abort" - needs to rewind undo stack */
|
|
|
|
+ switch (query_dialog
|
|
|
|
+ (_("File locked"), msg, D_NORMAL, 2, _("&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 */
|
|
/* Create lock symlink */
|
|
newlock = lock_build_name ();
|
|
newlock = lock_build_name ();
|
|
- if (symlink (newlock, lockfname) == -1) {
|
|
|
|
- g_free (lockfname);
|
|
|
|
- g_free (newlock);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- g_free (lockfname);
|
|
|
|
|
|
+ symlink_ok = (symlink (newlock, lockfname) != -1);
|
|
g_free (newlock);
|
|
g_free (newlock);
|
|
- return 1;
|
|
|
|
|
|
+ g_free (lockfname);
|
|
|
|
+
|
|
|
|
+ return symlink_ok ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* Lowers file lock if possible
|
|
/* Lowers file lock if possible
|
|
@@ -233,26 +246,32 @@ unlock_file (const char *fname)
|
|
struct stat statbuf;
|
|
struct stat statbuf;
|
|
|
|
|
|
/* Just to be sure */
|
|
/* Just to be sure */
|
|
- if (!fname || !*fname)
|
|
|
|
- return 0;
|
|
|
|
|
|
+ if (fname == NULL || *fname == '\0')
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
+ fname = tilde_expand (fname);
|
|
lockfname = lock_build_symlink_name (fname);
|
|
lockfname = lock_build_symlink_name (fname);
|
|
|
|
+ g_free (fname);
|
|
|
|
+
|
|
if (lockfname == NULL)
|
|
if (lockfname == NULL)
|
|
- return 0;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
/* Check if lock exists */
|
|
/* Check if lock exists */
|
|
- if (lstat (lockfname, &statbuf) == -1) {
|
|
|
|
- g_free (lockfname);
|
|
|
|
- return 0;
|
|
|
|
|
|
+ if (lstat (lockfname, &statbuf) == -1)
|
|
|
|
+ {
|
|
|
|
+ g_free (lockfname);
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
lock = lock_get_info (lockfname);
|
|
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;
|
|
|
|
- }
|
|
|
|
|
|
+ if (lock != NULL)
|
|
|
|
+ {
|
|
|
|
+ /* Don't touch if lock is not ours */
|
|
|
|
+ if (lock_extract_info (lock)->pid != getpid ())
|
|
|
|
+ {
|
|
|
|
+ g_free (lockfname);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/* Remove lock */
|
|
/* Remove lock */
|