Какова причина жесткого ограничения на глубину вложенности каталогов, возвращаемого getcwd в macOS, и как его можно обойти? - PullRequest
3 голосов
/ 22 марта 2019

В linux и macOS каталоги могут быть вложены на кажущуюся произвольную глубину, как показано в следующей программе на Си. Однако в macOS, но не в linux, существует жесткое ограничение на уровень вложенности, возвращаемый getcwd, в частности уровень вложенности 256. Когда этот предел достигнут, getcwd возвращает ENOENT, довольно странный код ошибки. Откуда этот предел? Есть ли способ обойти это?

#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;
}

Обновление

Вышеприведенная программа была обновлена ​​для печати значения, возвращенного pathconf("/", _PC_PATH_MAX), и для печати длины пути, возвращенного getcwd.

На моей машине с MacOS Mojave 10.14 PATH_MAX равен 1024, а самая длинная строка, правильно возвращаемая getcwd, имеет длину 2542 символа. Затем каталог * 2552 символа длиной 256 вложений создается с помощью mkdir, а затем после успешного chdir в этот каталог getcwd завершается неудачно с ENOENT.

Если sprintf(name, "%09d", i); изменить на sprintf(name, "%03d", i);, пути будут значительно короче, но getcwd все равно не удастся, когда глубина вложения каталога достигает 256.

Таким образом, ограничивающим фактором здесь является глубина вложения, а не PATH_MAX.

Мое понимание исходного кода здесь заключается в том, что основная часть работы выполняется вызовом fcntl(fd, F_GETPATH, b), поэтому проблема может быть в fcntl.

...