- /* Keep the old directory cached and report open failure,
- unless EMFILE/ENFILE means it's possible that falling
- through to close the old directory would mean we
- could successfully retry from the chdir_fd level.
- When reporting failure, there is no need to
- null-terminate the old directory, since the code does
- not assume null termination. */
- if (errno != EMFILE && errno != ENFILE)
- return (struct fdbase) { .fd = BADFD, .base = base };
+ /* The new directory is a subdirectory of the old,
+ so open relative to FD rather than to chdir_fd. */
+ int subfd = open_subdir (fd, &subdir[c->subdirlen],
+ child_oflags);
+ if (subfd < 0)
+ {
+ /* Keep the old directory cached and report open failure,
+ unless EMFILE/ENFILE means it's possible that falling
+ through to close the old directory would mean we
+ could successfully retry from the chdir_fd level.
+ When reporting failure, there is no need to
+ null-terminate the old directory, since the code does
+ not assume null termination. */
+ if (errno != EMFILE && errno != ENFILE)
+ return (struct fdbase) { .fd = BADFD, .base = base };
+ }
+ else
+ {
+ /* Replace the old directory with the new one. */
+ if (!chdirable (fd))
+ close (fd);
+ c->fd = subfd;
+ c->subdirlen = subdirlen;
+ return (struct fdbase) { .fd = subfd, .base = base };
+ }