Function: do-auto-save

do-auto-save is an interactive function defined in fileio.c.

Signature

(do-auto-save &optional NO-MESSAGE CURRENT-ONLY)

Documentation

Auto-save all buffers that need it.

This auto-saves all buffers that have auto-saving enabled and were changed since last auto-saved.

Auto-saving writes the buffer into a file so that your edits are not lost if the system crashes.

The auto-save file is not the file you visited; that changes only when you save.

Normally, run the normal hook auto-save-hook before saving.

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.

View in manual

Key Bindings

Source Code

// Defined in /usr/src/emacs/src/fileio.c
// Skipping highlighting due to helpful-max-highlight.
{
  struct buffer *old = current_buffer, *b;
  Lisp_Object tail, buf, hook;
  bool auto_saved = 0;
  int do_handled_files;
  Lisp_Object oquit;
  FILE *stream = NULL;
  specpdl_ref count = SPECPDL_INDEX ();
  bool orig_minibuffer_auto_raise = minibuffer_auto_raise;
  bool old_message_p = 0;
  struct auto_save_unwind auto_save_unwind;

  if (minibuf_level)
    no_message = Qt;

  if (NILP (no_message))
    {
      old_message_p = push_message ();
      record_unwind_protect_void (pop_message_unwind);
    }

  /* Ordinarily don't quit within this function,
     but don't make it impossible to quit (in case we get hung in I/O).  */
  oquit = Vquit_flag;
  Vquit_flag = Qnil;

  hook = intern ("auto-save-hook");
  safe_run_hooks (hook);

  if (STRINGP (Vauto_save_list_file_name))
    {
      Lisp_Object listfile;

      listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);

      /* Don't try to create the directory when shutting down Emacs,
         because creating the directory might signal an error, and
         that would leave Emacs in a strange state.  */
      if (!NILP (Vrun_hooks))
	{
	  Lisp_Object dir;
	  dir = file_name_directory (listfile);
	  if (NILP (Ffile_directory_p (dir)))
	    internal_condition_case_1 (do_auto_save_make_dir,
				       dir, Qt,
				       do_auto_save_eh);
	}

      stream = emacs_fopen (SSDATA (listfile), "w");
    }

  auto_save_unwind.stream = stream;
  auto_save_unwind.auto_raise = minibuffer_auto_raise;
  record_unwind_protect_ptr (do_auto_save_unwind, &auto_save_unwind);
  minibuffer_auto_raise = 0;
  auto_saving = 1;
  auto_save_error_occurred = 0;

  /* On first pass, save all files that don't have handlers.
     On second pass, save all files that do 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 autosave perfectly ordinary files because it
     couldn't handle some ange-ftp'd file.  */

  for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
    FOR_EACH_LIVE_BUFFER (tail, buf)
      {
	b = XBUFFER (buf);

	/* Record all the buffers that have auto save mode
	   in the special file that lists them.  For each of these buffers,
	   Record visited name (if any) and auto save name.  */
	if (STRINGP (BVAR (b, auto_save_file_name))
	    && stream != NULL && do_handled_files == 0)
	  {
	    block_input ();
	    if (!NILP (BVAR (b, filename)))
	      fwrite (SDATA (BVAR (b, filename)), 1,
		      SBYTES (BVAR (b, filename)), stream);
	    putc ('\n', stream);
	    fwrite (SDATA (BVAR (b, auto_save_file_name)), 1,
		    SBYTES (BVAR (b, auto_save_file_name)), stream);
	    putc ('\n', stream);
	    unblock_input ();
	  }

	if (!NILP (current_only)
	    && b != current_buffer)
	  continue;

	/* Don't auto-save indirect buffers.
	   The base buffer takes care of it.  */
	if (b->base_buffer)
	  continue;

	/* Check for auto save enabled
	   and file changed since last auto save
	   and file changed since last real save.  */
	if (STRINGP (BVAR (b, auto_save_file_name))
	    && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)
	    && BUF_AUTOSAVE_MODIFF (b) < BUF_MODIFF (b)
	    /* -1 means we've turned off autosaving for a while--see below.  */
	    && FIXNUMP (BVAR (b, save_length))
	    && XFIXNUM (BVAR (b, save_length)) >= 0
	    && (do_handled_files
		|| NILP (Ffind_file_name_handler (BVAR (b, auto_save_file_name),
						  Qwrite_region))))
	  {
	    struct timespec before_time = current_timespec ();
	    struct timespec after_time;

	    /* If we had a failure, don't try again for 20 minutes.  */
	    if (b->auto_save_failure_time > 0
		&& before_time.tv_sec - b->auto_save_failure_time < 1200)
	      continue;

	    enum { growth_factor = 4 };
	    verify (BUF_BYTES_MAX <= EMACS_INT_MAX / growth_factor);

	    set_buffer_internal (b);
	    if (NILP (Vauto_save_include_big_deletions)
		&& FIXNUMP (BVAR (b, save_length))
		/* A short file is likely to change a large fraction;
		   spare the user annoying messages.  */
		&& XFIXNUM (BVAR (b, save_length)) > 5000
		&& (growth_factor * (BUF_Z (b) - BUF_BEG (b))
		    < (growth_factor - 1) * XFIXNUM (BVAR (b, save_length)))
		/* These messages are frequent and annoying for `*mail*'.  */
		&& !NILP (BVAR (b, filename))
		&& NILP (no_message))
	      {
		/* It has shrunk too much; turn off auto-saving here.  */
		minibuffer_auto_raise = orig_minibuffer_auto_raise;
		message_with_string ("Buffer %s has shrunk a lot; auto save disabled in that buffer until next real save",
				     BVAR (b, name), 1);
		minibuffer_auto_raise = 0;
		/* Turn off auto-saving until there's a real save,
		   and prevent any more warnings.  */
		XSETINT (BVAR (b, save_length), -1);
		Fsleep_for (make_fixnum (1), Qnil);
		continue;
	      }
	    if (!auto_saved && NILP (no_message))
	      message1 ("Auto-saving...");
	    internal_condition_case (auto_save_1, Qt, auto_save_error);
	    auto_saved = 1;
	    BUF_AUTOSAVE_MODIFF (b) = BUF_MODIFF (b);
	    XSETFASTINT (BVAR (current_buffer, save_length), Z - BEG);
	    set_buffer_internal (old);

	    after_time = current_timespec ();

	    /* If auto-save took more than 60 seconds,
	       assume it was an NFS failure that got a timeout.  */
	    if (after_time.tv_sec - before_time.tv_sec > 60)
	      b->auto_save_failure_time = after_time.tv_sec;
	  }
      }

  /* Prevent another auto save till enough input events come in.  */
  record_auto_save ();

  if (auto_saved && NILP (no_message))
    {
      if (old_message_p)
	{
	  /* If we are going to restore an old message,
	     give time to read ours.  */
	  sit_for (make_fixnum (1), 0, 0);
	  restore_message ();
	}
      else if (!auto_save_error_occurred)
	/* Don't overwrite the error message if an error occurred.
	   If we displayed a message and then restored a state
	   with no message, leave a "done" message on the screen.  */
	message1 ("Auto-saving...done");
    }

  Vquit_flag = oquit;

  /* This restores the message-stack status.  */
  return unbind_to (count, Qnil);
}