X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/67fbc0cb3ae4c523798c4dde7867e5c637cea2ff..72af86bd8cf1812d1fcc8924c4093d692040a664:/src/fileio.c diff --git a/src/fileio.c b/src/fileio.c index 9651ac8e18..ee2dc9fa52 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -1,7 +1,7 @@ /* 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. @@ -28,6 +28,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #ifdef HAVE_UNISTD_H #include @@ -52,10 +53,9 @@ along with GNU Emacs. If not, see . */ #include #include -#ifndef vax11c -#ifndef USE_CRT_DLL -extern int errno; -#endif +#ifdef HAVE_LIBSELINUX +#include +#include #endif #include "lisp.h" @@ -78,17 +78,11 @@ extern int errno; #ifdef MSDOS #include "msdos.h" #include -#if __DJGPP__ >= 2 #include #include #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 @@ -193,6 +187,9 @@ Lisp_Object Vauto_save_list_file_name; /* 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; @@ -203,7 +200,7 @@ int write_region_inhibit_fsync; #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; @@ -211,6 +208,12 @@ 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 @@ -221,8 +224,6 @@ extern int minibuf_level; 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. @@ -239,15 +240,13 @@ Lisp_Object Qfile_name_history; Lisp_Object Qcar_less_than_car; -static int a_write P_ ((int, Lisp_Object, int, int, - Lisp_Object *, struct coding_system *)); -static int e_write P_ ((int, Lisp_Object, int, int, struct coding_system *)); +static int a_write (int, Lisp_Object, int, int, + Lisp_Object *, struct coding_system *); +static int e_write (int, Lisp_Object, int, int, struct coding_system *); void -report_file_error (string, data) - const char *string; - Lisp_Object data; +report_file_error (const char *string, Lisp_Object data) { Lisp_Object errstring; int errorno = errno; @@ -275,7 +274,7 @@ report_file_error (string, data) int c; str = (char *) SDATA (errstring); - c = STRING_CHAR (str, 0); + c = STRING_CHAR (str); Faset (errstring, make_number (0), make_number (DOWNCASE (c))); } @@ -285,8 +284,7 @@ report_file_error (string, data) } Lisp_Object -close_file_unwind (fd) - Lisp_Object fd; +close_file_unwind (Lisp_Object fd) { emacs_close (XFASTINT (fd)); return Qnil; @@ -294,9 +292,8 @@ close_file_unwind (fd) /* Restore point, having saved it as a marker. */ -static Lisp_Object -restore_point_unwind (location) - Lisp_Object location; +Lisp_Object +restore_point_unwind (Lisp_Object location) { Fgoto_char (location); Fset_marker (location, Qnil, Qnil); @@ -314,7 +311,7 @@ Lisp_Object Qfile_name_as_directory; 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; @@ -331,6 +328,8 @@ Lisp_Object Qfile_accessible_directory_p; 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; @@ -424,9 +423,11 @@ Given a Unix syntax file name, returns a string ending in slash. */) 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); + memcpy (beg, SDATA (filename), SBYTES (filename) + 1); +#else + beg = SDATA (filename); #endif p = beg + SBYTES (filename); @@ -465,7 +466,7 @@ Given a Unix syntax file name, returns a string ending in slash. */) 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)); @@ -534,8 +535,7 @@ get a current directory to run processes in. */) char * -file_name_as_directory (out, in) - char *out, *in; +file_name_as_directory (char *out, char *in) { int size = strlen (in) - 1; @@ -552,12 +552,11 @@ file_name_as_directory (out, in) /* 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; } @@ -600,8 +599,7 @@ For a Unix-syntax file name, just appends a slash. */) */ int -directory_file_name (src, dst) - char *src, *dst; +directory_file_name (char *src, char *dst) { long slen; @@ -618,7 +616,7 @@ directory_file_name (src, dst) ) dst[slen - 1] = 0; #ifdef DOS_NT - CORRECT_DIR_SEPS (dst); + dostounix_filename (dst); #endif return 1; } @@ -653,7 +651,7 @@ In Unix-syntax, this function just removes the final slash. */) 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', @@ -684,9 +682,7 @@ static unsigned make_temp_name_count, make_temp_name_count_initialized_p; generated. */ Lisp_Object -make_temp_name (prefix, base64_p) - Lisp_Object prefix; - int base64_p; +make_temp_name (Lisp_Object prefix, int base64_p) { Lisp_Object val; int len, clen; @@ -729,10 +725,10 @@ make_temp_name (prefix, base64_p) if (!STRING_MULTIBYTE (prefix)) STRING_SET_UNIBYTE (val); data = SDATA (val); - bcopy(SDATA (prefix), data, len); + memcpy (data, SDATA (prefix), len); p = data + len; - bcopy (pidbuf, p, pidlen); + memcpy (p, pidbuf, pidlen); p += pidlen; /* Here we try to minimize useless stat'ing when this function is @@ -941,10 +937,9 @@ filesystem tree, not (expand-file-name ".." dirname). */) } } - 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); + memcpy (nm, SDATA (name), SBYTES (name) + 1); #ifdef DOS_NT /* Note if special escape prefix is present, but remove for now. */ @@ -1024,10 +1019,9 @@ filesystem tree, not (expand-file-name ".." dirname). */) 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])) { @@ -1099,7 +1093,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) unsigned char *o, *p; for (p = nm; *p && (!IS_DIRECTORY_SEP (*p)); p++); o = alloca (p - nm + 1); - bcopy ((char *) nm, o, p - nm); + memcpy (o, nm, p - nm); o [p - nm] = 0; BLOCK_INPUT; @@ -1250,7 +1244,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) ) { unsigned char *temp = (unsigned char *) alloca (length); - bcopy (newdir, temp, length - 1); + memcpy (temp, newdir, length - 1); temp[length - 1] = 0; newdir = temp; } @@ -1373,7 +1367,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) target[0] = '/'; target[1] = ':'; } - CORRECT_DIR_SEPS (target); + dostounix_filename (target); #endif /* DOS_NT */ result = make_specified_string (target, -1, o - target, multibyte); @@ -1399,8 +1393,9 @@ filesystem tree, not (expand-file-name ".." dirname). */) 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, @@ -1472,7 +1467,7 @@ See also the function `substitute-in-file-name'.") int len = ptr ? ptr - user : strlen (user); /* Copy the user name into temp storage. */ o = (unsigned char *) alloca (len + 1); - bcopy ((char *) user, o, len); + memcpy (o, user, len); o[len] = 0; /* Look up the user name. */ @@ -1555,8 +1550,7 @@ See also the function `substitute-in-file-name'.") /* If /~ or // appears, discard everything through first slash. */ static int -file_name_absolute_p (filename) - const unsigned char *filename; +file_name_absolute_p (const unsigned char *filename) { return (IS_DIRECTORY_SEP (*filename) || *filename == '~' @@ -1568,8 +1562,7 @@ file_name_absolute_p (filename) } static unsigned char * -search_embedded_absfilename (nm, endp) - unsigned char *nm, *endp; +search_embedded_absfilename (unsigned char *nm, unsigned char *endp) { unsigned char *p, *s; @@ -1590,7 +1583,7 @@ search_embedded_absfilename (nm, endp) { unsigned char *o = alloca (s - p + 1); struct passwd *pw; - bcopy (p, o, s - p); + memcpy (o, p, s - p); o [s - p] = 0; /* If we have ~user and `user' exists, discard @@ -1616,7 +1609,10 @@ DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name, the value of that variable. The variable name should be terminated with a character not a letter, digit or underscore; otherwise, enclose the entire variable name in braces. -If `/~' appears, all of FILENAME through that `/' is discarded. */) + +If `/~' appears, all of FILENAME through that `/' is discarded. +If `//' appears, everything up to and including the first of +those `/' is discarded. */) (filename) Lisp_Object filename; { @@ -1626,21 +1622,28 @@ If `/~' appears, all of FILENAME through that `/' is discarded. */) 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); + memcpy (nm, SDATA (filename), 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); @@ -1652,9 +1655,7 @@ If `/~' appears, all of FILENAME through that `/' is discarded. */) 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' */ @@ -1700,8 +1701,16 @@ If `/~' appears, all of FILENAME through that `/' is discarded. */) /* 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 == '}') @@ -1759,21 +1768,22 @@ If `/~' appears, all of FILENAME through that `/' is discarded. */) *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; } } @@ -1786,7 +1796,7 @@ If `/~' appears, all of FILENAME through that `/' is discarded. */) 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"); @@ -1803,8 +1813,7 @@ If `/~' appears, all of FILENAME through that `/' is discarded. */) (directory-file-name (expand-file-name FOO)). */ Lisp_Object -expand_and_dir_to_file (filename, defdir) - Lisp_Object filename, defdir; +expand_and_dir_to_file (Lisp_Object filename, Lisp_Object defdir) { register Lisp_Object absname; @@ -1833,12 +1842,7 @@ expand_and_dir_to_file (filename, defdir) If QUICK is nonzero, we ask for y or n, not yes or no. */ void -barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick) - Lisp_Object absname; - unsigned char *querystring; - int interactive; - struct stat *statptr; - int quick; +barf_or_query_if_file_exists (Lisp_Object absname, unsigned char *querystring, int interactive, struct stat *statptr, int quick) { register Lisp_Object tem, encoded_filename; struct stat statbuf; @@ -1875,7 +1879,7 @@ barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick) 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. @@ -1897,10 +1901,13 @@ last-modified time as the old one. (This works on only some systems.) 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]; @@ -1910,6 +1917,10 @@ uid and gid of FILE to NEWNAME. */) 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); @@ -1930,8 +1941,9 @@ uid and gid of FILE to 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); @@ -1985,7 +1997,15 @@ uid and gid of FILE to 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) { @@ -1993,7 +2013,6 @@ uid and gid of FILE to NEWNAME. */) 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) @@ -2044,6 +2063,18 @@ uid and gid of FILE to NEWNAME. */) } #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)); @@ -2064,7 +2095,7 @@ uid and gid of FILE to NEWNAME. */) 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, @@ -2074,7 +2105,7 @@ uid and gid of FILE to NEWNAME. */) 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. */ @@ -2115,7 +2146,8 @@ DEFUN ("make-directory-internal", Fmake_directory_internal, 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; @@ -2126,16 +2158,7 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete 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) @@ -2144,11 +2167,22 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete 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; @@ -2165,9 +2199,9 @@ If file has multiple names, it continues to exist with the other names. */) 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); @@ -2178,20 +2212,20 @@ If file has multiple names, it continues to exist with the other names. */) } static Lisp_Object -internal_delete_file_1 (ignore) - Lisp_Object ignore; +internal_delete_file_1 (Lisp_Object ignore) { 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); } @@ -2224,7 +2258,11 @@ This is what happens in interactive use with M-x. */) && (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); @@ -2262,15 +2300,26 @@ This is what happens in interactive use with M-x. */) 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 @@ -2429,8 +2478,7 @@ On Unix, this is a name starting with a `/' or a `~'. */) /* Return nonzero if file FILENAME exists and can be executed. */ static int -check_executable (filename) - char *filename; +check_executable (char *filename) { #ifdef DOS_NT int len = strlen (filename); @@ -2438,16 +2486,7 @@ check_executable (filename) 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); @@ -2463,8 +2502,7 @@ check_executable (filename) /* Return nonzero if file FILENAME exists and can be written. */ static int -check_writable (filename) - char *filename; +check_writable (char *filename) { #ifdef MSDOS struct stat st; @@ -2695,7 +2733,7 @@ points to a nonexistent file. */) { bufsize *= 2; buf = (char *) xrealloc (buf, bufsize); - bzero (buf, bufsize); + memset (buf, 0, bufsize); errno = 0; valsize = readlink (SDATA (filename), buf, bufsize); @@ -2824,6 +2862,140 @@ See `file-symlink-p' to distinguish symlinks. */) #endif } +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); +} + +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; +} + 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. */) @@ -2846,10 +3018,6 @@ 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); } @@ -2914,7 +3082,7 @@ The value is an integer. */) return value; } -extern int lisp_time_argument P_ ((Lisp_Object, time_t *, int *)); +extern int lisp_time_argument (Lisp_Object, time_t *, int *); DEFUN ("set-file-times", Fset_file_times, Sset_file_times, 1, 2, 0, doc: /* Set times of file FILENAME to TIME. @@ -3032,8 +3200,6 @@ Lisp_Object Qfind_buffer_file_type; #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 @@ -3050,8 +3216,7 @@ extern void adjust_markers_for_delete P_ ((int, int, int, int)); o set back the buffer multibyteness. */ static Lisp_Object -decide_coding_unwind (unwind_data) - Lisp_Object unwind_data; +decide_coding_unwind (Lisp_Object unwind_data) { Lisp_Object multibyte, undo_list, buffer; @@ -3078,19 +3243,19 @@ decide_coding_unwind (unwind_data) /* 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. - Read non_regular_trytry bytes max from non_regular_fd. + Read non_regular_nbytes bytes max from non_regular_fd. Non_regular_inserted specifies where to put the read bytes. Value is the number of bytes read. */ static Lisp_Object -read_non_regular () +read_non_regular (Lisp_Object ignore) { - int nbytes; + EMACS_INT nbytes; immediate_quit = 1; QUIT; @@ -3106,7 +3271,7 @@ read_non_regular () in insert-file-contents. */ static Lisp_Object -read_non_regular_quit () +read_non_regular_quit (Lisp_Object ignore) { return Qnil; } @@ -3140,15 +3305,15 @@ variable `last-coding-system-used' to the coding system actually used. */) { 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; @@ -3284,7 +3449,11 @@ variable `last-coding-system-used' to the coding system actually used. */) 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 @@ -3320,7 +3489,7 @@ variable `last-coding-system-used' to the coding system actually used. */) 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); @@ -3430,9 +3599,9 @@ variable `last-coding-system-used' to the coding system actually used. */) /* 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. */ @@ -3451,7 +3620,7 @@ variable `last-coding-system-used' to the coding system actually used. */) 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) @@ -3502,7 +3671,7 @@ variable `last-coding-system-used' to the coding system actually used. */) 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); @@ -3558,7 +3727,7 @@ variable `last-coding-system-used' to the coding system actually used. */) if (! giveup_match_end) { - int temp; + EMACS_INT temp; /* We win! We can handle REPLACE the optimized way. */ @@ -3618,7 +3787,7 @@ variable `last-coding-system-used' to the coding system actually used. */) 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; @@ -3643,8 +3812,9 @@ variable `last-coding-system-used' to the coding system actually used. */) /* 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; @@ -3667,7 +3837,7 @@ variable `last-coding-system-used' to the coding system actually used. */) conversion_buffer); unprocessed = coding.carryover_bytes; if (coding.carryover_bytes > 0) - bcopy (coding.carryover, read_buf, unprocessed); + memcpy (read_buf, coding.carryover, unprocessed); } UNGCPRO; emacs_close (fd); @@ -3693,6 +3863,7 @@ variable `last-coding-system-used' to the coding system actually used. */) } 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))); @@ -3847,13 +4018,13 @@ variable `last-coding-system-used' to the coding system actually used. */) /* 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) { @@ -4072,11 +4243,12 @@ variable `last-coding-system-used' to the coding system actually used. */) 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)) @@ -4110,7 +4282,7 @@ variable `last-coding-system-used' to the coding system actually used. */) { /* 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); @@ -4136,9 +4308,9 @@ variable `last-coding-system-used' to the coding system actually used. */) 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); @@ -4174,9 +4346,9 @@ variable `last-coding-system-used' to the coding system actually used. */) { /* 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); @@ -4253,11 +4425,10 @@ variable `last-coding-system-used' to the coding system actually used. */) RETURN_UNGCPRO (unbind_to (count, val)); } -static Lisp_Object build_annotations P_ ((Lisp_Object, Lisp_Object)); +static Lisp_Object build_annotations (Lisp_Object, Lisp_Object); static Lisp_Object -build_annotations_unwind (arg) - Lisp_Object arg; +build_annotations_unwind (Lisp_Object arg) { Vwrite_region_annotation_buffers = arg; return Qnil; @@ -4266,10 +4437,9 @@ build_annotations_unwind (arg) /* Decide the coding-system to encode the data with. */ static Lisp_Object -choose_write_coding_system (start, end, filename, - append, visit, lockname, coding) - Lisp_Object start, end, filename, append, visit, lockname; - struct coding_system *coding; +choose_write_coding_system (Lisp_Object start, Lisp_Object end, Lisp_Object filename, + Lisp_Object append, Lisp_Object visit, Lisp_Object lockname, + struct coding_system *coding) { Lisp_Object val; Lisp_Object eol_parent = Qnil; @@ -4406,7 +4576,10 @@ The optional seventh arg MUSTBENEW, if non-nil, insists on a check This does code conversion according to the value of `coding-system-for-write', `buffer-file-coding-system', or `file-coding-system-alist', and sets the variable -`last-coding-system-used' to the coding system actually used. */) +`last-coding-system-used' to the coding system actually used. + +This calls `write-region-annotate-functions' at the start, and +`write-region-post-annotation-function' at the end. */) (start, end, filename, append, visit, lockname, mustbenew) Lisp_Object start, end, filename, append, visit, lockname, mustbenew; { @@ -4648,7 +4821,7 @@ This does code conversion according to the value of specpdl_ptr = specpdl + count1; /* Call write-region-post-annotation-function. */ - while (!NILP (Vwrite_region_annotation_buffers)) + while (CONSP (Vwrite_region_annotation_buffers)) { Lisp_Object buf = XCAR (Vwrite_region_annotation_buffers); if (!NILP (Fbuffer_live_p (buf))) @@ -4672,7 +4845,10 @@ This does code conversion according to the value of 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), @@ -4706,7 +4882,7 @@ This does code conversion according to the value of return Qnil; } -Lisp_Object merge (); +Lisp_Object merge (Lisp_Object, Lisp_Object, Lisp_Object); DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0, doc: /* Return t if (car A) is numerically less than (car B). */) @@ -4725,8 +4901,7 @@ DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0, as save-excursion would do. */ static Lisp_Object -build_annotations (start, end) - Lisp_Object start, end; +build_annotations (Lisp_Object start, Lisp_Object end) { Lisp_Object annotations; Lisp_Object p, res; @@ -4815,13 +4990,7 @@ build_annotations (start, end) The return value is negative in case of system call failure. */ static int -a_write (desc, string, pos, nchars, annot, coding) - int desc; - Lisp_Object string; - register int nchars; - int pos; - Lisp_Object *annot; - struct coding_system *coding; +a_write (int desc, Lisp_Object string, int pos, register int nchars, Lisp_Object *annot, struct coding_system *coding) { Lisp_Object tem; int nextpos; @@ -4865,11 +5034,7 @@ a_write (desc, string, pos, nchars, annot, coding) are indexes to the string STRING. */ static int -e_write (desc, string, start, end, coding) - int desc; - Lisp_Object string; - int start, end; - struct coding_system *coding; +e_write (int desc, Lisp_Object string, int start, int end, struct coding_system *coding) { if (STRINGP (string)) { @@ -4981,11 +5146,13 @@ See Info node `(elisp)Modification Time' for more details. */) 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; } @@ -4997,6 +5164,7 @@ Next attempt to save will certainly not complain of a discrepancy. */) () { current_buffer->modtime = 0; + current_buffer->modtime_size = -1; return Qnil; } @@ -5026,7 +5194,10 @@ An argument specifies the modification time value to use 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; @@ -5045,15 +5216,17 @@ An argument specifies the modification time value to use 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; } Lisp_Object -auto_save_error (error) - Lisp_Object error; +auto_save_error (Lisp_Object error) { Lisp_Object args[3], msg; int i, nbytes; @@ -5072,7 +5245,7 @@ auto_save_error (error) GCPRO1 (msg); nbytes = SBYTES (msg); SAFE_ALLOCA (msgbuf, char *, nbytes); - bcopy (SDATA (msg), msgbuf, nbytes); + memcpy (msgbuf, SDATA (msg), nbytes); for (i = 0; i < 3; ++i) { @@ -5089,7 +5262,7 @@ auto_save_error (error) } Lisp_Object -auto_save_1 () +auto_save_1 (void) { struct stat st; Lisp_Object modes; @@ -5115,8 +5288,8 @@ auto_save_1 () } static Lisp_Object -do_auto_save_unwind (arg) /* used as unwind-protect function */ - Lisp_Object arg; +do_auto_save_unwind (Lisp_Object arg) /* used as unwind-protect function */ + { FILE *stream = (FILE *) XSAVE_VALUE (arg)->pointer; auto_saving = 0; @@ -5130,16 +5303,15 @@ do_auto_save_unwind (arg) /* used as unwind-protect function */ } static Lisp_Object -do_auto_save_unwind_1 (value) /* used as unwind-protect function */ - Lisp_Object value; +do_auto_save_unwind_1 (Lisp_Object value) /* used as unwind-protect function */ + { minibuffer_auto_raise = XINT (value); return Qnil; } static Lisp_Object -do_auto_save_make_dir (dir) - Lisp_Object dir; +do_auto_save_make_dir (Lisp_Object dir) { Lisp_Object mode; @@ -5149,8 +5321,7 @@ do_auto_save_make_dir (dir) } static Lisp_Object -do_auto_save_eh (ignore) - Lisp_Object ignore; +do_auto_save_eh (Lisp_Object ignore) { return Qnil; } @@ -5283,7 +5454,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) 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 @@ -5299,8 +5470,10 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) && 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 @@ -5319,12 +5492,11 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) 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); @@ -5369,7 +5541,9 @@ DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved, 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; @@ -5392,7 +5566,9 @@ in the visited file. If the buffer has no visited file, 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); } /* Reading and completing file names */ @@ -5401,7 +5577,7 @@ DEFUN ("next-read-file-uses-dialog-p", Fnext_read_file_uses_dialog_p, Snext_read_file_uses_dialog_p, 0, 0, 0, doc: /* Return t if a call to `read-file-name' will use a dialog. The return value is only relevant for a call to `read-file-name' that happens -before any other event (mouse or keypress) is handeled. */) +before any other event (mouse or keypress) is handled. */) () { #if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK) @@ -5415,8 +5591,7 @@ before any other event (mouse or keypress) is handeled. */) } Lisp_Object -Fread_file_name (prompt, dir, default_filename, mustmatch, initial, predicate) - Lisp_Object prompt, dir, default_filename, mustmatch, initial, predicate; +Fread_file_name (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object initial, Lisp_Object predicate) { struct gcpro gcpro1, gcpro2; Lisp_Object args[7]; @@ -5434,50 +5609,44 @@ Fread_file_name (prompt, dir, default_filename, mustmatch, initial, predicate) void -init_fileio_once () +syms_of_fileio (void) { - /* Must be set before any path manipulation is performed. */ - XSETFASTINT (Vdirectory_sep_char, '/'); -} - - -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); @@ -5490,7 +5659,7 @@ syms_of_fileio () 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); @@ -5507,6 +5676,8 @@ syms_of_fileio () 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); @@ -5514,21 +5685,21 @@ syms_of_fileio () 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 */ @@ -5548,34 +5719,30 @@ instead use `file-name-coding-system' to get a constant encoding 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. @@ -5641,7 +5808,7 @@ buffer current. */); 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, @@ -5682,6 +5849,13 @@ a non-nil value. */); 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'. @@ -5692,12 +5866,18 @@ A non-nil value may result in data loss! */); 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); @@ -5710,7 +5890,7 @@ When non-nil, the function `move-file-to-trash' will be used by 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); @@ -5728,6 +5908,8 @@ When non-nil, the function `move-file-to-trash' will be used by 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);