/* 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, 2010 Free Software Foundation, Inc.
+
+Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009, 2010 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <config.h>
#include <limits.h>
-
-#ifdef HAVE_FCNTL_H
#include <fcntl.h>
-#endif
-
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.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 WINDOWSNT
#define NOMINMAX 1
#include <windows.h>
-#include <stdlib.h>
#include <fcntl.h>
#endif /* not WINDOWSNT */
#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
#endif
#include "commands.h"
-extern int use_dialog_box;
-extern int use_file_dialog;
-
-#ifndef O_WRONLY
-#define O_WRONLY 1
-#endif
-
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
#ifndef S_ISLNK
# define lstat stat
/* 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;
-
#ifdef HAVE_FSYNC
/* Nonzero means skip the call to fsync in Fwrite-region. */
int write_region_inhibit_fsync;
/* Lisp function for recursively deleting directories. */
Lisp_Object Qdelete_directory;
-extern Lisp_Object Vuser_login_name;
-
#ifdef WINDOWSNT
extern Lisp_Object Vw32_get_true_file_attributes;
#endif
-extern int minibuf_level;
-
-extern int minibuffer_auto_raise;
-
/* These variables describe handlers that have "already" had a chance
to handle the current operation.
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 *);
\f
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;
}
Lisp_Object
-close_file_unwind (fd)
- Lisp_Object fd;
+close_file_unwind (Lisp_Object fd)
{
emacs_close (XFASTINT (fd));
return Qnil;
/* Restore point, having saved it as a marker. */
Lisp_Object
-restore_point_unwind (location)
- Lisp_Object location;
+restore_point_unwind (Lisp_Object location)
{
Fgoto_char (location);
Fset_marker (location, Qnil, Qnil);
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;
any handlers that are members of `inhibit-file-name-handlers',
but we still do run any other handlers. This lets handlers
use the standard functions without calling themselves recursively. */)
- (filename, operation)
- Lisp_Object filename, operation;
+ (Lisp_Object filename, Lisp_Object operation)
{
/* This function must not munge the match data. */
Lisp_Object chain, inhibited_handlers, result;
Return nil if FILENAME does not include a directory.
Otherwise return a directory name.
Given a Unix syntax file name, returns a string ending in slash. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
#ifndef DOS_NT
register const unsigned char *beg;
filename = FILE_SYSTEM_CASE (filename);
#ifdef DOS_NT
beg = (unsigned char *) alloca (SBYTES (filename) + 1);
- bcopy (SDATA (filename), beg, SBYTES (filename) + 1);
+ memcpy (beg, SDATA (filename), SBYTES (filename) + 1);
#else
beg = SDATA (filename);
#endif
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 example, in a Unix-syntax file name,
this is everything after the last slash,
or the entire name if it contains no slash. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
register const unsigned char *beg, *p, *end;
Lisp_Object handler;
then this should return nil.
The `call-process' and `start-process' functions use this function to
get a current directory to run processes in. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
Lisp_Object handler;
\f
char *
-file_name_as_directory (out, in)
- char *out, *in;
+file_name_as_directory (char *out, char *in)
{
int size = strlen (in) - 1;
/* 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;
}
The result can be used as the value of `default-directory'
or passed as second argument to `expand-file-name'.
For a Unix-syntax file name, just appends a slash. */)
- (file)
- Lisp_Object file;
+ (Lisp_Object file)
{
char *buf;
Lisp_Object handler;
*/
int
-directory_file_name (src, dst)
- char *src, *dst;
+directory_file_name (char *src, char *dst)
{
long slen;
)
dst[slen - 1] = 0;
#ifdef DOS_NT
- CORRECT_DIR_SEPS (dst);
+ dostounix_filename (dst);
#endif
return 1;
}
This operation exists because a directory is also a file, but its name as
a directory is different from its name as a file.
In Unix-syntax, this function just removes the final slash. */)
- (directory)
- Lisp_Object directory;
+ (Lisp_Object directory)
{
char *buf;
Lisp_Object handler;
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;
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
* If you are creating the file in the user's home directory.
* If you are creating a directory rather than an ordinary file.
* If you are taking special precautions as `make-temp-file' does. */)
- (prefix)
- Lisp_Object prefix;
+ (Lisp_Object prefix)
{
return make_temp_name (prefix, 0);
}
\(expand-file-name ".." "/") returns "/..". For this reason, use
\(directory-file-name (file-name-directory dirname)) to traverse a
filesystem tree, not (expand-file-name ".." dirname). */)
- (name, default_directory)
- Lisp_Object name, default_directory;
+ (Lisp_Object name, Lisp_Object default_directory)
{
/* These point to SDATA and need to be careful with string-relocation
during GC (via DECODE_FILE). */
To avoid this, we set default_directory to the root of the
current drive. */
- extern char *emacs_root_dir (void);
-
default_directory = build_string (emacs_root_dir ());
#else
default_directory = build_string ("/");
/* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */
nm = (unsigned char *) alloca (SBYTES (name) + 1);
- bcopy (SDATA (name), nm, SBYTES (name) + 1);
+ memcpy (nm, SDATA (name), 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]))
{
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;
)
{
unsigned char *temp = (unsigned char *) alloca (length);
- bcopy (newdir, temp, length - 1);
+ memcpy (temp, newdir, length - 1);
temp[length - 1] = 0;
newdir = temp;
}
target[0] = '/';
target[1] = ':';
}
- CORRECT_DIR_SEPS (target);
+ dostounix_filename (target);
#endif /* DOS_NT */
result = make_specified_string (target, -1, o - target, multibyte);
/* Get past ~ to user */
unsigned char *user = nm + 1;
/* Find end of name. */
- unsigned char *ptr = (unsigned char *) index (user, '/');
+ unsigned char *ptr = (unsigned char *) strchr (user, '/');
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. */
\f
/* 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 == '~'
}
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;
{
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
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;
+ (Lisp_Object filename)
{
unsigned char *nm;
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);
+ memcpy (nm, SDATA (filename), SBYTES (filename) + 1);
#ifdef DOS_NT
- CORRECT_DIR_SEPS (nm);
+ dostounix_filename (nm);
substituted = (strcmp (nm, SDATA (filename)) != 0);
#endif
endp = nm + SBYTES (filename);
(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;
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, const unsigned char *querystring, int interactive, struct stat *statptr, int quick)
{
register Lisp_Object tem, encoded_filename;
struct stat statbuf;
tem = format2 ("File %s already exists; %s anyway? ",
absname, build_string (querystring));
if (quick)
- tem = Fy_or_n_p (tem);
+ tem = call1 (intern ("y-or-n-p"), tem);
else
tem = do_yes_or_no_p (tem);
UNGCPRO;
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)
- Lisp_Object file, newname, ok_if_already_exists, keep_time;
- Lisp_Object 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. */)
+ (Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists, Lisp_Object keep_time, Lisp_Object preserve_uid_gid, Lisp_Object 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. */
DEFUN ("make-directory-internal", Fmake_directory_internal,
Smake_directory_internal, 1, 1, 0,
doc: /* Create a new directory named DIRECTORY. */)
- (directory)
- Lisp_Object directory;
+ (Lisp_Object directory)
{
const unsigned char *dir;
Lisp_Object handler;
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;
+ (Lisp_Object directory)
{
const unsigned char *dir;
Lisp_Object handler;
CHECK_STRING (directory);
directory = Fdirectory_file_name (Fexpand_file_name (directory, Qnil));
-
- 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)
- Lisp_Object 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. */)
+ (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);
}
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);
}
unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.
A number as third arg means request confirmation if NEWNAME already exists.
This is what happens in interactive use with M-x. */)
- (file, newname, ok_if_already_exists)
- Lisp_Object file, newname, ok_if_already_exists;
+ (Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists)
{
Lisp_Object handler;
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
have copy-file prompt again. */
Fcopy_file (file, newname,
NILP (ok_if_already_exists) ? Qnil : Qt,
- Qt, Qt);
+ Qt, Qt, Qt);
count = SPECPDL_INDEX ();
specbind (Qdelete_by_moving_to_trash, Qnil);
)
call2 (Qdelete_directory, file, Qt);
else
- Fdelete_file (file);
+ Fdelete_file (file, Qnil);
unbind_to (count, Qnil);
}
else
unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.
A number as third arg means request confirmation if NEWNAME already exists.
This is what happens in interactive use with M-x. */)
- (file, newname, ok_if_already_exists)
- Lisp_Object file, newname, ok_if_already_exists;
+ (Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists)
{
Lisp_Object handler;
Lisp_Object encoded_file, encoded_newname;
unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.
A number as third arg means request confirmation if LINKNAME already exists.
This happens for interactive use with M-x. */)
- (filename, linkname, ok_if_already_exists)
- Lisp_Object filename, linkname, ok_if_already_exists;
+ (Lisp_Object filename, Lisp_Object linkname, Lisp_Object ok_if_already_exists)
{
Lisp_Object handler;
Lisp_Object encoded_filename, encoded_linkname;
1, 1, 0,
doc: /* Return t if file FILENAME specifies an absolute file name.
On Unix, this is a name starting with a `/' or a `~'. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
CHECK_STRING (filename);
return file_name_absolute_p (SDATA (filename)) ? Qt : Qnil;
/* 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);
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);
/* Return nonzero if file FILENAME exists and can be written. */
static int
-check_writable (filename)
- char *filename;
+check_writable (const char *filename)
{
#ifdef MSDOS
struct stat st;
See also `file-readable-p' and `file-attributes'.
This returns nil for a symlink to a nonexistent file.
Use `file-symlink-p' to test for such links. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
Lisp_Object absname;
Lisp_Object handler;
DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
doc: /* Return t if FILENAME can be executed by you.
For a directory, this means you can access files in that directory. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
Lisp_Object absname;
Lisp_Object handler;
DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
doc: /* Return t if file FILENAME exists and you can read it.
See also `file-exists-p' and `file-attributes'. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
Lisp_Object absname;
Lisp_Object handler;
on the RT/PC. */
DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
doc: /* Return t if file FILENAME can be written or created by you. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
Lisp_Object absname, dir, encoded;
Lisp_Object handler;
doc: /* Access file FILENAME, and get an error if that does not work.
The second argument STRING is used in the error message.
If there is no error, returns nil. */)
- (filename, string)
- Lisp_Object filename, string;
+ (Lisp_Object filename, Lisp_Object string)
{
Lisp_Object handler, encoded_filename, absname;
int fd;
This function returns t when given the name of a symlink that
points to a nonexistent file. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
Lisp_Object handler;
{
bufsize *= 2;
buf = (char *) xrealloc (buf, bufsize);
- bzero (buf, bufsize);
+ memset (buf, 0, bufsize);
errno = 0;
valsize = readlink (SDATA (filename), buf, bufsize);
while (valsize >= bufsize);
val = make_string (buf, valsize);
- if (buf[0] == '/' && index (buf, ':'))
+ if (buf[0] == '/' && strchr (buf, ':'))
val = concat2 (build_string ("/:"), val);
xfree (buf);
val = DECODE_FILE (val);
doc: /* Return t if FILENAME names an existing directory.
Symbolic links to directories count as directories.
See `file-symlink-p' to distinguish symlinks. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
register Lisp_Object absname;
struct stat st;
A directory name spec may be given instead; then the value is t
if the directory so specified exists and really is a readable and
searchable directory. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
Lisp_Object handler;
int tem;
This is the sort of file that holds an ordinary stream of data bytes.
Symbolic links to regular files count as regular files.
See `file-symlink-p' to distinguish symlinks. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
register Lisp_Object absname;
struct stat st;
#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 */)
+ (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. */)
+ (Lisp_Object filename, Lisp_Object 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. */)
- (filename)
- Lisp_Object filename;
+ (Lisp_Object filename)
{
Lisp_Object absname;
struct stat st;
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);
}
Interactively, mode bits are read by `read-file-modes', which accepts
symbolic notation, like the `chmod' command from GNU Coreutils. */)
- (filename, mode)
- Lisp_Object filename, mode;
+ (Lisp_Object filename, Lisp_Object mode)
{
Lisp_Object absname, encoded_absname;
Lisp_Object handler;
doc: /* Set the file permission bits for newly created files.
The argument MODE should be an integer; only the low 9 bits are used.
This setting is inherited by subprocesses. */)
- (mode)
- Lisp_Object mode;
+ (Lisp_Object mode)
{
CHECK_NUMBER (mode);
DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
doc: /* Return the default file protection for created files.
The value is an integer. */)
- ()
+ (void)
{
int realmask;
Lisp_Object value;
return value;
}
\f
-extern int lisp_time_argument P_ ((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.
Return t on success, else nil.
Use the current time if TIME is nil. TIME is in the format of
`current-time'. */)
- (filename, time)
- Lisp_Object filename, time;
+ (Lisp_Object filename, Lisp_Object time)
{
Lisp_Object absname, encoded_absname;
Lisp_Object handler;
#ifdef HAVE_SYNC
DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
doc: /* Tell Unix to finish all pending disk updates. */)
- ()
+ (void)
{
sync ();
return Qnil;
doc: /* Return t if file FILE1 is newer than file FILE2.
If FILE1 does not exist, the answer is nil;
otherwise, if FILE2 does not exist, the answer is t. */)
- (file1, file2)
- Lisp_Object file1, file2;
+ (Lisp_Object file1, Lisp_Object file2)
{
Lisp_Object absname1, absname2;
struct stat st;
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;
/* 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)
{
EMACS_INT nbytes;
in insert-file-contents. */
static Lisp_Object
-read_non_regular_quit ()
+read_non_regular_quit (Lisp_Object ignore)
{
return Qnil;
}
This function does code conversion according to the value of
`coding-system-for-read' or `file-coding-system-alist', and sets the
variable `last-coding-system-used' to the coding system actually used. */)
- (filename, visit, beg, end, replace)
- Lisp_Object filename, visit, beg, end, replace;
+ (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, Lisp_Object replace)
{
struct stat st;
register int fd;
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);
if (NILP (handler))
{
current_buffer->modtime = st.st_mtime;
+ current_buffer->modtime_size = st.st_size;
current_buffer->filename = orig_filename;
}
RETURN_UNGCPRO (unbind_to (count, val));
}
\f
-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;
/* 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;
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;
+ (Lisp_Object start, Lisp_Object end, Lisp_Object filename, Lisp_Object append, Lisp_Object visit, Lisp_Object lockname, Lisp_Object mustbenew)
{
register int desc;
int failure;
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),
return Qnil;
}
\f
-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). */)
- (a, b)
- Lisp_Object a, b;
+ (Lisp_Object a, Lisp_Object b)
{
return Flss (Fcar (a), Fcar (b));
}
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;
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;
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))
{
}
\f
DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
- Sverify_visited_file_modtime, 1, 1, 0,
+ Sverify_visited_file_modtime, 0, 1, 0,
doc: /* Return t if last mod time of BUF's visited file matches what BUF records.
This means that the file has not been changed since it was visited or saved.
+If BUF is omitted or nil, it defaults to the current buffer.
See Info node `(elisp)Modification Time' for more details. */)
- (buf)
- Lisp_Object buf;
+ (Lisp_Object buf)
{
struct buffer *b;
struct stat st;
Lisp_Object handler;
Lisp_Object filename;
- CHECK_BUFFER (buf);
- b = XBUFFER (buf);
+ if (NILP (buf))
+ b = current_buffer;
+ else
+ {
+ CHECK_BUFFER (buf);
+ b = XBUFFER (buf);
+ }
if (!STRINGP (b->filename)) return Qt;
if (b->modtime == 0) return Qt;
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;
}
Sclear_visited_file_modtime, 0, 0, 0,
doc: /* Clear out records of last mod time of visited file.
Next attempt to save will certainly not complain of a discrepancy. */)
- ()
+ (void)
{
current_buffer->modtime = 0;
+ current_buffer->modtime_size = -1;
return Qnil;
}
that `file-attributes' returns. If the current buffer has no recorded
file modification time, this function returns 0.
See Info node `(elisp)Modification Time' for more details. */)
- ()
+ (void)
{
if (! current_buffer->modtime)
return make_number (0);
An argument specifies the modification time value to use
\(instead of that of the visited file), in the form of a list
\(HIGH . LOW) or (HIGH LOW). */)
- (time_list)
- Lisp_Object time_list;
+ (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;
}
\f
Lisp_Object
-auto_save_error (error)
- Lisp_Object error;
+auto_save_error (Lisp_Object error)
{
Lisp_Object args[3], msg;
int i, nbytes;
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)
{
}
Lisp_Object
-auto_save_1 ()
+auto_save_1 (void)
{
struct stat st;
Lisp_Object modes;
}
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;
}
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;
}
static Lisp_Object
-do_auto_save_eh (ignore)
- Lisp_Object ignore;
+do_auto_save_eh (Lisp_Object ignore)
{
return Qnil;
}
A non-nil NO-MESSAGE argument means do not print any message if successful.
A non-nil CURRENT-ONLY argument means save only current buffer. */)
- (no_message, current_only)
- Lisp_Object no_message, current_only;
+ (Lisp_Object no_message, Lisp_Object current_only)
{
struct buffer *old = current_buffer, *b;
Lisp_Object tail, buf;
Sset_buffer_auto_saved, 0, 0, 0,
doc: /* Mark current buffer as auto-saved with its current text.
No auto-save file will be written until the buffer changes again. */)
- ()
+ (void)
{
/* FIXME: This should not be called in indirect buffers, since
they're not autosaved. */
DEFUN ("clear-buffer-auto-save-failure", Fclear_buffer_auto_save_failure,
Sclear_buffer_auto_save_failure, 0, 0, 0,
doc: /* Clear any record of a recent auto-save failure in the current buffer. */)
- ()
+ (void)
{
current_buffer->auto_save_failure_time = -1;
return Qnil;
More precisely, if it has been auto-saved since last read from or saved
in the visited file. If the buffer has no visited file,
then any auto-save counts as "recent". */)
- ()
+ (void)
{
/* FIXME: maybe we should return nil for indirect buffers since
they're never autosaved. */
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 handled. */)
- ()
+ (void)
{
#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK)
if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
}
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];
\f
void
-syms_of_fileio ()
+syms_of_fileio (void)
{
Qoperations = intern_c_string ("operations");
Qexpand_file_name = intern_c_string ("expand-file-name");
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");
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);
Fput (Qfile_date_error, Qerror_message,
make_pure_c_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 `/'. */);
- XSETFASTINT (Vdirectory_sep_char, '/');
-
DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
doc: /* *Alist of elements (REGEXP . HANDLER) for file names handled specially.
If a file name matches REGEXP, then all I/O on that file is done by calling
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_c_string ("delete-by-moving-to-trash");
Qmove_file_to_trash = intern_c_string ("move-file-to-trash");
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);
#endif
}
-/* arch-tag: 64ba3fd7-f844-4fb2-ba4b-427eb928786c
- (do not change this comment) */