diff --git a/ChangeLog b/ChangeLog
index df7d735d9f7206f2e61817b1680ed20f5313e3a2..d240b3f7ac1850e8986f5b900c0f4ef1ab3fee34 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -23,6 +23,13 @@ CVS code -
 	- Decouple the paragraph searching code and the justifying code.
 	  Removed function do_para_operation(); new function
 	  do_para_search(); changes to do_justify(). (DLR)
+	- Add -E/--backupdir option.  When used with -B/--backup, backup
+	  files will be saved in the specified directory with their
+	  canonical pathnames encoded in their names (all '/'s replaced
+	  with '!'s).  Changes to write_file(). (Martin Ehmsen)  DLR:
+	  Add function init_backup_dir() to handle relative paths
+	  correctly, use get_full_path() to get the canonical pathname,
+	  and use tail() to get the filename if get_full_path() fails.
 - files.c:
   add_open_files()
 	- Make the saving of marked status in open_files->file_flags
@@ -199,6 +206,11 @@ CVS code -
 	  not 1.1.12. (DLR)
 - nano.1, nanorc.5, nano.texi
 	- Clarify the description for -T/--tabsize a bit. (DLR)
+	- Add -E/--backupdir description. (Martin Ehmsen; minor cosmetic
+	  fixes by DLR)
+- nanorc.sample:
+	- Add backupdir description. (Martin Ehmsen; minor cosmetic
+	  fixes by DLR)
 - README:
 	- Reformat to 72 characters per line, fix wording in one spot,
 	  and fix spacing in several spots. (DLR)
diff --git a/doc/man/nano.1 b/doc/man/nano.1
index a8b7e63007d1ef27210c140ac7d9547e609ca011..889732c02a78e95bf71096a6ced643e12ae885d3 100644
--- a/doc/man/nano.1
+++ b/doc/man/nano.1
@@ -42,6 +42,10 @@ filename suffixed with a ~.
 .B \-D (\-\-dos)
 Write file in DOS format.
 .TP
+.B \-E \fIdir\fP (\-\-backupdir=\fIdir\fP)
+Set the directory where \fBnano\fP puts the backup files if file backups
+are enabled.
+.TP
 .B \-F (\-\-multibuffer)
 Enable multiple file buffers, if available.
 .TP
diff --git a/doc/man/nanorc.5 b/doc/man/nanorc.5
index 05873459a872f83da1452cf5d5c0477c486b6bdd..924da881ee72adee5964784180f827a1178e88af 100644
--- a/doc/man/nanorc.5
+++ b/doc/man/nanorc.5
@@ -47,6 +47,10 @@ Use auto-indentation.
 Create backup files in
 .IR filename~ .
 .TP
+\fBset backupdir "\fIdirectory\fP"\fP
+Set the directory where \fBnano\fP puts the backup files if file backups
+are enabled.
+.TP
 \fBset/unset const\fP
 Constantly display the cursor position in the status bar.
 .TP
diff --git a/doc/nanorc.sample b/doc/nanorc.sample
index eee7cdb36621c554a4ffc479b2ba7494d7f5c63d..98bb6a8a2573833e5e5f79df0696ec6d56f4d224 100644
--- a/doc/nanorc.sample
+++ b/doc/nanorc.sample
@@ -14,6 +14,9 @@
 ## Backup files to filename~
 # set backup
 
+## The directory to put the backup files in.
+# set backupdir ""
+
 ## Constantly display the cursor position in the status bar.
 # set const
 
diff --git a/doc/texinfo/nano.texi b/doc/texinfo/nano.texi
index 487f555de281f85211e509af08a64a0afe7e1a73..1158d28ab244e7eaca5e7609395b07617c88968a 100644
--- a/doc/texinfo/nano.texi
+++ b/doc/texinfo/nano.texi
@@ -114,6 +114,10 @@ filename suffixed with a ~.
 @item -D, --dos
 Write file in DOS format.
 
+@item -E, --backupdir=[dir]
+Set the directory where @code{nano) puts the backup files if file
+backups are enabled.
+
 @item -F, --multibuffer
 Enable multiple file buffers, if available.
 
diff --git a/src/files.c b/src/files.c
index 04d043d7497321ebb02c3dda8d99f2d0e7fc3615..d69c46b8734f6fcd953a80a4c99499ab3a40ac13 100644
--- a/src/files.c
+++ b/src/files.c
@@ -1026,7 +1026,7 @@ int close_open_file(void)
 }
 #endif /* MULTIBUFFER */
 
