From 18a80473ed3fd815d99e64a8e7392066125a7e3c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 1 Feb 2013 11:23:23 +0200 Subject: w32proc.c (sys_spawnve): Initialize escape_char. src/w32proc.c (sys_spawnve): Make sure escape_char is initialized, even if w32-quote-process-args is nil. --- src/ChangeLog | 5 +++++ src/w32proc.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ChangeLog b/src/ChangeLog index 0fd835747ce..e80458c172f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2013-02-01 Eli Zaretskii + + * w32proc.c (sys_spawnve): Make sure escape_char is initialized, + even if w32-quote-process-args is nil. + 2013-01-27 Eli Zaretskii * w32.c (sys_open): Zero out the flags for the new file descriptor. diff --git a/src/w32proc.c b/src/w32proc.c index 3201fa9397e..8c09a1b1beb 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -1431,7 +1431,6 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) child_process *cp; int is_dos_app, is_cygnus_app, is_gui_app; int do_quoting = 0; - char escape_char; /* We pass our process ID to our children by setting up an environment variable in their environment. */ char ppid_env_var_buffer[64]; @@ -1444,6 +1443,8 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) Some extra whitespace characters need quoting in Cygwin programs, so this list is conditionally modified below. */ char *sepchars = " \t*?"; + /* This is for native w32 apps; modified below for Cygwin apps. */ + char escape_char = '\\'; /* We don't care about the other modes */ if (mode != _P_NOWAIT) -- cgit v1.2.1 From e7c3fb0624a88210f3a95adb103eba274b0fdba7 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 1 Feb 2013 12:15:36 +0200 Subject: Make sure program names are encoded before using them to invoke subprocesses. src/callproc.c (Fcall_process): Make sure program name in PATH and new_argv[0] is encoded, if needed. Otherwise, un-encoded string is passed to exec/spawnve, which fails unless the file-name encoding is UTF-8. --- src/ChangeLog | 5 +++++ src/callproc.c | 48 +++++++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/ChangeLog b/src/ChangeLog index e80458c172f..d09ad50ba12 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,10 @@ 2013-02-01 Eli Zaretskii + * callproc.c (Fcall_process): Make sure program name in PATH and + new_argv[0] is encoded, if needed. Otherwise, un-encoded string + is passed to exec/spawnve, which fails unless the file-name + encoding is UTF-8. + * w32proc.c (sys_spawnve): Make sure escape_char is initialized, even if w32-quote-process-args is nil. diff --git a/src/callproc.c b/src/callproc.c index d152da19f7b..c4177d5044c 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -416,28 +416,34 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) path = Fsubstring (path, make_number (2), Qnil); new_argv = SAFE_ALLOCA ((nargs > 4 ? nargs - 2 : 2) * sizeof *new_argv); - if (nargs > 4) - { - ptrdiff_t i; - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; - GCPRO5 (infile, buffer, current_dir, path, error_file); - argument_coding.dst_multibyte = 0; - for (i = 4; i < nargs; i++) - { - argument_coding.src_multibyte = STRING_MULTIBYTE (args[i]); - if (CODING_REQUIRE_ENCODING (&argument_coding)) - /* We must encode this argument. */ - args[i] = encode_coding_string (&argument_coding, args[i], 1); - } - UNGCPRO; - for (i = 4; i < nargs; i++) - new_argv[i - 3] = SDATA (args[i]); - new_argv[i - 3] = 0; - } - else - new_argv[1] = 0; - new_argv[0] = SDATA (path); + { + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; + + GCPRO5 (infile, buffer, current_dir, path, error_file); + if (nargs > 4) + { + ptrdiff_t i; + + argument_coding.dst_multibyte = 0; + for (i = 4; i < nargs; i++) + { + argument_coding.src_multibyte = STRING_MULTIBYTE (args[i]); + if (CODING_REQUIRE_ENCODING (&argument_coding)) + /* We must encode this argument. */ + args[i] = encode_coding_string (&argument_coding, args[i], 1); + } + for (i = 4; i < nargs; i++) + new_argv[i - 3] = SDATA (args[i]); + new_argv[i - 3] = 0; + } + else + new_argv[1] = 0; + if (STRING_MULTIBYTE (path)) + path = ENCODE_FILE (path); + new_argv[0] = SDATA (path); + UNGCPRO; + } #ifdef MSDOS /* MW, July 1993 */ -- cgit v1.2.1 From d9c287e589bdb05c2c818e340946546868d34e04 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 1 Feb 2013 22:04:06 -0800 Subject: Spelling fixes. --- src/w32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/w32.c b/src/w32.c index 64f8a0335ac..64e989a3b36 100644 --- a/src/w32.c +++ b/src/w32.c @@ -4280,7 +4280,7 @@ fstatat (int fd, char const *name, struct stat *st, int flags) /* Rely on a hack: an open directory is modeled as file descriptor 0. This is good enough for the current usage in Emacs, but is fragile. - FIXME: Add proper support for fdopendir, fstatatat, readlinkat. + FIXME: Add proper support for fdopendir, fstatat, readlinkat. Gnulib does this and can serve as a model. */ char fullname[MAX_PATH]; -- cgit v1.2.1 From e7ac588e198385a9bc5a2338000ab6db69c2353c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 2 Feb 2013 19:14:24 +0200 Subject: Avoid encoding file names run through dostounix_filename on MS-Windows. src/w32.c (normalize_filename): Accept an additional argument MULTIBYTE; if non-zero, traverse the file name by bytes and don't downcase it even if w32-downcase-file-names is non-nil. (dostounix_filename): Accept an additional argument MULTIBYTE and pass it to normalize_filename. (emacs_root_dir): Adjust. src/msdos.h (dostounix_filename): Adjust prototype. src/w32.h (dostounix_filename): Adjust prototype. src/msdos.c (dostounix_filename): Accept an additional argument and ignore it. (init_environment): Adjust callers of dostounix_filename. src/fileio.c (Ffile_name_directory, file_name_as_directory) (directory_file_name, Fexpand_file_name) (Fsubstitute_in_file_name): [DOS_NT] Adjust call to dostounix_filename. [WINDOWSNT]: Downcase file names if w32-downcase-file-names is non-nil. (Fsubstitute_in_file_name): [DOS_NT] Don't downcase environment variables, as egetenv is case-insensitive for DOS_NT. src/dired.c (file_name_completion): Don't call Fdirectory_file_name with an encoded file name. src/w32proc.c (Fw32_short_file_name, Fw32_long_file_name): Adjust calls to dostounix_filename. src/w32fns.c (Fx_file_dialog): Adjust call to dostounix_filename. src/unexw32.c (unexec): Adjust call to dostounix_filename. src/termcap.c (tgetent) [MSDOS]: Adjust call to dostounix_filename. src/emacs.c (decode_env_path) [DOS_NT]: Adjust call to dostounix_filename. src/callproc.c (Fcall_process) [MSDOS]: Adjust call to dostounix_filename. --- src/ChangeLog | 44 ++++++++++++++++++++ src/callproc.c | 2 +- src/dired.c | 4 +- src/emacs.c | 2 +- src/fileio.c | 125 +++++++++++++++++++++++++-------------------------------- src/msdos.c | 6 +-- src/msdos.h | 2 +- src/termcap.c | 2 +- src/unexw32.c | 2 +- src/w32.c | 21 ++++++---- src/w32.h | 2 +- src/w32fns.c | 2 +- src/w32proc.c | 5 ++- 13 files changed, 128 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/ChangeLog b/src/ChangeLog index 302010ec769..b90f18eba91 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,49 @@ 2013-02-02 Eli Zaretskii + Avoid encoding file names on MS-Windows when they need to be run + through dostounix_filename. + * w32.c (normalize_filename): Accept an additional argument + MULTIBYTE; if non-zero, traverse the file name by bytes and don't + downcase it even if w32-downcase-file-names is non-nil. + (dostounix_filename): Accept an additional argument MULTIBYTE and + pass it to normalize_filename. + (emacs_root_dir): Adjust. + + * msdos.h (dostounix_filename): Adjust prototype. + + * w32.h (dostounix_filename): Adjust prototype. + + * msdos.c (dostounix_filename): Accept an additional argument and + ignore it. + (init_environment): Adjust callers of dostounix_filename. + + * fileio.c (Ffile_name_directory, file_name_as_directory) + (directory_file_name, Fexpand_file_name) + (Fsubstitute_in_file_name): [DOS_NT] Adjust call to + dostounix_filename. + [WINDOWSNT]: Downcase file names if w32-downcase-file-names is + non-nil. + (Fsubstitute_in_file_name): [DOS_NT] Don't downcase environment + variables, as egetenv is case-insensitive for DOS_NT. + + * dired.c (file_name_completion): Don't call Fdirectory_file_name + with an encoded file name. + + * w32proc.c (Fw32_short_file_name, Fw32_long_file_name): Adjust + calls to dostounix_filename. + + * w32fns.c (Fx_file_dialog): Adjust call to dostounix_filename. + + * unexw32.c (unexec): Adjust call to dostounix_filename. + + * termcap.c (tgetent) [MSDOS]: Adjust call to dostounix_filename. + + * emacs.c (decode_env_path) [DOS_NT]: Adjust call to + dostounix_filename. + + * callproc.c (Fcall_process) [MSDOS]: Adjust call to + dostounix_filename. + * callproc.c (Fcall_process): Make sure program name in PATH and new_argv[0] is encoded, if needed. Otherwise, un-encoded string is passed to exec/spawnve, which fails unless the file-name diff --git a/src/callproc.c b/src/callproc.c index 9d81bb18295..ea79da7ff5a 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -487,7 +487,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) tempfile = alloca (20); *tempfile = '\0'; } - dostounix_filename (tempfile); + dostounix_filename (tempfile, 0); if (*tempfile == '\0' || tempfile[strlen (tempfile) - 1] != '/') strcat (tempfile, "/"); strcat (tempfile, "detmp.XXX"); diff --git a/src/dired.c b/src/dired.c index ed0571fe9fe..0e37568f211 100644 --- a/src/dired.c +++ b/src/dired.c @@ -484,9 +484,9 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag, on the encoded file name. */ encoded_file = STRING_MULTIBYTE (file) ? ENCODE_FILE (file) : file; - encoded_dir = ENCODE_FILE (dirname); + encoded_dir = ENCODE_FILE (Fdirectory_file_name (dirname)); - d = open_directory (SSDATA (Fdirectory_file_name (encoded_dir)), &fd); + d = open_directory (SSDATA (encoded_dir), &fd); if (!d) report_file_error ("Opening directory", Fcons (dirname, Qnil)); diff --git a/src/emacs.c b/src/emacs.c index 597fb2daf95..c351b1e9b9e 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -2152,7 +2152,7 @@ decode_env_path (const char *evarname, const char *defalt) { char *path_copy = alloca (strlen (path) + 1); strcpy (path_copy, path); - dostounix_filename (path_copy); + dostounix_filename (path_copy, 0); path = path_copy; } #endif diff --git a/src/fileio.c b/src/fileio.c index fb6ecfedeb4..99c5f7a5837 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -383,11 +383,13 @@ Given a Unix syntax file name, returns a string ending in slash. */) if (getdefdir (c_toupper (*beg) - 'A' + 1, r)) { - if (!IS_DIRECTORY_SEP (res[strlen (res) - 1])) + size_t l = strlen (res); + + if (l > 3 || !IS_DIRECTORY_SEP (res[l - 1])) strcat (res, "/"); beg = res; p = beg + strlen (beg); - dostounix_filename (beg); + dostounix_filename (beg, 0); tem_fn = make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename)); } @@ -397,13 +399,16 @@ Given a Unix syntax file name, returns a string ending in slash. */) } else if (STRING_MULTIBYTE (filename)) { - tem_fn = ENCODE_FILE (make_specified_string (beg, -1, p - beg, 1)); - dostounix_filename (SSDATA (tem_fn)); - tem_fn = DECODE_FILE (tem_fn); + tem_fn = make_specified_string (beg, -1, p - beg, 1); + dostounix_filename (SSDATA (tem_fn), 1); +#ifdef WINDOWSNT + if (!NILP (Vw32_downcase_file_names)) + tem_fn = Fdowncase (tem_fn); +#endif } else { - dostounix_filename (beg); + dostounix_filename (beg, 0); tem_fn = make_specified_string (beg, -1, p - beg, 0); } return tem_fn; @@ -507,17 +512,7 @@ file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen, srclen++; } #ifdef DOS_NT - if (multibyte) - { - Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1); - - tem_fn = ENCODE_FILE (tem_fn); - dostounix_filename (SSDATA (tem_fn)); - tem_fn = DECODE_FILE (tem_fn); - memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1); - } - else - dostounix_filename (dst); + dostounix_filename (dst, multibyte); #endif return srclen; } @@ -552,6 +547,10 @@ For a Unix-syntax file name, just appends a slash. */) error ("Invalid handler in `file-name-handler-alist'"); } +#ifdef WINDOWSNT + if (!NILP (Vw32_downcase_file_names)) + file = Fdowncase (file); +#endif buf = alloca (SBYTES (file) + 10); length = file_name_as_directory (buf, SSDATA (file), SBYTES (file), STRING_MULTIBYTE (file)); @@ -580,17 +579,7 @@ directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte) srclen--; } #ifdef DOS_NT - if (multibyte) - { - Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1); - - tem_fn = ENCODE_FILE (tem_fn); - dostounix_filename (SSDATA (tem_fn)); - tem_fn = DECODE_FILE (tem_fn); - memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1); - } - else - dostounix_filename (dst); + dostounix_filename (dst, multibyte); #endif return srclen; } @@ -625,6 +614,10 @@ In Unix-syntax, this function just removes the final slash. */) error ("Invalid handler in `file-name-handler-alist'"); } +#ifdef WINDOWSNT + if (!NILP (Vw32_downcase_file_names)) + directory = Fdowncase (directory); +#endif buf = alloca (SBYTES (directory) + 20); length = directory_file_name (buf, SSDATA (directory), SBYTES (directory), STRING_MULTIBYTE (directory)); @@ -925,6 +918,11 @@ filesystem tree, not (expand-file-name ".." dirname). */) } } +#ifdef WINDOWSNT + if (!NILP (Vw32_downcase_file_names)) + default_directory = Fdowncase (default_directory); +#endif + /* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */ nm = alloca (SBYTES (name) + 1); memcpy (nm, SSDATA (name), SBYTES (name) + 1); @@ -1008,18 +1006,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) #ifdef DOS_NT /* Make sure directories are all separated with /, but avoid allocation of a new string when not required. */ - if (multibyte) - { - Lisp_Object tem_name = make_specified_string (nm, -1, strlen (nm), - multibyte); - - tem_name = ENCODE_FILE (tem_name); - dostounix_filename (SSDATA (tem_name)); - tem_name = DECODE_FILE (tem_name); - memcpy (nm, SSDATA (tem_name), SBYTES (tem_name) + 1); - } - else - dostounix_filename (nm); + dostounix_filename (nm, multibyte); #ifdef WINDOWSNT if (IS_DIRECTORY_SEP (nm[1])) { @@ -1037,6 +1024,10 @@ filesystem tree, not (expand-file-name ".." dirname). */) temp[0] = DRIVE_LETTER (drive); name = concat2 (build_string (temp), name); } +#ifdef WINDOWSNT + if (!NILP (Vw32_downcase_file_names)) + name = Fdowncase (name); +#endif return name; #else /* not DOS_NT */ if (strcmp (nm, SSDATA (name)) == 0) @@ -1400,14 +1391,11 @@ filesystem tree, not (expand-file-name ".." dirname). */) target[1] = ':'; } result = make_specified_string (target, -1, o - target, multibyte); - if (multibyte) - { - result = ENCODE_FILE (result); - dostounix_filename (SSDATA (result)); - result = DECODE_FILE (result); - } - else - dostounix_filename (SSDATA (result)); + dostounix_filename (SSDATA (result), multibyte); +#ifdef WINDOWSNT + if (!NILP (Vw32_downcase_file_names)) + result = Fdowncase (result); +#endif #else /* !DOS_NT */ result = make_specified_string (target, -1, o - target, multibyte); #endif /* !DOS_NT */ @@ -1689,24 +1677,8 @@ those `/' is discarded. */) memcpy (nm, SDATA (filename), SBYTES (filename) + 1); #ifdef DOS_NT - if (multibyte) - { - Lisp_Object encoded_filename = ENCODE_FILE (filename); - Lisp_Object tem_fn; - - dostounix_filename (SDATA (encoded_filename)); - tem_fn = DECODE_FILE (encoded_filename); - nm = alloca (SBYTES (tem_fn) + 1); - memcpy (nm, SDATA (tem_fn), SBYTES (tem_fn) + 1); - substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0); - if (substituted) - filename = tem_fn; - } - else - { - dostounix_filename (nm); - substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0); - } + dostounix_filename (nm, multibyte); + substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0); #endif endp = nm + SBYTES (filename); @@ -1780,7 +1752,13 @@ those `/' is discarded. */) } if (!substituted) - return filename; + { +#ifdef WINDOWSNT + if (!NILP (Vw32_downcase_file_names)) + filename = Fdowncase (filename); +#endif + return filename; + } /* If substitution required, recopy the string and do it. */ /* Make space in stack frame for the new copy. */ @@ -1819,9 +1797,6 @@ those `/' is discarded. */) target = alloca (s - o + 1); memcpy (target, o, s - o); target[s - o] = 0; -#ifdef DOS_NT - strupr (target); /* $home == $HOME etc. */ -#endif /* DOS_NT */ /* Get variable value. */ o = egetenv (target); @@ -1858,6 +1833,16 @@ those `/' is discarded. */) need to quote some $ to $$ first. */ xnm = p; +#ifdef WINDOWSNT + if (!NILP (Vw32_downcase_file_names)) + { + Lisp_Object xname = make_specified_string (xnm, -1, x - xnm, multibyte); + + xname = Fdowncase (xname); + return xname; + } + else +#endif return make_specified_string (xnm, -1, x - xnm, multibyte); badsubst: diff --git a/src/msdos.c b/src/msdos.c index 5174bc4dfcd..1b2deaf7478 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -3339,7 +3339,7 @@ void msdos_downcase_filename (unsigned char *); /* Destructively turn backslashes into slashes. */ void -dostounix_filename (char *p) +dostounix_filename (char *p, int ignore) { msdos_downcase_filename (p); @@ -3603,7 +3603,7 @@ init_environment (int argc, char **argv, int skip_args) if (!s) s = "c:/command.com"; t = alloca (strlen (s) + 1); strcpy (t, s); - dostounix_filename (t); + dostounix_filename (t, 0); setenv ("SHELL", t, 0); /* PATH is also downcased and backslashes mirrored. */ @@ -3613,7 +3613,7 @@ init_environment (int argc, char **argv, int skip_args) /* Current directory is always considered part of MsDos's path but it is not normally mentioned. Now it is. */ strcat (strcpy (t, ".;"), s); - dostounix_filename (t); /* Not a single file name, but this should work. */ + dostounix_filename (t, 0); /* Not a single file name, but this should work. */ setenv ("PATH", t, 1); /* In some sense all dos users have root privileges, so... */ diff --git a/src/msdos.h b/src/msdos.h index 57609d62218..ee0d49464ae 100644 --- a/src/msdos.h +++ b/src/msdos.h @@ -29,7 +29,7 @@ void dos_set_window_size (int *, int *); int getdefdir (int, char*); void unixtodos_filename (char *); -void dostounix_filename (char *); +void dostounix_filename (char *, int); char *rootrelativepath (char *); void init_environment (int, char **, int); void internal_terminal_init (void); diff --git a/src/termcap.c b/src/termcap.c index 82c2b1fda07..99bbfce27f5 100644 --- a/src/termcap.c +++ b/src/termcap.c @@ -393,7 +393,7 @@ tgetent (char *bp, const char *name) if (termcap_name && (*termcap_name == '\\' || *termcap_name == '/' || termcap_name[1] == ':')) - dostounix_filename (termcap_name); + dostounix_filename (termcap_name, 0); #endif filep = termcap_name && valid_filename_p (termcap_name); diff --git a/src/unexw32.c b/src/unexw32.c index 66071295727..e8b553a87d3 100644 --- a/src/unexw32.c +++ b/src/unexw32.c @@ -722,7 +722,7 @@ unexec (const char *new_name, const char *old_name) /* Ignore old_name, and get our actual location from the OS. */ if (!GetModuleFileName (NULL, in_filename, MAX_PATH)) abort (); - dostounix_filename (in_filename); + dostounix_filename (in_filename, 0); strcpy (out_filename, in_filename); /* Change the base of the output filename to match the requested name. */ diff --git a/src/w32.c b/src/w32.c index 64e989a3b36..8b89bd3e660 100644 --- a/src/w32.c +++ b/src/w32.c @@ -1598,12 +1598,17 @@ max_filename_mbslen (void) case path name components to lower case. */ static void -normalize_filename (register char *fp, char path_sep) +normalize_filename (register char *fp, char path_sep, int multibyte) { char sep; char *elem, *p2; int dbcs_p = max_filename_mbslen () > 1; + /* Multibyte file names are in the Emacs internal representation, so + we can traverse them by bytes with no problems. */ + if (multibyte) + dbcs_p = 0; + /* Always lower-case drive letters a-z, even if the filesystem preserves case in filenames. This is so filenames can be compared by string comparison @@ -1620,7 +1625,7 @@ normalize_filename (register char *fp, char path_sep) fp += 2; } - if (NILP (Vw32_downcase_file_names)) + if (multibyte || NILP (Vw32_downcase_file_names)) { while (*fp) { @@ -1668,18 +1673,20 @@ normalize_filename (register char *fp, char path_sep) } while (*fp); } -/* Destructively turn backslashes into slashes. */ +/* Destructively turn backslashes into slashes. MULTIBYTE non-zero + means the file name is a multibyte string in Emacs's internal + representation. */ void -dostounix_filename (register char *p) +dostounix_filename (register char *p, int multibyte) { - normalize_filename (p, '/'); + normalize_filename (p, '/', multibyte); } /* Destructively turn slashes into backslashes. */ void unixtodos_filename (register char *p) { - normalize_filename (p, '\\'); + normalize_filename (p, '\\', 0); } /* Remove all CR's that are followed by a LF. @@ -2222,7 +2229,7 @@ emacs_root_dir (void) emacs_abort (); strcpy (root_dir, p); root_dir[parse_root (root_dir, NULL)] = '\0'; - dostounix_filename (root_dir); + dostounix_filename (root_dir, 0); return root_dir; } diff --git a/src/w32.h b/src/w32.h index 895e7f31d63..6bf165f52ba 100644 --- a/src/w32.h +++ b/src/w32.h @@ -180,7 +180,7 @@ extern void init_environment (char **); extern void check_windows_init_file (void); extern void syms_of_ntproc (void); extern void syms_of_ntterm (void); -extern void dostounix_filename (register char *); +extern void dostounix_filename (register char *, int); extern void unixtodos_filename (register char *); extern BOOL init_winsock (int load_now); extern void srandom (int); diff --git a/src/w32fns.c b/src/w32fns.c index 6c098cae3a3..0841ad3468e 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -6254,7 +6254,7 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */) /* we get one of the two final 0 bytes for free. */ 1 + sizeof (wchar_t) * wcslen (filename_buf))); #else /* !NTGUI_UNICODE */ - dostounix_filename (filename_buf); + dostounix_filename (filename_buf, 0); filename = DECODE_FILE (build_string (filename_buf)); #endif /* NTGUI_UNICODE */ diff --git a/src/w32proc.c b/src/w32proc.c index 615e5329e8c..8bf57602927 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -2558,8 +2558,9 @@ All path elements in FILENAME are converted to their short names. */) if (GetShortPathName (SDATA (ENCODE_FILE (filename)), shortname, MAX_PATH) == 0) return Qnil; - dostounix_filename (shortname); + dostounix_filename (shortname, 0); + /* No need to DECODE_FILE, because 8.3 names are pure ASCII. */ return build_string (shortname); } @@ -2586,7 +2587,7 @@ All path elements in FILENAME are converted to their long names. */) if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname, MAX_PATH)) return Qnil; - dostounix_filename (longname); + dostounix_filename (longname, 0); /* If we were passed only a drive, make sure that a slash is not appended for consistency with directories. Allow for drive mapping via SUBST -- cgit v1.2.1 From 8ea41ea99608c7483ef5c91e230a760cf90bfb54 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 2 Feb 2013 11:18:00 -0800 Subject: Avoid file time stamp bug on MS-Windows. * fileio.c (Fwrite_region): Don't use the heuristic on empty files, as FAT32 doesn't update time stamps when truncating them. Also, check that a file time stamp is not a multiple of 100 ns; this should catch all instances of the problem on MS-Windows, as its native file system resolution is 100 ns or worse, and checking for a non-multiple of 100 ns should impose only a small overhead on systems with ns resolution. Fixes: debbugs:13149 --- src/ChangeLog | 11 +++++++++++ src/fileio.c | 19 +++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/ChangeLog b/src/ChangeLog index b90f18eba91..092302d6492 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,14 @@ +2013-02-02 Paul Eggert + + Avoid file time stamp bug on MS-Windows (Bug#13149). + * fileio.c (Fwrite_region): Don't use the heuristic on empty files, + as FAT32 doesn't update time stamps when truncating them. + Also, check that a file time stamp is not a multiple of 100 ns; + this should catch all instances of the problem on MS-Windows, + as its native file system resolution is 100 ns or worse, and + checking for a non-multiple of 100 ns should impose only a small + overhead on systems with ns resolution. + 2013-02-02 Eli Zaretskii Avoid encoding file names on MS-Windows when they need to be run diff --git a/src/fileio.c b/src/fileio.c index 99c5f7a5837..e76f2bc2420 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5020,11 +5020,22 @@ This calls `write-region-annotate-functions' at the start, and if (fstat (desc1, &st1) == 0 && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) { + /* Use the heuristic if it appears to be valid. With neither + O_EXCL nor O_TRUNC, if Emacs happened to write nothing to the + file, the time stamp won't change. Also, some non-POSIX + systems don't update an empty file's time stamp when + truncating it. Finally, file systems with 100 ns or worse + resolution sometimes seem to have bugs: on a system with ns + resolution, checking ns % 100 incorrectly avoids the heuristic + 1% of the time, but the problem should be temporary as we will + try again on the next time stamp. */ + bool use_heuristic + = ((open_flags & (O_EXCL | O_TRUNC)) != 0 + && st.st_size != 0 + && EMACS_NSECS (modtime) % 100 != 0); + EMACS_TIME modtime1 = get_stat_mtime (&st1); - /* If neither O_EXCL nor O_TRUNC is used, and Emacs happened to - write nothing to the file, the file's time stamp won't change - so it should not be used in this heuristic. */ - if ((open_flags & (O_EXCL | O_TRUNC)) != 0 + if (use_heuristic && EMACS_TIME_EQ (modtime, modtime1) && st.st_size == st1.st_size) { -- cgit v1.2.1