From 85e35e67a280a6380b70c0a611aa521b45aa7e87 Mon Sep 17 00:00:00 2001
From: David Lawrence Ramsey <pooka109@gmail.com>
Date: Wed, 5 Jul 2006 14:14:06 +0000
Subject: [PATCH] in get_full_path(), don't return NULL when the current
 directory doesn't exist, as we can still recover from that, and also add
 various cleanups

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@3752 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
---
 ChangeLog   |   5 ++
 src/files.c | 149 ++++++++++++++++++++++++++++------------------------
 2 files changed, 84 insertions(+), 70 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 94a71b59..137b5f22 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -55,6 +55,11 @@ CVS code -
 	  allocated, use null_at() to strip the directory from the
 	  string.  Also, return the stripped path instead of modifying
 	  path. (DLR)
+- files.c:
+  get_full_path()
+	- Don't return NULL when the current directory doesn't exist, as
+	  we can still recover from that. (DLR, found by Mike Frysinger)
+	- Add various cleanups. (DLR)
 - help.c:
   do_help()
 	- Simplify screen update handling and exiting. (DLR)
diff --git a/src/files.c b/src/files.c
index 716ffa89..82f4f4e8 100644
--- a/src/files.c
+++ b/src/files.c
@@ -902,21 +902,28 @@ void do_insertfile_void(void)
  * able to go there. */
 char *get_full_path(const char *origpath)
 {
-    char *d_here, *d_there = NULL;
+    struct stat fileinfo;
+    char *d_here, *d_there, *d_there_file = NULL;
+    const char *last_slash;
+    bool path_only;
 
     if (origpath == NULL)
     	return NULL;
 
-    /* Get the current directory. */
+    /* Get the current directory.  If it doesn't exist, back up and try
+     * again until we get a directory that does exist. */
     d_here = charalloc(PATH_MAX + 1);
     d_here = getcwd(d_here, PATH_MAX + 1);
 
-    if (d_here != NULL) {
-	const char *last_slash;
-	char *d_there_file = NULL;
-	bool path_only;
-	struct stat fileinfo;
+    while (d_here == NULL) {
+	if (chdir("..") == -1)
+	    break;
+
+	d_here = getcwd(d_here, PATH_MAX + 1);
+    }
 
+    /* If we succeeded, canonicalize it in d_here. */
+    if (d_here != NULL) {
 	align(&d_here);
 
 	/* If the current directory isn't "/", tack a slash onto the end
@@ -925,89 +932,91 @@ char *get_full_path(const char *origpath)
 	    d_here = charealloc(d_here, strlen(d_here) + 2);
 	    strcat(d_here, "/");
 	}
+    /* Otherwise, set d_here to "". */
+    } else
+	d_here = mallocstrcpy(NULL, "");
 
-	d_there = real_dir_from_tilde(origpath);
+    d_there = real_dir_from_tilde(origpath);
 
-	assert(d_there != NULL);
+    assert(d_there != NULL);
 
-	/* Stat d_there.  If stat() fails, assume that d_there refers to
-	 * a new file that hasn't been saved to disk yet.  Set path_only
-	 * to TRUE if d_there refers to a directory, and FALSE if
-	 * d_there refers to a file. */
-	path_only = !stat(d_there, &fileinfo) &&
-		S_ISDIR(fileinfo.st_mode);
+    /* If stat()ing d_there fails, assume that d_there refers to a new
+     * file that hasn't been saved to disk yet.  Set path_only to TRUE
+     * if d_there refers to a directory, and FALSE otherwise. */
+    path_only = stat(d_there, &fileinfo) == 0 &&
+	S_ISDIR(fileinfo.st_mode);
 
-	/* If path_only is TRUE, make sure d_there ends in a slash. */
-	if (path_only) {
-	    size_t d_there_len = strlen(d_there);
+    /* If path_only is TRUE, make sure d_there ends in a slash. */
+    if (path_only) {
+	size_t d_there_len = strlen(d_there);
 
-	    if (d_there[d_there_len - 1] != '/') {
-		d_there = charealloc(d_there, d_there_len + 2);
-		strcat(d_there, "/");
-	    }
+	if (d_there[d_there_len - 1] != '/') {
+	    d_there = charealloc(d_there, d_there_len + 2);
+	    strcat(d_there, "/");
 	}
+    }
 
-	/* Search for the last slash in d_there. */
-	last_slash = strrchr(d_there, '/');
+    /* Search for the last slash in d_there. */
+    last_slash = strrchr(d_there, '/');
 
-	/* If we didn't find one, then make sure the answer is in the
-	 * format "d_here/d_there". */
-	if (last_slash == NULL) {
-	    assert(!path_only);
+    /* If we didn't find one, then make sure the answer is in the format
+     * "d_here/d_there". */
+    if (last_slash == NULL) {
+	assert(!path_only);
 
-	    d_there_file = d_there;
-	    d_there = d_here;
+	d_there_file = d_there;
+	d_there = d_here;
+    } else {
+	/* If path_only is FALSE, then save the filename portion of the
+	 * answer (everything after the last slash) in d_there_file. */
+	if (!path_only)
+	    d_there_file = mallocstrcpy(NULL, last_slash + 1);
+
+	/* And remove the filename portion of the answer from
+	 * d_there. */
+	null_at(&d_there, last_slash - d_there + 1);
+
+	/* chdir() to the path specified in d_there. */
+	if (chdir(d_there) == -1) {
+	    free(d_there);
+	    d_there = NULL;
 	} else {
-	    /* If path_only is FALSE, then save the filename portion of
-	     * the answer, everything after the last slash, in
-	     * d_there_file. */
-	    if (!path_only)
-		d_there_file = mallocstrcpy(NULL, last_slash + 1);
-
-	    /* And remove the filename portion of the answer from
-	     * d_there. */
-	    null_at(&d_there, last_slash - d_there + 1);
-
-	    /* Go to the path specified in d_there. */
-	    if (chdir(d_there) == -1) {
-		free(d_there);
-		d_there = NULL;
-	    } else {
-		/* Get the full path and save it in d_there. */
-		free(d_there);
+	    free(d_there);
 
-		d_there = charalloc(PATH_MAX + 1);
-		d_there = getcwd(d_there, PATH_MAX + 1);
+	    /* Get the full path. */
+	    d_there = charalloc(PATH_MAX + 1);
+	    d_there = getcwd(d_there, PATH_MAX + 1);
 
-		if (d_there != NULL) {
-		    align(&d_there);
+	    /* If we succeeded, canonicalize it in d_there. */
+	    if (d_there != NULL) {
+		align(&d_there);
 
-		    if (strcmp(d_there, "/") != 0) {
-			/* Make sure d_there ends in a slash. */
-			d_there = charealloc(d_there,
-				strlen(d_there) + 2);
-			strcat(d_there, "/");
-		    }
-		} else
-		    /* If we couldn't get the full path, set path_only
-		     * to TRUE so that we clean up correctly, free all
-		     * allocated memory, and return NULL. */
-		    path_only = TRUE;
-
-		/* Finally, go back to the path specified in d_here,
-		 * where we were before. */
-		chdir(d_here);
-	    }
+		/* If the current directory isn't "/", tack a slash onto
+		 * the end of it. */
+		if (strcmp(d_there, "/") != 0) {
+		    d_there = charealloc(d_there, strlen(d_there) + 2);
+		    strcat(d_there, "/");
+		}
+	    } else
+		/* Otherwise, set path_only to TRUE, so that we clean up
+		 * correctly, free all allocated memory, and return
+		 * NULL. */
+		path_only = TRUE;
+
+	    /* Finally, go back to the path specified in d_here,
+	     * where we were before.  We don't check for a chdir()
+	     * error, since we can do nothing then. */
+	    chdir(d_here);
 
 	    /* Free d_here, since we're done using it. */
 	    free(d_here);
 	}
 
-	/* At this point, if path_only is FALSE and d_there exists,
+	/* At this point, if path_only is FALSE and d_there isn't NULL,
 	 * d_there contains the path portion of the answer and
 	 * d_there_file contains the filename portion of the answer.  If
-	 * this is the case, tack d_there_file onto the end of
-	 * d_there, so that d_there contains the complete answer. */
+	 * this is the case, tack the latter onto the end of the former.
+	 * d_there will then contain the complete answer. */
 	if (!path_only && d_there != NULL) {
 	    d_there = charealloc(d_there, strlen(d_there) +
 		strlen(d_there_file) + 1);
-- 
GitLab