Work around bug in CIFS and vboxsf file systems.
The bug was observed on Ubuntu operating inside a virtual machine, editing files mounted via CIFS or vboxsf from the MS Windows 7 host. The workaround introduces a race condition on non-buggy hosts, but it's an unlikely race and anyway there's a nearly identical nearby race that can't be fixed. * fileio.c (valid_timestamp_file_system, timestamp_file_system): New static vars. (Fwrite_region): Test for file system time stamp bug. (init_fileio): New function. * lisp.h (init_fileio): Declare it. * emacs.c (main): Call it. Fixes: debbugs:13149
This commit is contained in:
parent
fa705c9927
commit
9fe43ff672
4 changed files with 68 additions and 0 deletions
|
@ -1,5 +1,18 @@
|
|||
2013-01-19 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Work around bug in CIFS and vboxsf file systems (Bug#13149).
|
||||
The bug was observed on Ubuntu operating inside a virtual machine,
|
||||
editing files mounted via CIFS or vboxsf from the MS Windows 7 host.
|
||||
The workaround introduces a race condition on non-buggy hosts,
|
||||
but it's an unlikely race and anyway there's a nearly identical
|
||||
nearby race that can't be fixed.
|
||||
* fileio.c (valid_timestamp_file_system, timestamp_file_system):
|
||||
New static vars.
|
||||
(Fwrite_region): Test for file system time stamp bug.
|
||||
(init_fileio): New function.
|
||||
* lisp.h (init_fileio): Declare it.
|
||||
* emacs.c (main): Call it.
|
||||
|
||||
* fileio.c (Finsert_file_contents): Simplify new diagnostic
|
||||
and make it more consistent with other stat-failure diagnostics.
|
||||
|
||||
|
|
|
@ -1317,6 +1317,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
|
|||
}
|
||||
|
||||
init_callproc (); /* Must follow init_cmdargs but not init_sys_modes. */
|
||||
init_fileio ();
|
||||
init_lread ();
|
||||
#ifdef WINDOWSNT
|
||||
/* Check to see if Emacs has been installed correctly. */
|
||||
|
|
53
src/fileio.c
53
src/fileio.c
|
@ -103,6 +103,11 @@ static mode_t auto_save_mode_bits;
|
|||
/* Set by auto_save_1 if an error occurred during the last auto-save. */
|
||||
static bool auto_save_error_occurred;
|
||||
|
||||
/* If VALID_TIMESTAMP_FILE_SYSTEM, then TIMESTAMP_FILE_SYSTEM is the device
|
||||
number of a file system where time stamps were observed to to work. */
|
||||
static bool valid_timestamp_file_system;
|
||||
static dev_t timestamp_file_system;
|
||||
|
||||
/* The symbol bound to coding-system-for-read when
|
||||
insert-file-contents is called for recovering a file. This is not
|
||||
an actual coding system name, but just an indicator to tell
|
||||
|
@ -4971,6 +4976,48 @@ This calls `write-region-annotate-functions' at the start, and
|
|||
/* Discard the unwind protect for close_file_unwind. */
|
||||
specpdl_ptr = specpdl + count1;
|
||||
|
||||
/* Some file systems have a bug where st_mtime is not updated
|
||||
properly after a write. For example, CIFS might not see the
|
||||
st_mtime change until after the file is opened again.
|
||||
|
||||
Attempt to detect this file system bug, and update MODTIME to the
|
||||
newer st_mtime if the bug appears to be present. This introduces
|
||||
a race condition, so to avoid most instances of the race condition
|
||||
on non-buggy file systems, skip this check if the most recently
|
||||
encountered non-buggy file system was the current file system.
|
||||
|
||||
A race condition can occur if some other process modifies the
|
||||
file between the fstat above and the fstat below, but the race is
|
||||
unlikely and a similar race between the last write and the fstat
|
||||
above cannot possibly be closed anyway. */
|
||||
|
||||
if (EMACS_TIME_VALID_P (modtime)
|
||||
&& ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system))
|
||||
{
|
||||
int desc1 = emacs_open (fn, O_WRONLY, 0);
|
||||
if (0 <= desc1)
|
||||
{
|
||||
struct stat st1;
|
||||
if (fstat (desc1, &st1) == 0
|
||||
&& st.st_dev == st1.st_dev && st.st_ino == st1.st_ino)
|
||||
{
|
||||
EMACS_TIME modtime1 = get_stat_mtime (&st1);
|
||||
if (EMACS_TIME_EQ (modtime, modtime1)
|
||||
&& st.st_size == st1.st_size)
|
||||
{
|
||||
timestamp_file_system = st.st_dev;
|
||||
valid_timestamp_file_system = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
st.st_size = st1.st_size;
|
||||
modtime = modtime1;
|
||||
}
|
||||
}
|
||||
emacs_close (desc1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call write-region-post-annotation-function. */
|
||||
while (CONSP (Vwrite_region_annotation_buffers))
|
||||
{
|
||||
|
@ -5767,6 +5814,12 @@ Fread_file_name (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filena
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
init_fileio (void)
|
||||
{
|
||||
valid_timestamp_file_system = 0;
|
||||
}
|
||||
|
||||
void
|
||||
syms_of_fileio (void)
|
||||
{
|
||||
|
|
|
@ -3299,6 +3299,7 @@ extern _Noreturn void report_file_error (const char *, Lisp_Object);
|
|||
extern bool internal_delete_file (Lisp_Object);
|
||||
extern bool file_directory_p (const char *);
|
||||
extern bool file_accessible_directory_p (const char *);
|
||||
extern void init_fileio (void);
|
||||
extern void syms_of_fileio (void);
|
||||
extern Lisp_Object make_temp_name (Lisp_Object, bool);
|
||||
extern Lisp_Object Qdelete_file;
|
||||
|
|
Loading…
Add table
Reference in a new issue