From d7ca85c86c03e1267b389a61f51b56675e37fa57 Mon Sep 17 00:00:00 2001
From: David Lawrence Ramsey <pooka109@gmail.com>
Date: Wed, 9 Feb 2005 18:56:21 +0000
Subject: [PATCH] add DB's overhauls of get_full_path() and
 check_writable_directory(), plus a few tweaks of mine

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2312 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
---
 ChangeLog   |   3 +-
 src/files.c | 221 ++++++++++++++++++++++++++--------------------------
 2 files changed, 111 insertions(+), 113 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f827a956..c1e790fe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -151,7 +151,8 @@ CVS code -
 	  get_totals(), and do_cursorpos(). (DLR)
 	- Overhaul the tab completion code and a few related functions
 	  to increase efficiency and support multibyte characters.  New
-	  functions strrchrn() and is_dir(); changes to diralphasort(),
+	  functions strrchrn() and is_dir(); changes to get_full_path(),
+	  check_writable_directory(), diralphasort(),
 	  username_tab_completion(), cwd_tab_completion(), input_tab(),
 	  tail(), and striponedir(); removal of append_slash_if_dir()
 	  and check_wildcard_match(). (David Benbennick)  DLR: Move the
diff --git a/src/files.c b/src/files.c
index e0b0a056..68227817 100644
--- a/src/files.c
+++ b/src/files.c
@@ -969,160 +969,157 @@ bool close_open_file(void)
 #endif /* ENABLE_MULTIBUFFER */
 
 #if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR)
