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); + free(d_there); - /* And remove the filename portion of the answer from - * d_there. */ - null_at(&d_there, last_slash - d_there + 1); + /* Get the full path. */ + d_there = charalloc(PATH_MAX + 1); + d_there = getcwd(d_there, PATH_MAX + 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); + /* If we succeeded, canonicalize it in d_there. */ + if (d_there != NULL) { + align(&d_there); - d_there = charalloc(PATH_MAX + 1); - d_there = getcwd(d_there, PATH_MAX + 1); + /* 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; - 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); - } + /* 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);