summaryrefslogtreecommitdiff
path: root/src/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fileio.c')
-rw-r--r--src/fileio.c217
1 files changed, 101 insertions, 116 deletions
diff --git a/src/fileio.c b/src/fileio.c
index b4653017b28..4ba1c5914e8 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -396,13 +396,6 @@ Otherwise return a directory name.
Given a Unix syntax file name, returns a string ending in slash. */)
(Lisp_Object filename)
{
-#ifndef DOS_NT
- register const char *beg;
-#else
- register char *beg;
- Lisp_Object tem_fn;
-#endif
- register const char *p;
Lisp_Object handler;
CHECK_STRING (filename);
@@ -417,12 +410,8 @@ Given a Unix syntax file name, returns a string ending in slash. */)
return STRINGP (handled_name) ? handled_name : Qnil;
}
-#ifdef DOS_NT
- beg = xlispstrdupa (filename);
-#else
- beg = SSDATA (filename);
-#endif
- p = beg + SBYTES (filename);
+ char *beg = SSDATA (filename);
+ char const *p = beg + SBYTES (filename);
while (p != beg && !IS_DIRECTORY_SEP (p[-1])
#ifdef DOS_NT
@@ -438,6 +427,11 @@ Given a Unix syntax file name, returns a string ending in slash. */)
return Qnil;
#ifdef DOS_NT
/* Expansion of "c:" to drive and default directory. */
+ Lisp_Object tem_fn;
+ USE_SAFE_ALLOCA;
+ SAFE_ALLOCA_STRING (beg, filename);
+ p = beg + (p - SSDATA (filename));
+
if (p[-1] == ':')
{
/* MAXPATHLEN+1 is guaranteed to be enough space for getdefdir. */
@@ -481,6 +475,7 @@ Given a Unix syntax file name, returns a string ending in slash. */)
dostounix_filename (beg);
tem_fn = make_specified_string (beg, -1, p - beg, 0);
}
+ SAFE_FREE ();
return tem_fn;
#else /* DOS_NT */
return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename));
@@ -847,8 +842,6 @@ probably use `make-temp-file' instead, except in three circumstances:
return make_temp_name (prefix, 0);
}
-
-
DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
doc: /* Convert filename NAME to absolute, and canonicalize it.
Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative
@@ -878,7 +871,9 @@ filesystem tree, not (expand-file-name ".." dirname). */)
/* These point to SDATA and need to be careful with string-relocation
during GC (via DECODE_FILE). */
char *nm;
+ char *nmlim;
const char *newdir;
+ const char *newdirlim;
/* This should only point to alloca'd data. */
char *target;
@@ -886,10 +881,10 @@ filesystem tree, not (expand-file-name ".." dirname). */)
struct passwd *pw;
#ifdef DOS_NT
int drive = 0;
- bool collapse_newdir = 1;
+ bool collapse_newdir = true;
bool is_escaped = 0;
#endif /* DOS_NT */
- ptrdiff_t length;
+ ptrdiff_t length, nbytes;
Lisp_Object handler, result, handled_name;
bool multibyte;
Lisp_Object hdir;
@@ -989,7 +984,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
{
unsigned char *p = SDATA (name);
- while (*p && ASCII_BYTE_P (*p))
+ while (*p && ASCII_CHAR_P (*p))
p++;
if (*p == '\0')
{
@@ -1018,8 +1013,9 @@ filesystem tree, not (expand-file-name ".." dirname). */)
default_directory = Fdowncase (default_directory);
#endif
- /* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */
- nm = xlispstrdupa (name);
+ /* Make a local copy of NAME to protect it from GC in DECODE_FILE below. */
+ SAFE_ALLOCA_STRING (nm, name);
+ nmlim = nm + SBYTES (name);
#ifdef DOS_NT
/* Note if special escape prefix is present, but remove for now. */
@@ -1104,7 +1100,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
if (IS_DIRECTORY_SEP (nm[1]))
{
if (strcmp (nm, SSDATA (name)) != 0)
- name = make_specified_string (nm, -1, strlen (nm), multibyte);
+ name = make_specified_string (nm, -1, nmlim - nm, multibyte);
}
else
#endif
@@ -1115,18 +1111,19 @@ filesystem tree, not (expand-file-name ".." dirname). */)
name = make_specified_string (nm, -1, p - nm, multibyte);
temp[0] = DRIVE_LETTER (drive);
- name = concat2 (build_string (temp), name);
+ AUTO_STRING (drive_prefix, temp);
+ name = concat2 (drive_prefix, name);
}
#ifdef WINDOWSNT
if (!NILP (Vw32_downcase_file_names))
name = Fdowncase (name);
#endif
- return name;
#else /* not DOS_NT */
- if (strcmp (nm, SSDATA (name)) == 0)
- return name;
- return make_specified_string (nm, -1, strlen (nm), multibyte);
+ if (strcmp (nm, SSDATA (name)) != 0)
+ name = make_specified_string (nm, -1, nmlim - nm, multibyte);
#endif /* not DOS_NT */
+ SAFE_FREE ();
+ return name;
}
}
@@ -1146,7 +1143,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
return an absolute name, if the final prefix is not absolute we
append it to the current working directory. */
- newdir = 0;
+ newdir = newdirlim = 0;
if (nm[0] == '~') /* prefix ~ */
{
@@ -1156,7 +1153,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
Lisp_Object tem;
if (!(newdir = egetenv ("HOME")))
- newdir = "";
+ newdir = newdirlim = "";
nm++;
/* `egetenv' may return a unibyte string, which will bite us since
we expect the directory to be multibyte. */
@@ -1171,13 +1168,15 @@ filesystem tree, not (expand-file-name ".." dirname). */)
else
#endif
tem = build_string (newdir);
+ newdirlim = newdir + SBYTES (tem);
if (multibyte && !STRING_MULTIBYTE (tem))
{
hdir = DECODE_FILE (tem);
newdir = SSDATA (hdir);
+ newdirlim = newdir + SBYTES (hdir);
}
#ifdef DOS_NT
- collapse_newdir = 0;
+ collapse_newdir = false;
#endif
}
else /* ~user/filename */
@@ -1201,14 +1200,16 @@ filesystem tree, not (expand-file-name ".." dirname). */)
bite us since we expect the directory to be
multibyte. */
tem = build_string (newdir);
+ newdirlim = newdir + SBYTES (tem);
if (multibyte && !STRING_MULTIBYTE (tem))
{
hdir = DECODE_FILE (tem);
newdir = SSDATA (hdir);
+ newdirlim = newdir + SBYTES (hdir);
}
nm = p;
#ifdef DOS_NT
- collapse_newdir = 0;
+ collapse_newdir = false;
#endif
}
@@ -1234,8 +1235,11 @@ filesystem tree, not (expand-file-name ".." dirname). */)
Lisp_Object tem = build_string (adir);
tem = DECODE_FILE (tem);
+ newdirlim = adir + SBYTES (tem);
memcpy (adir, SSDATA (tem), SBYTES (tem) + 1);
}
+ else
+ newdirlim = adir + strlen (adir);
}
if (!adir)
{
@@ -1245,6 +1249,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
adir[1] = ':';
adir[2] = '/';
adir[3] = 0;
+ newdirlim = adir + 3;
}
newdir = adir;
}
@@ -1265,6 +1270,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
&& !newdir)
{
newdir = SSDATA (default_directory);
+ newdirlim = newdir + SBYTES (default_directory);
#ifdef DOS_NT
/* Note if special escape prefix is present, but remove for now. */
if (newdir[0] == '/' && newdir[1] == ':')
@@ -1309,12 +1315,15 @@ filesystem tree, not (expand-file-name ".." dirname). */)
}
if (!IS_DIRECTORY_SEP (nm[0]))
{
- ptrdiff_t newlen = strlen (newdir);
- char *tmp = alloca (newlen + file_name_as_directory_slop
- + strlen (nm) + 1);
- file_name_as_directory (tmp, newdir, newlen, multibyte);
- strcat (tmp, nm);
+ ptrdiff_t nmlen = nmlim - nm;
+ ptrdiff_t newdirlen = newdirlim - newdir;
+ char *tmp = alloca (newdirlen + file_name_as_directory_slop
+ + nmlen + 1);
+ ptrdiff_t dlen = file_name_as_directory (tmp, newdir, newdirlen,
+ multibyte);
+ memcpy (tmp + dlen, nm, nmlen + 1);
nm = tmp;
+ nmlim = nm + dlen + nmlen;
}
adir = alloca (adir_size);
if (drive)
@@ -1329,8 +1338,11 @@ filesystem tree, not (expand-file-name ".." dirname). */)
Lisp_Object tem = build_string (adir);
tem = DECODE_FILE (tem);
+ newdirlim = adir + SBYTES (tem);
memcpy (adir, SSDATA (tem), SBYTES (tem) + 1);
}
+ else
+ newdirlim = adir + strlen (adir);
newdir = adir;
}
@@ -1349,35 +1361,32 @@ filesystem tree, not (expand-file-name ".." dirname). */)
if (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1])
&& !IS_DIRECTORY_SEP (newdir[2]))
{
- char *adir = strcpy (alloca (strlen (newdir) + 1), newdir);
+ char *adir = strcpy (alloca (newdirlim - newdir + 1), newdir);
char *p = adir + 2;
while (*p && !IS_DIRECTORY_SEP (*p)) p++;
p++;
while (*p && !IS_DIRECTORY_SEP (*p)) p++;
*p = 0;
newdir = adir;
+ newdirlim = newdir + strlen (adir);
}
else
#endif
- newdir = "";
+ newdir = newdirlim = "";
}
}
#endif /* DOS_NT */
- if (newdir)
- {
- /* Ignore any slash at the end of newdir, unless newdir is
- just "/" or "//". */
- length = strlen (newdir);
- while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1])
- && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0])))
- length--;
- }
- else
- length = 0;
+ /* Ignore any slash at the end of newdir, unless newdir is
+ just "/" or "//". */
+ length = newdirlim - newdir;
+ while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1])
+ && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0])))
+ length--;
/* Now concatenate the directory and name to new space in the stack frame. */
- tlen = length + file_name_as_directory_slop + strlen (nm) + 1;
+ tlen = length + file_name_as_directory_slop + (nmlim - nm) + 1;
+ eassert (tlen > file_name_as_directory_slop + 1);
#ifdef DOS_NT
/* Reserve space for drive specifier and escape prefix, since either
or both may need to be inserted. (The Microsoft x86 compiler
@@ -1388,6 +1397,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
target = SAFE_ALLOCA (tlen);
#endif /* not DOS_NT */
*target = 0;
+ nbytes = 0;
if (newdir)
{
@@ -1405,13 +1415,14 @@ filesystem tree, not (expand-file-name ".." dirname). */)
{
memcpy (target, newdir, length);
target[length] = 0;
+ nbytes = length;
}
}
else
- file_name_as_directory (target, newdir, length, multibyte);
+ nbytes = file_name_as_directory (target, newdir, length, multibyte);
}
- strcat (target, nm);
+ memcpy (target + nbytes, nm, nmlim - nm + 1);
/* Now canonicalize by removing `//', `/.' and `/foo/..' if they
appear. */
@@ -1717,7 +1728,8 @@ search_embedded_absfilename (char *nm, char *endp)
for (s = p; *s && !IS_DIRECTORY_SEP (*s); s++);
if (p[0] == '~' && s > p + 1) /* We've got "/~something/". */
{
- char *o = alloca (s - p + 1);
+ USE_SAFE_ALLOCA;
+ char *o = SAFE_ALLOCA (s - p + 1);
struct passwd *pw;
memcpy (o, p, s - p);
o [s - p] = 0;
@@ -1728,6 +1740,7 @@ search_embedded_absfilename (char *nm, char *endp)
block_input ();
pw = getpwnam (o + 1);
unblock_input ();
+ SAFE_FREE ();
if (pw)
return p;
}
@@ -1776,7 +1789,8 @@ those `/' is discarded. */)
/* 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 = xlispstrdupa (filename);
+ USE_SAFE_ALLOCA;
+ SAFE_ALLOCA_STRING (nm, filename);
#ifdef DOS_NT
dostounix_filename (nm);
@@ -1790,8 +1804,13 @@ those `/' is discarded. */)
/* Start over with the new string, so we check the file-name-handler
again. Important with filenames like "/home/foo//:/hello///there"
which would substitute to "/:/hello///there" rather than "/there". */
- return Fsubstitute_in_file_name
- (make_specified_string (p, -1, endp - p, multibyte));
+ {
+ Lisp_Object result
+ = (Fsubstitute_in_file_name
+ (make_specified_string (p, -1, endp - p, multibyte)));
+ SAFE_FREE ();
+ return result;
+ }
/* See if any variables are substituted into the string. */
@@ -1813,6 +1832,7 @@ those `/' is discarded. */)
if (!NILP (Vw32_downcase_file_names))
filename = Fdowncase (filename);
#endif
+ SAFE_FREE ();
return filename;
}
@@ -1831,14 +1851,14 @@ those `/' is discarded. */)
{
Lisp_Object xname = make_specified_string (xnm, -1, x - xnm, multibyte);
- xname = Fdowncase (xname);
- return xname;
+ filename = Fdowncase (xname);
}
else
#endif
- return (xnm == SSDATA (filename)
- ? filename
- : make_specified_string (xnm, -1, x - xnm, multibyte));
+ if (xnm != SSDATA (filename))
+ filename = make_specified_string (xnm, -1, x - xnm, multibyte);
+ SAFE_FREE ();
+ return filename;
}
/* A slightly faster and more convenient way to get
@@ -2671,7 +2691,10 @@ emacs_readlinkat (int fd, char const *filename)
val = build_unibyte_string (buf);
if (buf[0] == '/' && strchr (buf, ':'))
- val = concat2 (build_unibyte_string ("/:"), val);
+ {
+ AUTO_STRING (slash_colon, "/:");
+ val = concat2 (slash_colon, val);
+ }
if (buf != readlink_buf)
xfree (buf);
val = DECODE_FILE (val);
@@ -2765,23 +2788,24 @@ searchable directory. */)
}
absname = ENCODE_FILE (absname);
- return file_accessible_directory_p (SSDATA (absname)) ? Qt : Qnil;
+ return file_accessible_directory_p (absname) ? Qt : Qnil;
}
/* If FILE is a searchable directory or a symlink to a
searchable directory, return true. Otherwise return
false and set errno to an error number. */
bool
-file_accessible_directory_p (char const *file)
+file_accessible_directory_p (Lisp_Object file)
{
#ifdef DOS_NT
/* There's no need to test whether FILE is searchable, as the
searchable/executable bit is invented on DOS_NT platforms. */
- return file_directory_p (file);
+ return file_directory_p (SSDATA (file));
#else
/* On POSIXish platforms, use just one system call; this avoids a
race and is typically faster. */
- ptrdiff_t len = strlen (file);
+ const char *data = SSDATA (file);
+ ptrdiff_t len = SBYTES (file);
char const *dir;
bool ok;
int saved_errno;
@@ -2793,15 +2817,15 @@ file_accessible_directory_p (char const *file)
"/" and "//" are distinct on some platforms, whereas "/", "///",
"////", etc. are all equivalent. */
if (! len)
- dir = file;
+ dir = data;
else
{
/* Just check for trailing '/' when deciding whether to append '/'.
That's simpler than testing the two special cases "/" and "//",
and it's a safe optimization here. */
char *buf = SAFE_ALLOCA (len + 3);
- memcpy (buf, file, len);
- strcpy (buf + len, &"/."[file[len - 1] == '/']);
+ memcpy (buf, data, len);
+ strcpy (buf + len, &"/."[data[len - 1] == '/']);
dir = buf;
}
@@ -2910,7 +2934,7 @@ or if SELinux is disabled, or if Emacs lacks SELinux support. */)
}
#endif
- return Flist (sizeof (values) / sizeof (values[0]), values);
+ return Flist (ARRAYELTS (values), values);
}
DEFUN ("set-file-selinux-context", Fset_file_selinux_context,
@@ -3624,13 +3648,14 @@ by calling `format-decode', which see. */)
report_file_error ("Read error", orig_filename);
else if (nread > 0)
{
+ AUTO_STRING (name, " *code-converting-work*");
struct buffer *prev = current_buffer;
Lisp_Object workbuf;
struct buffer *buf;
record_unwind_current_buffer ();
- workbuf = Fget_buffer_create (build_string (" *code-converting-work*"));
+ workbuf = Fget_buffer_create (name);
buf = XBUFFER (workbuf);
delete_all_overlays (buf);
@@ -4082,13 +4107,11 @@ by calling `format-decode', which see. */)
if (NILP (visit) && total > 0)
{
-#ifdef CLASH_DETECTION
if (!NILP (BVAR (current_buffer, file_truename))
/* Make binding buffer-file-name to nil effective. */
&& !NILP (BVAR (current_buffer, filename))
&& SAVE_MODIFF >= MODIFF)
we_locked_file = 1;
-#endif /* CLASH_DETECTION */
prepare_to_modify_buffer (PT, PT, NULL);
}
@@ -4188,10 +4211,8 @@ by calling `format-decode', which see. */)
if (inserted == 0)
{
-#ifdef CLASH_DETECTION
if (we_locked_file)
unlock_file (BVAR (current_buffer, file_truename));
-#endif
Vdeactivate_mark = old_Vdeactivate_mark;
}
else
@@ -4340,14 +4361,12 @@ by calling `format-decode', which see. */)
SAVE_MODIFF = MODIFF;
BUF_AUTOSAVE_MODIFF (current_buffer) = MODIFF;
XSETFASTINT (BVAR (current_buffer, save_length), Z - BEG);
-#ifdef CLASH_DETECTION
if (NILP (handler))
{
if (!NILP (BVAR (current_buffer, file_truename)))
unlock_file (BVAR (current_buffer, file_truename));
unlock_file (filename);
}
-#endif /* CLASH_DETECTION */
if (not_regular)
xsignal2 (Qfile_error,
build_string ("not a regular file"), orig_filename);
@@ -4806,13 +4825,11 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
= choose_write_coding_system (start, end, filename,
append, visit, lockname, &coding);
-#ifdef CLASH_DETECTION
if (open_and_close_file && !auto_saving)
{
lock_file (lockname);
file_locked = 1;
}
-#endif /* CLASH_DETECTION */
encoded_filename = ENCODE_FILE (filename);
fn = SSDATA (encoded_filename);
@@ -4834,10 +4851,8 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
if (desc < 0)
{
int open_errno = errno;
-#ifdef CLASH_DETECTION
if (file_locked)
unlock_file (lockname);
-#endif /* CLASH_DETECTION */
UNGCPRO;
report_file_errno ("Opening output file", filename, open_errno);
}
@@ -4852,10 +4867,8 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
if (ret < 0)
{
int lseek_errno = errno;
-#ifdef CLASH_DETECTION
if (file_locked)
unlock_file (lockname);
-#endif /* CLASH_DETECTION */
UNGCPRO;
report_file_errno ("Lseek error", filename, lseek_errno);
}
@@ -4998,10 +5011,8 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
unbind_to (count, Qnil);
-#ifdef CLASH_DETECTION
if (file_locked)
unlock_file (lockname);
-#endif /* CLASH_DETECTION */
/* Do this before reporting IO error
to avoid a "file has changed on disk" warning on
@@ -5306,20 +5317,12 @@ If BUF is omitted or nil, it defaults to the current buffer.
See Info node `(elisp)Modification Time' for more details. */)
(Lisp_Object buf)
{
- struct buffer *b;
+ struct buffer *b = decode_buffer (buf);
struct stat st;
Lisp_Object handler;
Lisp_Object filename;
struct timespec mtime;
- if (NILP (buf))
- b = current_buffer;
- else
- {
- CHECK_BUFFER (buf);
- b = XBUFFER (buf);
- }
-
if (!STRINGP (BVAR (b, filename))) return Qt;
if (b->modtime.tv_nsec == UNKNOWN_MODTIME_NSECS) return Qt;
@@ -5413,7 +5416,7 @@ An argument specifies the modification time value to use
static Lisp_Object
auto_save_error (Lisp_Object error_val)
{
- Lisp_Object args[3], msg;
+ Lisp_Object msg;
int i;
struct gcpro gcpro1;
@@ -5421,10 +5424,10 @@ auto_save_error (Lisp_Object error_val)
ring_bell (XFRAME (selected_frame));
- args[0] = build_string ("Auto-saving %s: %s");
- args[1] = BVAR (current_buffer, name);
- args[2] = Ferror_message_string (error_val);
- msg = Fformat (3, args);
+ AUTO_STRING (format, "Auto-saving %s: %s");
+ msg = Fformat (3, ((Lisp_Object [])
+ {format, BVAR (current_buffer, name),
+ Ferror_message_string (error_val)}));
GCPRO1 (msg);
for (i = 0; i < 3; ++i)
@@ -5767,24 +5770,6 @@ before any other event (mouse or keypress) is handled. */)
return Qnil;
}
-Lisp_Object
-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;
- Lisp_Object args[7];
-
- GCPRO1 (default_filename);
- args[0] = intern ("read-file-name");
- args[1] = prompt;
- args[2] = dir;
- args[3] = default_filename;
- args[4] = mustmatch;
- args[5] = initial;
- args[6] = predicate;
- RETURN_UNGCPRO (Ffuncall (7, args));
-}
-
-
void
init_fileio (void)
{