nano-devel
[Top][All Lists]
Advanced

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

Re: [Nano-devel] nano hates it when you delete $PWD


From: David Lawrence Ramsey
Subject: Re: [Nano-devel] nano hates it when you delete $PWD
Date: Wed, 05 Jul 2006 11:48:12 -0400
User-agent: Thunderbird 1.5.0.4 (X11/20060516)

Mike Frysinger wrote:
> $ mkdir foo
> $ cd foo
> $ nano
> <works fine>
> $ rmdir $PWD
> $ nano
>
> Error in /etc/nanorc on line 218: Error reading
> /usr/share/nano/nanorc.nanorc: No such file or directory

Thanks for the report.  The attached patch (which is already in CVS)
seems to fix this.  The problem is actually in get_full_path(), which
would return NULL if the current directory didn't exist.  It now backs
up until it finds an existing directory, and if that fails, it uses ""
as the current directory.

Note that there's one minor issue: it assumes that if it backs up far
enough, there will always be an existing path, so if getcwd() fails on
"/", nano will go into an infinite loop.  However, there appears to be
no way of knowing if we've backed up to "/" if getcwd() fails, and,
besides, if it fails there, you have much worse problems.

In any case, I hope it's acceptable.

diff -ur nano-1.3.12/src/files.c nano-1.3.12-fixed/src/files.c
--- nano-1.3.12/src/files.c     2006-06-14 09:19:43.000000000 -0400
+++ nano-1.3.12-fixed/src/files.c       2006-07-05 11:44:17.000000000 -0400
@@ -902,21 +902,29 @@
  * 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, and use that as the
+     * current directory. */
     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 +933,91 @@
            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 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 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);
 
-       /* Search for the last slash in d_there. */
-       last_slash = strrchr(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 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 (d_there[d_there_len - 1] != '/') {
+           d_there = charealloc(d_there, d_there_len + 2);
+           strcat(d_there, "/");
+       }
+    }
 
-           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 = NULL;
-           } else {
-               /* Get the full path and save it in d_there. */
-               free(d_there);
+    /* Search for the last slash in d_there. */
+    last_slash = strrchr(d_there, '/');
 
-               d_there = charalloc(PATH_MAX + 1);
-               d_there = getcwd(d_there, PATH_MAX + 1);
+    /* 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 (d_there != NULL) {
-                   align(&d_there);
+       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 = NULL;
+       } else {
+           free(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);
-           }
+           /* Get the full path. */
+           d_there = charalloc(PATH_MAX + 1);
+           d_there = getcwd(d_there, PATH_MAX + 1);
+
+           /* If we succeeded, canonicalize it in d_there. */
+           if (d_there != NULL) {
+               align(&d_there);
+
+               /* 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);

reply via email to

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