3

On linux and macOS, directories can be nested to seemingly arbitrary depth, as demonstrated by the following C program. However, on macOS but not on linux, there seems to be a hard limit on the nesting level returned by getcwd, specifically a nesting level of 256. When that limit is reached, getcwd returns ENOENT, a rather strange error code. Where does this limit come from? Is there a way around it?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>

void fail(char *msg) { perror(msg); exit(1); }

void create_nested_dirs(int n) {

  int i;
  char name[10];
  char cwd[10000];

  if (chdir("/tmp") < 0) fail("chdir(\"/tmp\")");

  for (i=2; i<=n; i++) {
    sprintf(name, "%09d", i);
    printf("%s\n",name);
    if (mkdir(name, 0777) < 0 && errno != EEXIST) fail("mkdir");
    if (chdir(name) < 0) fail("chdir(name)");
    if (getcwd(cwd, sizeof(cwd)) == NULL) fail("getcwd");
    printf("cwd = \"%s\" strlen(cwd)=%d\n", cwd, strlen(cwd));
  }
}

int main() {
  long ret = pathconf("/", _PC_PATH_MAX);
  printf("PATH_MAX is %ld\n", ret);
  create_nested_dirs(300);
  return 0;
}

Update

The above program was updated to print the value returned by pathconf("/", _PC_PATH_MAX) and to print the length of the path returned by getcwd.

On my machine running macOS Mojave 10.14, the PATH_MAX is 1024 and the longest string correctly returned by getcwd is 2542 characters long. Then a 2552 character long directory of nesting depth 256 is created by mkdir and then after a successful chdir to that directory a getcwd fails with ENOENT.

If the sprintf(name, "%09d", i); is changed to sprintf(name, "%03d", i); the paths are considerably shorter but the getcwd still fails when the directory nesting depth reaches 256.

So the limiting factor here is the nesting depth, not PATH_MAX.

My understanding of the source code here is that the meat of the work is done by the call fcntl(fd, F_GETPATH, b) so the problem may be in fcntl.

feeley
  • 71
  • 4
  • It does not appear to be Posix; see [Does POSIX limit the number of directories in the os root?](https://unix.stackexchange.com/q/295999/56041). I seem to recall OS X has a 4K limit on `PATH_MAX`, however. You can query it at runtime with `long ret = pathconf(name, _PC_PATH_MAX);`. – jww Mar 22 '19 at 05:24
  • 2
    The source is [here](https://opensource.apple.com/source/Libc/Libc-1272.200.26/gen/FreeBSD/getcwd.c.auto.html). – Ken Thomases Mar 22 '19 at 06:09

0 Answers0