#define DRIVE_LETTER(x) c_tolower (x)
#endif
+#ifdef HAVE_POSIX_ACL
+/* FIXME: this macro was copied from gnulib's private acl-internal.h
+ header file. */
+/* Recognize some common errors such as from an NFS mount that does
+ not support ACLs, even when local drives do. */
+#if defined __APPLE__ && defined __MACH__ /* Mac OS X */
+#define ACL_NOT_WELL_SUPPORTED(Err) \
+ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == ENOENT)
+#elif defined EOPNOTSUPP /* Tru64 NFS */
+#define ACL_NOT_WELL_SUPPORTED(Err) \
+ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == EOPNOTSUPP)
+#elif defined WINDOWSNT
+#define ACL_NOT_WELL_SUPPORTED(Err) ((Err) == ENOTSUP)
+#else
+#define ACL_NOT_WELL_SUPPORTED(Err) \
+ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
+#endif
+#endif /* HAVE_POSIX_ACL */
+
#include "systime.h"
#include <allocator.h>
#include <careadlinkat.h>
is added here. */
static Lisp_Object Vwrite_region_annotation_buffers;
-#ifdef HAVE_FSYNC
-#endif
-
static Lisp_Object Qdelete_by_moving_to_trash;
/* Lisp function for moving files to trash. */
static Lisp_Object Qset_file_acl;
static Lisp_Object Qfile_newer_than_file_p;
Lisp_Object Qinsert_file_contents;
-Lisp_Object Qchoose_write_coding_system;
+static Lisp_Object Qchoose_write_coding_system;
Lisp_Object Qwrite_region;
static Lisp_Object Qverify_visited_file_modtime;
static Lisp_Object Qset_visited_file_modtime;
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));
}
}
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;
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;
}
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));
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;
}
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));
}
}
+#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);
#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]))
{
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)
#ifdef WINDOWSNT
char *prev_o = o;
#endif
- while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
- ;
+ while (o != target && (--o, !IS_DIRECTORY_SEP (*o)))
+ continue;
#ifdef WINDOWSNT
/* Don't go below server level in UNC filenames. */
if (o == target + 1 && IS_DIRECTORY_SEP (*o)
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 */
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);
else if (*p == '{')
{
o = ++p;
- while (p != endp && *p != '}') p++;
- if (*p != '}') goto missingclose;
+ p = memchr (p, '}', endp - p);
+ if (! p)
+ goto missingclose;
s = p;
}
else
}
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. */
else if (*p == '{')
{
o = ++p;
- while (p != endp && *p != '}') p++;
- if (*p != '}') goto missingclose;
+ p = memchr (p, '}', endp - p);
+ if (! p)
+ goto missingclose;
s = p++;
}
else
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);
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:
error ("Missing \"}\" in environment-variable substitution");
badvar:
error ("Substituting nonexistent environment variable \"%s\"", target);
-
- /* NOTREACHED */
- return Qnil;
}
\f
/* A slightly faster and more convenient way to get
{
#ifdef HAVE_POSIX_ACL
acl = acl_get_file (SDATA (encoded_file), ACL_TYPE_ACCESS);
- if (acl == NULL && errno != ENOTSUP)
+ if (acl == NULL && !ACL_NOT_WELL_SUPPORTED (errno))
report_file_error ("Getting ACL", Fcons (file, Qnil));
#endif
}
{
bool fail =
acl_set_file (SDATA (encoded_newname), ACL_TYPE_ACCESS, acl) != 0;
- if (fail && errno != ENOTSUP)
+ if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
report_file_error ("Setting ACL", Fcons (newname, Qnil));
acl_free (acl);
#ifdef HAVE_POSIX_ACL
acl = acl_get_fd (ifd);
- if (acl == NULL && errno != ENOTSUP)
+ if (acl == NULL && !ACL_NOT_WELL_SUPPORTED (errno))
report_file_error ("Getting ACL", Fcons (file, Qnil));
#endif
}
if (acl != NULL)
{
bool fail = acl_set_fd (ofd, acl) != 0;
- if (fail && errno != ENOTSUP)
+ if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
report_file_error ("Setting ACL", Fcons (newname, Qnil));
acl_free (acl);
fail = (acl_set_file (SSDATA (encoded_absname), ACL_TYPE_ACCESS,
acl)
!= 0);
- if (fail && errno != ENOTSUP)
+ if (fail && !ACL_NOT_WELL_SUPPORTED (errno))
report_file_error ("Setting ACL", Fcons (absname, Qnil));
acl_free (acl);
return Qnil;
#endif
report_file_error ("Setting file times", Fcons (absname, Qnil));
- return Qnil;
}
}
/* If display currently starts at beginning of line,
keep it that way. */
- if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
+ if (XBUFFER (XWINDOW (selected_window)->contents) == current_buffer)
XWINDOW (selected_window)->start_at_line_beg = !NILP (Fbolp ());
replace_handled = 1;
/* If display currently starts at beginning of line,
keep it that way. */
- if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
+ if (XBUFFER (XWINDOW (selected_window)->contents) == current_buffer)
XWINDOW (selected_window)->start_at_line_beg = !NILP (Fbolp ());
/* Replace the chars that we need to replace,
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),
+ make_save_value (SAVE_TYPE_INT_INT_INT, (ptrdiff_t) fd,
+ inserted, trytry),
Qerror, read_non_regular_quit);
if (NILP (nbytes))
immediate_quit = 0;
-#ifdef HAVE_FSYNC
- /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
+ /* fsync appears to change the modtime on BSD4.2.
Disk full in NFS may be reported here. */
/* mib says that closing the file will try to write as fast as NFS can do
it, and that means the fsync here is not crucial for autosave files. */
- if (!auto_saving && !write_region_inhibit_fsync && fsync (desc) < 0)
+ if (!auto_saving && !write_region_inhibit_fsync)
{
- /* If fsync fails with EINTR, don't treat that as serious. Also
+ /* Transfer data and metadata to disk, retrying if interrupted. Also,
ignore EINVAL which happens when fsync is not supported on this
file. */
- if (errno != EINTR && errno != EINVAL)
- ok = 0, save_errno = errno;
+ while (fsync (desc) != 0)
+ if (errno != EINTR)
+ {
+ if (errno != EINVAL)
+ ok = 0, save_errno = errno;
+ break;
+ }
}
-#endif
modtime = invalid_emacs_time ();
if (visiting)
&& ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system))
{
int desc1 = emacs_open (fn, O_WRONLY | O_BINARY, 0);
- if (0 <= desc1)
+ if (desc1 >= 0)
{
struct stat st1;
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)
{
if (EMACS_NSECS (current_buffer->modtime) == NONEXISTENT_MODTIME_NSECS)
{
/* make_lisp_time won't work here if time_t is unsigned. */
- return list4 (make_number (-1), make_number (65535),
- make_number (0), make_number (0));
+ return list4i (-1, 65535, 0, 0);
}
return make_number (0);
}
if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
&& use_dialog_box
&& use_file_dialog
- && have_menus_p ())
+ && window_system_available (SELECTED_FRAME ()))
return Qt;
#endif
return Qnil;
file is usually more useful if it contains the deleted text. */);
Vauto_save_include_big_deletions = Qnil;
-#ifdef HAVE_FSYNC
DEFVAR_BOOL ("write-region-inhibit-fsync", write_region_inhibit_fsync,
doc: /* Non-nil means don't call fsync in `write-region'.
This variable affects calls to `write-region' as well as save commands.
A non-nil value may result in data loss! */);
write_region_inhibit_fsync = 0;
-#endif
DEFVAR_BOOL ("delete-by-moving-to-trash", delete_by_moving_to_trash,
doc: /* Specifies whether to use the system's trash can.