web-dev-qa-db-ja.com

boost :: filesystem :: canonical()がターゲットパスの存在を必要とするのはなぜですか?

boost::filesystem::canonical(const path& p) のドキュメントには次のように記載されています。

概要:存在する必要があるpを、シンボリックリンク、ドット、またはドットドット要素のない絶対パスに変換します。
.。
備考:!exists(p)はエラーです。

この結果、pがターゲットが存在しないシンボリックリンクを識別した場合、関数は_file not found_で失敗し、パスを返しません。

これは私には過度に制限されているようです。リンクのターゲットが存在しないという理由だけで、関数がその存在しないターゲットのpathを解決できない理由はわかりません。 (比較すると、absolute()はそのような制限を課しません。)

(明らかに、シンボリックリンクwithinパスが壊れている場合、ターゲットパスを解決できません。)

それで、この制限の正当な理由はありますか?

そして、たとえあったとしても、この制限がない関数のバリアントを作成する理由もありませんか? (このようなバリアントがない場合、パスを取得するには、canonical()がすでに実行していることの99%をエラーが発生しやすい手動で複製する必要があります。)

stat()lstat()の間に存在する意味上の微妙な点がこの場合にも等しく当てはまることに感謝します。これが、関数のバリアントが等しく正当化される理由です。

注意:この質問は、_std::experimental::filesystem_に基づく_boost::filesystem_ライブラリ( n41 )にも同様に当てはまります。

編集:

以下の@JonathanWakeleyの非常に知識豊富な回答の後、私はまだ元の質問の本質を残しています。これについては少し再構成します。

  • 根本的な技術的または論理的理由boost::filesystem::canonical()がターゲットの存在を要求する理由はありますか?つまり、ターゲットが存在しないために、正規の形式へのパスを解決することがどういうわけか不可能になっているのでしょうか。

  • そうでない場合、notが必要とするという点で、既存のフォームとのみ異なる関数のバリエーションを提案する技術的または論理的な理由はありますかnot存在するターゲット?

  • _boost::filesystem_から提案されたN4100 _std::experimental::filesystem_への変換(私が理解しているように)では、canonical()に対するこの制限は、十分な検討の後に採用されていますか、それとも単にブーストの定義から落ちていますか?

編集2:

Boost1.60が関数weakly_canonical()を提供することに気づきました: "シンボリックリンクが解決され、結果が正規化されたpを返します。戻り値:パスでcanonical()関数を呼び出した結果で構成されるパス存在する場合はpの先頭要素で構成され、存在する場合は存在しないpの要素が続きます。」

編集3:

これについての詳細な説明 _std::filesystem_に関連して。

14
Jeremy

weakly_canonical()を試してください。Macにパスが存在する必要はありません。

8
apiashko

基本的には、同じ要件を持つ realpath のラッパーであるためです。

realpathについて同じ質問をすることもできますが、答えは、パス名が参照する実際の物理ファイルまたはディレクトリを見つけようとしている場合、それが壊れたシンボリックリンクである場合です。答えはありません。実際のファイルまたはディレクトリを参照していないので、エラーが必要です。

以下のOPのコメントは、filesystem::canonicalrealpathが同じ操作を実装しているという私の主張に疑問を投げかけていますが、N4100とPOSIXの定義は私とほとんど同じようです。比較してください。

realpath()関数は、file_nameが指すパス名から、同じディレクトリエントリに解決される絶対パス名を派生させるものとします。この解決には、'.''..'、またはシンボリックリンクは含まれません。

そして:

存在する必要があるpを、シンボリックリンク、"."、または".."要素のない絶対パスに変換します。

どちらの場合も、要件は次のとおりです。

  • シンボリックリンクなし、最後のコンポーネントがシンボリックリンクであるパスを返した場合、その要件は満たされません。

  • 正規パスは存在するものを参照します。これは、N4100では明示的であり、POSIXではディレクトリエントリ(つまり、存在するもの)を指すという点で暗黙的です。 )およびディレクトリエントリはシンボリックリンクではありません(最初の要件のため)。

なぜこれらが要件である必要があるかについては、N4100の注記が役立ちます。

[注:正規のパス名を使用すると、パスのセキュリティチェックが可能になります(たとえば、このパスは/home/goodguyまたは/home/badguyにありますか?)-文末脚注 ]

すでに上で述べたように、パスが実際には何も指していないシンボリックリンクであっても正常に戻る場合は、解決するかどうかを確認するために追加の作業を行う必要があります実際のファイルにするかどうかに関係なく、使用目的の利便性が低下します。

そして、たとえあったとしても、この制限がない関数のバリアントを作成する理由もありませんか? (このようなバリアントがない場合、パスを取得するには、canonical()がすでに実行しているものの99%のエラーが発生しやすい手動レプリケーションが必要です。)

おそらく、そのバリアントはあまり一般的には役に立たないので、デフォルトにするべきではありませんが、必要な場合は、次のことを行うのは難しくありません。

// 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);
}
6
Jonathan Wakely