#endif /* HPUX_PRE_8_0 */
#endif /* HPUX */
+#if defined(WIN32_NATIVE) || defined(CYGWIN)
+#define WIN32_FILENAMES
#ifdef WIN32_NATIVE
+#include "nt.h"
+#include <aclapi.h>
+#endif /* WIN32_NATIVE */
+#ifdef CYGWIN
+#include <w32api/aclapi.h>
+#endif
+
+
#define IS_DRIVE(x) isalpha (x)
/* Need to lower-case the drive letter, or else expanded
filenames will sometimes compare inequal, because
`expand-file-name' doesn't always down-case the drive letter. */
#define DRIVE_LETTER(x) tolower (x)
-#endif /* WIN32_NATIVE */
+#ifndef CORRECT_DIR_SEPS
+#define CORRECT_DIR_SEPS(s) \
+ normalize_filename(s, DIRECTORY_SEP)
+/* Default implementation that coerces a file to use path_sep. */
+static void
+normalize_filename (Bufbyte *fp, Bufbyte path_sep)
+{
+ /* 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
+ functions that are case-sensitive. Even case-preserving filesystems
+ do not distinguish case in drive letters. */
+ if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
+ {
+ *fp += 'a' - 'A';
+ fp += 2;
+ }
+
+ while (*fp)
+ {
+ if (*fp == '/' || *fp == '\\')
+ *fp = path_sep;
+ fp++;
+ }
+}
+#endif /* CORRECT_DIR_SEPS */
+#endif /* WIN32_NATIVE || CYGWIN */
int lisp_to_time (Lisp_Object, time_t *);
Lisp_Object time_to_lisp (time_t);
any handlers that are members of `inhibit-file-name-handlers',
but we still do run any other handlers. This lets handlers
use the standard functions without calling themselves recursively.
+
+Otherwise, OPERATION is the name of a funcall'able function.
*/
(filename, operation))
{
p = beg + XSTRING_LENGTH (filename);
while (p != beg && !IS_ANY_SEP (p[-1])
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* only recognize drive specifier at beginning */
&& !(p[-1] == ':' && p == beg + 2)
#endif
end = p = beg + XSTRING_LENGTH (filename);
while (p != beg && !IS_ANY_SEP (p[-1])
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* only recognize drive specifier at beginning */
&& !(p[-1] == ':' && p == beg + 2)
#endif
strcpy (dst, src);
if (slen > 1
&& IS_DIRECTORY_SEP (dst[slen - 1])
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
&& !IS_ANY_SEP (dst[slen - 2])
-#endif /* WIN32_NATIVE */
+#endif /* WIN32_FILENAMES */
)
dst[slen - 1] = 0;
return 1;
Bufbyte *newdir, *p, *o;
int tlen;
Bufbyte *target;
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
int drive = 0;
int collapse_newdir = 1;
-#else
+#endif
+#ifndef WIN32_NATIVE
struct passwd *pw;
-#endif /* WIN32_NATIVE */
+#endif /* WIN32_FILENAMES */
int length;
Lisp_Object handler = Qnil;
#ifdef CYGWIN
/* Save time in some common cases - as long as default_directory
is not relative, it can be canonicalized with name below (if it
is needed at all) without requiring it to be expanded now. */
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* Detect Windows file names with drive specifiers. */
&& ! (IS_DRIVE (o[0]) && (IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2])))
/* Detect Windows file names in UNC format. */
&& ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1]))
-
-#else /* not WIN32_NATIVE */
-
+#endif /* not WIN32_FILENAMES */
+#ifndef WIN32_NATIVE
/* Detect Unix absolute file names (/... alone is not absolute on
Windows). */
&& ! (IS_DIRECTORY_SEP (o[0]))
into name should be safe during all of this, though. */
nm = XSTRING_DATA (name);
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* We will force directory separators to be either all \ or /, so make
a local copy to modify, even if there ends up being no change. */
- nm = strcpy ((char *)alloca (strlen ((char *)nm) + 1), (char *)nm);
+ nm = (Bufbyte *) strcpy ((char *) alloca (strlen ((char *) nm) + 1),
+ (char *) nm);
/* Find and remove drive specifier if present; this makes nm absolute
even if the rest of the name appears to be relative. */
Bufbyte *colon = (Bufbyte *) strrchr ((char *)nm, ':');
if (colon)
+ {
/* Only recognize colon as part of drive specifier if there is a
single alphabetic character preceding the colon (and if the
character before the drive letter, if present, is a directory
if (colon[0] == ':')
goto look_again;
}
+ }
}
/* If we see "c://somedir", we want to strip the first slash after the
"//somedir". */
if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
nm++;
-#endif /* WIN32_NATIVE */
+#endif /* WIN32_FILENAMES */
/* If nm is absolute, look for /./ or /../ sequences; if none are
found, we can probably return right away. We will avoid allocating
}
if (!lose)
{
-#ifdef WIN32_NATIVE
- /* Make sure directories are all separated with / or \ as
- desired, but avoid allocation of a new string when not
- required. */
- CORRECT_DIR_SEPS (nm);
- if (IS_DIRECTORY_SEP (nm[1]))
+#ifdef WIN32_FILENAMES
+ if (drive || IS_DIRECTORY_SEP (nm[1]))
{
- if (strcmp (nm, XSTRING_DATA (name)) != 0)
- name = build_string (nm);
- }
- /* drive must be set, so this is okay */
- else if (strcmp (nm - 2, XSTRING_DATA (name)) != 0)
- {
- name = make_string (nm - 2, p - nm + 2);
- XSTRING_DATA (name)[0] = DRIVE_LETTER (drive);
- XSTRING_DATA (name)[1] = ':';
+ /* Make sure directories are all separated with / or \ as
+ desired, but avoid allocation of a new string when not
+ required. */
+ CORRECT_DIR_SEPS (nm);
+ if (IS_DIRECTORY_SEP (nm[1]))
+ {
+ if (strcmp ((char *) nm, (char *) XSTRING_DATA (name)) != 0)
+ name = build_string ((Bufbyte *) nm);
+ }
+ /* drive must be set, so this is okay */
+ else if (strcmp ((char *) nm - 2,
+ (char *) XSTRING_DATA (name)) != 0)
+ {
+ name = make_string (nm - 2, p - nm + 2);
+ XSTRING_DATA (name)[0] = DRIVE_LETTER (drive);
+ XSTRING_DATA (name)[1] = ':';
+ }
+ RETURN_UNGCPRO (name);
}
- RETURN_UNGCPRO (name);
-#else /* not WIN32_NATIVE */
+#endif /* not WIN32_FILENAMES */
+#ifndef WIN32_NATIVE
if (nm == XSTRING_DATA (name))
RETURN_UNGCPRO (name);
RETURN_UNGCPRO (build_string ((char *) nm));
Qfile_name);
nm++;
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
collapse_newdir = 0;
#endif
}
memcpy (o, (char *) nm, p - nm);
o [p - nm] = 0;
- /* #### marcpa's syncing note: FSF uses getpwnam even on NT,
- which does not work. The following works only if ~USER
- names the user who runs this instance of XEmacs. While
- NT is single-user (for the moment) you still can have
- multiple user profiles users defined, each with its HOME.
- Therefore, the following should be reworked to handle
- this case. */
-#ifdef WIN32_NATIVE
- /* Now if the file given is "~foo/file" and HOME="c:/", then
- we want the file to be named "c:/file" ("~foo" becomes
- "c:/"). The variable o has "~foo", so we can use the
- length of that string to offset nm. August Hill, 31 Aug
- 1998. */
- newdir = (Bufbyte *) get_home_directory();
- dostounix_filename (newdir);
- nm += strlen(o) + 1;
-#else /* not WIN32_NATIVE */
+ /* #### While NT is single-user (for the moment) you still
+ can have multiple user profiles users defined, each with
+ its HOME. So maybe possibly we should think about handling
+ ~user. --ben */
+#ifndef WIN32_NATIVE
#ifdef CYGWIN
if ((user = user_login_name (NULL)) != NULL)
{
}
}
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* On DOS and Windows, nm is absolute if a drive name was specified;
use the drive's current directory as the prefix if needed. */
if (!newdir && drive)
{
+#ifdef WIN32_NATIVE
/* Get default directory if needed to make nm absolute. */
if (!IS_DIRECTORY_SEP (nm[0]))
{
- newdir = alloca (MAXPATHLEN + 1);
+ newdir = (Bufbyte *) alloca (MAXPATHLEN + 1);
if (!_getdcwd (toupper (drive) - 'A' + 1, newdir, MAXPATHLEN))
newdir = NULL;
}
+#endif /* WIN32_NATIVE */
if (!newdir)
{
/* Either nm starts with /, or drive isn't mounted. */
- newdir = alloca (4);
+ newdir = (Bufbyte *) alloca (4);
newdir[0] = DRIVE_LETTER (drive);
newdir[1] = ':';
newdir[2] = '/';
newdir[3] = 0;
}
}
-#endif /* WIN32_NATIVE */
+#endif /* WIN32_FILENAMES */
/* Finally, if no prefix has been specified and nm is not absolute,
then it must be expanded relative to default_directory. */
#ifndef WIN32_NATIVE
/* /... alone is not absolute on DOS and Windows. */
&& !IS_DIRECTORY_SEP (nm[0])
-#else
+#endif
+#ifdef WIN32_FILENAMES
&& !(IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
#endif
&& !newdir)
newdir = XSTRING_DATA (default_directory);
}
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
if (newdir)
{
/* First ensure newdir is an absolute name. */
&& ! (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1]))
/* Detect drive spec by itself */
&& ! (IS_DEVICE_SEP (newdir[1]) && newdir[2] == 0)
+ /* Detect unix format. */
+#ifndef WIN32_NATIVE
+ && ! (IS_DIRECTORY_SEP (newdir[0]))
+#endif
)
{
/* Effectively, let newdir be (expand-file-name newdir cwd).
}
if (!IS_DIRECTORY_SEP (nm[0]))
{
- char * tmp = alloca (strlen (newdir) + strlen (nm) + 2);
- file_name_as_directory (tmp, newdir);
- strcat (tmp, nm);
+ Bufbyte *tmp = (Bufbyte *) alloca (strlen ((char *) newdir) +
+ strlen ((char *) nm) + 2);
+ file_name_as_directory ((char *) tmp, (char *) newdir);
+ strcat ((char *) tmp, (char *) nm);
nm = tmp;
}
- newdir = alloca (MAXPATHLEN + 1);
+ newdir = (Bufbyte *) alloca (MAXPATHLEN + 1);
if (drive)
{
+#ifdef WIN32_NATIVE
if (!_getdcwd (toupper (drive) - 'A' + 1, newdir, MAXPATHLEN))
- newdir = "/";
+#endif
+ newdir = (Bufbyte *) "/";
}
else
- getwd (newdir);
+ getcwd ((char *) newdir, MAXPATHLEN);
}
/* Strip off drive name from prefix, if present. */
/* Keep only a prefix from newdir if nm starts with slash
(/ /server/share for UNC, nothing otherwise). */
- if (IS_DIRECTORY_SEP (nm[0]) && collapse_newdir)
+ if (IS_DIRECTORY_SEP (nm[0])
+#ifndef WIN32_NATIVE
+ && IS_DIRECTORY_SEP (nm[1])
+#endif
+ && collapse_newdir)
{
if (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1]))
{
- newdir = strcpy (alloca (strlen (newdir) + 1), newdir);
+ newdir =
+ (Bufbyte *)
+ strcpy ((char *) alloca (strlen ((char *) newdir) + 1),
+ (char *) newdir);
p = newdir + 2;
while (*p && !IS_DIRECTORY_SEP (*p)) p++;
p++;
*p = 0;
}
else
- newdir = "";
+ newdir = (Bufbyte *) "";
}
}
-#endif /* WIN32_NATIVE */
+#endif /* WIN32_FILENAMES */
if (newdir)
{
just // (an incomplete UNC name). */
length = strlen ((char *) newdir);
if (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1])
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
&& !(length == 2 && IS_DIRECTORY_SEP (newdir[0]))
#endif
)
/* Now concatenate the directory and name to new space in the stack frame */
tlen += strlen ((char *) nm) + 1;
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* Add reserved space for drive name. (The Microsoft x86 compiler
produces incorrect code if the following two lines are combined.) */
target = (Bufbyte *) alloca (tlen + 2);
target += 2;
-#else /* not WIN32_NATIVE */
+#else /* not WIN32_FILENAMES */
target = (Bufbyte *) alloca (tlen);
-#endif /* not WIN32_NATIVE */
+#endif /* not WIN32_FILENAMES */
*target = 0;
if (newdir)
++o;
p += 3;
}
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* if drive is set, we're not dealing with an UNC, so
multiple dir-seps are redundant (and reportedly cause trouble
under win95) */
}
}
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* At last, set drive name, except for network file name. */
if (drive)
{
target[0] = DRIVE_LETTER (drive);
target[1] = ':';
}
+#ifdef WIN32_NATIVE
else
{
assert (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]));
}
+#endif
CORRECT_DIR_SEPS (target);
-#endif /* WIN32_NATIVE */
+#endif /* WIN32_FILENAMES */
RETURN_UNGCPRO (make_string (target, o - target));
}
TO_EXTERNAL_FORMAT (LISP_STRING, expanded_name,
ALLOCA, (path, elen),
Qfile_name);
+
+#if defined(WIN32_FILENAMES) && defined(CYGWIN)
+ /* When using win32 filenames in cygwin we want file-truename to
+ detect that c:/windows == /windows for example. */
+ if ((IS_DIRECTORY_SEP (path[0])
+ && (elen == 1 || !IS_DIRECTORY_SEP (path[1])))
+ || (isalpha (path[0])
+ && (elen == 1 || !IS_DEVICE_SEP (path[1])))) {
+ int ltwff2 =
+ cygwin_posix_to_win32_path_list_buf_size (path);
+ p = (Bufbyte *) alloca (ltwff2);
+ cygwin_posix_to_win32_path_list (path, p);
+ path = p;
+ }
+#endif
p = path;
+
if (elen > MAXPATHLEN)
goto toolong;
{
Extbyte *pos;
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
if (IS_DRIVE (p[0]) && IS_DEVICE_SEP (p[1])
&& IS_DIRECTORY_SEP (p[2]))
/* don't test c: on windows */
for (p = nm; p != endp; p++)
{
if ((p[0] == '~'
-#if defined (WIN32_NATIVE) || defined (CYGWIN)
+#if defined (WIN32_FILENAMES)
/* // at start of file name is meaningful in WindowsNT systems */
|| (IS_DIRECTORY_SEP (p[0]) && p - 1 != nm)
-#else /* not (WIN32_NATIVE || CYGWIN) */
+#else /* not (WIN32_FILENAMES) */
|| IS_DIRECTORY_SEP (p[0])
-#endif /* not (WIN32_NATIVE || CYGWIN) */
+#endif /* not (WIN32_FILENAMES) */
)
&& p != nm
&& (IS_DIRECTORY_SEP (p[-1])))
nm = p;
substituted = 1;
}
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
/* see comment in expand-file-name about drive specifiers */
else if (IS_DRIVE (p[0]) && p[1] == ':'
&& p > nm && IS_DIRECTORY_SEP (p[-1]))
nm = p;
substituted = 1;
}
-#endif /* WIN32_NATIVE */
+#endif /* WIN32_FILENAMES */
}
/* See if any variables are substituted into the string
for (p = xnm; p != x; p++)
if ((p[0] == '~'
-#if defined (WIN32_NATIVE)
+#if defined (WIN32_FILENAMES)
|| (IS_DIRECTORY_SEP (p[0]) && p - 1 != xnm)
-#else /* not WIN32_NATIVE */
+#else /* not WIN32_FILENAMES */
|| IS_DIRECTORY_SEP (p[0])
-#endif /* not WIN32_NATIVE */
+#endif /* not WIN32_FILENAMES */
)
/* don't do p[-1] if that would go off the beginning --jwz */
&& p != nm && p > xnm && IS_DIRECTORY_SEP (p[-1]))
xnm = p;
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
else if (IS_DRIVE (p[0]) && p[1] == ':'
&& p > nm && IS_DIRECTORY_SEP (p[-1]))
xnm = p;
return;
}
-/* A slightly higher-level interface than `set_file_times' */
-static int
-lisp_string_set_file_times (Lisp_Object filename,
- EMACS_TIME atime, EMACS_TIME mtime)
-{
- char *ext_filename;
- LISP_STRING_TO_EXTERNAL (filename, ext_filename, Qfile_name);
- return set_file_times (ext_filename, atime, mtime);
-}
-
DEFUN ("copy-file", Fcopy_file, 2, 4,
"fCopy file: \nFCopy %s to file: \np\nP", /*
Copy FILENAME to NEWNAME. Both args must be strings.
EMACS_TIME atime, mtime;
EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
- if (lisp_string_set_file_times (newname, atime, mtime))
+ if (set_file_times (newname, atime, mtime))
report_file_error ("I/O error", list1 (newname));
}
chmod ((const char *) XSTRING_DATA (newname),
CHECK_STRING (filename);
ptr = XSTRING_DATA (filename);
return (IS_DIRECTORY_SEP (*ptr) || *ptr == '~'
-#ifdef WIN32_NATIVE
+#ifdef WIN32_FILENAMES
|| (IS_DRIVE (*ptr) && ptr[1] == ':' && IS_DIRECTORY_SEP (ptr[2]))
#endif
) ? Qt : Qnil;
#endif /* not WIN32_NATIVE */
}
+
+
/* Return nonzero if file FILENAME exists and can be written. */
static int
check_writable (const char *filename)
{
+#if defined(WIN32_NATIVE) || defined(CYGWIN)
+#ifdef CYGWIN
+ char filename_buffer[PATH_MAX];
+#endif
+ // Since this has to work for a directory, we can't just call 'CreateFile'
+ PSECURITY_DESCRIPTOR pDesc; /* Must be freed with LocalFree */
+ /* these need not be freed, they point into pDesc */
+ PSID psidOwner;
+ PSID psidGroup;
+ PACL pDacl;
+ PACL pSacl;
+ /* end of insides of descriptor */
+ DWORD error;
+ DWORD attributes;
+ HANDLE tokenHandle;
+ GENERIC_MAPPING genericMapping;
+ DWORD accessMask;
+ PRIVILEGE_SET PrivilegeSet;
+ DWORD dwPrivSetSize = sizeof( PRIVILEGE_SET );
+ BOOL fAccessGranted = FALSE;
+ DWORD dwAccessAllowed;
+
+#ifdef CYGWIN
+ cygwin_conv_to_full_win32_path(filename, filename_buffer);
+ filename = filename_buffer;
+#endif
+
+ /* Win32 prototype lacks const. */
+ error = GetNamedSecurityInfo((LPTSTR)filename, SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION,
+ &psidOwner, &psidGroup, &pDacl, &pSacl, &pDesc);
+ if (error != ERROR_SUCCESS) { // FAT?
+ attributes = GetFileAttributes(filename);
+ return (attributes & FILE_ATTRIBUTE_DIRECTORY) || (0 == (attributes & FILE_ATTRIBUTE_READONLY));
+ }
+
+ genericMapping.GenericRead = FILE_GENERIC_READ;
+ genericMapping.GenericWrite = FILE_GENERIC_WRITE;
+ genericMapping.GenericExecute = FILE_GENERIC_EXECUTE;
+ genericMapping.GenericAll = FILE_ALL_ACCESS;
+
+ if (!ImpersonateSelf(SecurityDelegation)) {
+ return 0;
+ }
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &tokenHandle)) {
+ return 0;
+ }
+
+ accessMask = GENERIC_WRITE;
+ MapGenericMask(&accessMask, &genericMapping);
+
+ if (!AccessCheck(pDesc, tokenHandle, accessMask, &genericMapping,
+ &PrivilegeSet, // receives privileges used in check
+ &dwPrivSetSize, // size of PrivilegeSet buffer
+ &dwAccessAllowed, // receives mask of allowed access rights
+ &fAccessGranted))
+ {
+ DWORD oops = GetLastError();
+ CloseHandle(tokenHandle);
+ RevertToSelf();
+ LocalFree(pDesc);
+ return 0;
+ }
+ CloseHandle(tokenHandle);
+ RevertToSelf();
+ LocalFree(pDesc);
+ return fAccessGranted == TRUE;
+#else
#ifdef HAVE_EACCESS
return (eaccess (filename, W_OK) >= 0);
#else
but would lose for directories. */
return (access (filename, W_OK) >= 0);
#endif
+#endif
}
DEFUN ("file-exists-p", Ffile_exists_p, 1, 1, 0, /*
if (!NILP (handler))
RETURN_UNGCPRO (call2 (handler, Qfile_readable_p, abspath));
-#if defined(WIN32_NATIVE) || defined(CYGWIN)
+#if defined(WIN32_FILENAMES)
/* Under MS-DOS and Windows, open does not work for directories. */
UNGCPRO;
if (access (XSTRING_DATA (abspath), 0) == 0)
return Qt;
else
return Qnil;
-#else /* not WIN32_NATIVE */
+#else /* not WIN32_FILENAMES */
{
int desc = interruptible_open ((char *) XSTRING_DATA (abspath), O_RDONLY | OPEN_BINARY, 0);
UNGCPRO;
close (desc);
return Qt;
}
-#endif /* not WIN32_NATIVE */
+#endif /* not WIN32_FILENAMES */
}
/* Having this before file-symlink-p mysteriously caused it to be forgotten
present, both functions are identical and ignore the CODESYS argument.)
If support for Mule exists in this Emacs, the file is encoded according
to the value of CODESYS. If this is nil, no code conversion occurs.
+
+As a special kludge to support auto-saving, when START is nil START and
+END are set to the beginning and end, respectively, of the buffer,
+regardless of any restrictions. Don't use this feature. It is documented
+here because write-region handler writers need to be aware of it.
*/
(start, end, filename, append, visit, lockname, codesys))
{
return
/* !!#### need to deal with this 'escape-quoted everywhere */
Fwrite_region_internal (Qnil, Qnil, a, Qnil, Qlambda, Qnil,
-#ifdef MULE
- Qescape_quoted
+#ifdef FILE_CODING
+ current_buffer->buffer_file_coding_system
#else
Qnil
#endif
and if so, tries to avoid touching lisp objects.
The only time that Fdo_auto_save() is called while GC is in progress
- is if we're going down, as a result of an abort() or a kill signal.
+ is if we're going down, as a result of an ABORT() or a kill signal.
It's fairly important that we generate autosave files in that case!
*/