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

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

コミット

  • コミットハッシュ: 58a9268f265843e2720adbcbdaf0bc1d367046a1
  • 作者: David du Colombier (0intro@gmail.com)
  • コミット日時: 2014年2月20日 木曜日 07:59:38 +0100

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

https://github.com/golang/go/commit/58a9268f265843e2720adbcbdaf0bc1d367046a1

元コミット内容

os: fix Rename on Plan 9

Rename should fail when the directory doesn't match.
It will fix the newly introduced test from cmd/pack
on Plan 9.

LGTM=r
R=golang-codereviews, r
CC=golang-codereviews
https://golang.org/cl/65270044

変更の背景

このコミットは、Go言語のosパッケージにおけるRename関数のPlan 9オペレーティングシステム上での挙動を修正することを目的としています。具体的には、Rename関数が、移動元と移動先のディレクトリが一致しない場合に正しくエラーを返すように変更されました。

この修正が必要となった背景には、cmd/packというGoのツール(おそらくアーカイブ関連のツール)で新しく導入されたテストがPlan 9上で失敗するという問題がありました。Rename関数が期待されるエラーを返さないために、このテストが誤った結果を出していたと考えられます。このコミットは、Renameの挙動をOSのセマンティクスに合わせ、テストの失敗を解消するために行われました。

前提知識の解説

  • Plan 9 from Bell Labs: Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、ファイルシステムを中心とした設計思想が特徴です。すべてのリソース(プロセス、ネットワーク接続、デバイスなど)がファイルとして表現され、標準的なファイルシステムインターフェースを通じてアクセスされます。Go言語は、その設計思想の一部をPlan 9から継承しており、Goの初期開発者の中にはPlan 9の開発者が多く含まれています。
  • os.Rename関数: Go言語の標準ライブラリosパッケージに含まれる関数で、ファイルまたはディレクトリの名前を変更したり、移動したりするために使用されます。通常、os.Rename(oldpath, newpath string)という形式で呼び出され、oldpathで指定されたパスのファイルまたはディレクトリをnewpathに移動または名前変更します。
  • LinkError: Go言語のosパッケージで定義されているエラー型の一つです。ファイルシステム操作(リンク、名前変更など)が失敗した場合に返されることがあります。このエラー型は、操作の種類(Op)、古いパス(Old)、新しいパス(New)、そして根本的なエラー(Err)の情報を持ちます。
  • ErrInvalid: Go言語のosパッケージで定義されているエラー変数の一つで、無効な引数や操作が指定された場合に返されることがあります。

技術的詳細

このコミットは、src/pkg/os/file_plan9.goファイル内のrename関数に焦点を当てています。このファイルは、GoのosパッケージがPlan 9オペレーティングシステム上で動作するための特定の実装を含んでいます。

rename関数は、oldname(元のパス)とnewname(新しいパス)を受け取ります。変更前のコードでは、newnameoldnameのディレクトリ部分をプレフィックスとして持っている場合、そのプレフィックスを取り除いて相対パスに変換していました。しかし、newnameoldnameと同じディレクトリにない場合(つまり、ディレクトリをまたぐ移動の場合)、この処理はnewnameを適切に処理せず、Renameが期待されるエラーを返さない可能性がありました。

Plan 9のファイルシステムセマンティクスでは、Rename操作は、移動元と移動先のディレクトリが一致しない場合に失敗すべきです。このコミットは、このセマンティクスを強制するために、newnameoldnameのディレクトリ部分をプレフィックスとして持たない場合に、即座にLinkErrorを返すように修正を加えました。これにより、ディレクトリをまたぐ不適切なRename操作が早期に検出され、エラーとして報告されるようになります。

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

diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index e6496558ca..a804b81973 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -332,6 +332,8 @@ func rename(oldname, newname string) error {
 	dirname := oldname[:lastIndex(oldname, '/')+1]
 	if hasPrefix(newname, dirname) {
 		newname = newname[len(dirname):]
+	} else {
+		return &LinkError{"rename", oldname, newname, ErrInvalid}
 	}
 
 	// If newname still contains slashes after removing the oldname

コアとなるコードの解説

変更はsrc/pkg/os/file_plan9.goファイルのrename関数内で行われています。

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

	dirname := oldname[:lastIndex(oldname, '/')+1]
	if hasPrefix(newname, dirname) {
		newname = newname[len(dirname):]
	}

ここで、oldnameのディレクトリ部分(例: /a/b/cの場合の/a/b/)をdirnameとして抽出し、newnameがそのdirnameで始まるかどうかをチェックしています。もしnewnamedirnameで始まる場合、newnameからdirnameを取り除き、相対パスに変換しています。これは、同じディレクトリ内での名前変更を効率的に処理するためのロジックです。

このコミットで追加されたのは、elseブロックです。

+	} else {
+		return &LinkError{"rename", oldname, newname, ErrInvalid}
 	}

このelseブロックは、newnameoldnamedirnameをプレフィックスとして持たない場合に実行されます。つまり、oldnamenewnameが異なるディレクトリに属している場合です。このような状況は、Plan 9のRenameセマンティクスではエラーと見なされるべきです。

したがって、このelseブロックでは、LinkErrorを生成して返しています。

  • Op: "rename" (操作の種類)
  • Old: oldname (元のパス)
  • New: newname (新しいパス)
  • Err: ErrInvalid (無効な操作であることを示すエラー)

この変更により、os.Rename関数はPlan 9上で、ディレクトリをまたぐ不適切な名前変更/移動操作に対して、より正確なエラーを返すようになりました。これにより、cmd/packのテストが期待通りに失敗し、問題が修正されたと考えられます。

関連リンク

参考にした情報源リンク

  • (特になし。コミットメッセージとGoの標準ライブラリの知識に基づいています。)