Now on revision 111552. ------------------------------------------------------------ revno: 111552 committer: Eli Zaretskii branch nick: trunk timestamp: Sat 2013-01-19 09:32:36 +0200 message: Make 'fstat' on MS-Windows behave more like 'stat' and 'lstat'. src/w32.c (fstat): Return owner and group like 'stat' and 'lstat' do. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-01-19 07:13:19 +0000 +++ src/ChangeLog 2013-01-19 07:32:36 +0000 @@ -3,6 +3,7 @@ * w32.c (acl_set_file): Treat ERROR_ACCESS_DENIED from set_file_security as failure due to insufficient privileges. Reported by Fabrice Popineau . + (fstat): Return owner and group like 'stat' and 'lstat' do. 2013-01-19 Paul Eggert === modified file 'src/w32.c' --- src/w32.c 2013-01-19 07:13:19 +0000 +++ src/w32.c 2013-01-19 07:32:36 +0000 @@ -4164,13 +4164,23 @@ else buf->st_ino = fake_inode; - /* Consider files to belong to current user. - FIXME: this should use GetSecurityInfo API, but it is only - available for _WIN32_WINNT >= 0x501. */ - buf->st_uid = dflt_passwd.pw_uid; - buf->st_gid = dflt_passwd.pw_gid; - strcpy (buf->st_uname, dflt_passwd.pw_name); - strcpy (buf->st_gname, dflt_group.gr_name); + /* If the caller so requested, get the true file owner and group. + Otherwise, consider the file to belong to the current user. */ + if (!w32_stat_get_owner_group || is_windows_9x () == TRUE) + get_file_owner_and_group (NULL, buf); + else + { + PSECURITY_DESCRIPTOR psd = NULL; + + psd = get_file_security_desc_by_handle (fh); + if (psd) + { + get_file_owner_and_group (psd, buf); + LocalFree (psd); + } + else + get_file_owner_and_group (NULL, buf); + } buf->st_dev = info.dwVolumeSerialNumber; buf->st_rdev = info.dwVolumeSerialNumber; ------------------------------------------------------------ revno: 111551 committer: Eli Zaretskii branch nick: trunk timestamp: Sat 2013-01-19 09:13:19 +0200 message: Minor fix in acl_set_file. src/w32.c (acl_set_file): Treat ERROR_ACCESS_DENIED from set_file_security as failure due to insufficient privileges. Reported by Fabrice Popineau . diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-01-19 04:44:34 +0000 +++ src/ChangeLog 2013-01-19 07:13:19 +0000 @@ -1,3 +1,9 @@ +2013-01-19 Eli Zaretskii + + * w32.c (acl_set_file): Treat ERROR_ACCESS_DENIED from + set_file_security as failure due to insufficient privileges. + Reported by Fabrice Popineau . + 2013-01-19 Paul Eggert Work around bug in CIFS and vboxsf file systems (Bug#13149). === modified file 'src/w32.c' --- src/w32.c 2013-01-09 15:07:01 +0000 +++ src/w32.c 2013-01-19 07:13:19 +0000 @@ -4875,7 +4875,8 @@ retval = 0; errno = e; } - else if (err == ERROR_INVALID_OWNER || err == ERROR_NOT_ALL_ASSIGNED) + else if (err == ERROR_INVALID_OWNER || err == ERROR_NOT_ALL_ASSIGNED + || err == ERROR_ACCESS_DENIED) { /* Maybe the requested ACL and the one the file already has are identical, in which case we can silently ignore the ------------------------------------------------------------ revno: 111550 fixes bug: http://debbugs.gnu.org/13149 committer: Paul Eggert branch nick: trunk timestamp: Fri 2013-01-18 20:44:34 -0800 message: 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. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-01-19 00:40:07 +0000 +++ src/ChangeLog 2013-01-19 04:44:34 +0000 @@ -1,5 +1,18 @@ 2013-01-19 Paul Eggert + 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. === modified file 'src/emacs.c' --- src/emacs.c 2013-01-13 20:03:01 +0000 +++ src/emacs.c 2013-01-19 04:44:34 +0000 @@ -1317,6 +1317,7 @@ } 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. */ === modified file 'src/fileio.c' --- src/fileio.c 2013-01-19 00:40:07 +0000 +++ src/fileio.c 2013-01-19 04:44:34 +0000 @@ -103,6 +103,11 @@ /* 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 @@ /* 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)) { @@ -5768,6 +5815,12 @@ void +init_fileio (void) +{ + valid_timestamp_file_system = 0; +} + +void syms_of_fileio (void) { DEFSYM (Qoperations, "operations"); === modified file 'src/lisp.h' --- src/lisp.h 2013-01-17 06:29:40 +0000 +++ src/lisp.h 2013-01-19 04:44:34 +0000 @@ -3299,6 +3299,7 @@ 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; ------------------------------------------------------------ revno: 111549 committer: Paul Eggert branch nick: trunk timestamp: Fri 2013-01-18 16:40:07 -0800 message: * fileio.c (Finsert_file_contents): Simplify new diagnostic and make it more consistent with other stat-failure diagnostics. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-01-18 06:32:12 +0000 +++ src/ChangeLog 2013-01-19 00:40:07 +0000 @@ -1,3 +1,8 @@ +2013-01-19 Paul Eggert + + * fileio.c (Finsert_file_contents): Simplify new diagnostic + and make it more consistent with other stat-failure diagnostics. + 2013-01-18 Dmitry Antipov Fix crash when inserting data from non-regular files. See === modified file 'src/fileio.c' --- src/fileio.c 2013-01-18 06:32:12 +0000 +++ src/fileio.c 2013-01-19 00:40:07 +0000 @@ -3574,8 +3574,7 @@ record_unwind_protect (close_file_unwind, make_number (fd)); if (fstat (fd, &st) != 0) - report_file_error ("Getting input file status", - Fcons (orig_filename, Qnil)); + report_file_error ("Input file status", Fcons (orig_filename, Qnil)); mtime = get_stat_mtime (&st); /* This code will need to be changed in order to work on named ------------------------------------------------------------ revno: 111548 committer: Leo Liu branch nick: trunk timestamp: Sat 2013-01-19 02:22:18 +0800 message: * lisp/progmodes/js.el: Tweak autoload cookie for alias. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-01-17 19:12:40 +0000 +++ lisp/ChangeLog 2013-01-18 18:22:18 +0000 @@ -1,3 +1,7 @@ +2013-01-18 Leo Liu + + * progmodes/js.el: Tweak autoload cookie for alias. + 2013-01-17 Michael Albinus * autorevert.el (auto-revert-notify-watch-descriptor): Make it === modified file 'lisp/progmodes/js.el' --- lisp/progmodes/js.el 2013-01-11 23:24:52 +0000 +++ lisp/progmodes/js.el 2013-01-18 18:22:18 +0000 @@ -3405,8 +3405,7 @@ ;; calls to syntax-propertize wherever it's really needed. (syntax-propertize (point-max))) -;;;###autoload -(defalias 'javascript-mode 'js-mode) +;;;###autoload (defalias 'javascript-mode 'js-mode) (eval-after-load 'folding '(when (fboundp 'folding-add-to-marks-list) ------------------------------------------------------------ revno: 111547 committer: Dmitry Antipov branch nick: trunk timestamp: Fri 2013-01-18 10:32:12 +0400 message: Fix crash when inserting data from non-regular files. See http://lists.gnu.org/archive/html/emacs-devel/2013-01/msg00406.html for the error description produced by valgrind. * fileio.c (read_non_regular): Rename to read_contents. Free Lisp_Save_Value object used to pass parameters. (read_non_regular_quit): Rename to read_contents_quit. (Finsert_file_contents): Redesign internal file reading loop to adjust gap and end positions after each read and so help make_gap to work properly. Do not signal an I/O error too early and so do not leave not yet decoded characters in a buffer, which was the reason of redisplay crash. Use list2 to build return value. Adjust comments. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-01-18 05:12:08 +0000 +++ src/ChangeLog 2013-01-18 06:32:12 +0000 @@ -1,3 +1,17 @@ +2013-01-18 Dmitry Antipov + + Fix crash when inserting data from non-regular files. See + http://lists.gnu.org/archive/html/emacs-devel/2013-01/msg00406.html + for the error description produced by valgrind. + * fileio.c (read_non_regular): Rename to read_contents. + Free Lisp_Save_Value object used to pass parameters. + (read_non_regular_quit): Rename to read_contents_quit. + (Finsert_file_contents): Redesign internal file reading loop to adjust + gap and end positions after each read and so help make_gap to work + properly. Do not signal an I/O error too early and so do not leave + not yet decoded characters in a buffer, which was the reason of + redisplay crash. Use list2 to build return value. Adjust comments. + 2013-01-17 Paul Eggert Close a race when statting and reading files (Bug#13149). === modified file 'src/fileio.c' --- src/fileio.c 2013-01-18 05:12:08 +0000 +++ src/fileio.c 2013-01-18 06:32:12 +0000 @@ -3408,13 +3408,13 @@ return Qnil; } -/* Read from a non-regular file. STATE is a Lisp_Save_Value +/* Check quit and read from the file. STATE is a Lisp_Save_Value object where slot 0 is the file descriptor, slot 1 specifies an offset to put the read bytes, and slot 2 is the maximum amount of bytes to read. Value is the number of bytes read. */ static Lisp_Object -read_non_regular (Lisp_Object state) +read_contents (Lisp_Object state) { int nbytes; @@ -3425,15 +3425,15 @@ + XSAVE_INTEGER (state, 1)), XSAVE_INTEGER (state, 2)); immediate_quit = 0; + /* Fast recycle this object for the likely next call. */ + free_misc (state); return make_number (nbytes); } - -/* Condition-case handler used when reading from non-regular files - in insert-file-contents. */ +/* Condition-case handler used when reading files in insert-file-contents. */ static Lisp_Object -read_non_regular_quit (Lisp_Object ignore) +read_contents_quit (Lisp_Object ignore) { return Qnil; } @@ -3505,7 +3505,7 @@ Lisp_Object p; ptrdiff_t total = 0; bool not_regular = 0; - int save_errno = 0; + int save_errno = 0, read_errno = 0; char read_buf[READ_BUF_SIZE]; struct coding_system coding; char buffer[1 << 14]; @@ -4195,88 +4195,72 @@ Fcons (orig_filename, Qnil)); } - /* In the following loop, HOW_MUCH contains the total bytes read so - far for a regular file, and not changed for a special file. But, - before exiting the loop, it is set to a negative value if I/O - error occurs. */ + /* In the following loop, HOW_MUCH contains the total bytes read + so far for a regular file, and not changed for a special file. */ how_much = 0; /* Total bytes inserted. */ inserted = 0; - /* Here, we don't do code conversion in the loop. It is done by - decode_coding_gap after all data are read into the buffer. */ - { - ptrdiff_t gap_size = GAP_SIZE; - - while (how_much < total) - { - /* try is reserved in some compilers (Microsoft C) */ - ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); - ptrdiff_t this; - - if (not_regular) - { - Lisp_Object nbytes; - - /* Maybe make more room. */ - if (gap_size < trytry) - { - make_gap (total - gap_size); - gap_size = GAP_SIZE; - } - - /* Read from the file, capturing `quit'. When an - error occurs, end the loop, and arrange for a quit - to be signaled after decoding the text we read. */ - nbytes = internal_condition_case_1 - (read_non_regular, - make_save_value ("iii", (ptrdiff_t) fd, inserted, trytry), - Qerror, read_non_regular_quit); - - if (NILP (nbytes)) - { - read_quit = 1; - break; - } - - this = XINT (nbytes); - } - else - { - /* Allow quitting out of the actual I/O. We don't make text - part of the buffer until all the reading is done, so a C-g - here doesn't do any harm. */ - immediate_quit = 1; - QUIT; - this = emacs_read (fd, - ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE - + inserted), - trytry); - immediate_quit = 0; - } - - if (this <= 0) - { - how_much = this; - break; - } - - gap_size -= this; - - /* For a regular file, where TOTAL is the real size, - count HOW_MUCH to compare with it. - For a special file, where TOTAL is just a buffer size, - so don't bother counting in HOW_MUCH. - (INSERTED is where we count the number of characters inserted.) */ - if (! not_regular) - how_much += this; - inserted += this; - } - } - - /* Now we have read all the file data into the gap. - If it was empty, undo marking the buffer modified. */ + /* Here we don't do code conversion in the loop. It is done by + decode_coding_gap after all data are read into the buffer, or + reading loop is interrupted with quit or due to I/O error. */ + + while (how_much < total) + { + ptrdiff_t nread, maxread = min (total - how_much, READ_BUF_SIZE); + Lisp_Object result; + + /* For a special file, gap is enlarged as we read, + so GAP_SIZE should be checked every time. */ + if (not_regular && (GAP_SIZE < maxread)) + make_gap (maxread - GAP_SIZE); + + /* Read from the file, capturing `quit'. */ + result = internal_condition_case_1 + (read_contents, + make_save_value ("iii", (ptrdiff_t) fd, inserted, maxread), + Qerror, read_contents_quit); + if (NILP (result)) + { + /* Quit is signaled. End the loop and arrange + real quit after decoding the text we read. */ + read_quit = 1; + break; + } + nread = XINT (result); + if (nread <= 0) + { + /* End of file or I/O error. End the loop and + save error code in case of I/O error. */ + if (nread < 0) + read_errno = errno; + break; + } + + /* Adjust gap and end positions. */ + GAP_SIZE -= nread; + GPT += nread; + ZV += nread; + Z += nread; + GPT_BYTE += nread; + ZV_BYTE += nread; + Z_BYTE += nread; + if (GAP_SIZE > 0) + *(GPT_ADDR) = 0; + + /* For a regular file, where TOTAL is the real size, count HOW_MUCH to + compare with it. For a special file, where TOTAL is just a buffer + size, don't bother counting in HOW_MUCH, but always accumulate the + number of bytes read in INSERTED. */ + if (!not_regular) + how_much += nread; + inserted += nread; + } + + /* Now we have either read all the file data into the gap, + or stop reading on I/O error or quit. If nothing was + read, undo marking the buffer modified. */ if (inserted == 0) { @@ -4289,28 +4273,11 @@ else Vdeactivate_mark = Qt; - /* Make the text read part of the buffer. */ - GAP_SIZE -= inserted; - GPT += inserted; - GPT_BYTE += inserted; - ZV += inserted; - ZV_BYTE += inserted; - Z += inserted; - Z_BYTE += inserted; - - if (GAP_SIZE > 0) - /* Put an anchor to ensure multi-byte form ends at gap. */ - *GPT_ADDR = 0; - emacs_close (fd); /* Discard the unwind protect for closing the file. */ specpdl_ptr--; - if (how_much < 0) - error ("IO error reading %s: %s", - SDATA (orig_filename), emacs_strerror (errno)); - notfound: if (NILP (coding_system)) @@ -4599,14 +4566,17 @@ report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); } + /* There was an error reading file. */ + if (read_errno) + error ("IO error reading %s: %s", + SDATA (orig_filename), emacs_strerror (read_errno)); + + /* Quit was signaled. */ if (read_quit) Fsignal (Qquit, Qnil); - /* ??? Retval needs to be dealt with in all cases consistently. */ if (NILP (val)) - val = Fcons (orig_filename, - Fcons (make_number (inserted), - Qnil)); + val = list2 (orig_filename, make_number (inserted)); RETURN_UNGCPRO (unbind_to (count, val)); }