Почему boost:: filesystem:: canonical() требует, чтобы целевой путь существовал?

В документации для boost::filesystem::canonical(const path& p) указано:

Обзор. Преобразует p, который должен существовать, в абсолютный путь, который не имеет символьных ссылок, точек или точек....
Замечания:! Существует (p) - ошибка.

Следствием этого является то, что если p идентифицирует символическую ссылку, цель которой не существует, функция не работает с file not found и не возвращает путь.

Это выглядит слишком ограничительным для меня: только потому, что цель ссылки не существует, я не вижу причин, по которым функция не может решить путь этой несуществующей цели. (Для сравнения, absolute() не налагает такого ограничения.)

(Очевидно, что если символическая ссылка внутри пути нарушена, целевой путь не может быть разрешен.)

Итак, есть ли законное оправдание для этого ограничения?

И даже если есть, нет ли также оправдания для создания варианта функции, который не имеет этого ограничения? (Без такого варианта для получения пути требуется ручная репликация с ошибкой 99% от того, что canonical() уже делает.)

Я понимаю, что семантические тонкости, существующие между stat() и lstat(), одинаково применимы к этому случаю - именно поэтому я считаю, что вариант функции одинаково оправдан.

Примечание. Этот вопрос в равной степени применим к библиотеке std::experimental::filesystem (n4100), которая основана на boost::filesystem.

EDIT:

После того, как @Jonathan Wakeley очень хорошо осведомленный ответ ниже, я все еще остаюсь в сущности моих оригинальных вопросов, которые я немного перефразирую:

  • Существует ли техническая или логическая причина, по которой boost::filesystem::canonical() требует, чтобы цель существовала? Под этим я подразумеваю, что несуществование цели каким-то образом не позволяет решить путь к канонической форме?

  • Если нет, есть ли какая-либо техническая или логическая причина не предлагать вариацию функции, которая отличается только от существующей формы тем, что она не требует, чтобы цель существовала?

  • В преобразовании (как я понимаю, имеет место) boost::filesystem в предлагаемый N4100 std::experimental::filesystem, имеет ли это ограничение на canonical() после должного рассмотрения или просто "проваливается" 'из определения Boost?

ИЗМЕНИТЬ 2:

Я заметил, что Boost 1.60 теперь предоставляет функцию weakly_canonical(): "Возвращает p с разрешенными символическими ссылками и результат нормализуется. Возвращает: Путь, состоящий из результата вызова функции canonical() на пути, состоящем из ведущих элементов of p, которые существуют, если они есть, за которыми следуют элементы из p, которые не существуют, если они есть."

ИЗМЕНИТЬ 3:

Подробнее об этом относительно std::filesystem.

Ответ 1

В основном потому, что это оболочка для realpath, которая имеет такое же требование.

Вы можете задать тот же вопрос realpath, но я думаю, что ответ заключается в том, что если вы пытаетесь найти реальный, физический файл или каталог, к которому относится путь, тогда, если это сломанная символьная ссылка, нет ответа, он не относится к реальному файлу или каталогу, поэтому вы хотите получить ошибку.

В комментарии к модулю ниже указано, что filesystem::canonical и realpath реализуют ту же операцию, но определения в N4100 и POSIX кажутся почти идентичными мне, сравните:

Функция realpath() должна выводить из имени пути, на которое указывает file_name, абсолютное имя пути, которое разрешает одну и ту же запись в каталоге, разрешение которой не включает '.', '..' или символические ссылки.

и

Преобразует p, который должен существовать, в абсолютный путь, который не имеет символической ссылки, "." или ".." элементов.

В обоих случаях требования:

  • нет символических ссылок, если он вернул путь, где последний компонент является символической ссылкой, что требование не будет выполнено.

  • канонический путь относится к тому, что существует, это явное в N4100 и неявное в POSIX, поскольку оно указывает на какую-либо запись в каталоге (то есть что-то существующее) и запись каталога не является символической ссылкой (из-за первого требования).

Что касается требований, которые должны быть такими, примечание в N4100 полезно:

[Примечание: канонические пути позволяют проверять безопасность пути (например, работает ли этот путь в /home/goodguy или /home/badguy?) -end note]

Как я уже говорил выше, если он возвращается успешно, даже когда путь является символической ссылкой, которая на самом деле не указывает на что-либо, вам нужно сделать дополнительную работу, чтобы проверить, разрешает ли он реальному файлу или нет, предназначенный предел использования нет удобный.

И даже если есть, нет ли также оправдания для создания варианта функции, который не имеет этого ограничения? (Без такого варианта для получения пути требуется подверженная ошибкам ручная репликация 99% того, что canonical() уже делает.)

Возможно, этот вариант будет менее полезным, и поэтому не должен быть по умолчанию, но если вам это нужно, то это не сложно сделать:

// like canonical() but allows the last component of p to be a broken symlink
filesystem::path
resolve_most_symlinks(filesystem::path const& p, filesystem::path const& base = filesystem::current_path())
{
  if (is_symlink(p) && !exists(p))
    return canonical(absolute(p, base).remove_filename()) / p.filename();
  return canonical(p);
}

Ответ 2

попробуйте weakly_canonical() для него не требуется существование пути на mac