-/*
- * When passed "[relative path]" or "[relative path][filename]" in
+/* When passed "[relative path]" or "[relative path][filename]" in
  * origpath, return "[full path]" or "[full path][filename]" on success,
- * or NULL on error.  This is still done if the file doesn't exist but
- * the relative path does (since the file could exist in memory but not
- * yet on disk); it is not done if the relative path doesn't exist (since
- * the first call to chdir() will fail then).
- */
+ * or NULL on error.  Do this if the file doesn't exist but the relative
+ * path does, since the file could exist in memory but not yet on disk).
+ * Don't do this if the relative path doesn't exist, since we won't be
+ * able to go there. */
 char *get_full_path(const char *origpath)
 {
-    char *newpath = NULL, *last_slash, *d_here, *d_there, *d_there_file, tmp;
-    int path_only, last_slash_index;
-    struct stat fileinfo;
-    char *expanded_origpath;
+    char *d_here, *d_there = NULL;
 
-    /* first, get the current directory, and tack a slash onto the end of
-       it, unless it turns out to be "/", in which case leave it alone */
+    if (origpath == NULL)
+    	return NULL;
 
-    d_here = getcwd(NULL, PATH_MAX + 1);
+    /* Get the current directory. */
+#if PATH_MAX != -1
+    d_here = charalloc(PATH_MAX + 1);
+#else
+    d_here = NULL;
+#endif
+    d_here = getcwd(d_here, PATH_MAX + 1);
+#if PATH_MAX != -1
+    align(&d_here);
+#endif
 
     if (d_here != NULL) {
+	const char *last_slash;
+	char *d_there_file = NULL;
+	bool path_only;
+	struct stat fileinfo;
 
-	align(&d_here);
+	/* If the current directory isn't "/", tack a slash onto the end
+	 * of it. */
 	if (strcmp(d_here, "/") != 0) {
 	    d_here = charealloc(d_here, strlen(d_here) + 2);
 	    strcat(d_here, "/");
 	}
 
-	/* stat origpath; if stat() fails, assume that origpath refers to
-	   a new file that hasn't been saved to disk yet (i. e. set
-	   path_only to 0); if stat() succeeds, set path_only to 0 if
-	   origpath doesn't refer to a directory, or to 1 if it does */
-	path_only = !stat(origpath, &fileinfo) && S_ISDIR(fileinfo.st_mode);
-
-	expanded_origpath = real_dir_from_tilde(origpath);
-	/* save the value of origpath in both d_there and d_there_file */
-	d_there = mallocstrcpy(NULL, expanded_origpath);
-	d_there_file = mallocstrcpy(NULL, expanded_origpath);
-	free(expanded_origpath);
-
-	/* if we have a path but no filename, tack slashes onto the ends
-	   of both d_there and d_there_file, if they don't end in slashes
-	   already */
+	d_there = real_dir_from_tilde(origpath);
+
+	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 path_only is TRUE, make sure d_there ends in a slash. */
 	if (path_only) {
-	    tmp = d_there[strlen(d_there) - 1];
-	    if (tmp != '/') {
-		d_there = charealloc(d_there, strlen(d_there) + 2);
+	    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, "/");
-		d_there_file = charealloc(d_there_file, strlen(d_there_file) + 2);
-		strcat(d_there_file, "/");
 	    }
 	}
 
-	/* search for the last slash in d_there */
+	/* Search for the last slash in d_there. */
 	last_slash = strrchr(d_there, '/');
 
-	/* if we didn't find one, copy d_here into d_there; all data is
-	   then set up */
-	if (last_slash == NULL)
-	    d_there = mallocstrcpy(d_there, d_here);
-	else {
-	    /* otherwise, remove all non-path elements from d_there
-	       (i. e. everything after the last slash) */
-	    last_slash_index = strlen(d_there) - strlen(last_slash);
-	    null_at(&d_there, last_slash_index + 1);
-
-	    /* and remove all non-file elements from d_there_file (i. e.
-	       everything before and including the last slash); if we
-	       have a path but no filename, don't do anything */
-	    if (!path_only) {
-		last_slash = strrchr(d_there_file, '/');
-		last_slash++;
-		strcpy(d_there_file, last_slash);
-		align(&d_there_file);
-	    }
-
-	    /* now go to the path specified in d_there */
-	    if (chdir(d_there) != -1) {
-		/* get the full pathname, and save it back in d_there,
-		   tacking a slash on the end if we have a path but no
-		   filename; if the saving fails, get out */
+	/* 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;
+	} 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 = getcwd(NULL, PATH_MAX + 1);
-
+		d_there = NULL;
+	    } else {
+		/* Get the full path and save it in d_there. */
+		free(d_there);
+#if PATH_MAX != -1
+		d_there = charalloc(PATH_MAX + 1);
+#else
+		d_there = NULL;
+#endif
+		d_there = getcwd(d_there, PATH_MAX + 1);
+#if PATH_MAX != -1
 		align(&d_there);
-		if (d_there != NULL) {
-
-		    /* add a slash to d_there, unless it's "/", in which
-		       case we don't need it */
-		    if (strcmp(d_there, "/") != 0) {
-			d_there = charealloc(d_there, strlen(d_there) + 2);
-			strcat(d_there, "/");
-		    }
+#endif
+
+		if (d_there == NULL)
+		    /* 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;
+		else 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
-		    return NULL;
+
+		/* Finally, go back to the path specified in d_here,
+		 * where we were before. */
+		chdir(d_here);
 	    }
 
-	    /* finally, go back to where we were before, d_here (no error
-	       checking is done on this chdir(), because we can do
-	       nothing if it fails) */
-	    chdir(d_here);
-	}
-	
-	/* all data is set up; fill in newpath */
-
-	/* if we have a path and a filename, newpath = d_there +
-	   d_there_file; otherwise, newpath = d_there */
-	if (!path_only) {
-	    newpath = charalloc(strlen(d_there) + strlen(d_there_file) + 1);
-	    strcpy(newpath, d_there);
-	    strcat(newpath, d_there_file);
-	}
-	else {
-	    newpath = charalloc(strlen(d_there) + 1);
-	    strcpy(newpath, d_there);
+	    /* Free d_here, since we're done using it. */
+	    free(d_here);
 	}
 
-	/* finally, clean up */
+	/* At this point, if path_only is FALSE and d_there exists,
+	 * 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. */
+	if (!path_only && d_there) {
+	    d_there = charealloc(d_there, strlen(d_there) +
+		strlen(d_there_file) + 1);
+	    strcat(d_there, d_there_file);
+ 	}
+
+	/* Free d_there_file, since we're done using it. */
 	free(d_there_file);
-	free(d_there);
-	free(d_here);
     }
 
-    return newpath;
+    return d_there;
 }
 #endif /* !DISABLE_SPELLER || !DISABLE_OPERATINGDIR */
 
 #ifndef DISABLE_SPELLER
-/*
- * This function accepts a path and returns the full path (via
- * get_full_path()).  On error, if the path doesn't reference a
- * directory, or if the directory isn't writable, it returns NULL.
- */
+/* Return the full version of path, as returned by get_full_path().  On
+ * error, if path doesn't reference a directory, or if the directory
+ * isn't writable, return NULL. */
 char *check_writable_directory(const char *path)
 {
     char *full_path = get_full_path(path);
-    int writable;
-    struct stat fileinfo;
 
-    /* if get_full_path() failed, return NULL */
+    /* If get_full_path() fails, return NULL. */
     if (full_path == NULL)
 	return NULL;
 
-    /* otherwise, stat() the full path to see if it's writable by the
-       user; set writable to 1 if it is, or 0 if it isn't */
-    writable = !stat(full_path, &fileinfo) && (fileinfo.st_mode & S_IWUSR);
-
-    /* if the full path doesn't end in a slash (meaning get_full_path()
-       found that it isn't a directory) or isn't writable, free full_path
-       and return NULL */
-    if (full_path[strlen(full_path) - 1] != '/' || writable == 0) {
+    /* If we can't write to path or path isn't a directory, return
+     * NULL. */
+    if (access(full_path, W_OK) != 0 ||
+		full_path[strlen(full_path) - 1] != '/') {
 	free(full_path);
 	return NULL;
     }
-- 
GitLab