-#if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR)
+#if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR) || !defined(NANO_SMALL)
 /*
  * When passed "[relative path]" or "[relative path][filename]" in
  * origpath, return "[full path]" or "[full path][filename]" on success,
@@ -1333,6 +1333,30 @@ int check_operating_dir(const char *currpath, int allow_tabcomp)
 }
 #endif
 
+#ifndef NANO_SMALL
+void init_backup_dir(void)
+{
+    char *full_backup_dir;
+
+    if (backup_dir == NULL)
+	return;
+
+    full_backup_dir = get_full_path(backup_dir);
+
+    /* If get_full_path() failed or the backup directory is
+     * inaccessible, unset backup_dir. */
+    if (full_backup_dir == NULL ||
+	full_backup_dir[strlen(full_backup_dir) - 1] != '/') {
+	free(full_backup_dir);
+	free(backup_dir);
+	backup_dir = NULL;
+    } else {
+	free(backup_dir);
+	backup_dir = full_backup_dir;
+    }
+}
+#endif
+
 /* Read from inn, write to out.  We assume inn is opened for reading,
  * and out for writing.  We return 0 on success, -1 on read error, -2 on
  * write error. */
@@ -1465,8 +1489,38 @@ int write_file(const char *name, int tmp, int append, int nonamechange)
 	    goto cleanup_and_exit;
 	}
 
-	backupname = charalloc(strlen(realname) + 2);
-	sprintf(backupname, "%s~", realname);
+	/* If backup_dir is set, we set backupname to
+	 * backup_dir/backupname~, where backupnae is the canonicalized
+	 * absolute pathname of realname with every '/' replaced with a
+	 * '!'.  This means that /home/foo/file is backed up in
+	 * backup_dir/!home!foo!file~. */
+	if (backup_dir != NULL) {
+	    char *canon_realname = get_full_path(realname);
+	    size_t i;
+
+	    if (canon_realname == NULL)
+		/* If get_full_path() failed, we don't have a
+		 * canonicalized absolute pathname, so just use the
+		 * filename portion of the pathname.  We use tail() so
+		 * that e.g. ../backupname will be backed up in
+		 * backupdir/backupname~ instead of
+		 * backupdir/../backupname~. */
+		canon_realname = mallocstrcpy(NULL, tail(realname));
+	    else {
+		for (i = 0; canon_realname[i] != '\0'; i++) {
+		    if (canon_realname[i] == '/')
+			canon_realname[i] = '!';
+		}
+	    }
+
+	    backupname = charalloc(strlen(backup_dir) +
+		strlen(canon_realname) + 2);
+	    sprintf(backupname, "%s%s~", backup_dir, canon_realname);
+	    free(canon_realname);
+	} else {
+	    backupname = charalloc(strlen(realname) + 2);
+	    sprintf(backupname, "%s~", realname);
+	}
 
 	/* Open the destination backup file.  Before we write to it, we
 	 * set its permissions, so no unauthorized person can read it as
@@ -2370,6 +2424,23 @@ char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list)
 }
 #endif /* !DISABLE_TABCOMP */
 
+#if !defined(DISABLE_BROWSER) || !defined(NANO_SMALL)
+/* Only print the last part of a path; isn't there a shell
+ * command for this? */
+const char *tail(const char *foo)
+{
+    const char *tmp = foo + strlen(foo);
+
+    while (*tmp != '/' && tmp != foo)
+	tmp--;
+
+    if (*tmp == '/')
+	tmp++;
+
+    return tmp;
+}
+#endif
+
 #ifndef DISABLE_BROWSER
 /* Our sort routine for file listings -- sort directories before
  * files, and then alphabetically. */ 
@@ -2396,21 +2467,6 @@ void free_charptrarray(char **array, int len)
     free(array);
 }
 
