/* Process as Unix format: just remove any final slash.
But leave "/" unchanged; do not change it to "". */
strcpy (dst, src);
+#ifdef APOLLO
+ /* Handle // as root for apollo's. */
+ if ((slen > 2 && dst[slen - 1] == '/')
+ || (slen > 1 && dst[0] != '/' && dst[slen - 1] == '/'))
+ dst[slen - 1] = 0;
+#else
if (slen > 1
&& IS_DIRECTORY_SEP (dst[slen - 1])
- && !IS_ANY_SEP (dst[slen - 2]))
+#ifdef DOS_NT
+ && !IS_ANY_SEP (dst[slen - 2])
+#endif
+ )
dst[slen - 1] = 0;
+#endif
return 1;
}
}
#endif /* DOS_NT */
+ /* Handle // and /~ in middle of file name
+ by discarding everything through the first / of that sequence. */
+ p = nm;
+ while (*p)
+ {
+ /* Since we know the path is absolute, we can assume that each
+ element starts with a "/". */
+
+ /* "//" anywhere isn't necessarily hairy; we just start afresh
+ with the second slash. */
+ if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
+#if defined (APOLLO) || defined (WINDOWSNT)
+ /* // at start of filename is meaningful on Apollo
+ and WindowsNT systems */
+ && nm != p
+#endif /* APOLLO || WINDOWSNT */
+ )
+ nm = p + 1;
+
+ /* "~" is hairy as the start of any path element. */
+ if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~')
+ nm = p + 1;
+
+ p++;
+ }
+
/* If nm is absolute, flush ...// and detect /./ and /../.
If no /./ or /../ we can return right away. */
if (
/* Since we know the path is absolute, we can assume that each
element starts with a "/". */
- /* "//" anywhere isn't necessarily hairy; we just start afresh
- with the second slash. */
- if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
-#if defined (APOLLO) || defined (WINDOWSNT)
- /* // at start of filename is meaningful on Apollo
- and WindowsNT systems */
- && nm != p
-#endif /* APOLLO || WINDOWSNT */
- )
- nm = p + 1;
-
- /* "~" is hairy as the start of any path element. */
- if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~')
- nm = p + 1, lose = 1;
-
/* "." and ".." are hairy. */
if (IS_DIRECTORY_SEP (p[0])
&& p[1] == '.'
return abspath;
}
\f
+/* Signal an error if the file ABSNAME already exists.
+ If INTERACTIVE is nonzero, ask the user whether to proceed,
+ and bypass the error if the user says to go ahead.
+ QUERYSTRING is a name for the action that is being considered
+ to alter the file.
+ *STATPTR is used to store the stat information if the file exists.
+ If the file does not exist, STATPTR->st_mode is set to 0. */
+
void
-barf_or_query_if_file_exists (absname, querystring, interactive)
+barf_or_query_if_file_exists (absname, querystring, interactive, statptr)
Lisp_Object absname;
unsigned char *querystring;
int interactive;
+ struct stat *statptr;
{
register Lisp_Object tem;
struct stat statbuf;
Fsignal (Qfile_already_exists,
Fcons (build_string ("File already exists"),
Fcons (absname, Qnil)));
+ if (statptr)
+ *statptr = statbuf;
+ }
+ else
+ {
+ if (statptr)
+ statptr->st_mode = 0;
}
return;
}
{
int ifd, ofd, n;
char buf[16 * 1024];
- struct stat st;
+ struct stat st, out_st;
Lisp_Object handler;
struct gcpro gcpro1, gcpro2;
int count = specpdl_ptr - specpdl;
if (NILP (ok_if_already_exists)
|| INTEGERP (ok_if_already_exists))
barf_or_query_if_file_exists (newname, "copy to it",
- INTEGERP (ok_if_already_exists));
+ INTEGERP (ok_if_already_exists), &out_st);
+ else if (stat (XSTRING (newname)->data, &out_st) < 0)
+ out_st.st_mode = 0;
ifd = open (XSTRING (filename)->data, O_RDONLY);
if (ifd < 0)
copyable by us. */
input_file_statable_p = (fstat (ifd, &st) >= 0);
+#ifndef DOS_NT
+ if (out_st.st_mode != 0
+ && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
+ {
+ errno = 0;
+ report_file_error ("Input and output files are the same",
+ Fcons (filename, Fcons (newname, Qnil)));
+ }
+#endif
+
#if defined (S_ISREG) && defined (S_ISLNK)
if (input_file_statable_p)
{
/* Get a better looking error message. */
errno = EISDIR;
#endif /* EISDIR */
- report_file_error ("Non-regular file", Fcons (filename, Qnil));
+ report_file_error ("Non-regular file", Fcons (filename, Qnil));
}
}
#endif /* S_ISREG && S_ISLNK */
#endif /* not MSDOS */
#endif /* VMS */
if (ofd < 0)
- report_file_error ("Opening output file", Fcons (newname, Qnil));
+ report_file_error ("Opening output file", Fcons (newname, Qnil));
record_unwind_protect (close_file_unwind, make_number (ofd));
QUIT;
while ((n = read (ifd, buf, sizeof buf)) > 0)
if (write (ofd, buf, n) != n)
- report_file_error ("I/O error", Fcons (newname, Qnil));
+ report_file_error ("I/O error", Fcons (newname, Qnil));
immediate_quit = 0;
/* Closing the output clobbers the file times on some systems. */
if (set_file_times (XSTRING (newname)->data, atime, mtime))
report_file_error ("I/O error", Fcons (newname, Qnil));
}
-#ifdef APOLLO
- if (!egetenv ("USE_DOMAIN_ACLS"))
-#endif
+#ifndef MSDOS
+ chmod (XSTRING (newname)->data, st.st_mode & 07777);
+#else /* MSDOS */
+#if defined (__DJGPP__) && __DJGPP__ > 1
+ /* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
+ and if it can't, it tells so. Otherwise, under MSDOS we usually
+ get only the READ bit, which will make the copied file read-only,
+ so it's better not to chmod at all. */
+ if ((_djstat_flags & _STFAIL_WRITEBIT) == 0)
chmod (XSTRING (newname)->data, st.st_mode & 07777);
+#endif /* DJGPP version 2 or newer */
+#endif /* MSDOS */
}
close (ifd);
if (NILP (ok_if_already_exists)
|| INTEGERP (ok_if_already_exists))
barf_or_query_if_file_exists (newname, "rename to it",
- INTEGERP (ok_if_already_exists));
+ INTEGERP (ok_if_already_exists), 0);
#ifndef BSD4_1
if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
#else
RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
newname, ok_if_already_exists));
+ /* If the new name has special constructs in it,
+ call the corresponding file handler. */
+ handler = Ffind_file_name_handler (newname, Qadd_name_to_file);
+ if (!NILP (handler))
+ RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
+ newname, ok_if_already_exists));
+
if (NILP (ok_if_already_exists)
|| INTEGERP (ok_if_already_exists))
barf_or_query_if_file_exists (newname, "make it a new name",
- INTEGERP (ok_if_already_exists));
+ INTEGERP (ok_if_already_exists), 0);
#ifdef WINDOWSNT
/* Windows does not support this operation. */
report_file_error ("Adding new name", Flist (2, &filename));
RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
linkname, ok_if_already_exists));
+ /* If the new link name has special constructs in it,
+ call the corresponding file handler. */
+ handler = Ffind_file_name_handler (linkname, Qmake_symbolic_link);
+ if (!NILP (handler))
+ RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
+ linkname, ok_if_already_exists));
+
if (NILP (ok_if_already_exists)
|| INTEGERP (ok_if_already_exists))
barf_or_query_if_file_exists (linkname, "make it a link",
- INTEGERP (ok_if_already_exists));
+ INTEGERP (ok_if_already_exists), 0);
if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
{
/* If we didn't complain already, silently delete existing file. */
check_executable (filename)
char *filename;
{
+#ifdef DOS_NT
+ int len = strlen (filename);
+ char *suffix;
+ struct stat st;
+ if (stat (filename, &st) < 0)
+ return 0;
+ return (S_ISREG (st.st_mode)
+ && len >= 5
+ && (stricmp ((suffix = filename + len-4), ".com") == 0
+ || stricmp (suffix, ".exe") == 0
+ || stricmp (suffix, ".bat") == 0)
+ || (st.st_mode & S_IFMT) == S_IFDIR);
+#else /* not DOS_NT */
#ifdef HAVE_EACCESS
return (eaccess (filename, 1) >= 0);
#else
But Unix doesn't give us a right way to do it. */
return (access (filename, 1) >= 0);
#endif
+#endif /* not DOS_NT */
}
/* Return nonzero if file FILENAME exists and can be written. */
check_writable (filename)
char *filename;
{
+#ifdef MSDOS
+ struct stat st;
+ if (stat (filename, &st) < 0)
+ return 0;
+ return (st.st_mode & S_IWRITE || (st.st_mode & S_IFMT) == S_IFDIR);
+#else /* not MSDOS */
#ifdef HAVE_EACCESS
return (eaccess (filename, 2) >= 0);
#else
but would lose for directories. */
return (access (filename, 2) >= 0);
#endif
+#endif /* not MSDOS */
}
DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
if (stat (XSTRING (abspath)->data, &st) < 0)
return Qnil;
#ifdef DOS_NT
- {
- int len;
- char *suffix;
- if (S_ISREG (st.st_mode)
- && (len = XSTRING (abspath)->size) >= 5
- && (stricmp ((suffix = XSTRING (abspath)->data + len-4), ".com") == 0
- || stricmp (suffix, ".exe") == 0
- || stricmp (suffix, ".bat") == 0))
- st.st_mode |= S_IEXEC;
- }
+ if (check_executable (XSTRING (abspath)->data))
+ st.st_mode |= S_IEXEC;
#endif /* DOS_NT */
return make_number (st.st_mode & 07777);
if (!NILP (handler))
return call3 (handler, Qset_file_modes, abspath, mode);
-#ifndef APOLLO
if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
report_file_error ("Doing chmod", Fcons (abspath, Qnil));
-#else /* APOLLO */
- if (!egetenv ("USE_DOMAIN_ACLS"))
- {
- struct stat st;
- struct timeval tvp[2];
-
- /* chmod on apollo also change the file's modtime; need to save the
- modtime and then restore it. */
- if (stat (XSTRING (abspath)->data, &st) < 0)
- {
- report_file_error ("Doing chmod", Fcons (abspath, Qnil));
- return (Qnil);
- }
-
- if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
- report_file_error ("Doing chmod", Fcons (abspath, Qnil));
-
- /* reset the old accessed and modified times. */
- tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
- tvp[0].tv_usec = 0;
- tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
- tvp[1].tv_usec = 0;
-
- if (utimes (XSTRING (abspath)->data, tvp) < 0)
- report_file_error ("Doing utimes", Fcons (abspath, Qnil));
- }
-#endif /* APOLLO */
return Qnil;
}
Otherwise loop around and scan the preceding bufferfull. */
if (bufpos != 0)
break;
+ /* If display current starts at beginning of line,
+ keep it that way. */
+ if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
+ XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
}
immediate_quit = 0;
#ifdef CLASH_DETECTION
if (NILP (handler))
{
- if (!NILP (current_buffer->filename))
- unlock_file (current_buffer->filename);
+ if (!NILP (current_buffer->file_truename))
+ unlock_file (current_buffer->file_truename);
unlock_file (filename);
}
#endif /* CLASH_DETECTION */
return Qnil;
}
-DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
+DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 6,
"r\nFWrite region to file: ",
"Write current region into specified file.\n\
When called from a program, takes three arguments:\n\
VISIT is also the file name to lock and unlock for clash detection.\n\
If VISIT is neither t nor nil nor a string,\n\
that means do not print the \"Wrote file\" message.\n\
+The optional sixth arg LOCKNAME, if non-nil, specifies the name to\n\
+ use for locking and unlocking, overriding FILENAME and VISIT.\n\
Kludgy feature: if START is a string, then that string is written\n\
to the file, instead of any buffer contents, and END is ignored.")
- (start, end, filename, append, visit)
- Lisp_Object start, end, filename, append, visit;
+ (start, end, filename, append, visit, lockname)
+ Lisp_Object start, end, filename, append, visit, lockname;
{
register int desc;
int failure;
Lisp_Object visit_file;
Lisp_Object annotations;
int visiting, quietly;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
struct buffer *given_buffer;
#ifdef DOS_NT
int buffer_file_type
if (!NILP (start) && !STRINGP (start))
validate_region (&start, &end);
- GCPRO2 (filename, visit);
+ GCPRO3 (filename, visit, lockname);
filename = Fexpand_file_name (filename, Qnil);
if (STRINGP (visit))
visit_file = Fexpand_file_name (visit, Qnil);
annotations = Qnil;
- GCPRO4 (start, filename, annotations, visit_file);
+ if (NILP (lockname))
+ lockname = visit_file;
+
+ GCPRO5 (start, filename, annotations, visit_file, lockname);
/* If the file name has special constructs in it,
call the corresponding file handler. */
#ifdef CLASH_DETECTION
if (!auto_saving)
- lock_file (visit_file);
+ lock_file (lockname);
#endif /* CLASH_DETECTION */
fn = XSTRING (filename)->data;
{
#ifdef CLASH_DETECTION
save_errno = errno;
- if (!auto_saving) unlock_file (visit_file);
+ if (!auto_saving) unlock_file (lockname);
errno = save_errno;
#endif /* CLASH_DETECTION */
report_file_error ("Opening output file", Fcons (filename, Qnil));
if (lseek (desc, 0, 2) < 0)
{
#ifdef CLASH_DETECTION
- if (!auto_saving) unlock_file (visit_file);
+ if (!auto_saving) unlock_file (lockname);
#endif /* CLASH_DETECTION */
report_file_error ("Lseek error", Fcons (filename, Qnil));
}
nwritten += XINT (end) - tem;
save_errno = errno;
}
-
- if (nwritten == 0)
- {
- /* If file was empty, still need to write the annotations */
- failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
- save_errno = errno;
- }
+ }
+ else
+ {
+ /* If file was empty, still need to write the annotations */
+ failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
+ save_errno = errno;
}
immediate_quit = 0;
/* mib says that closing the file will try to write as fast as NFS can do
it, and that means the fsync here is not crucial for autosave files. */
if (!auto_saving && fsync (desc) < 0)
- failure = 1, save_errno = errno;
+ {
+ /* If fsync fails with EINTR, don't treat that as serious. */
+ if (errno != EINTR)
+ failure = 1, save_errno = errno;
+ }
#endif
/* Spurious "file has changed on disk" warnings have been
#ifdef CLASH_DETECTION
if (!auto_saving)
- unlock_file (visit_file);
+ unlock_file (lockname);
#endif /* CLASH_DETECTION */
/* Do this before reporting IO error
that `file-attributes' returns.")
()
{
- return long_to_cons (current_buffer->modtime);
+ return long_to_cons ((unsigned long) current_buffer->modtime);
}
DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
return
Fwrite_region (Qnil, Qnil,
current_buffer->auto_save_file_name,
- Qnil, Qlambda);
+ Qnil, Qlambda, Qnil);
}
static Lisp_Object
do_auto_save_unwind (desc) /* used as unwind-protect function */
Lisp_Object desc;
{
+ auto_saving = 0;
close (XINT (desc));
return Qnil;
}
/* No GCPRO needed, because (when it matters) all Lisp_Object variables
point to non-strings reached from Vbuffer_alist. */
- auto_saving = 1;
if (minibuf_level)
no_message = Qt;
if (STRINGP (Vauto_save_list_file_name))
{
+ Lisp_Object listfile;
+ listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
#ifdef DOS_NT
- listdesc = open (XSTRING (Vauto_save_list_file_name)->data,
+ listdesc = open (XSTRING (listfile)->data,
O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
S_IREAD | S_IWRITE);
#else /* not DOS_NT */
- listdesc = creat (XSTRING (Vauto_save_list_file_name)->data, 0666);
+ listdesc = creat (XSTRING (listfile)->data, 0666);
#endif /* not DOS_NT */
}
else
listdesc = -1;
- /* Arrange to close that file whether or not we get an error. */
+ /* Arrange to close that file whether or not we get an error.
+ Also reset auto_saving to 0. */
if (listdesc >= 0)
record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
+ auto_saving = 1;
+
/* First, save all files which don't have handlers. If Emacs is
crashing, the handlers may tweak what is causing Emacs to crash
in the first place, and it would be a shame if Emacs failed to
b = XBUFFER (buf);
/* Record all the buffers that have auto save mode
- in the special file that lists them. */
+ in the special file that lists them. For each of these buffers,
+ Record visited name (if any) and auto save name. */
if (STRINGP (b->auto_save_file_name)
&& listdesc >= 0 && do_handled_files == 0)
{
+ if (!NILP (b->filename))
+ {
+ write (listdesc, XSTRING (b->filename)->data,
+ XSTRING (b->filename)->size);
+ }
+ write (listdesc, "\n", 1);
write (listdesc, XSTRING (b->auto_save_file_name)->data,
XSTRING (b->auto_save_file_name)->size);
write (listdesc, "\n", 1);
Vquit_flag = oquit;
- auto_saving = 0;
unbind_to (count, Qnil);
return Qnil;
}
Vinhibit_file_name_operation = Qnil;
DEFVAR_LISP ("auto-save-list-file-name", &Vauto_save_list_file_name,
- "File name in which we write a list of all auto save file names.");
+ "File name in which we write a list of all auto save file names.\n\
+This variable is initialized automatically from `auto-save-list-file-prefix'\n\
+shortly after Emacs reads your `.emacs' file, if you have not yet given it\n\
+a non-nil value.");
Vauto_save_list_file_name = Qnil;
defsubr (&Sfind_file_name_handler);