Function: rename-file

rename-file is an interactive function defined in fileio.c.

Signature

(rename-file FILE NEWNAME &optional OK-IF-ALREADY-EXISTS)

Documentation

Rename FILE as NEWNAME. Both args must be strings.

If file has names other than FILE, it continues to have those names. If NEWNAME is a directory name, rename FILE to a like-named file under NEWNAME. For NEWNAME to be recognized as a directory name, it should end in a slash.

Signal a file-already-exists error if a file NEWNAME already exists unless optional third argument OK-IF-ALREADY-EXISTS is non-nil. An integer third arg means request confirmation if NEWNAME already exists. This is what happens in interactive use with M-x.

Other relevant functions are documented in the file group.

View in manual

Probably introduced at or before Emacs version 17.

Key Bindings

Shortdoc

;; file
(rename-file "/tmp/foo" "/tmp/newname")

Source Code

// Defined in /usr/src/emacs/src/fileio.c
{
  Lisp_Object handler;
  Lisp_Object encoded_file, encoded_newname;

  file = Fexpand_file_name (file, Qnil);

  /* If the filesystem is case-insensitive and the file names are
     identical but for case, treat it as a change-case request, and do
     not worry whether NEWNAME exists or whether it is a directory, as
     it is already another name for FILE.  */
  bool case_only_rename = false;
#if defined CYGWIN || defined DOS_NT
  if (!NILP (Ffile_name_case_insensitive_p (file)))
    {
      newname = Fexpand_file_name (newname, Qnil);
      case_only_rename = !NILP (Fstring_equal (Fdowncase (file),
					       Fdowncase (newname)));
    }
#endif

  if (!case_only_rename)
    newname = expand_cp_target (Fdirectory_file_name (file), newname);

  /* If the file name has special constructs in it,
     call the corresponding file name handler.  */
  handler = Ffind_file_name_handler (file, Qrename_file);
  if (NILP (handler))
    handler = Ffind_file_name_handler (newname, Qrename_file);
  if (!NILP (handler))
    return calln (handler, Qrename_file,
		  file, newname, ok_if_already_exists);

  encoded_file = ENCODE_FILE (file);
  encoded_newname = ENCODE_FILE (newname);

  bool plain_rename = (case_only_rename
		       || (!NILP (ok_if_already_exists)
			   && !FIXNUMP (ok_if_already_exists)));
  int rename_errno UNINIT;
  if (!plain_rename)
    {
      if (emacs_renameat_noreplace (AT_FDCWD,
				    SSDATA (encoded_file),
				    AT_FDCWD,
				    SSDATA (encoded_newname))
	  == 0)
	return Qnil;

      rename_errno = errno;
      switch (rename_errno)
	{
	case EEXIST: case EINVAL: case ENOSYS:
#if ENOSYS != ENOTSUP
	case ENOTSUP:
#endif
	  barf_or_query_if_file_exists (newname, rename_errno == EEXIST,
					"rename to it",
					FIXNUMP (ok_if_already_exists),
					false);
	  plain_rename = true;
	  break;
	}
    }

  if (plain_rename)
    {
      if (emacs_rename (SSDATA (encoded_file),
			SSDATA (encoded_newname)) == 0)
	return Qnil;
      rename_errno = errno;
      /* Don't prompt again.  */
      ok_if_already_exists = Qt;
    }
  else if (!NILP (ok_if_already_exists))
    ok_if_already_exists = Qt;

  if (rename_errno != EXDEV)
    report_file_errno ("Renaming", list2 (file, newname), rename_errno);

  struct stat file_st;
  bool dirp = !NILP (Fdirectory_name_p (file));
  if (!dirp)
    {
      if (emacs_fstatat (AT_FDCWD, SSDATA (encoded_file),
			 &file_st, AT_SYMLINK_NOFOLLOW)
	  != 0)
	report_file_error ("Renaming", list2 (file, newname));
      dirp = S_ISDIR (file_st.st_mode) != 0;
    }
  if (dirp)
    calln (Qcopy_directory, file, newname, Qt, Qnil);
  else if (S_ISREG (file_st.st_mode))
    Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt);
  else if (S_ISLNK (file_st.st_mode))
    {
      Lisp_Object target = emacs_readlinkat (AT_FDCWD,
					     SSDATA (encoded_file));
      if (!NILP (target))
	Fmake_symbolic_link (target, newname, ok_if_already_exists);
      else
	report_file_error ("Renaming", list2 (file, newname));
    }
  else
    report_file_errno ("Renaming", list2 (file, newname), rename_errno);

  specpdl_ref count = SPECPDL_INDEX ();
  specbind (Qdelete_by_moving_to_trash, Qnil);
  if (dirp)
    calln (Qdelete_directory, file, Qt);
  else
    calln (Qdelete_file, file, Qnil);
  return unbind_to (count, Qnil);
}