-/* Only print the last part of a path; isn't there a shell 
- * command for this? */
-const char *tail(const char *foo)
-{
-    const char *tmp = foo + strlen(foo);
-
-    while (*tmp != '/' && tmp != foo)
-	tmp--;
-
-    if (*tmp == '/')
-	tmp++;
-
-    return tmp;
-}
-
 /* Strip one dir from the end of a string. */
 void striponedir(char *foo)
 {
diff --git a/src/global.c b/src/global.c
index 4e4ec3774106e8d2fedd09eb1c1c0c6b450e1095..34d27aa04b072b85ffa8319f33a22419958dd87a 100644
--- a/src/global.c
+++ b/src/global.c
@@ -72,6 +72,10 @@ char *quotestr = NULL;		/* Quote string.  The default value is
 				   set in main(). */
 #endif
 
+#ifndef NANO_SMALL
+char *backup_dir = NULL;	/* Backup directory. */
+#endif
+
 int resetstatuspos;		/* Hack for resetting the status bar 
 				   cursor position */
 char *answer = NULL;		/* Answer str to many questions */
@@ -932,6 +936,10 @@ void thanks_for_all_the_fish(void)
     if (quotestr != NULL)
 	free(quotestr);
 #endif
+#ifndef NANO_SMALL
+    if (backup_dir != NULL)
+        free(backup_dir);
+#endif
 #ifndef DISABLE_OPERATINGDIR
     if (operating_dir != NULL)
 	free(operating_dir);
diff --git a/src/nano.c b/src/nano.c
index e2dc353ecb0a639d69149a9e03b1ae0edc973b10..15c1fe5eb4361083d583a069f9382203b89539cb 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -629,6 +629,7 @@ void usage(void)
 #ifndef NANO_SMALL
     print1opt("-B", "--backup", _("Backup existing files on save"));
     print1opt("-D", "--dos", _("Write file in DOS format"));
+    print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files"));
 #endif
 #ifdef ENABLE_MULTIBUFFER
     print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
@@ -3152,6 +3153,7 @@ int main(int argc, char *argv[])
 #ifndef NANO_SMALL
 	{"backup", 0, 0, 'B'},
 	{"dos", 0, 0, 'D'},
+	{"backupdir", 1, 0, 'E'},
 	{"mac", 0, 0, 'M'},
 	{"noconvert", 0, 0, 'N'},
 	{"smooth", 0, 0, 'S'},
@@ -3176,11 +3178,11 @@ int main(int argc, char *argv[])
 #endif
 
 #ifdef HAVE_GETOPT_LONG
-    while ((optchr = getopt_long(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
+    while ((optchr = getopt_long(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
 				 long_options, NULL)) != -1) {
 #else
     while ((optchr =
-	    getopt(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
+	    getopt(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
 #endif
 
 	switch (optchr) {
@@ -3200,6 +3202,9 @@ int main(int argc, char *argv[])
 	case 'D':
 	    SET(DOS_FILE);
 	    break;
+	case 'E':
+	    backup_dir = mallocstrcpy(backup_dir, optarg);
+	    break;
 #endif
 #ifdef ENABLE_MULTIBUFFER
 	case 'F':
@@ -3350,6 +3355,9 @@ int main(int argc, char *argv[])
 #ifndef DISABLE_WRAPPING
 	int wrap_at_cpy = wrap_at;
 #endif
+#ifndef NANO_SMALL
+	char *backup_dir_cpy = backup_dir;
+#endif
 #ifndef DISABLE_JUSTIFY
 	char *quotestr_cpy = quotestr;
 #endif
@@ -3362,6 +3370,9 @@ int main(int argc, char *argv[])
 #ifndef DISABLE_OPERATINGDIR
 	operating_dir = NULL;
 #endif
+#ifndef NANO_SMALL
+	backup_dir = NULL;
+#endif
 #ifndef DISABLE_JUSTIFY
 	quotestr = NULL;
 #endif
@@ -3381,6 +3392,12 @@ int main(int argc, char *argv[])
 	if (fill_flag_used)
 	    wrap_at = wrap_at_cpy;
 #endif
+#ifndef NANO_SMALL
+	if (backup_dir_cpy != NULL) {
+	    free(backup_dir);
+	    backup_dir = backup_dir_cpy;
+	}
+#endif	
 #ifndef DISABLE_JUSTIFY
 	if (quotestr_cpy != NULL) {
 	    free(quotestr);
@@ -3411,6 +3428,12 @@ int main(int argc, char *argv[])
 #endif
 #endif
 
+#ifndef NANO_SMALL
+    /* Set up the backup directory.  This entails making sure it exists
+     * and is a directory, so that backup files will be saved there. */
+    init_backup_dir();
+#endif
+
 #ifndef DISABLE_OPERATINGDIR
     /* Set up the operating directory.  This entails chdir()ing there,
        so that file reads and writes will be based there. */
@@ -3425,6 +3448,7 @@ int main(int argc, char *argv[])
 	quotestr = mallocstrcpy(NULL, "> ");
 #endif
 #endif /* !DISABLE_JUSTIFY */
+
     if (tabsize == -1)
 	tabsize = 8;
 
diff --git a/src/proto.h b/src/proto.h
index d330b7d6758bac2cb48ffbf6851df871e650b445..83697ffcb3392e7e3ee89d6082c37efe2648551c 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -50,6 +50,10 @@ extern int currslen;
 extern char *quotestr;
 #endif
 
+#ifndef NANO_SMALL
+extern char *backup_dir;
+#endif
+
 extern WINDOW *edit, *topwin, *bottomwin;
 extern char *filename;
 extern struct stat originalfilestat;
@@ -178,6 +182,9 @@ char *safe_tempnam(const char *dirname, const char *filename_prefix);
 void init_operating_dir(void);
 int check_operating_dir(const char *currpath, int allow_tabcomp);
 #endif
+#ifndef NANO_SMALL
+void init_backup_dir(void);
+#endif
 int write_file(const char *name, int tmp, int append, int nonamechange);
 #ifndef NANO_SMALL
 int write_marked(const char *name, int tmp, int append, int
@@ -192,10 +199,12 @@ char **username_tab_completion(char *buf, int *num_matches);
 char **cwd_tab_completion(char *buf, int *num_matches);
 char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list);
 #endif
+#if !defined(DISABLE_BROWSER) || !defined(NANO_SMALL)
+const char *tail(const char *foo);
+#endif
 #ifndef DISABLE_BROWSER
 int diralphasort(const void *va, const void *vb);
 void free_charptrarray(char **array, int len);
-const char *tail(const char *foo);
 void striponedir(char *foo);
 int readable_dir(const char *path);
 char **browser_init(const char *path, int *longest, int *numents);
diff --git a/src/rcfile.c b/src/rcfile.c
index e15379c90d52fe9a43c821cdfd92c2f8c58dfd0b..dcfdb8c7959e24fa7e3ff2ac5eb0d5fdfe9f40aa 100644
--- a/src/rcfile.c
+++ b/src/rcfile.c
@@ -41,6 +41,7 @@ const static rcoption rcopts[] = {
 #ifndef NANO_SMALL
     {"autoindent", AUTOINDENT},
     {"backup", BACKUP_FILE},
+    {"backupdir", 0},
 #endif
     {"const", CONSTUPDATE},
 #ifndef NANO_SMALL
@@ -145,12 +146,12 @@ char *parse_next_word(char *ptr)
     return ptr;
 }
 
-/* The keywords operatingdir, fill, tabsize, speller, and quotestr take
- * an argument when set.  Among these, operatingdir, speller, and
- * quotestr have to allow tabs and spaces in the argument.  Thus, if the
- * next word starts with a ", we say it ends with the last " of the line.
- * Otherwise, the word is interpreted as usual.  That is so the arguments
- * can contain "s too. */
+/* The keywords operatingdir, backupdir, fill, tabsize, speller, and
+ * quotestr take an argument when set.  Among these, operatingdir,
+ * backupdir, speller, and quotestr have to allow tabs and spaces in the
+ * argument.  Thus, if the next word starts with a ", we say it ends
+ * with the last " of the line.  Otherwise, the word is interpreted as
+ * usual.  That is so the arguments can contain "s too. */
 char *parse_argument(char *ptr)
 {
     const char *ptr_bak = ptr;
@@ -540,6 +541,9 @@ void parse_rcfile(FILE *rcstream)
 #ifndef DISABLE_JUSTIFY
 				|| !strcasecmp(rcopts[i].name, "quotestr")
 #endif
+#ifndef NANO_SMALL
+			        || !strcasecmp(rcopts[i].name, "backupdir")
+#endif
 #ifndef DISABLE_SPELLER
 				|| !strcasecmp(rcopts[i].name, "speller")
 #endif
@@ -582,6 +586,11 @@ void parse_rcfile(FILE *rcstream)
 				quotestr = mallocstrcpy(NULL, option);
 			    else
 #endif
+#ifndef NANO_SMALL
+			    if (!strcasecmp(rcopts[i].name, "backupdir"))
+				backup_dir = mallocstrcpy(NULL, option);
+			    else
+#endif
 #ifndef DISABLE_SPELLER
 			    if (!strcasecmp(rcopts[i].name, "speller"))
 				alt_speller = mallocstrcpy(NULL, option);