mingw: simplify PATH handling

On Windows the environment variable PATH contains a semicolon-separated list of directories to search for, in order, when looking for the location of a binary to run. get_path_split() parses it and returns an array of string copies, which is iterated by path_lookup(), which in turn passes each entry to lookup_prog(). Change lookup_prog() to take the directory name as a length-limited string instead of as a NUL-terminated one and parse PATH directly in path_lookup(). This avoids memory allocations, simplifying the code. Helped-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Rene Scharfe <l.s.r@web.de> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed May 20, 2017 at 21:35 UTC e0ca1ca20a0bde51c4eb9242dd9521ac1ed08304
1 file changed +23 -68
compat/mingw.c
+23 -68
@@ -940,65 +940,15 @@ static const char *parse_interpreter(const char *cmd)
940 return p+1;
941 }
942
943 -/*
944 - * Splits the PATH into parts.
945 - */
946 -static char **get_path_split(void)
947 -{
948 - char *p, **path, *envpath = mingw_getenv("PATH");
949 - int i, n = 0;
950 -
951 - if (!envpath || !*envpath)
952 - return NULL;
953 -
954 - envpath = xstrdup(envpath);
955 - p = envpath;
956 - while (p) {
957 - char *dir = p;
958 - p = strchr(p, ';');
959 - if (p) *p++ = '\0';
960 - if (*dir) { /* not earlier, catches series of ; */
961 - ++n;
962 - }
963 - }
964 - if (!n)
965 - return NULL;
966 -
967 - ALLOC_ARRAY(path, n + 1);
968 - p = envpath;
969 - i = 0;
970 - do {
971 - if (*p)
972 - path[i++] = xstrdup(p);
973 - p = p+strlen(p)+1;
974 - } while (i < n);
975 - path[i] = NULL;
976 -
977 - free(envpath);
978 -
979 - return path;
980 -}
981 -
982 -static void free_path_split(char **path)
983 -{
984 - char **p = path;
985 -
986 - if (!path)
987 - return;
988 -
989 - while (*p)
990 - free(*p++);
991 - free(path);
992 -}
993 -
943 /*
944 * exe_only means that we only want to detect .exe files, but not scripts
945 * (which do not have an extension)
946 */
998 -static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
947 +static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
948 + int isexe, int exe_only)
949 {
950 char path[MAX_PATH];
1001 - snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
951 + snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
952
953 if (!isexe && access(path, F_OK) == 0)
954 return xstrdup(path);
@@ -1013,17 +963,29 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on
963 * Determines the absolute path of cmd using the split path in path.
964 * If cmd contains a slash or backslash, no lookup is performed.
965 */
1016 -static char *path_lookup(const char *cmd, char **path, int exe_only)
966 +static char *path_lookup(const char *cmd, int exe_only)
967 {
968 + const char *path;
969 char *prog = NULL;
970 int len = strlen(cmd);
971 int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
972
973 if (strchr(cmd, '/') || strchr(cmd, '\\'))
1023 - prog = xstrdup(cmd);
974 + return xstrdup(cmd);
975 +
976 + path = mingw_getenv("PATH");
977 + if (!path)
978 + return NULL;
979
1025 - while (!prog && *path)
1026 - prog = lookup_prog(*path++, cmd, isexe, exe_only);
980 + while (!prog) {
981 + const char *sep = strchrnul(path, ';');
982 + int dirlen = sep - path;
983 + if (dirlen)
984 + prog = lookup_prog(path, dirlen, cmd, isexe, exe_only);
985 + if (!*sep)
986 + break;
987 + path = sep + 1;
988 + }
989
990 return prog;
991 }
@@ -1190,8 +1152,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1152 int fhin, int fhout, int fherr)
1153 {
1154 pid_t pid;
1193 - char **path = get_path_split();
1194 - char *prog = path_lookup(cmd, path, 0);
1155 + char *prog = path_lookup(cmd, 0);
1156
1157 if (!prog) {
1158 errno = ENOENT;
@@ -1202,7 +1163,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1163
1164 if (interpr) {
1165 const char *argv0 = argv[0];
1205 - char *iprog = path_lookup(interpr, path, 1);
1166 + char *iprog = path_lookup(interpr, 1);
1167 argv[0] = prog;
1168 if (!iprog) {
1169 errno = ENOENT;
@@ -1220,21 +1181,18 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1181 fhin, fhout, fherr);
1182 free(prog);
1183 }
1223 - free_path_split(path);
1184 return pid;
1185 }
1186
1187 static int try_shell_exec(const char *cmd, char *const *argv)
1188 {
1189 const char *interpr = parse_interpreter(cmd);
1230 - char **path;
1190 char *prog;
1191 int pid = 0;
1192
1193 if (!interpr)
1194 return 0;
1236 - path = get_path_split();
1237 - prog = path_lookup(interpr, path, 1);
1195 + prog = path_lookup(interpr, 1);
1196 if (prog) {
1197 int argc = 0;
1198 const char **argv2;
@@ -1253,7 +1211,6 @@ static int try_shell_exec(const char *cmd, char *const *argv)
1211 free(prog);
1212 free(argv2);
1213 }
1256 - free_path_split(path);
1214 return pid;
1215 }
1216
@@ -1275,8 +1232,7 @@ int mingw_execv(const char *cmd, char *const *argv)
1232
1233 int mingw_execvp(const char *cmd, char *const *argv)
1234 {
1278 - char **path = get_path_split();
1279 - char *prog = path_lookup(cmd, path, 0);
1235 + char *prog = path_lookup(cmd, 0);
1236
1237 if (prog) {
1238 mingw_execv(prog, argv);
@@ -1284,7 +1240,6 @@ int mingw_execvp(const char *cmd, char *const *argv)
1240 } else
1241 errno = ENOENT;
1242
1287 - free_path_split(path);
1243 return -1;
1244 }
1245