Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 17835] ファイルの概要

このコミットは、Goプロジェクトのコードレビューシステムに関連するPythonスクリプトである lib/codereview/codereview.py の変更です。具体的には、Plan 9オペレーティングシステム上でのファイル作成パーミッションの問題を修正しています。

コミット

commit 6d86d064e5b060ef7ab665ec5d6e3772090a7694
Author: Jeff Sickel <jas@corpus-callosum.com>
Date:   Wed Oct 23 10:28:28 2013 -0400

    plan9: correct create permissions with union directory

    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/15360045

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/6d86d064e5b060ef7ab665ec5d6e3772090a7694

元コミット内容

plan9: correct create permissions with union directory

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/15360045

変更の背景

このコミットは、Plan 9オペレーティングシステム上でGoのコードレビューツールを使用する際に発生していた、ユニオンディレクトリ(union directory)におけるファイル作成パーミッションの問題を解決するために行われました。

Plan 9では、複数のディレクトリを単一の論理的なディレクトリとして結合する「ユニオンディレクトリ」という強力な機能があります。これは、異なるソースからのファイルを透過的にアクセスできるようにするために使用されます。codereview.py スクリプトは、ユーザーのホームディレクトリ (~) とその中の ~/lib ディレクトリをユニオンディレクトリとしてバインドしていました。

しかし、このバインド設定だけでは、ユニオンされたディレクトリ内で新しいファイルを正しく作成するためのパーミッションが不足している場合がありました。具体的には、plan9.bind 関数に plan9.MBEFORE フラグのみを指定した場合、既存のファイルへのアクセスは可能でも、新しいファイルの作成が意図した通りに行われない、あるいはパーミッションエラーが発生する可能性がありました。この問題は、コードレビュープロセスにおいて、一時ファイルや設定ファイルなどの作成が必要な場合に支障をきたしていました。

このコミットは、plan9.bind 呼び出しに plan9.MCREATE フラグを追加することで、このファイル作成パーミッションの問題を修正し、Plan 9環境での codereview.py の正常な動作を保証することを目的としています。

前提知識の解説

Plan 9 from Bell Labs

Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。その設計哲学は「すべてをファイルとして扱う」というもので、プロセス、ネットワーク接続、デバイスなど、システム内のあらゆるリソースがファイルシステムを通じてアクセスされます。これにより、シンプルで一貫性のあるインターフェースが提供され、分散システムを容易に構築できます。

ユニオンディレクトリ (Union Directory) / 名前空間の結合

Plan 9の最も特徴的な機能の一つが「名前空間の結合(namespace merging)」、一般に「ユニオンディレクトリ」と呼ばれるものです。これは、複数のディレクトリの内容を単一の論理的なディレクトリツリーに結合する機能です。例えば、/usr/local/bin/usr/bin/bin に結合することで、ユーザーは両方のディレクトリにある実行ファイルを /bin から透過的にアクセスできます。

ユニオンディレクトリは、bind システムコールによって実現されます。bind は、あるディレクトリを別のディレクトリに「マウント」するような操作ですが、既存のディレクトリの内容を置き換えるのではなく、結合します。結合の順序(どちらのディレクトリが優先されるか)や、ファイル作成時の挙動などを制御するためのフラグが提供されます。

plan9.bind 関数

plan9.bind は、Plan 9のファイルシステム操作をPythonから行うためのインターフェースを提供する関数です。これは、Plan 9の bind システムコールをラップしたものです。

bind(new, old, flags) の形式で呼び出され、new ディレクトリを old ディレクトリにバインドします。flags はバインドの挙動を制御するビットマスクです。

MBEFORE フラグ

plan9.MBEFOREbind システムコールで使用されるフラグの一つです。このフラグが指定されると、new ディレクトリの内容が old ディレクトリの既存の内容の「前に」結合されます。つまり、同じ名前のファイルやディレクトリが存在する場合、new ディレクトリ内のものが優先されます。これは、既存のパスを上書きすることなく、新しいパスを追加する際に便利です。

MCREATE フラグ

plan9.MCREATEbind システムコールで使用されるフラグの一つです。このフラグは、ユニオンディレクトリ内で新しいファイルを作成する際の挙動を制御します。MCREATE が設定されている場合、新しいファイルはユニオンされたディレクトリの「最も上位のレイヤー」に作成されます。つまり、MBEFORE で結合されたディレクトリがある場合、そのディレクトリ内に新しいファイルが作成されます。このフラグがない場合、ファイル作成が許可されないか、意図しない場所に作成される可能性があります。

