@@ -7760,7 +7760,7 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg
77607760static int
77617761parse_file_actions(PyObject *file_actions,
77627762 posix_spawn_file_actions_t *file_actionsp,
7763- PyObject *temp_buffer, PyObject** cwd )
7763+ PyObject *temp_buffer, PyObject* cwd_buffer )
77647764{
77657765 PyObject *seq;
77667766 PyObject *file_action = NULL;
@@ -7884,8 +7884,10 @@ parse_file_actions(PyObject *file_actions,
78847884 Py_DECREF(path);
78857885 goto fail;
78867886 }
7887- Py_XDECREF(*cwd);
7888- *cwd = path;
7887+ if (PyList_Append(cwd_buffer, path)) {
7888+ Py_DECREF(path);
7889+ goto fail;
7890+ }
78897891 break;
78907892 }
78917893#endif
@@ -7925,7 +7927,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
79257927 Py_ssize_t argc, envc;
79267928 PyObject *result = NULL;
79277929 PyObject *temp_buffer = NULL;
7928- PyObject *cwd = NULL;
7930+ PyObject *cwd_buffer = NULL;
79297931 pid_t pid;
79307932 int err_code;
79317933
@@ -7997,7 +7999,12 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
79977999 if (!temp_buffer) {
79988000 goto exit;
79998001 }
8000- if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer, &cwd)) {
8002+ /* TODO there can be multiple cwd actions .... */
8003+ cwd_buffer = PyList_New(0);
8004+ if (!cwd_buffer) {
8005+ goto exit;
8006+ }
8007+ if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer, cwd_buffer)) {
80018008 goto exit;
80028009 }
80038010 file_actionsp = &file_actions_buf;
@@ -8030,13 +8037,36 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
80308037 if (err_code) {
80318038 errno = err_code;
80328039#ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP
8033- if (errno == ENOENT && cwd != NULL) {
8034- /* ENOENT can occur when either the path of the executable or the
8035- * cwd given via file_actions doesn't exist. Since it's not feasible
8036- * to determine which of those paths caused the problem, we return
8037- * an exception with both. */
8038- PyErr_Format(PyExc_FileNotFoundError, "Either '%S' or '%s' doesn't exist.",
8040+ Py_ssize_t cwd_size = PyList_GET_SIZE(cwd_buffer);
8041+ if (errno == ENOENT && cwd_size > 0) {
8042+ /* ENOENT can occur when either the path of the executable or any of
8043+ * the cwds given via file_actions doesn't exist. Since it's not
8044+ * possible to determine which of those paths caused the problem,
8045+ * we return an exception with all of those. */
8046+
8047+ if (cwd_size == 1) {
8048+ /* the common case */
8049+ PyObject *cwd = PyList_GET_ITEM(cwd_buffer, 0);
8050+ PyErr_Format(PyExc_FileNotFoundError, "Either '%S' or '%s' doesn't exist.",
80398051 path->object, PyBytes_AS_STRING(cwd));
8052+ } else {
8053+ /* TODO ..... */
8054+ PyObject *separator = PyBytes_FromString(", ");
8055+ if (!separator) {
8056+ goto exit;
8057+ }
8058+
8059+ PyObject *joined = PyObject_CallMethod(separator, "join", "O", cwd_buffer);
8060+ Py_DECREF(separator);
8061+ if (!joined) {
8062+ goto exit;
8063+ }
8064+ PyErr_Format(PyExc_FileNotFoundError,
8065+ "Either '%S' or one of (%s) doesn't exist.",
8066+ path->object, PyBytes_AS_STRING(joined));
8067+
8068+ Py_DECREF(joined);
8069+ }
80408070 goto exit;
80418071 }
80428072#endif
@@ -8061,7 +8091,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
80618091 if (argvlist) {
80628092 free_string_array(argvlist, argc);
80638093 }
8064- Py_XDECREF(cwd );
8094+ Py_XDECREF(cwd_buffer );
80658095 Py_XDECREF(temp_buffer);
80668096 return result;
80678097}
0 commit comments