/* File IO for GNU Emacs.
Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1996,
1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <setjmp.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
-#ifndef vax11c
-#ifndef USE_CRT_DLL
-extern int errno;
-#endif
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
#endif
#include "lisp.h"
#ifdef MSDOS
#include "msdos.h"
#include <sys/param.h>
-#if __DJGPP__ >= 2
#include <fcntl.h>
#include <string.h>
#endif
-#endif
#ifdef DOS_NT
-#define CORRECT_DIR_SEPS(s) \
- do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \
- else unixtodos_filename (s); \
- } while (0)
/* On Windows, drive letters must be alphabetic - on DOS, the Netware
redirector allows the six letters between 'Z' and 'a' as well. */
#ifdef MSDOS
/* Whether or not files are auto-saved into themselves. */
Lisp_Object Vauto_save_visited_file_name;
+/* Whether or not to continue auto-saving after a large deletion. */
+Lisp_Object Vauto_save_include_big_deletions;
+
/* On NT, specifies the directory separator character, used (eg.) when
expanding file names. This can be bound to / or \. */
Lisp_Object Vdirectory_sep_char;
#endif
/* Non-zero means call move-file-to-trash in Fdelete_file or
- Fdelete_directory. */
+ Fdelete_directory_internal. */
int delete_by_moving_to_trash;
Lisp_Object Qdelete_by_moving_to_trash;
/* Lisp function for moving files to trash. */
Lisp_Object Qmove_file_to_trash;
+/* Lisp function for recursively copying directories. */
+Lisp_Object Qcopy_directory;
+
+/* Lisp function for recursively deleting directories. */
+Lisp_Object Qdelete_directory;
+
extern Lisp_Object Vuser_login_name;
#ifdef WINDOWSNT
extern int minibuffer_auto_raise;
-extern int history_delete_duplicates;
-
/* These variables describe handlers that have "already" had a chance
to handle the current operation.
int c;
str = (char *) SDATA (errstring);
- c = STRING_CHAR (str, 0);
+ c = STRING_CHAR (str);
Faset (errstring, make_number (0), make_number (DOWNCASE (c)));
}
/* Restore point, having saved it as a marker. */
-static Lisp_Object
+Lisp_Object
restore_point_unwind (location)
Lisp_Object location;
{
Lisp_Object Qcopy_file;
Lisp_Object Qmake_directory_internal;
Lisp_Object Qmake_directory;
-Lisp_Object Qdelete_directory;
+Lisp_Object Qdelete_directory_internal;
Lisp_Object Qdelete_file;
Lisp_Object Qrename_file;
Lisp_Object Qadd_name_to_file;
Lisp_Object Qfile_modes;
Lisp_Object Qset_file_modes;
Lisp_Object Qset_file_times;
+Lisp_Object Qfile_selinux_context;
+Lisp_Object Qset_file_selinux_context;
Lisp_Object Qfile_newer_than_file_p;
Lisp_Object Qinsert_file_contents;
Lisp_Object Qwrite_region;
return call2 (handler, Qfile_name_directory, filename);
filename = FILE_SYSTEM_CASE (filename);
- beg = SDATA (filename);
#ifdef DOS_NT
- beg = strcpy (alloca (strlen (beg) + 1), beg);
+ beg = (unsigned char *) alloca (SBYTES (filename) + 1);
+ bcopy (SDATA (filename), beg, SBYTES (filename) + 1);
+#else
+ beg = SDATA (filename);
#endif
p = beg + SBYTES (filename);
p = beg + strlen (beg);
}
}
- CORRECT_DIR_SEPS (beg);
+ dostounix_filename (beg);
#endif /* DOS_NT */
return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename));
/* For Unix syntax, Append a slash if necessary */
if (!IS_DIRECTORY_SEP (out[size]))
{
- /* Cannot use DIRECTORY_SEP, which could have any value */
- out[size + 1] = '/';
+ out[size + 1] = DIRECTORY_SEP;
out[size + 2] = '\0';
}
#ifdef DOS_NT
- CORRECT_DIR_SEPS (out);
+ dostounix_filename (out);
#endif
return out;
}
)
dst[slen - 1] = 0;
#ifdef DOS_NT
- CORRECT_DIR_SEPS (dst);
+ dostounix_filename (dst);
#endif
return 1;
}
STRING_MULTIBYTE (directory));
}
-static char make_temp_name_tbl[64] =
+static const char make_temp_name_tbl[64] =
{
'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
}
}
- nm = SDATA (name);
-
/* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */
- nm = strcpy (alloca (strlen (nm) + 1), nm);
+ nm = (unsigned char *) alloca (SBYTES (name) + 1);
+ bcopy (SDATA (name), nm, SBYTES (name) + 1);
#ifdef DOS_NT
/* Note if special escape prefix is present, but remove for now. */
if (!lose)
{
#ifdef DOS_NT
- /* Make sure directories are all separated with / or \ as
- desired, but avoid allocation of a new string when not
- required. */
- CORRECT_DIR_SEPS (nm);
+ /* Make sure directories are all separated with /, but
+ avoid allocation of a new string when not required. */
+ dostounix_filename (nm);
#ifdef WINDOWSNT
if (IS_DIRECTORY_SEP (nm[1]))
{
target[0] = '/';
target[1] = ':';
}
- CORRECT_DIR_SEPS (target);
+ dostounix_filename (target);
#endif /* DOS_NT */
result = make_specified_string (target, -1, o - target, multibyte);
bugs _are_ found, it might be of interest to look at the old code and
see what did it do in the relevant situation.
- Don't remove this code: it's true that it will be accessible via CVS,
- but a few years from deletion, people will forget it is there. */
+ Don't remove this code: it's true that it will be accessible
+ from the repository, but a few years from deletion, people will
+ forget it is there. */
/* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'. */
DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
unsigned char *target = NULL;
int total = 0;
int substituted = 0;
+ int multibyte;
unsigned char *xnm;
Lisp_Object handler;
CHECK_STRING (filename);
+ multibyte = STRING_MULTIBYTE (filename);
+
/* If the file name has special constructs in it,
call the corresponding file handler. */
handler = Ffind_file_name_handler (filename, Qsubstitute_in_file_name);
if (!NILP (handler))
return call2 (handler, Qsubstitute_in_file_name, filename);
- nm = SDATA (filename);
+ /* Always work on a copy of the string, in case GC happens during
+ decode of environment variables, causing the original Lisp_String
+ data to be relocated. */
+ nm = (unsigned char *) alloca (SBYTES (filename) + 1);
+ bcopy (SDATA (filename), nm, SBYTES (filename) + 1);
+
#ifdef DOS_NT
- nm = strcpy (alloca (strlen (nm) + 1), nm);
- CORRECT_DIR_SEPS (nm);
+ dostounix_filename (nm);
substituted = (strcmp (nm, SDATA (filename)) != 0);
#endif
endp = nm + SBYTES (filename);
again. Important with filenames like "/home/foo//:/hello///there"
which whould substitute to "/:/hello///there" rather than "/there". */
return Fsubstitute_in_file_name
- (make_specified_string (p, -1, endp - p,
- STRING_MULTIBYTE (filename)));
-
+ (make_specified_string (p, -1, endp - p, multibyte));
/* See if any variables are substituted into the string
and find the total length of their values in `total' */
/* Get variable value */
o = (unsigned char *) egetenv (target);
if (o)
- { /* Eight-bit chars occupy upto 2 bytes in multibyte. */
- total += strlen (o) * (STRING_MULTIBYTE (filename) ? 2 : 1);
+ {
+ /* Don't try to guess a maximum length - UTF8 can use up to
+ four bytes per character. This code is unlikely to run
+ in a situation that requires performance, so decoding the
+ env variables twice should be acceptable. Note that
+ decoding may cause a garbage collect. */
+ Lisp_Object orig, decoded;
+ orig = make_unibyte_string (o, strlen (o));
+ decoded = DECODE_FILE (orig);
+ total += SBYTES (decoded);
substituted = 1;
}
else if (*p == '}')
*x++ = '$';
strcpy (x, target); x+= strlen (target);
}
- else if (STRING_MULTIBYTE (filename))
- {
- /* If the original string is multibyte,
- convert what we substitute into multibyte. */
- while (*o)
- {
- int c = *o++;
- c = unibyte_char_to_multibyte (c);
- x += CHAR_STRING (c, x);
- }
- }
else
{
- strcpy (x, o);
- x += strlen (o);
+ Lisp_Object orig, decoded;
+ int orig_length, decoded_length;
+ orig_length = strlen (o);
+ orig = make_unibyte_string (o, orig_length);
+ decoded = DECODE_FILE (orig);
+ decoded_length = SBYTES (decoded);
+ strncpy (x, SDATA (decoded), decoded_length);
+ x += decoded_length;
+
+ /* If environment variable needed decoding, return value
+ needs to be multibyte. */
+ if (decoded_length != orig_length
+ || strncmp (SDATA (decoded), o, orig_length))
+ multibyte = 1;
}
}
need to quote some $ to $$ first. */
xnm = p;
- return make_specified_string (xnm, -1, x - xnm, STRING_MULTIBYTE (filename));
+ return make_specified_string (xnm, -1, x - xnm, multibyte);
badsubst:
error ("Bad format environment-variable substitution");
return;
}
-DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 5,
+DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6,
"fCopy file: \nGCopy %s to file: \np\nP",
doc: /* Copy FILE to NEWNAME. Both args must be strings.
If NEWNAME names a directory, copy FILE there.
A prefix arg makes KEEP-TIME non-nil.
If PRESERVE-UID-GID is non-nil, we try to transfer the
-uid and gid of FILE to NEWNAME. */)
- (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid)
+uid and gid of FILE to NEWNAME.
+
+If PRESERVE-SELINUX-CONTEXT is non-nil and SELinux is enabled
+on the system, we copy the SELinux context of FILE to NEWNAME. */)
+ (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid, preserve_selinux_context)
Lisp_Object file, newname, ok_if_already_exists, keep_time;
- Lisp_Object preserve_uid_gid;
+ Lisp_Object preserve_uid_gid, preserve_selinux_context;
{
int ifd, ofd, n;
char buf[16 * 1024];
int count = SPECPDL_INDEX ();
int input_file_statable_p;
Lisp_Object encoded_file, encoded_newname;
+#if HAVE_LIBSELINUX
+ security_context_t con;
+ int fail, conlength = 0;
+#endif
encoded_file = encoded_newname = Qnil;
GCPRO4 (file, newname, encoded_file, encoded_newname);
if (NILP (handler))
handler = Ffind_file_name_handler (newname, Qcopy_file);
if (!NILP (handler))
- RETURN_UNGCPRO (call6 (handler, Qcopy_file, file, newname,
- ok_if_already_exists, keep_time, preserve_uid_gid));
+ RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname,
+ ok_if_already_exists, keep_time, preserve_uid_gid,
+ preserve_selinux_context));
encoded_file = ENCODE_FILE (file);
encoded_newname = ENCODE_FILE (newname);
copyable by us. */
input_file_statable_p = (fstat (ifd, &st) >= 0);
-#if !defined (MSDOS) || __DJGPP__ > 1
+#if HAVE_LIBSELINUX
+ if (!NILP (preserve_selinux_context) && is_selinux_enabled ())
+ {
+ conlength = fgetfilecon (ifd, &con);
+ if (conlength == -1)
+ report_file_error ("Doing fgetfilecon", Fcons (file, Qnil));
+ }
+#endif
+
if (out_st.st_mode != 0
&& st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
{
report_file_error ("Input and output files are the same",
Fcons (file, Fcons (newname, Qnil)));
}
-#endif
#if defined (S_ISREG) && defined (S_ISLNK)
if (input_file_statable_p)
}
#endif /* not MSDOS */
+#if HAVE_LIBSELINUX
+ if (conlength > 0)
+ {
+ /* Set the modified context back to the file. */
+ fail = fsetfilecon (ofd, con);
+ if (fail)
+ report_file_error ("Doing fsetfilecon", Fcons (newname, Qnil));
+
+ freecon (con);
+ }
+#endif
+
/* Closing the output clobbers the file times on some systems. */
if (emacs_close (ofd) < 0)
report_file_error ("I/O error", Fcons (newname, Qnil));
emacs_close (ifd);
-#if defined (__DJGPP__) && __DJGPP__ > 1
+#ifdef MSDOS
if (input_file_statable_p)
{
/* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
if ((_djstat_flags & _STFAIL_WRITEBIT) == 0)
chmod (SDATA (encoded_newname), st.st_mode & 07777);
}
-#endif /* DJGPP version 2 or newer */
+#endif /* MSDOS */
#endif /* not WINDOWSNT */
/* Discard the unwind protects. */
return Qnil;
}
-DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
+DEFUN ("delete-directory-internal", Fdelete_directory_internal,
+ Sdelete_directory_internal, 1, 1, 0,
doc: /* Delete the directory named DIRECTORY. Does not follow symlinks. */)
(directory)
Lisp_Object directory;
CHECK_STRING (directory);
directory = Fdirectory_file_name (Fexpand_file_name (directory, Qnil));
-
- handler = Ffind_file_name_handler (directory, Qdelete_directory);
- if (!NILP (handler))
- return call2 (handler, Qdelete_directory, directory);
-
- if (delete_by_moving_to_trash)
- return call1 (Qmove_file_to_trash, directory);
-
encoded_dir = ENCODE_FILE (directory);
-
dir = SDATA (encoded_dir);
if (rmdir (dir) != 0)
return Qnil;
}
-DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
+DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 2,
+ "(list (read-file-name \
+ (if (and delete-by-moving-to-trash (null current-prefix-arg)) \
+ \"Move file to trash: \" \"Delete file: \") \
+ nil default-directory (confirm-nonexistent-file-or-buffer)) \
+ (null current-prefix-arg))",
doc: /* Delete file named FILENAME. If it is a symlink, remove the symlink.
-If file has multiple names, it continues to exist with the other names. */)
- (filename)
+If file has multiple names, it continues to exist with the other names.
+TRASH non-nil means to trash the file instead of deleting, provided
+`delete-by-moving-to-trash' is non-nil.
+
+When called interactively, TRASH is t if no prefix argument is given.
+With a prefix argument, TRASH is nil. */)
+ (filename, trash)
Lisp_Object filename;
+ Lisp_Object trash;
{
Lisp_Object handler;
Lisp_Object encoded_file;
handler = Ffind_file_name_handler (filename, Qdelete_file);
if (!NILP (handler))
- return call2 (handler, Qdelete_file, filename);
+ return call3 (handler, Qdelete_file, filename, trash);
- if (delete_by_moving_to_trash)
+ if (delete_by_moving_to_trash && !NILP (trash))
return call1 (Qmove_file_to_trash, filename);
encoded_file = ENCODE_FILE (filename);
return Qt;
}
-/* Delete file FILENAME, returning 1 if successful and 0 if failed. */
+/* Delete file FILENAME, returning 1 if successful and 0 if failed.
+ This ignores `delete-by-moving-to-trash'. */
int
-internal_delete_file (filename)
- Lisp_Object filename;
+internal_delete_file (Lisp_Object filename)
{
Lisp_Object tem;
- tem = internal_condition_case_1 (Fdelete_file, filename,
+
+ tem = internal_condition_case_2 (Fdelete_file, filename, Qnil,
Qt, internal_delete_file_1);
return NILP (tem);
}
&& (NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname))))
#endif
)
- newname = Fexpand_file_name (Ffile_name_nondirectory (file), newname);
+ {
+ Lisp_Object fname = NILP (Ffile_directory_p (file))
+ ? file : Fdirectory_file_name (file);
+ newname = Fexpand_file_name (Ffile_name_nondirectory (fname), newname);
+ }
else
newname = Fexpand_file_name (newname, Qnil);
NILP (ok_if_already_exists) ? Qnil : Qt);
else
#endif
+ if (!NILP (Ffile_directory_p (file)))
+ call4 (Qcopy_directory, file, newname, Qt, Qnil);
+ else
+ /* We have already prompted if it was an integer, so don't
+ have copy-file prompt again. */
Fcopy_file (file, newname,
- /* We have already prompted if it was an integer,
- so don't have copy-file prompt again. */
NILP (ok_if_already_exists) ? Qnil : Qt,
- Qt, Qt);
+ Qt, Qt, Qt);
count = SPECPDL_INDEX ();
specbind (Qdelete_by_moving_to_trash, Qnil);
- Fdelete_file (file);
+
+ if (!NILP (Ffile_directory_p (file))
+#ifdef S_IFLNK
+ && NILP (symlink_target)
+#endif
+ )
+ call2 (Qdelete_directory, file, Qt);
+ else
+ Fdelete_file (file, Qnil);
unbind_to (count, Qnil);
}
else
struct stat st;
if (stat (filename, &st) < 0)
return 0;
-#if defined (WINDOWSNT) || (defined (MSDOS) && __DJGPP__ > 1)
return ((st.st_mode & S_IEXEC) != 0);
-#else
- return (S_ISREG (st.st_mode)
- && len >= 5
- && (xstrcasecmp ((suffix = filename + len-4), ".com") == 0
- || xstrcasecmp (suffix, ".exe") == 0
- || xstrcasecmp (suffix, ".bat") == 0)
- || (st.st_mode & S_IFMT) == S_IFDIR);
-#endif /* not WINDOWSNT */
#else /* not DOS_NT */
#ifdef HAVE_EUIDACCESS
return (euidaccess (filename, 1) >= 0);
#endif
}
\f
+DEFUN ("file-selinux-context", Ffile_selinux_context,
+ Sfile_selinux_context, 1, 1, 0,
+ doc: /* Return SELinux context of file named FILENAME,
+as a list ("user", "role", "type", "range"). Return (nil, nil, nil, nil)
+if file does not exist, is not accessible, or SELinux is disabled */)
+ (filename)
+ Lisp_Object filename;
+{
+ Lisp_Object absname;
+ Lisp_Object values[4];
+ Lisp_Object handler;
+#if HAVE_LIBSELINUX
+ security_context_t con;
+ int conlength;
+ context_t context;
+#endif
+
+ absname = expand_and_dir_to_file (filename, current_buffer->directory);
+
+ /* If the file name has special constructs in it,
+ call the corresponding file handler. */
+ handler = Ffind_file_name_handler (absname, Qfile_selinux_context);
+ if (!NILP (handler))
+ return call2 (handler, Qfile_selinux_context, absname);
+
+ absname = ENCODE_FILE (absname);
+
+ values[0] = Qnil;
+ values[1] = Qnil;
+ values[2] = Qnil;
+ values[3] = Qnil;
+#if HAVE_LIBSELINUX
+ if (is_selinux_enabled ())
+ {
+ conlength = lgetfilecon (SDATA (absname), &con);
+ if (conlength > 0)
+ {
+ context = context_new (con);
+ if (context_user_get (context))
+ values[0] = build_string (context_user_get (context));
+ if (context_role_get (context))
+ values[1] = build_string (context_role_get (context));
+ if (context_type_get (context))
+ values[2] = build_string (context_type_get (context));
+ if (context_range_get (context))
+ values[3] = build_string (context_range_get (context));
+ context_free (context);
+ }
+ if (con)
+ freecon (con);
+ }
+#endif
+
+ return Flist (sizeof(values) / sizeof(values[0]), values);
+}
+\f
+DEFUN ("set-file-selinux-context", Fset_file_selinux_context,
+ Sset_file_selinux_context, 2, 2, 0,
+ doc: /* Set SELinux context of file named FILENAME to CONTEXT
+as a list ("user", "role", "type", "range"). Has no effect if SELinux
+is disabled. */)
+ (filename, context)
+ Lisp_Object filename, context;
+{
+ Lisp_Object absname, encoded_absname;
+ Lisp_Object handler;
+ Lisp_Object user = CAR_SAFE (context);
+ Lisp_Object role = CAR_SAFE (CDR_SAFE (context));
+ Lisp_Object type = CAR_SAFE (CDR_SAFE (CDR_SAFE (context)));
+ Lisp_Object range = CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (context))));
+#if HAVE_LIBSELINUX
+ security_context_t con;
+ int fail, conlength;
+ context_t parsed_con;
+#endif
+
+ absname = Fexpand_file_name (filename, current_buffer->directory);
+
+ /* If the file name has special constructs in it,
+ call the corresponding file handler. */
+ handler = Ffind_file_name_handler (absname, Qset_file_selinux_context);
+ if (!NILP (handler))
+ return call3 (handler, Qset_file_selinux_context, absname, context);
+
+ encoded_absname = ENCODE_FILE (absname);
+
+#if HAVE_LIBSELINUX
+ if (is_selinux_enabled ())
+ {
+ /* Get current file context. */
+ conlength = lgetfilecon (SDATA (encoded_absname), &con);
+ if (conlength > 0)
+ {
+ parsed_con = context_new (con);
+ /* Change the parts defined in the parameter.*/
+ if (STRINGP (user))
+ {
+ if (context_user_set (parsed_con, SDATA (user)))
+ error ("Doing context_user_set");
+ }
+ if (STRINGP (role))
+ {
+ if (context_role_set (parsed_con, SDATA (role)))
+ error ("Doing context_role_set");
+ }
+ if (STRINGP (type))
+ {
+ if (context_type_set (parsed_con, SDATA (type)))
+ error ("Doing context_type_set");
+ }
+ if (STRINGP (range))
+ {
+ if (context_range_set (parsed_con, SDATA (range)))
+ error ("Doing context_range_set");
+ }
+
+ /* Set the modified context back to the file. */
+ fail = lsetfilecon (SDATA (encoded_absname), context_str (parsed_con));
+ if (fail)
+ report_file_error ("Doing lsetfilecon", Fcons (absname, Qnil));
+
+ context_free (parsed_con);
+ }
+ else
+ report_file_error("Doing lgetfilecon", Fcons (absname, Qnil));
+
+ if (con)
+ freecon (con);
+ }
+#endif
+
+ return Qnil;
+}
+\f
DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
doc: /* Return mode bits of file named FILENAME, as an integer.
Return nil, if file does not exist or is not accessible. */)
if (stat (SDATA (absname), &st) < 0)
return Qnil;
-#if defined (MSDOS) && __DJGPP__ < 2
- if (check_executable (SDATA (absname)))
- st.st_mode |= S_IEXEC;
-#endif /* MSDOS && __DJGPP__ < 2 */
return make_number (st.st_mode & 07777);
}
#define READ_BUF_SIZE (64 << 10)
#endif
-extern void adjust_markers_for_delete P_ ((int, int, int, int));
-
/* This function is called after Lisp functions to decide a coding
system are called, or when they cause an error. Before they are
called, the current buffer is set unibyte and it contains only a
/* Used to pass values from insert-file-contents to read_non_regular. */
static int non_regular_fd;
-static int non_regular_inserted;
-static int non_regular_nbytes;
+static EMACS_INT non_regular_inserted;
+static EMACS_INT non_regular_nbytes;
/* Read from a non-regular file.
static Lisp_Object
read_non_regular ()
{
- int nbytes;
+ EMACS_INT nbytes;
immediate_quit = 1;
QUIT;
{
struct stat st;
register int fd;
- int inserted = 0;
+ EMACS_INT inserted = 0;
int nochange = 0;
- register int how_much;
- register int unprocessed;
+ register EMACS_INT how_much;
+ register EMACS_INT unprocessed;
int count = SPECPDL_INDEX ();
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
Lisp_Object handler, val, insval, orig_filename, old_undo;
Lisp_Object p;
- int total = 0;
+ EMACS_INT total = 0;
int not_regular = 0;
unsigned char read_buf[READ_BUF_SIZE];
struct coding_system coding;
overflow. The calculations below double the file size
twice, so check that it can be multiplied by 4 safely. */
if (XINT (end) != st.st_size
- || st.st_size > INT_MAX / 4)
+ /* Actually, it should test either INT_MAX or LONG_MAX
+ depending on which one is used for EMACS_INT. But in
+ any case, in practice, this test is redundant with the
+ one above.
+ || st.st_size > INT_MAX / 4 */)
error ("Maximum buffer size exceeded");
/* The file size returned from stat may be zero, but data
We assume that the 1K-byte and 3K-byte for heading
and tailing respectively are sufficient for this
purpose. */
- int nread;
+ EMACS_INT nread;
if (st.st_size <= (1024 * 4))
nread = emacs_read (fd, read_buf, 1024 * 4);
/* same_at_start and same_at_end count bytes,
because file access counts bytes
and BEG and END count bytes. */
- int same_at_start = BEGV_BYTE;
- int same_at_end = ZV_BYTE;
- int overlap;
+ EMACS_INT same_at_start = BEGV_BYTE;
+ EMACS_INT same_at_end = ZV_BYTE;
+ EMACS_INT overlap;
/* There is still a possibility we will find the need to do code
conversion. If that happens, we set this variable to 1 to
give up on handling REPLACE in the optimized way. */
match the text at the beginning of the buffer. */
while (1)
{
- int nread, bufpos;
+ EMACS_INT nread, bufpos;
nread = emacs_read (fd, buffer, sizeof buffer);
if (nread < 0)
already found that decoding is necessary, don't waste time. */
while (!giveup_match_end)
{
- int total_read, nread, bufpos, curpos, trial;
+ EMACS_INT total_read, nread, bufpos, curpos, trial;
/* At what file position are we now scanning? */
curpos = XINT (end) - (ZV_BYTE - same_at_end);
if (! giveup_match_end)
{
- int temp;
+ EMACS_INT temp;
/* We win! We can handle REPLACE the optimized way. */
EMACS_INT overlap;
EMACS_INT bufpos;
unsigned char *decoded;
- int temp;
+ EMACS_INT temp;
int this_count = SPECPDL_INDEX ();
int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
Lisp_Object conversion_buffer;
/* We read one bunch by one (READ_BUF_SIZE bytes) to allow
quitting while reading a huge while. */
/* try is reserved in some compilers (Microsoft C) */
- int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed);
- int this;
+ EMACS_INT trytry = min (total - how_much,
+ READ_BUF_SIZE - unprocessed);
+ EMACS_INT this;
/* Allow quitting out of the actual I/O. */
immediate_quit = 1;
}
coding_system = CODING_ID_NAME (coding.id);
+ set_coding_system = 1;
decoded = BUF_BEG_ADDR (XBUFFER (conversion_buffer));
inserted = (BUF_Z_BYTE (XBUFFER (conversion_buffer))
- BUF_BEG_BYTE (XBUFFER (conversion_buffer)));
/* 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. */
{
- int gap_size = GAP_SIZE;
+ EMACS_INT gap_size = GAP_SIZE;
while (how_much < total)
{
/* try is reserved in some compilers (Microsoft C) */
- int trytry = min (total - how_much, READ_BUF_SIZE);
- int this;
+ EMACS_INT trytry = min (total - how_much, READ_BUF_SIZE);
+ EMACS_INT this;
if (not_regular)
{
if (NILP (handler))
{
current_buffer->modtime = st.st_mtime;
+ current_buffer->modtime_size = st.st_size;
current_buffer->filename = orig_filename;
}
SAVE_MODIFF = MODIFF;
- current_buffer->auto_save_modified = MODIFF;
+ BUF_AUTOSAVE_MODIFF (current_buffer) = MODIFF;
XSETFASTINT (current_buffer->save_length, Z - BEG);
#ifdef CLASH_DETECTION
if (NILP (handler))
{
/* Don't run point motion or modification hooks when decoding. */
int count = SPECPDL_INDEX ();
- int old_inserted = inserted;
+ EMACS_INT old_inserted = inserted;
specbind (Qinhibit_point_motion_hooks, Qt);
specbind (Qinhibit_modification_hooks, Qt);
Hence we temporarily save `point' and `inserted' here and
restore `point' iff format-decode did not insert or delete
any text. Otherwise we leave `point' at point-min. */
- int opoint = PT;
- int opoint_byte = PT_BYTE;
- int oinserted = ZV - BEGV;
+ EMACS_INT opoint = PT;
+ EMACS_INT opoint_byte = PT_BYTE;
+ EMACS_INT oinserted = ZV - BEGV;
int ochars_modiff = CHARS_MODIFF;
TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
{
/* For the rationale of this see the comment on
format-decode above. */
- int opoint = PT;
- int opoint_byte = PT_BYTE;
- int oinserted = ZV - BEGV;
+ EMACS_INT opoint = PT;
+ EMACS_INT opoint_byte = PT_BYTE;
+ EMACS_INT oinserted = ZV - BEGV;
int ochars_modiff = CHARS_MODIFF;
TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
to avoid a "file has changed on disk" warning on
next attempt to save. */
if (visiting)
- current_buffer->modtime = st.st_mtime;
+ {
+ current_buffer->modtime = st.st_mtime;
+ current_buffer->modtime_size = st.st_size;
+ }
if (failure)
error ("IO error writing %s: %s", SDATA (filename),
else
st.st_mtime = 0;
}
- if (st.st_mtime == b->modtime
- /* If both are positive, accept them if they are off by one second. */
- || (st.st_mtime > 0 && b->modtime > 0
- && (st.st_mtime == b->modtime + 1
- || st.st_mtime == b->modtime - 1)))
+ if ((st.st_mtime == b->modtime
+ /* If both are positive, accept them if they are off by one second. */
+ || (st.st_mtime > 0 && b->modtime > 0
+ && (st.st_mtime == b->modtime + 1
+ || st.st_mtime == b->modtime - 1)))
+ && (st.st_size == b->modtime_size
+ || b->modtime_size < 0))
return Qt;
return Qnil;
}
()
{
current_buffer->modtime = 0;
+ current_buffer->modtime_size = -1;
return Qnil;
}
Lisp_Object time_list;
{
if (!NILP (time_list))
- current_buffer->modtime = cons_to_long (time_list);
+ {
+ current_buffer->modtime = cons_to_long (time_list);
+ current_buffer->modtime_size = -1;
+ }
else
{
register Lisp_Object filename;
filename = ENCODE_FILE (filename);
if (stat (SDATA (filename), &st) >= 0)
- current_buffer->modtime = st.st_mtime;
+ {
+ current_buffer->modtime = st.st_mtime;
+ current_buffer->modtime_size = st.st_size;
+ }
}
return Qnil;
and file changed since last real save. */
if (STRINGP (b->auto_save_file_name)
&& BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)
- && b->auto_save_modified < BUF_MODIFF (b)
+ && BUF_AUTOSAVE_MODIFF (b) < BUF_MODIFF (b)
/* -1 means we've turned off autosaving for a while--see below. */
&& XINT (b->save_length) >= 0
&& (do_handled_files
&& EMACS_SECS (before_time) - b->auto_save_failure_time < 1200)
continue;
- if ((XFASTINT (b->save_length) * 10
- > (BUF_Z (b) - BUF_BEG (b)) * 13)
+ set_buffer_internal (b);
+ if (NILP (Vauto_save_include_big_deletions)
+ && (XFASTINT (b->save_length) * 10
+ > (BUF_Z (b) - BUF_BEG (b)) * 13)
/* A short file is likely to change a large fraction;
spare the user annoying messages. */
&& XFASTINT (b->save_length) > 5000
Fsleep_for (make_number (1), Qnil);
continue;
}
- set_buffer_internal (b);
if (!auto_saved && NILP (no_message))
message1 ("Auto-saving...");
internal_condition_case (auto_save_1, Qt, auto_save_error);
auto_saved++;
- b->auto_save_modified = BUF_MODIFF (b);
+ BUF_AUTOSAVE_MODIFF (b) = BUF_MODIFF (b);
XSETFASTINT (current_buffer->save_length, Z - BEG);
set_buffer_internal (old);
No auto-save file will be written until the buffer changes again. */)
()
{
- current_buffer->auto_save_modified = MODIFF;
+ /* FIXME: This should not be called in indirect buffers, since
+ they're not autosaved. */
+ BUF_AUTOSAVE_MODIFF (current_buffer) = MODIFF;
XSETFASTINT (current_buffer->save_length, Z - BEG);
current_buffer->auto_save_failure_time = -1;
return Qnil;
then any auto-save counts as "recent". */)
()
{
- return (SAVE_MODIFF < current_buffer->auto_save_modified) ? Qt : Qnil;
+ /* FIXME: maybe we should return nil for indirect buffers since
+ they're never autosaved. */
+ return (SAVE_MODIFF < BUF_AUTOSAVE_MODIFF (current_buffer) ? Qt : Qnil);
}
\f
/* Reading and completing file names */
}
\f
-void
-init_fileio_once ()
-{
- /* Must be set before any path manipulation is performed. */
- XSETFASTINT (Vdirectory_sep_char, '/');
-}
-
-\f
void
syms_of_fileio ()
{
- Qoperations = intern ("operations");
- Qexpand_file_name = intern ("expand-file-name");
- Qsubstitute_in_file_name = intern ("substitute-in-file-name");
- Qdirectory_file_name = intern ("directory-file-name");
- Qfile_name_directory = intern ("file-name-directory");
- Qfile_name_nondirectory = intern ("file-name-nondirectory");
- Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
- Qfile_name_as_directory = intern ("file-name-as-directory");
- Qcopy_file = intern ("copy-file");
- Qmake_directory_internal = intern ("make-directory-internal");
- Qmake_directory = intern ("make-directory");
- Qdelete_directory = intern ("delete-directory");
- Qdelete_file = intern ("delete-file");
- Qrename_file = intern ("rename-file");
- Qadd_name_to_file = intern ("add-name-to-file");
- Qmake_symbolic_link = intern ("make-symbolic-link");
- Qfile_exists_p = intern ("file-exists-p");
- Qfile_executable_p = intern ("file-executable-p");
- Qfile_readable_p = intern ("file-readable-p");
- Qfile_writable_p = intern ("file-writable-p");
- Qfile_symlink_p = intern ("file-symlink-p");
- Qaccess_file = intern ("access-file");
- Qfile_directory_p = intern ("file-directory-p");
- Qfile_regular_p = intern ("file-regular-p");
- Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
- Qfile_modes = intern ("file-modes");
- Qset_file_modes = intern ("set-file-modes");
- Qset_file_times = intern ("set-file-times");
- Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
- Qinsert_file_contents = intern ("insert-file-contents");
- Qwrite_region = intern ("write-region");
- Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
- Qset_visited_file_modtime = intern ("set-visited-file-modtime");
- Qauto_save_coding = intern ("auto-save-coding");
+ Qoperations = intern_c_string ("operations");
+ Qexpand_file_name = intern_c_string ("expand-file-name");
+ Qsubstitute_in_file_name = intern_c_string ("substitute-in-file-name");
+ Qdirectory_file_name = intern_c_string ("directory-file-name");
+ Qfile_name_directory = intern_c_string ("file-name-directory");
+ Qfile_name_nondirectory = intern_c_string ("file-name-nondirectory");
+ Qunhandled_file_name_directory = intern_c_string ("unhandled-file-name-directory");
+ Qfile_name_as_directory = intern_c_string ("file-name-as-directory");
+ Qcopy_file = intern_c_string ("copy-file");
+ Qmake_directory_internal = intern_c_string ("make-directory-internal");
+ Qmake_directory = intern_c_string ("make-directory");
+ Qdelete_directory_internal = intern_c_string ("delete-directory-internal");
+ Qdelete_file = intern_c_string ("delete-file");
+ Qrename_file = intern_c_string ("rename-file");
+ Qadd_name_to_file = intern_c_string ("add-name-to-file");
+ Qmake_symbolic_link = intern_c_string ("make-symbolic-link");
+ Qfile_exists_p = intern_c_string ("file-exists-p");
+ Qfile_executable_p = intern_c_string ("file-executable-p");
+ Qfile_readable_p = intern_c_string ("file-readable-p");
+ Qfile_writable_p = intern_c_string ("file-writable-p");
+ Qfile_symlink_p = intern_c_string ("file-symlink-p");
+ Qaccess_file = intern_c_string ("access-file");
+ Qfile_directory_p = intern_c_string ("file-directory-p");
+ Qfile_regular_p = intern_c_string ("file-regular-p");
+ Qfile_accessible_directory_p = intern_c_string ("file-accessible-directory-p");
+ Qfile_modes = intern_c_string ("file-modes");
+ Qset_file_modes = intern_c_string ("set-file-modes");
+ Qset_file_times = intern_c_string ("set-file-times");
+ Qfile_selinux_context = intern_c_string("file-selinux-context");
+ Qset_file_selinux_context = intern_c_string("set-file-selinux-context");
+ Qfile_newer_than_file_p = intern_c_string ("file-newer-than-file-p");
+ Qinsert_file_contents = intern_c_string ("insert-file-contents");
+ Qwrite_region = intern_c_string ("write-region");
+ Qverify_visited_file_modtime = intern_c_string ("verify-visited-file-modtime");
+ Qset_visited_file_modtime = intern_c_string ("set-visited-file-modtime");
+ Qauto_save_coding = intern_c_string ("auto-save-coding");
staticpro (&Qoperations);
staticpro (&Qexpand_file_name);
staticpro (&Qcopy_file);
staticpro (&Qmake_directory_internal);
staticpro (&Qmake_directory);
- staticpro (&Qdelete_directory);
+ staticpro (&Qdelete_directory_internal);
staticpro (&Qdelete_file);
staticpro (&Qrename_file);
staticpro (&Qadd_name_to_file);
staticpro (&Qfile_modes);
staticpro (&Qset_file_modes);
staticpro (&Qset_file_times);
+ staticpro (&Qfile_selinux_context);
+ staticpro (&Qset_file_selinux_context);
staticpro (&Qfile_newer_than_file_p);
staticpro (&Qinsert_file_contents);
staticpro (&Qwrite_region);
staticpro (&Qset_visited_file_modtime);
staticpro (&Qauto_save_coding);
- Qfile_name_history = intern ("file-name-history");
+ Qfile_name_history = intern_c_string ("file-name-history");
Fset (Qfile_name_history, Qnil);
staticpro (&Qfile_name_history);
- Qfile_error = intern ("file-error");
+ Qfile_error = intern_c_string ("file-error");
staticpro (&Qfile_error);
- Qfile_already_exists = intern ("file-already-exists");
+ Qfile_already_exists = intern_c_string ("file-already-exists");
staticpro (&Qfile_already_exists);
- Qfile_date_error = intern ("file-date-error");
+ Qfile_date_error = intern_c_string ("file-date-error");
staticpro (&Qfile_date_error);
- Qexcl = intern ("excl");
+ Qexcl = intern_c_string ("excl");
staticpro (&Qexcl);
#ifdef DOS_NT
- Qfind_buffer_file_type = intern ("find-buffer-file-type");
+ Qfind_buffer_file_type = intern_c_string ("find-buffer-file-type");
staticpro (&Qfind_buffer_file_type);
#endif /* DOS_NT */
of file names regardless of the current language environment. */);
Vdefault_file_name_coding_system = Qnil;
- Qformat_decode = intern ("format-decode");
+ Qformat_decode = intern_c_string ("format-decode");
staticpro (&Qformat_decode);
- Qformat_annotate_function = intern ("format-annotate-function");
+ Qformat_annotate_function = intern_c_string ("format-annotate-function");
staticpro (&Qformat_annotate_function);
- Qafter_insert_file_set_coding = intern ("after-insert-file-set-coding");
+ Qafter_insert_file_set_coding = intern_c_string ("after-insert-file-set-coding");
staticpro (&Qafter_insert_file_set_coding);
- Qcar_less_than_car = intern ("car-less-than-car");
+ Qcar_less_than_car = intern_c_string ("car-less-than-car");
staticpro (&Qcar_less_than_car);
Fput (Qfile_error, Qerror_conditions,
- list2 (Qfile_error, Qerror));
+ Fpurecopy (list2 (Qfile_error, Qerror)));
Fput (Qfile_error, Qerror_message,
- build_string ("File error"));
+ make_pure_c_string ("File error"));
Fput (Qfile_already_exists, Qerror_conditions,
- list3 (Qfile_already_exists, Qfile_error, Qerror));
+ Fpurecopy (list3 (Qfile_already_exists, Qfile_error, Qerror)));
Fput (Qfile_already_exists, Qerror_message,
- build_string ("File already exists"));
+ make_pure_c_string ("File already exists"));
Fput (Qfile_date_error, Qerror_conditions,
- list3 (Qfile_date_error, Qfile_error, Qerror));
+ Fpurecopy (list3 (Qfile_date_error, Qfile_error, Qerror)));
Fput (Qfile_date_error, Qerror_message,
- build_string ("Cannot set file date"));
-
- DEFVAR_LISP ("directory-sep-char", &Vdirectory_sep_char,
- doc: /* Directory separator character for built-in functions that return file names.
-The value is always ?/. Don't use this variable, just use `/'. */);
+ make_pure_c_string ("Cannot set file date"));
DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
doc: /* *Alist of elements (REGEXP . HANDLER) for file names handled specially.
Vwrite_region_annotate_functions = Qnil;
staticpro (&Qwrite_region_annotate_functions);
Qwrite_region_annotate_functions
- = intern ("write-region-annotate-functions");
+ = intern_c_string ("write-region-annotate-functions");
DEFVAR_LISP ("write-region-post-annotation-function",
&Vwrite_region_post_annotation_function,
Normally auto-save files are written under other names. */);
Vauto_save_visited_file_name = Qnil;
+ DEFVAR_LISP ("auto-save-include-big-deletions", &Vauto_save_include_big_deletions,
+ doc: /* If non-nil, auto-save even if a large part of the text is deleted.
+If nil, deleting a substantial portion of the text disables auto-save
+in the buffer; this is the default behavior, because the auto-save
+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'.
DEFVAR_BOOL ("delete-by-moving-to-trash", &delete_by_moving_to_trash,
doc: /* Specifies whether to use the system's trash can.
-When non-nil, the function `move-file-to-trash' will be used by
-`delete-file' and `delete-directory'. */);
+When non-nil, certain file deletion commands use the function
+`move-file-to-trash' instead of deleting files outright.
+This includes interactive calls to `delete-file' and
+`delete-directory' and the Dired deletion commands. */);
delete_by_moving_to_trash = 0;
- Qdelete_by_moving_to_trash = intern ("delete-by-moving-to-trash");
- Qmove_file_to_trash = intern ("move-file-to-trash");
+ Qdelete_by_moving_to_trash = intern_c_string ("delete-by-moving-to-trash");
+ Qmove_file_to_trash = intern_c_string ("move-file-to-trash");
staticpro (&Qmove_file_to_trash);
+ Qcopy_directory = intern_c_string ("copy-directory");
+ staticpro (&Qcopy_directory);
+ Qdelete_directory = intern_c_string ("delete-directory");
+ staticpro (&Qdelete_directory);
defsubr (&Sfind_file_name_handler);
defsubr (&Sfile_name_directory);
defsubr (&Ssubstitute_in_file_name);
defsubr (&Scopy_file);
defsubr (&Smake_directory_internal);
- defsubr (&Sdelete_directory);
+ defsubr (&Sdelete_directory_internal);
defsubr (&Sdelete_file);
defsubr (&Srename_file);
defsubr (&Sadd_name_to_file);
defsubr (&Sfile_modes);
defsubr (&Sset_file_modes);
defsubr (&Sset_file_times);
+ defsubr (&Sfile_selinux_context);
+ defsubr (&Sset_file_selinux_context);
defsubr (&Sset_default_file_modes);
defsubr (&Sdefault_file_modes);
defsubr (&Sfile_newer_than_file_p);