Thanks a bunch for the comments.
Tammo
Some inline responses:
On Wed, Mar 08, 2006 at 09:58:52PM -0500, Morten Welinder wrote:
> Very interesting. Some comments:
>
> 1. Bugzilla is a far better place. Please open a bug and
> attach the patch.
Done, I submitted a patch that also includes the changes described in
this mail.
> 2. The guts of this ought to live in goffice, probably go-file.c
Not sure I see this argument. The "guts" primarily are specialized to
the semantics of gnumeric, doing things like adjusting gui properties.
I agree that probably some of the file operations could move there,
but it seems cleaner to keep it together.
> 3. I don't think the mechanism to lock should be O_EXCL
> because it does not work with NFS. Symlinks would
> work there, but might be an issue on Win32.
O_EXCL is said to (and actually appears to) work fine on modern
kernels (>= 2.6.5).
> 4. Please use g_get_host_name if available. Alway use g_get_user_name.
Done, see attached incremental patch.
> 5. You need to ensure that other people can read the lock
> files.
Ah, I suppose you mean setting the umask... Done.
> 6. If $EVIL creates a 1GB fake lock file, will Gnumeric crash?
Not planning to test this one ;) I was using g_get_file_contents,
which I would hope does not simply crash when files are too big...
The attached new patch explicitly reads only a bounded amount.
> 7. What about character set for the file? Since the encoding of the username
> is
> not known, it appears that we can end up trying to display non-UTF8 text.
> (Same issue if $EVIL puts random binary stuff into a lockfile.)
New patch should address this.
> 8. You are writing a zero byte at the end of the file. Worse, it looks like
> you
> depend on it being there when you read the file.
Should be fixed now.
> 9. Things need to be translated, i.e., use _() as appropriate.
Done.
> Morten
--- gnumeric-1.6.2/src/workbook-view.h.dotlocking.1 2006-03-09
11:56:04.000000000 -0500
+++ gnumeric-1.6.2/src/workbook-view.h 2006-03-09 11:56:19.000000000 -0500
@@ -49,12 +49,16 @@ typedef struct {
#define WORKBOOK_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k),
WORKBOOK_VIEW_TYPE, WorkbookViewClass))
#define IS_WORKBOOK_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
WORKBOOK_VIEW_TYPE))
+/* File Locking */
typedef enum {
WBV_EXT_LOCK_OPEN,
WBV_EXT_LOCK_SAVE,
WBV_EXT_LOCK_SAVEAS,
WBV_SELF_LOCK_FAULT
} WbvLockNotification;
+void wb_view_adapt_to_locking (WorkbookView *wbv,
+ const char *lockdata,
+ WbvLockNotification ln);
/* Lifecycle */
GType workbook_view_get_type (void);
--- gnumeric-1.6.2/src/flock.c.dotlocking.1 2006-03-09 09:05:56.000000000
-0500
+++ gnumeric-1.6.2/src/flock.c 2006-03-09 11:57:33.000000000 -0500
@@ -13,6 +13,7 @@
#include <glib.h>
#include <glib/gstdio.h>
#include <goffice/utils/go-file.h>
+#include <glib/gi18n.h>
#include "gnumeric.h"
#include "flock.h"
@@ -21,17 +22,16 @@
#define O_NOFOLLOW (0)
#endif
-const unsigned max_lockdata_sz = 128;
+const unsigned max_lockdata_sz = 1024;
-char * gen_lockname (const char *);
-char * gen_lockdata (void);
+static char * gen_lockname (const char *);
+static char * gen_lockdata (void);
+static char * read_lockdata (char *);
-char *
+static char *
gen_lockname (const char *uri)
{
char *dir, *base, *lockname;
- const char *s0 = "/.";
- const char *s1 = ".lock";
if ((uri == NULL) || (strlen(uri) == 0) || (strncmp (uri, "file://", 7)
!= 0)) {
return NULL;
@@ -39,8 +39,7 @@ gen_lockname (const char *uri)
dir = go_dirname_from_uri (uri, TRUE);
base = go_basename_from_uri (uri);
- lockname = (char *) g_malloc (strlen (dir) + strlen (base) + strlen
(s0) + strlen (s1) + 1);
- sprintf (lockname, "%s%s%s%s", dir, s0, base, s1);
+ lockname = g_strdup_printf ("%s/.%s.lock", dir, base);
g_free (base);
g_free (dir);
@@ -50,37 +49,70 @@ gen_lockname (const char *uri)
return lockname;
}
-char *
+#if (! ((GLIB_MAJOR_VERSION > 2) || ((GLIB_MAJOR_VERSION == 2) &&
(GLIB_MINOR_VERSION >= 8))))
+static const char *
+g_get_host_name (void)
+{
+ static char hostname [HOST_NAME_MAX + 1];
+
+ if (gethostname (hostname, HOST_NAME_MAX) == -1) {
+ return _("localhost");
+ }
+ return hostname;
+}
+#endif
+
+static char *
gen_lockdata ()
{
- char hostname [HOST_NAME_MAX + 1];
- struct passwd *pw;
+ const gchar *username;
+ const gchar *hostname;
uid_t uid;
pid_t pid;
- char *uid_str, *pid_str;
char *data;
- const char *s0 = "@";
- const char *s1 = " (uid ";
- const char *s2 = ", pid ";
- const char *s3 = ")";
- if (gethostname (hostname, HOST_NAME_MAX) == -1) {
- return NULL;
- }
+ username = g_get_user_name();
+ hostname = g_get_host_name();
uid = getuid ();
pid = getpid ();
- if ((pw = getpwuid (uid)) == NULL) {
+ data = g_strdup_printf ("[EMAIL PROTECTED] (uid %lu, pid %lu)",
username, hostname,
+ (long unsigned) uid, (long unsigned) pid);
+
+ if (strlen (data) >= max_lockdata_sz) {
+ g_printerr (_("WARNING: lock data size exceeds allowance (%lu
>= %lu)\n"),
+ strlen (data), max_lockdata_sz);
+ }
+
+ return data;
+}
+
+static char *
+read_lockdata (char *lockname)
+{
+ int fd, r_rc, c_rc;
+ char *data;
+
+ fd = g_open (lockname, O_RDONLY);
+ if (fd == -1) {
+ return NULL;
+ }
+
+ data = (char *) g_malloc0 (max_lockdata_sz);
+
+ r_rc = read (fd, data, max_lockdata_sz - 1);
+ c_rc = close (fd);
+
+ /* XXX debugging */
+ /* g_printerr ("lockdata is '%s'\n", data); */
+
+ if ((r_rc == -1) || (c_rc == -1) ||
+ (! g_utf8_validate(data, -1, NULL))) {
+ g_free (data);
return NULL;
}
- uid_str = g_strdup_printf ("%lu", (long unsigned) uid);
- pid_str = g_strdup_printf ("%lu", (long unsigned) pid);
- data = (char *) g_malloc (MIN(strlen (pw->pw_name) + strlen (hostname)
+ strlen (uid_str) +
- strlen (pid_str) + strlen (s0) + strlen
(s1) + strlen (s2) +
- strlen (s3) + 1, max_lockdata_sz));
- snprintf (data, max_lockdata_sz - 1, "%s%s%s%s%s%s%s%s",
- pw->pw_name, s0, hostname, s1, uid_str, s2, pid_str, s3);
- g_free(uid_str);
- g_free(pid_str);
+
+ /* XXX debugging */
+ /* g_printerr ("lockdata is utf8-kosher\n", data); */
return data;
}
@@ -91,45 +123,46 @@ flock_acquire (const char* uri)
char *lockname = NULL;
char *lockdata = NULL;
const char *err_msg = NULL;
+ mode_t mask;
int fd;
lockname = gen_lockname (uri);
if (lockname == NULL) {
- err_msg = "illegal lockname";
+ err_msg = _("illegal lockname");
goto flock_lock_finish;
}
/* XXX debugging */
/* g_printerr ("locking '%s'\n", lockname); */
+ mask = umask(0);
fd = g_open (lockname, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ umask(mask);
if (fd != -1) {
int w_rc, c_rc;
lockdata = gen_lockdata ();
if (lockdata == NULL) {
- err_msg = "lock data generation error";
+ err_msg = _("lock data generation error");
goto flock_lock_finish;
}
- w_rc = write (fd, lockdata, strlen (lockdata) + 1);
+ w_rc = write (fd, lockdata, MIN(strlen (lockdata),
max_lockdata_sz));
g_free(lockdata);
lockdata = NULL;
c_rc = close (fd);
if (w_rc == -1) {
- err_msg = "lock write failure";
+ err_msg = _("lock write failure");
goto flock_lock_finish;
}
if (c_rc == -1) {
- err_msg = "lock close failure";
+ err_msg = _("lock close failure");
goto flock_lock_finish;
}
} else if (g_file_error_from_errno(errno) == G_FILE_ERROR_EXIST) {
- GError *error = NULL;
-
- if (! g_file_get_contents (lockname, &lockdata, NULL, &error)) {
- err_msg = "lock exists, but reading it failed";
+ if ((lockdata = read_lockdata (lockname)) == NULL) {
+ err_msg = _("lock exists, but reading it failed");
goto flock_lock_finish;
}
@@ -137,7 +170,7 @@ flock_acquire (const char* uri)
/* g_printerr ("lock already held by '%s'\n", lockdata); */
} else {
- err_msg = "lock open failed";
+ err_msg = _("lock open failed");
}
flock_lock_finish:
@@ -146,7 +179,7 @@ flock_acquire (const char* uri)
/* g_printerr ("locking failed for '%s'\n", lockname); */
g_assert (lockdata == NULL);
- lockdata = g_strdup_printf ("unknown (%s)", err_msg);
+ lockdata = g_strdup_printf ("%s (%s)", _("unknown"), err_msg);
}
if (lockname != NULL) {
@@ -162,31 +195,24 @@ flock_verify (const char* uri)
char *expected_lockdata = NULL;
char *actual_lockdata = NULL;
const char *err_msg = NULL;
- GError *error = NULL;
lockname = gen_lockname (uri);
if (lockname == NULL) {
- err_msg = "illegal lockname";
+ err_msg = _("illegal lockname");
goto flock_verify_finish;
}
expected_lockdata = gen_lockdata ();
if (expected_lockdata == NULL) {
- err_msg = "lock data generation error";
+ err_msg = _("lock data generation error");
goto flock_verify_finish;
}
/* XXX debugging */
/* g_printerr ("verifying '%s'\n", lockname); */
- g_file_get_contents (lockname, &actual_lockdata, NULL, &error);
- g_assert ((actual_lockdata == NULL && error != NULL) ||
- (actual_lockdata != NULL && error == NULL));
- if (error != NULL) {
- /* XXX debugging */
- /* g_printerr ("ERROR: reading lock file -- %s\n",
error->message); */
- g_error_free (error);
- err_msg = "reading lock failed";
+ if ((actual_lockdata = read_lockdata (lockname)) == NULL) {
+ err_msg = _("reading lock failed");
goto flock_verify_finish;
}
@@ -204,7 +230,7 @@ flock_verify (const char* uri)
/* g_printerr ("lock verify failed for '%s'\n", lockname); */
g_assert (actual_lockdata == NULL);
- actual_lockdata = g_strdup_printf ("unknown (%s)", err_msg);
+ actual_lockdata = g_strdup_printf ("%s (%s)", _("unknown"),
err_msg);
}
if (lockname != NULL) {
--- gnumeric-1.6.2/src/workbook-view.c.dotlocking.1 2006-03-09
11:00:59.000000000 -0500
+++ gnumeric-1.6.2/src/workbook-view.c 2006-03-09 11:01:40.000000000 -0500
@@ -667,30 +667,30 @@ wb_view_adapt_to_locking (WorkbookView *
switch (ln) {
case WBV_EXT_LOCK_OPEN:
- raw_msg = "The workbook '%s' is locked, which should mean that "
- "someone else is currently using it. The workbook "
- "will be opened, but saving changes will be disabled "
- "to prevent the possibility of conflicting changes by "
- "concurrent users. Use the SAVE AS menu action to "
- "store any changes under a new name. Otherwise try "
- "re-opening the workbook later.";
+ raw_msg = _("The workbook '%s' is locked, which should mean
that "
+ "someone else is currently using it. The workbook "
+ "will be opened, but saving changes will be
disabled "
+ "to prevent the possibility of conflicting changes
by "
+ "concurrent users. Use the SAVE AS menu action to "
+ "store any changes under a new name. Otherwise try
"
+ "re-opening the workbook later.");
break;
case WBV_EXT_LOCK_SAVE:
- raw_msg = "Saving of workbook '%s' has been disabled. Use the "
- "SAVE AS menu action to store any changes under a new
name.";
+ raw_msg = _("Saving of workbook '%s' has been disabled. Use the
"
+ "SAVE AS menu action to store any changes under a
new name.");
break;
case WBV_EXT_LOCK_SAVEAS:
- raw_msg = "The workbook '%s' is locked. This likely means that
"
- "someone else is currently using it. To prevent the
possibility "
- "of conflicting changes by concurrent users, saving to
this "
- "workbook has been disabled.";
+ raw_msg = _("The workbook '%s' is locked. This likely means
that "
+ "someone else is currently using it. To prevent
the possibility "
+ "of conflicting changes by concurrent users, saving
to this "
+ "workbook has been disabled.");
break;
case WBV_SELF_LOCK_FAULT:
- raw_msg = "The lock for workbook '%s' has been removed or
damaged. "
- "This is unexpected and is probably a sign that
something "
- "has gone wrong. To prevent the possibility of
conflicting "
- "changes by concurrent users, saving to this workbook
has "
- "been disabled.";
+ raw_msg = _("The lock for workbook '%s' has been removed or
damaged. "
+ "This is unexpected and is probably a sign that
something "
+ "has gone wrong. To prevent the possibility of
conflicting "
+ "changes by concurrent users, saving to this
workbook has "
+ "been disabled.");
break;
default:
g_assert_not_reached();
_______________________________________________
gnumeric-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gnumeric-list