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

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

コミット

commit 8e109af83badc17ea204e3042005f6cce7fd271b
Author: Alex Brainman <alex.brainman@gmail.com>
Date:   Tue Apr 10 10:07:29 2012 +1000

    os: fix IsPermission on windows
    
    Fixes #3482.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5987070

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

https://github.com/golang/go/commit/8e109af83badc17ea204e3042005f6cce7fd271b

元コミット内容

os: fix IsPermission on windows

このコミットは、Windows環境におけるos.IsPermission関数の動作を修正することを目的としています。具体的には、Goの標準ライブラリであるosパッケージ内のIsPermission関数が、Windows上で発生する特定のパーミッションエラーを正しく識別できない問題を解決します。

変更の背景

Go言語のosパッケージには、ファイル操作などで発生するエラーがパーミッションエラーであるかどうかを判定するためのIsPermission関数が提供されています。しかし、Windows環境では、ファイルやディレクトリへのアクセスが拒否された際に発生するエラーコードが、Goの内部で定義されているErrPermissionとは異なる場合がありました。

このコミットが行われた2012年当時、Goはまだ比較的新しい言語であり、様々なプラットフォームでの互換性やエラーハンドリングの改善が活発に行われていました。Windows環境特有のシステムコールやエラーコードの扱いは、特に注意が必要な領域の一つでした。

この問題は、ユーザーがWindows上でGoアプリケーションを実行した際に、パーミッション関連のエラーが発生してもos.IsPermissionfalseを返し、アプリケーションがエラーの種類を正しく判断できないという形で現れていました。これにより、エラーハンドリングのロジックが複雑になったり、ユーザーに誤解を与える可能性がありました。

コミットメッセージに記載されているFixes #3482は、この変更がGoのIssueトラッカーに登録されていた問題3482を解決するものであることを示唆しています。ただし、現在のGoのIssueトラッカーで#3482を検索すると、このコミットとは無関係な新しいIssueが表示されるため、当時のIssueはクローズされたか、番号が再利用された可能性があります。しかし、コミット内容から、Windowsにおけるパーミッションエラーの正確な識別がこの変更の主要な動機であったことは明らかです。

前提知識の解説

Go言語のエラーハンドリング

Go言語では、エラーはerrorインターフェースによって表現されます。関数がエラーを返す場合、通常は戻り値の最後の要素としてerror型を返します。エラーが発生しなかった場合はnilを返します。

osパッケージ

osパッケージは、オペレーティングシステムと対話するための機能を提供します。これには、ファイルシステム操作、プロセス管理、環境変数へのアクセスなどが含まれます。

os.IsPermission関数

os.IsPermission(err error)関数は、与えられたエラーがパーミッションエラーである場合にtrueを返します。この関数は、ファイルやディレクトリへのアクセス拒否など、権限に関連する問題によって発生したエラーを特定するために使用されます。

os.PathError構造体

os.PathErrorは、パスに関連する操作(例: ファイルのオープン、読み書き)中に発生したエラーを表す構造体です。この構造体は、エラーが発生した操作、エラーが発生したパス、および元のエラー(Errフィールド)を含みます。os.IsPermission関数は、PathErrorがラップしている内部のエラーをチェックすることで、パーミッションエラーを判定します。

os.ErrPermission

os.ErrPermissionは、Goのosパッケージで定義されている、一般的なパーミッションエラーを示すエラー変数です。これは、Unix系システムにおけるEACCESのようなエラーに対応することを意図しています。

syscallパッケージとsyscall.ERROR_ACCESS_DENIED

syscallパッケージは、低レベルのオペレーティングシステムプリミティブへのアクセスを提供します。これには、システムコール、プロセス間通信、およびOS固有のエラーコードなどが含まれます。

syscall.ERROR_ACCESS_DENIEDは、Windows APIで定義されているエラーコードの一つで、アクセスが拒否されたことを示します。これは、ファイルやレジストリキーなどへのアクセス権がない場合に返される一般的なエラーコードです。Goのsyscallパッケージは、これらのOS固有のエラーコードをGoの定数としてラップしています。

技術的詳細

このコミットの技術的な核心は、Windows環境におけるパーミッションエラーの検出ロジックの拡張にあります。Goのos.IsPermission関数は、エラーがos.ErrPermissionと等しいかどうかをチェックすることでパーミッションエラーを判定していました。しかし、Windowsでは、アクセス拒否のエラーが常にos.ErrPermissionとしてラップされるわけではありませんでした。代わりに、Windowsのシステムコールが直接ERROR_ACCESS_DENIEDというエラーコードを返すことがありました。

この修正は、src/pkg/os/error_windows.goファイル内のisPermission関数(os.IsPermissionの実装の一部)を変更することで行われました。変更前は、この関数はPathErrorから元のエラーを取り出し、それがErrPermissionと等しい場合にのみtrueを返していました。

変更後は、isPermission関数は、元のエラーがErrPermissionであるか、またはsyscall.ERROR_ACCESS_DENIEDであるかのいずれかの場合にtrueを返すようになりました。これにより、Windowsが返すERROR_ACCESS_DENIEDエラーも、os.IsPermissionによって正しくパーミッションエラーとして識別されるようになります。

この修正は、GoアプリケーションがWindows上でより堅牢なエラーハンドリングを行うことを可能にし、開発者がプラットフォーム固有のエラーコードを意識することなく、一般的なパーミッションエラーとして処理できるようになります。

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

変更はsrc/pkg/os/error_windows.goファイル内のisPermission関数にあります。

--- a/src/pkg/os/error_windows.go
+++ b/src/pkg/os/error_windows.go
@@ -26,5 +26,5 @@ func isPermission(err error) bool {
 	if pe, ok := err.(*PathError); ok {
 		err = pe.Err
 	}
-	return err == ErrPermission
+	return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission
 }

コアとなるコードの解説

isPermission関数は、Goのosパッケージ内部で、与えられたerrorがパーミッションエラーであるかを判定するために使用されるヘルパー関数です。

  1. if pe, ok := err.(*PathError); ok { err = pe.Err }: この行は、入力されたerr*PathError型であるかどうかをチェックします。もしそうであれば、PathError構造体の内部にラップされている実際のエラー(pe.Err)を取り出し、それをerr変数に再代入します。これは、ファイル操作中に発生するエラーがしばしばPathErrorとしてラップされるため、その内部のエラーを検査する必要があるためです。

  2. return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission: これがこのコミットの核心的な変更点です。

    • 変更前は、return err == ErrPermissionとなっていました。これは、エラーがGoの内部で定義された一般的なパーミッションエラーErrPermissionと完全に一致する場合にのみtrueを返していました。
    • 変更後は、return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermissionとなりました。これにより、エラーがErrPermissionであるか、またはWindowsのシステムコールが返すsyscall.ERROR_ACCESS_DENIEDであるかのいずれかの場合にtrueを返すようになりました。|| (論理OR) 演算子を使用することで、どちらかの条件が満たされればtrueが返されます。

この修正により、Windows環境でファイルアクセス拒否などのパーミッションエラーが発生した場合に、os.IsPermission関数がより正確にそのエラーを識別できるようになり、Goアプリケーションのクロスプラットフォームなエラーハンドリングの信頼性が向上しました。

関連リンク

参考にした情報源リンク