diff options
| author | Paul Eggert | 2013-01-18 20:44:34 -0800 |
|---|---|---|
| committer | Paul Eggert | 2013-01-18 20:44:34 -0800 |
| commit | 9fe43ff672d02d6f43bd5bc7b08f40823c7a1851 (patch) | |
| tree | 89f42a987eff9a5559c4735c19b37d06994c342a /src | |
| parent | fa705c9927b57158e8973cd950419a2ac0f72c53 (diff) | |
| download | emacs-9fe43ff672d02d6f43bd5bc7b08f40823c7a1851.tar.gz emacs-9fe43ff672d02d6f43bd5bc7b08f40823c7a1851.zip | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 13 | ||||
| -rw-r--r-- | src/emacs.c | 1 | ||||
| -rw-r--r-- | src/fileio.c | 53 | ||||
| -rw-r--r-- | src/lisp.h | 1 |
4 files changed, 68 insertions, 0 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 4cd417868a1..2954df9d6b8 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,18 @@ | |||
| 1 | 2013-01-19 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2013-01-19 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | Work around bug in CIFS and vboxsf file systems (Bug#13149). | ||
| 4 | The bug was observed on Ubuntu operating inside a virtual machine, | ||
| 5 | editing files mounted via CIFS or vboxsf from the MS Windows 7 host. | ||
| 6 | The workaround introduces a race condition on non-buggy hosts, | ||
| 7 | but it's an unlikely race and anyway there's a nearly identical | ||
| 8 | nearby race that can't be fixed. | ||
| 9 | * fileio.c (valid_timestamp_file_system, timestamp_file_system): | ||
| 10 | New static vars. | ||
| 11 | (Fwrite_region): Test for file system time stamp bug. | ||
| 12 | (init_fileio): New function. | ||
| 13 | * lisp.h (init_fileio): Declare it. | ||
| 14 | * emacs.c (main): Call it. | ||
| 15 | |||
| 3 | * fileio.c (Finsert_file_contents): Simplify new diagnostic | 16 | * fileio.c (Finsert_file_contents): Simplify new diagnostic |
| 4 | and make it more consistent with other stat-failure diagnostics. | 17 | and make it more consistent with other stat-failure diagnostics. |
| 5 | 18 | ||
diff --git a/src/emacs.c b/src/emacs.c index 91a7ce6390d..6536c3708af 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -1317,6 +1317,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1317 | } | 1317 | } |
| 1318 | 1318 | ||
| 1319 | init_callproc (); /* Must follow init_cmdargs but not init_sys_modes. */ | 1319 | init_callproc (); /* Must follow init_cmdargs but not init_sys_modes. */ |
| 1320 | init_fileio (); | ||
| 1320 | init_lread (); | 1321 | init_lread (); |
| 1321 | #ifdef WINDOWSNT | 1322 | #ifdef WINDOWSNT |
| 1322 | /* Check to see if Emacs has been installed correctly. */ | 1323 | /* Check to see if Emacs has been installed correctly. */ |
diff --git a/src/fileio.c b/src/fileio.c index bd845c2f1e0..616f1c50f91 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -103,6 +103,11 @@ static mode_t auto_save_mode_bits; | |||
| 103 | /* Set by auto_save_1 if an error occurred during the last auto-save. */ | 103 | /* Set by auto_save_1 if an error occurred during the last auto-save. */ |
| 104 | static bool auto_save_error_occurred; | 104 | static bool auto_save_error_occurred; |
| 105 | 105 | ||
| 106 | /* If VALID_TIMESTAMP_FILE_SYSTEM, then TIMESTAMP_FILE_SYSTEM is the device | ||
| 107 | number of a file system where time stamps were observed to to work. */ | ||
| 108 | static bool valid_timestamp_file_system; | ||
| 109 | static dev_t timestamp_file_system; | ||
| 110 | |||
| 106 | /* The symbol bound to coding-system-for-read when | 111 | /* The symbol bound to coding-system-for-read when |
| 107 | insert-file-contents is called for recovering a file. This is not | 112 | insert-file-contents is called for recovering a file. This is not |
| 108 | an actual coding system name, but just an indicator to tell | 113 | 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 | |||
| 4971 | /* Discard the unwind protect for close_file_unwind. */ | 4976 | /* Discard the unwind protect for close_file_unwind. */ |
| 4972 | specpdl_ptr = specpdl + count1; | 4977 | specpdl_ptr = specpdl + count1; |
| 4973 | 4978 | ||
| 4979 | /* Some file systems have a bug where st_mtime is not updated | ||
| 4980 | properly after a write. For example, CIFS might not see the | ||
| 4981 | st_mtime change until after the file is opened again. | ||
| 4982 | |||
| 4983 | Attempt to detect this file system bug, and update MODTIME to the | ||
| 4984 | newer st_mtime if the bug appears to be present. This introduces | ||
| 4985 | a race condition, so to avoid most instances of the race condition | ||
| 4986 | on non-buggy file systems, skip this check if the most recently | ||
| 4987 | encountered non-buggy file system was the current file system. | ||
| 4988 | |||
| 4989 | A race condition can occur if some other process modifies the | ||
| 4990 | file between the fstat above and the fstat below, but the race is | ||
| 4991 | unlikely and a similar race between the last write and the fstat | ||
| 4992 | above cannot possibly be closed anyway. */ | ||
| 4993 | |||
| 4994 | if (EMACS_TIME_VALID_P (modtime) | ||
| 4995 | && ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system)) | ||
| 4996 | { | ||
| 4997 | int desc1 = emacs_open (fn, O_WRONLY, 0); | ||
| 4998 | if (0 <= desc1) | ||
| 4999 | { | ||
| 5000 | struct stat st1; | ||
| 5001 | if (fstat (desc1, &st1) == 0 | ||
| 5002 | && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) | ||
| 5003 | { | ||
| 5004 | EMACS_TIME modtime1 = get_stat_mtime (&st1); | ||
| 5005 | if (EMACS_TIME_EQ (modtime, modtime1) | ||
| 5006 | && st.st_size == st1.st_size) | ||
| 5007 | { | ||
| 5008 | timestamp_file_system = st.st_dev; | ||
| 5009 | valid_timestamp_file_system = 1; | ||
| 5010 | } | ||
| 5011 | else | ||
| 5012 | { | ||
| 5013 | st.st_size = st1.st_size; | ||
| 5014 | modtime = modtime1; | ||
| 5015 | } | ||
| 5016 | } | ||
| 5017 | emacs_close (desc1); | ||
| 5018 | } | ||
| 5019 | } | ||
| 5020 | |||
| 4974 | /* Call write-region-post-annotation-function. */ | 5021 | /* Call write-region-post-annotation-function. */ |
| 4975 | while (CONSP (Vwrite_region_annotation_buffers)) | 5022 | while (CONSP (Vwrite_region_annotation_buffers)) |
| 4976 | { | 5023 | { |
| @@ -5768,6 +5815,12 @@ Fread_file_name (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filena | |||
| 5768 | 5815 | ||
| 5769 | 5816 | ||
| 5770 | void | 5817 | void |
| 5818 | init_fileio (void) | ||
| 5819 | { | ||
| 5820 | valid_timestamp_file_system = 0; | ||
| 5821 | } | ||
| 5822 | |||
| 5823 | void | ||
| 5771 | syms_of_fileio (void) | 5824 | syms_of_fileio (void) |
| 5772 | { | 5825 | { |
| 5773 | DEFSYM (Qoperations, "operations"); | 5826 | DEFSYM (Qoperations, "operations"); |
diff --git a/src/lisp.h b/src/lisp.h index 5c81bc5dd8a..48fba653203 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3299,6 +3299,7 @@ extern _Noreturn void report_file_error (const char *, Lisp_Object); | |||
| 3299 | extern bool internal_delete_file (Lisp_Object); | 3299 | extern bool internal_delete_file (Lisp_Object); |
| 3300 | extern bool file_directory_p (const char *); | 3300 | extern bool file_directory_p (const char *); |
| 3301 | extern bool file_accessible_directory_p (const char *); | 3301 | extern bool file_accessible_directory_p (const char *); |
| 3302 | extern void init_fileio (void); | ||
| 3302 | extern void syms_of_fileio (void); | 3303 | extern void syms_of_fileio (void); |
| 3303 | extern Lisp_Object make_temp_name (Lisp_Object, bool); | 3304 | extern Lisp_Object make_temp_name (Lisp_Object, bool); |
| 3304 | extern Lisp_Object Qdelete_file; | 3305 | extern Lisp_Object Qdelete_file; |