#include <selinux/context.h>
#endif
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
#include <sys/acl.h>
#endif
#endif
#include "systime.h"
+#include <acl.h>
#include <allocator.h>
#include <careadlinkat.h>
#include <stat-time.h>
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
security_context_t con;
int conlength = 0;
#endif
-#ifdef HAVE_POSIX_ACL
+#ifdef WINDOWSNT
acl_t acl = NULL;
#endif
#ifdef WINDOWSNT
if (!NILP (preserve_extended_attributes))
{
-#ifdef HAVE_POSIX_ACL
acl = acl_get_file (SDATA (encoded_file), ACL_TYPE_ACCESS);
- if (acl == NULL && errno != ENOTSUP)
+ if (acl == NULL && acl_errno_valid (errno))
report_file_error ("Getting ACL", Fcons (file, Qnil));
-#endif
}
if (!CopyFile (SDATA (encoded_file),
SDATA (encoded_newname),
/* Restore original attributes. */
SetFileAttributes (filename, attributes);
}
-#ifdef HAVE_POSIX_ACL
if (acl != NULL)
{
bool fail =
acl_set_file (SDATA (encoded_newname), ACL_TYPE_ACCESS, acl) != 0;
- if (fail && errno != ENOTSUP)
+ if (fail && acl_errno_valid (errno))
report_file_error ("Setting ACL", Fcons (newname, Qnil));
acl_free (acl);
}
-#endif
#else /* not WINDOWSNT */
immediate_quit = 1;
ifd = emacs_open (SSDATA (encoded_file), O_RDONLY, 0);
report_file_error ("Doing fgetfilecon", Fcons (file, Qnil));
}
#endif
-
-#ifdef HAVE_POSIX_ACL
- acl = acl_get_fd (ifd);
- if (acl == NULL && errno != ENOTSUP)
- report_file_error ("Getting ACL", Fcons (file, Qnil));
-#endif
}
if (out_st.st_mode != 0
immediate_quit = 0;
#ifndef MSDOS
- /* Preserve the original file modes, and if requested, also its
+ /* Preserve the original file permissions, and if requested, also its
owner and group. */
{
mode_t mode_mask = 07777;
mode_mask |= 02000;
}
}
- if (fchmod (ofd, st.st_mode & mode_mask) != 0)
- report_file_error ("Doing chmod", Fcons (newname, Qnil));
+
+ switch (!NILP (preserve_extended_attributes)
+ ? qcopy_acl (SSDATA (encoded_file), ifd,
+ SSDATA (encoded_newname), ofd,
+ st.st_mode & mode_mask)
+ : fchmod (ofd, st.st_mode & mode_mask))
+ {
+ case -2: report_file_error ("Copying permissions from", list1 (file));
+ case -1: report_file_error ("Copying permissions to", list1 (newname));
+ }
}
#endif /* not MSDOS */
}
#endif
-#ifdef HAVE_POSIX_ACL
- if (acl != NULL)
- {
- bool fail = acl_set_fd (ofd, acl) != 0;
- if (fail && errno != ENOTSUP)
- report_file_error ("Setting ACL", Fcons (newname, Qnil));
-
- acl_free (acl);
- }
-#endif
-
if (!NILP (keep_time))
{
EMACS_TIME atime = get_stat_atime (&st);
and it's a safe optimization here. */
char *buf = SAFE_ALLOCA (len + 3);
memcpy (buf, file, len);
- strcpy (buf + len, "/." + (file[len - 1] == '/'));
+ strcpy (buf + len, &"/."[file[len - 1] == '/']);
dir = buf;
}
{
Lisp_Object absname;
Lisp_Object handler;
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
acl_t acl;
Lisp_Object acl_string;
char *str;
if (!NILP (handler))
return call2 (handler, Qfile_acl, absname);
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
absname = ENCODE_FILE (absname);
acl = acl_get_file (SSDATA (absname), ACL_TYPE_ACCESS);
{
Lisp_Object absname;
Lisp_Object handler;
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
Lisp_Object encoded_absname;
acl_t acl;
bool fail;
if (!NILP (handler))
return call3 (handler, Qset_file_acl, absname, acl_string);
-#ifdef HAVE_POSIX_ACL
+#ifdef HAVE_ACL_SET_FILE
if (STRINGP (acl_string))
{
acl = acl_from_text (SSDATA (acl_string));
fail = (acl_set_file (SSDATA (encoded_absname), ACL_TYPE_ACCESS,
acl)
!= 0);
- if (fail && errno != ENOTSUP)
+ if (fail && acl_errno_valid (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
- /* 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)
+ /* fsync is not crucial for auto-save files, since they might lose
+ some work anyway. */
+ if (!auto_saving && !write_region_inhibit_fsync)
{
- /* If fsync fails with EINTR, don't treat that as serious. Also
- ignore EINVAL which happens when fsync is not supported on this
- file. */
- if (errno != EINTR && errno != EINVAL)
- ok = 0, save_errno = errno;
+ /* Transfer data and metadata to disk, retrying if interrupted.
+ fsync can report a write failure here, e.g., due to disk full
+ under NFS. But ignore EINVAL, which means fsync is not
+ supported on this file. */
+ 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
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
+ /* fsync can be a significant performance hit. Often it doesn't
+ suffice to make the file-save operation survive a crash. For
+ batch scripts, which are typically part of larger shell commands
+ that don't fsync other files, its effect on performance can be
+ significant so its utility is particularly questionable.
+ Hence, for now by default fsync is used only when interactive.
+
+ For more on why fsync often fails to work on today's hardware, see:
+ Zheng M et al. Understanding the robustness of SSDs under power fault.
+ 11th USENIX Conf. on File and Storage Technologies, 2013 (FAST '13), 271-84
+ http://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf
+
+ For more on why fsync does not suffice even if it works properly, see:
+ Roche X. Necessary step(s) to synchronize filename operations on disk.
+ Austin Group Defect 672, 2013-03-19
+ http://austingroupbugs.net/view.php?id=672 */
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
+Setting this to nil may avoid data loss if the system loses power or
+the operating system crashes. */);
+ write_region_inhibit_fsync = noninteractive;
DEFVAR_BOOL ("delete-by-moving-to-trash", delete_by_moving_to_trash,
doc: /* Specifies whether to use the system's trash can.