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

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

このコミットは、Go言語の path/filepath パッケージにおけるWindows固有のパス処理に関するバグ修正です。具体的には、Windowsのドライブレターが数字であるケースを誤って認識していた問題を修正し、ドライブレターはアルファベットのみであることを明確にしています。

コミット

path/filepath: Windowsのドライブレターは数字であってはならない

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

https://github.com/golang/go/commit/f39ff80beaab4b366917575e5addcbdd551563c2

元コミット内容

commit f39ff80beaab4b366917575e5addcbdd551563c2
Author: Alex Brainman <alex.brainman@gmail.com>
Date:   Fri Mar 23 15:57:19 2012 +1100

    path/filepath: windows drive letter cannot be a digit
    
    R=golang-dev, r
    CC=golang-dev, mattn.jp
    https://golang.org/cl/5885056

変更の背景

このコミットの背景には、Windowsオペレーティングシステムにおけるファイルパスのドライブレターの認識に関する誤解がありました。Go言語の path/filepath パッケージは、OSに依存しないパス操作を提供しますが、各OSのパス規則に合わせた内部実装を持っています。

Windowsのファイルパスでは、通常 C:D: のように、アルファベット一文字とコロンでドライブレターが表現されます。しかし、以前の実装では、ドライブレターの最初の文字が数字である場合(例: 2:)も有効なドライブレターとして誤って認識してしまう可能性がありました。これは、Windowsの標準的なパス命名規則に反する動作であり、予期せぬパス解析の結果や、セキュリティ上の問題を引き起こす可能性がありました。

このコミットは、この誤った認識を修正し、path/filepath パッケージがWindowsのドライブレターをより正確に、すなわちアルファベットのみとして扱うように変更することを目的としています。これにより、パッケージの堅牢性とWindowsパス処理の正確性が向上します。

前提知識の解説

Windowsのファイルパスとドライブレター

Windowsのファイルパスは、UNIX系のパスとは異なり、ドライブレターの概念を持ちます。

  • ドライブレター: C:, D:, E: のように、単一のアルファベットとそれに続くコロンで構成されます。これは特定のストレージデバイスやパーティションを指します。
  • 絶対パス: ドライブレターから始まるパス(例: C:\Users\User\Documents\file.txt)。
  • 相対パス: 現在のディレクトリからの相対的なパス(例: ..\..\file.txt)。
  • UNCパス: ネットワーク上の共有リソースを指すパス(例: \\Server\Share\file.txt)。

重要なのは、Windowsのドライブレターは常にアルファベットであるという点です。数字がドライブレターとして使用されることはありません。

Go言語の path/filepath パッケージ

path/filepath パッケージは、Go言語の標準ライブラリの一部であり、ファイルパスを操作するための関数を提供します。このパッケージは、オペレーティングシステムに依存しないパス操作(例: パスの結合、ファイル名の抽出、ディレクトリ名の抽出など)を可能にすると同時に、各OSのパス規則に合わせた内部的な処理を行います。

  • filepath.VolumeName(path string) string: この関数は、与えられたパスのボリューム名(WindowsではドライブレターやUNCパスのホスト名部分)を返します。例えば、C:\foo\bar に対しては C: を返します。

このコミットで修正されるのは、filepath.VolumeName 関数がWindowsパスを解析する際のロジックです。

技術的詳細

このコミットの技術的な核心は、src/pkg/path/filepath/path_windows.go ファイル内の VolumeName 関数の条件式変更にあります。

変更前は、ドライブレターの最初の文字が以下のいずれかである場合に有効なドライブレターとして認識していました。

  • 数字 ('0' から '9')
  • 小文字のアルファベット ('a' から 'z')
  • 大文字のアルファベット ('A' から 'Z')
// 変更前
if path[1] == ':' &&
    ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
        'A' <= c && c <= 'Z') {
    return path[:2]
}

しかし、Windowsのドライブレターは数字ではありえません。このため、'0' <= c && c <= '9' の条件は誤りでした。

コミット後のコードでは、この数字のチェックが削除され、ドライブレターの最初の文字がアルファベット(小文字または大文字)である場合にのみ有効なドライブレターとして認識するように修正されました。

// 変更後
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
    return path[:2]
}

この変更により、2: のようなパスが VolumeName 関数によって空のボリューム名として正しく扱われるようになります。

また、src/pkg/path/filepath/path_test.go には、この変更を検証するための新しいテストケースが追加されています。 {2:, ``} というテストケースが追加され、2: というパスに対して VolumeName が空文字列を返すことを期待しています。これは、数字がドライブレターとして無効であることを明確にテストするものです。

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

src/pkg/path/filepath/path_test.go

--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -814,6 +814,7 @@ type VolumeNameTest struct {
 var volumenametests = []VolumeNameTest{
 	{`c:/foo/bar`, `c:`},
 	{`c:`, `c:`},
+	{`2:`, ``},
 	{``, ``},
 	{`\\\\\\host`, ``},
 	{`\\\\\\host\\`, ``},

src/pkg/path/filepath/path_windows.go

--- a/src/pkg/path/filepath/path_windows.go
+++ b/src/pkg/path/filepath/path_windows.go
@@ -35,9 +35,7 @@ func VolumeName(path string) (v string) {
 	}
 	// with drive letter
 	c := path[0]
-\tif path[1] == ':' &&
-\t\t('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
-\t\t\t'A' <= c && c <= 'Z') {
+\tif path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
 		return path[:2]
 	}
 	// is it UNC

コアとなるコードの解説

src/pkg/path/filepath/path_windows.go 内の VolumeName 関数は、Windowsパスのボリューム名(ドライブレターまたはUNCパスのホスト名)を特定する役割を担っています。

変更前のコードでは、パスの最初の文字 c がコロン : に続く場合、その c が数字、小文字アルファベット、大文字アルファベットのいずれかであれば、それをドライブレターとして認識していました。このロジックは、Windowsのドライブレターが数字ではありえないという事実を見落としていました。

修正後のコードでは、('0' <= c && c <= '9') という条件が削除されました。これにより、path[1] == ':' かつ c がアルファベットである場合にのみ、パスの最初の2文字(例: C:)がボリューム名として返されるようになります。

この変更は、path/filepath パッケージがWindowsのパス規則をより正確に反映し、2: のような不正なドライブレター形式を正しく処理(この場合はボリューム名なしと判断)するようにすることで、堅牢性と正確性を向上させます。

src/pkg/path/filepath/path_test.go に追加されたテストケース {"2:", ""} は、この修正が意図通りに機能することを確認します。つまり、2: というパスが与えられた場合、VolumeName 関数は空の文字列を返すことが期待されます。これは、2 が有効なドライブレターではないため、ボリューム名が存在しないことを意味します。

関連リンク

参考にした情報源リンク

  • Windows ドライブレターの命名規則に関する一般的な情報
  • Go言語の path/filepath パッケージのドキュメント (Go公式ドキュメント)
  • Gitのコミットと差分に関する一般的な知識