nano-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] tweaks: make use of realpath() in our get_full_path() function


From: Benno Schulenberg
Subject: [PATCH] tweaks: make use of realpath() in our get_full_path() function
Date: Thu, 31 Mar 2022 17:14:43 +0200

Since 2008, realpath() with NULL as second parameter is part of the
POSIX standard.  Operating systems have had nearly fourteen years to
catch up -- this should be time enough.

Using realpath() saves seventy lines of code and gets rid of some
weirdly complicated logic plus unwanted calls of chdir().

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
 src/files.c | 106 +++++++++-------------------------------------------
 1 file changed, 18 insertions(+), 88 deletions(-)

diff --git a/src/files.c b/src/files.c
index 9c598e1f..6641de01 100644
--- a/src/files.c
+++ b/src/files.c
@@ -1345,106 +1345,36 @@ void do_execute(void)
  * absolute path (plus filename) when the path exists, and NULL when not. */
 char *get_full_path(const char *origpath)
 {
-       char *allocation, *here, *target, *last_slash;
-       char *just_filename = NULL;
-       int attempts = 0;
+       char *untilded, *target, *slash;
        struct stat fileinfo;
-       bool path_only;
 
        if (origpath == NULL)
                return NULL;
 
-       allocation = nmalloc(PATH_MAX + 1);
-       here = getcwd(allocation, PATH_MAX + 1);
+       untilded = real_dir_from_tilde(origpath);
+       target = realpath(untilded, NULL);
+       slash = strrchr(untilded, '/');
 
-       /* If getting the current directory failed, go up one level and try 
again,
-        * until we find an existing directory, and use that as the current 
one. */
-       while (here == NULL && attempts < 20) {
-               IGNORE_CALL_RESULT(chdir(".."));
-               here = getcwd(allocation, PATH_MAX + 1);
-               attempts++;
-       }
-
-       /* If we found a directory, make sure its path ends in a slash. */
-       if (here != NULL) {
-               if (strcmp(here, "/") != 0) {
-                       here = nrealloc(here, strlen(here) + 2);
-                       strcat(here, "/");
-               }
-       } else {
-               here = copy_of("");
-               free(allocation);
-       }
-
-       target = real_dir_from_tilde(origpath);
-
-       /* Determine whether the target path refers to a directory.  If statting
-        * target fails, however, assume that it refers to a new, unsaved 
buffer. */
-       path_only = (stat(target, &fileinfo) != -1 && 
S_ISDIR(fileinfo.st_mode));
-
-       /* If the target is a directory, make sure its path ends in a slash. */
-       if (path_only) {
-               size_t length = strlen(target);
-
-               if (target[length - 1] != '/') {
-                       target = nrealloc(target, length + 2);
-                       strcat(target, "/");
-               }
-       }
-
-       last_slash = strrchr(target, '/');
-
-       /* If the target path does not contain a slash, then it is a bare 
filename
-        * and must therefore be located in the working directory. */
-       if (last_slash == NULL) {
-               just_filename = target;
-               target = here;
-       } else {
-               /* If target contains a filename, separate the two. */
-               if (!path_only) {
-                       just_filename = copy_of(last_slash + 1);
-                       *(last_slash + 1) = '\0';
-               }
-
-               /* If we can't change to the target directory, give up.  
Otherwise,
-                * get the canonical path to this target directory. */
-               if (chdir(target) == -1) {
-                       free(target);
-                       target = NULL;
-               } else {
-                       free(target);
-
-                       allocation = nmalloc(PATH_MAX + 1);
-                       target = getcwd(allocation, PATH_MAX + 1);
-
-                       /* If we got a result, make sure it ends in a slash.
-                        * Otherwise, ensure that we return NULL. */
-                       if (target != NULL) {
-                               if (strcmp(target, "/") != 0) {
-                                       target = nrealloc(target, 
strlen(target) + 2);
-                                       strcat(target, "/");
-                               }
-                       } else {
-                               path_only = TRUE;
-                               free(allocation);
-                       }
+       /* If realpath() returned NULL, try without the last component,
+        * as this can be a file that does not exist yet. */
+       if (!target && slash && slash[1]) {
+               *slash = '\0';
+               target = realpath(untilded, NULL);
 
-                       /* Finally, go back to where we were before.  We don't 
check
-                        * for an error, since we can't do anything if we get 
one. */
-                       IGNORE_CALL_RESULT(chdir(here));
+               /* Upon success, re-add the last component of the original 
path. */
+               if (target) {
+                       target = nrealloc(target, strlen(target) + strlen(slash 
+ 1) + 1);
+                       strcat(target, slash + 1);
                }
-
-               free(here);
        }
 
-       /* If we were given more than a bare path, concatenate the target path
-        * with the filename portion to get the full, absolute file path. */
-       if (!path_only && target != NULL) {
-               target = nrealloc(target, strlen(target) + 
strlen(just_filename) + 1);
-               strcat(target, just_filename);
+       /* Ensure that a directory path ends with a slash. */
+       if (target && stat(target, &fileinfo) == 0 && 
S_ISDIR(fileinfo.st_mode)) {
+               target = nrealloc(target, strlen(target) + 2);
+               strcat(target, "/");
        }
 
-       free(just_filename);
+       free(untilded);
 
        return target;
 }
-- 
2.34.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]