diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 52aedca459..982d864cb3 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -3314,7 +3314,7 @@ main(int argc, char *argv[]) fprintf(stderr, "%s", authwarning); /* Get directory specification used to start this executable */ - strcpy(bin_dir, argv[0]); + strlcpy(bin_dir, argv[0], sizeof(bin_dir)); get_parent_directory(bin_dir); printf(_("\nSuccess. You can now start the database server using:\n\n" diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 092678604e..c5ec9819ea 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -2052,10 +2052,10 @@ process_file(char *filename, bool single_txn, bool use_relative_path) * relative pathname, then prepend all but the last pathname component * of the current script to this pathname. */ - if (use_relative_path && pset.inputfile && !is_absolute_path(filename) - && !has_drive_prefix(filename)) + if (use_relative_path && pset.inputfile && + !is_absolute_path(filename) && !has_drive_prefix(filename)) { - snprintf(relpath, MAXPGPATH, "%s", pset.inputfile); + strlcpy(relpath, pset.inputfile, sizeof(relpath)); get_parent_directory(relpath); join_path_components(relpath, relpath, filename); canonicalize_path(relpath); diff --git a/src/port/path.c b/src/port/path.c index 738b5cc547..4b4b56d3ad 100644 --- a/src/port/path.c +++ b/src/port/path.c @@ -170,6 +170,8 @@ make_native_path(char *filename) /* * join_path_components - join two path components, inserting a slash * + * We omit the slash if either given component is empty. + * * ret_path is the output area (must be of size MAXPGPATH) * * ret_path can be the same as head, but not the same as tail. @@ -182,38 +184,22 @@ join_path_components(char *ret_path, strlcpy(ret_path, head, MAXPGPATH); /* - * Remove any leading "." and ".." in the tail component, adjusting head - * as needed. + * Remove any leading "." in the tail component. + * + * Note: we used to try to remove ".." as well, but that's tricky to get + * right; now we just leave it to be done by canonicalize_path() later. */ - for (;;) - { - if (tail[0] == '.' && IS_DIR_SEP(tail[1])) - { - tail += 2; - } - else if (tail[0] == '.' && tail[1] == '\0') - { - tail += 1; - break; - } - else if (tail[0] == '.' && tail[1] == '.' && IS_DIR_SEP(tail[2])) - { - trim_directory(ret_path); - tail += 3; - } - else if (tail[0] == '.' && tail[1] == '.' && tail[2] == '\0') - { - trim_directory(ret_path); - tail += 2; - break; - } - else - break; - } + while (tail[0] == '.' && IS_DIR_SEP(tail[1])) + tail += 2; + if (*tail) + { + /* only separate with slash if head wasn't empty */ snprintf(ret_path + strlen(ret_path), MAXPGPATH - strlen(ret_path), - /* only add slash if there is something already in head */ - "%s%s", head[0] ? "/" : "", tail); + "%s%s", + (*(skip_drive(head)) != '\0') ? "/" : "", + tail); + } } @@ -705,6 +691,15 @@ get_home_path(char *ret_path) * * Modify the given string in-place to name the parent directory of the * named file. + * + * If the input is just a file name with no directory part, the result is + * an empty string, not ".". This is appropriate when the next step is + * join_path_components(), but might need special handling otherwise. + * + * Caution: this will not produce desirable results if the string ends + * with "..". For most callers this is not a problem since the string + * is already known to name a regular file. If in doubt, apply + * canonicalize_path() first. */ void get_parent_directory(char *path)