codereview.py スクリプト

codereview.py は、Goプロジェクトの初期のコードレビューシステム(おそらくGerritのようなツールと連携していたか、あるいは独自のシステムの一部)とやり取りするためのPythonスクリプトです。開発者が変更をアップロードしたり、レビューコメントを取得したりするために使用されていました。このスクリプトは、Plan 9を含む様々なプラットフォームで動作するように設計されており、プラットフォーム固有のファイルシステム操作を行う必要がありました。

技術的詳細

このコミットの技術的な核心は、Plan 9のユニオンディレクトリにおけるファイル作成のセマンティクスを正しく理解し、適用することにあります。

元のコードでは、以下の行がありました。

n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE)

この行は、ユーザーのホームディレクトリ (~) に ~/lib ディレクトリをバインドし、~/lib の内容が ~ の既存の内容よりも優先されるように設定していました。これは、~/lib にあるツールや設定ファイルを ~ から直接アクセスできるようにするための一般的なパターンです。

しかし、plan9.MBEFORE フラグだけでは、ユニオンされた ~ ディレクトリ内で新しいファイルを「作成」する際のパーミッションが適切に処理されませんでした。Plan 9の bind システムコールは、デフォルトでは結合されたディレクトリでのファイル作成を許可しないか、あるいは作成されたファイルの場所が意図しないものになる可能性があります。

この問題を解決するために、コミットでは plan9.MCREATE フラグが追加されました。

n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE|plan9.MCREATE)

ここで使用されている | はビットごとのOR演算子です。これにより、plan9.MBEFOREplan9.MCREATE の両方のフラグが bind システムコールに渡されます。

  • plan9.MBEFORE: ~/lib の内容が ~ の既存の内容より優先されることを保証します。
  • plan9.MCREATE: ユニオンされたディレクトリ (~) 内で新しいファイルが作成されることを明示的に許可し、そのファイルが MBEFORE によって優先される ~/lib のレイヤーに作成されるようにします。

この変更により、codereview.py がPlan 9環境で実行される際に、一時ファイルやその他の必要なファイルをユニオンディレクトリ内で正しく作成できるようになり、スクリプトの機能が完全に動作するようになりました。これは、Plan 9のファイルシステムが持つ独特のセマンティクスを理解し、それに対応した適切なシステムコールフラグを使用することの重要性を示しています。

コアとなるコードの変更箇所

--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -65,7 +65,7 @@ from mercurial import util as hg_util
 if os.sys.platform == 'plan9':
 	try:
 		import plan9
-		n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE)
+		n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE|plan9.MCREATE)
 	except ImportError:
 		pass

コアとなるコードの解説

変更は lib/codereview/codereview.py ファイルの以下の1行です。

-		n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE)
+		n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE|plan9.MCREATE)

この変更は、plan9.bind 関数の第三引数である flagsplan9.MCREATE を追加しています。

  • os.sys.platform == 'plan9' の条件分岐は、このコードがPlan 9オペレーティングシステム上で実行されている場合にのみ適用されることを示しています。
  • import plan9 は、Plan 9固有のシステムコールをPythonから利用するためのモジュールをインポートしています。
  • os.path.expanduser("~/lib") は、ユーザーのホームディレクトリ内の lib ディレクトリへの絶対パスを生成します。
  • os.path.expanduser("~") は、ユーザーのホームディレクトリへの絶対パスを生成します。
  • plan9.bind(source, destination, flags) は、source ディレクトリを destination ディレクトリにバインドするPlan 9のシステムコールを呼び出します。
  • 変更前は plan9.MBEFORE のみがフラグとして渡されていました。これは ~/lib の内容が ~ の内容より優先されることを意味します。
  • 変更後は plan9.MBEFORE|plan9.MCREATE となり、ビットごとのOR演算子 (|) を使って MBEFOREMCREATE の両方のフラグが結合されています。これにより、~/lib~ の前にバインドされるだけでなく、ユニオンされた ~ ディレクトリ内で新しいファイルを作成する操作も許可されるようになります。

この修正により、Plan 9環境で codereview.py がファイルを作成する必要がある場合に、適切なパーミッションと場所でファイルが作成されることが保証されます。

関連リンク

参考にした情報源リンク

  • Plan 9 from Bell Labs Documentation (特に bind(2) manページ)
  • Goプロジェクトのコードレビューシステムの歴史に関する情報 (Gerrit導入以前の状況)
  • Pythonの os モジュールに関するドキュメント
  • ビットごとの演算子に関する一般的なプログラミング知識