[インデックス 10963] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおいて、NetBSDオペレーティングシステム上でのディレクトリエントリー読み取り機能(getdirentries
)の動作を修正するものです。具体的には、NetBSDのシステムコールであるgetdents
の呼び出し方法と、その戻り値であるdirent
構造体の定義を、NetBSDの実際の仕様に合わせて調整しています。これにより、GoプログラムがNetBSD上で正しくディレクトリの内容を列挙できるようになります。
コミット
コミットハッシュ: 43bc8a9b53e212af4d24f9a4960e5c452555efb6
作者: Joel Sing jsing@google.com
日付: 2011年12月22日 木曜日 23:42:43 +1100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/43bc8a9b53e212af4d24f9b4960e5c452555efb6
元コミット内容
syscall: make getdirentries work on netbsd
R=golang-dev, mikioh.mikioh
CC=golang-dev
https://golang.org/cl/5504068
変更の背景
Go言語のsyscall
パッケージは、オペレーティングシステムの低レベルな機能(システムコール)にアクセスするためのインターフェースを提供します。getdirentries
関数は、指定されたファイルディスクリプタからディレクトリのエントリーを読み取るための汎用的な関数であり、内部的には各OS固有のシステムコールを呼び出します。
NetBSD環境において、syscall
パッケージのgetdirentries
の実装が、実際のNetBSDのgetdents
システムコールの挙動や、そのシステムコールが返すdirent
構造体の定義と一致していませんでした。これにより、GoプログラムがNetBSD上でディレクトリを正しく読み取ることができないという問題が発生していました。
具体的には、以下の点が問題となっていました。
getdirentries
関数が、NetBSDのgetdents
システムコールを正しく呼び出していなかった。dirent
構造体のフィールド(特にFileno
とNamlen
の型、およびName
配列のサイズ)が、NetBSDの定義と異なっていた。
このコミットは、これらの不一致を解消し、NetBSD上でのディレクトリ操作の信頼性を向上させることを目的としています。
前提知識の解説
1. システムコール (System Call)
システムコールは、オペレーティングシステム(OS)のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイル操作、メモリ管理、プロセス制御など、OSの基本的な機能はシステムコールを通じて提供されます。Go言語のsyscall
パッケージは、これらのシステムコールをGoプログラムから直接呼び出すための機能を提供します。
2. getdents
システムコール
getdents
(get directory entries)は、Unix系OSでディレクトリの内容を読み取るために使用されるシステムコールの一つです。このシステムコールは、指定されたファイルディスクリプタ(ディレクトリを表す)から、ディレクトリ内のエントリー(ファイルやサブディレクトリ)の情報をバッファに書き込みます。各エントリーは通常、dirent
という構造体で表現されます。
3. dirent
構造体
dirent
構造体は、getdents
システムコールによって返されるディレクトリエントリーの情報を格納するためのデータ構造です。OSによってその定義は多少異なりますが、一般的には以下のフィールドを含みます。
d_fileno
(またはFileno
): ファイルのinode番号。ファイルシステム内で一意な識別子です。d_reclen
(またはReclen
): このディレクトリエントリーレコード全体の長さ。d_namlen
(またはNamlen
): ファイル名の長さ。d_type
(またはType
): ファイルの種類(例: 通常ファイル、ディレクトリ、シンボリックリンクなど)。d_name
(またはName
): ファイル名。
NetBSDにおけるdirent
構造体のC言語での定義は、通常 <sys/dirent.h>
にあり、以下のような形式です。
struct dirent {
ino_t d_fileno; /* file number of entry */
uint16_t d_reclen; /* length of this record */
uint16_t d_namlen; /* length of string in d_name */
uint8_t d_type; /* file type, see below */
char d_name[MAXNAMLEN + 1]; /* name must be NUL-terminated */
};
ここで、ino_t
は通常、32ビットまたは64ビットの符号なし整数型であり、64ビットシステムではuint64_t
であることが多いです。MAXNAMLEN
はファイル名の最大長を定義するマクロで、OSやファイルシステムによって値が異なります。
4. Go言語におけるシステムコールラッパーと型定義
Go言語のsyscall
パッケージは、各OSのシステムコールをGoの関数としてラップしています。これらのラッパー関数や、システムコールが使用する構造体のGo言語での型定義は、通常、自動生成ツールによって生成されます。
zsyscall_netbsd_386.go
/zsyscall_netbsd_amd64.go
: これらは、NetBSDの32ビット(i386)および64ビット(amd64)アーキテクチャ向けのシステムコールラッパー関数が定義されているファイルです。Syscall
関数を介して実際のシステムコールを呼び出すコードが含まれます。ztypes_netbsd_386.go
/ztypes_netbsd_amd64.go
: これらは、NetBSDのシステムコールが使用するC言語の構造体に対応するGo言語の型定義が記述されているファイルです。
これらのファイルは、Goのビルドプロセス中にmksyscall
などのツールによって生成されるため、手動で編集することは推奨されません(ファイル冒頭にTHIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
というコメントがあることが多いです)。このコミットでは、生成元のテンプレートや定義が修正され、それによってこれらのz
ファイルが更新されたと考えられます。
技術的詳細
このコミットの技術的な核心は、NetBSDのgetdents
システムコールとdirent
構造体のGo言語での表現を、NetBSDの実際の定義に厳密に合わせることにあります。
1. getdents
システムコールの導入とGetdirentries
の修正
変更前は、syscall_netbsd.go
内のGetdirentries
関数がTODO
コメントと共に未実装の状態でした。このコミットでは、getdents
という新しい内部関数を導入し、Getdirentries
がこのgetdents
を呼び出すように変更しています。
-
getdents
関数の追加:zsyscall_netbsd_386.go
とzsyscall_netbsd_amd64.go
に、NetBSDのgetdents
システムコールを呼び出すためのGoラッパー関数getdents
が追加されました。この関数は、ファイルディスクリプタ(fd
)とバッファ(buf
)を受け取り、SYS_GETDENTS
システムコール番号を使用してSyscall
関数を呼び出します。func getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) } else { _p0 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf))) n = int(r0) if e1 != 0 { err = e1 } return }
ここで、
unsafe.Pointer
はGoの型システムをバイパスして任意のメモリを指すポインタを作成するために使用され、C言語のポインタ引数にGoのスライスを渡す際に必要となります。Syscall
関数は、システムコール番号と引数を受け取り、システムコールを実行します。 -
Getdirentries
関数の修正:syscall_netbsd.go
内のGetdirentries
関数は、以前はTODO
コメントがあり、ENOSYS
(システムコールが実装されていないエラー)を返していました。このコミットでは、Getdirentries
が新しく追加されたgetdents
関数を呼び出すように変更されました。また、basep *uintptr
引数はgetdents
システムコールでは使用されないため、Getdirentries
のシグネチャからは削除されませんが、内部的には無視されます。//sys getdents(fd int, buf []byte) (n int, err error) func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { return getdents(fd, buf) }
これにより、Goの
Getdirentries
関数がNetBSD上で実際に機能するようになりました。
2. Dirent
構造体の修正
NetBSDのdirent
構造体のGo言語での表現が、実際のC言語の定義と一致するように修正されました。これは、ztypes_netbsd_386.go
とztypes_netbsd_amd64.go
内のDirent
構造体定義に反映されています。
-
Fileno
フィールドの型変更:- 変更前:
Fileno uint32
- 変更後:
Fileno uint64
NetBSDのdirent
構造体におけるd_fileno
フィールドはino_t
型であり、64ビットシステムではuint64_t
として定義されることが一般的です。この変更により、GoのDirent
構造体がNetBSDのino_t
のサイズと一致し、ファイル番号の正確な表現が可能になります。
- 変更前:
-
Namlen
フィールドの型変更:- 変更前:
Namlen uint8
- 変更後:
Namlen uint16
NetBSDのdirent
構造体におけるd_namlen
フィールドはuint16_t
型です。この変更により、ファイル名の長さが正しく表現されるようになります。
- 変更前:
-
Name
配列のサイズ変更:- 変更前:
Name [256]int8
- 変更後:
Name [512]int8
NetBSDのdirent
構造体におけるd_name
フィールドはchar d_name[MAXNAMLEN + 1]
として定義されます。MAXNAMLEN
はファイル名の最大長であり、システムによって異なります。以前の256
バイトでは、一部のNetBSD環境で長いファイル名を格納しきれない可能性がありました。512
バイトに拡張することで、より長いファイル名に対応できるようになり、バッファオーバーフローのリスクを低減します。
- 変更前:
これらの構造体定義の変更は、Goのsyscall
パッケージがNetBSDのカーネルから返されるdirent
データを正しく解釈するために不可欠です。
3. Sendfile
関数の位置変更と__getdents30
の削除
Sendfile
関数の位置変更:syscall_netbsd.go
内で、Sendfile
関数とGetdirentries
関数の定義が入れ替わっています。これは機能的な変更ではなく、コードの整理または関連する変更による副作用と考えられます。__getdents30
のコメントアウト:syscall_netbsd.go
のコメントリストから__getdents30
が削除されています。これは、NetBSDのgetdents
システムコールが直接Goのgetdents
関数によってラップされるようになったため、以前の(おそらく未実装または不適切な)ラッパーの参照が不要になったことを示唆しています。
コアとなるコードの変更箇所
src/pkg/syscall/syscall_netbsd.go
--- a/src/pkg/syscall/syscall_netbsd.go
+++ b/src/pkg/syscall/syscall_netbsd.go
@@ -74,13 +74,13 @@ func Pipe(p []int) (err error) {
return
}
-// TODO
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
- return -1, ENOSYS
+//sys getdents(fd int, buf []byte) (n int, err error)
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ return getdents(fd, buf)
}
// TODO
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
return -1, ENOSYS
}
@@ -176,7 +176,6 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// __fhstatvfs140
// __fstat30
// __getcwd
-// __getdents30
// __getfh30
// __getlogin
// __lstat30
src/pkg/syscall/zsyscall_netbsd_386.go
および src/pkg/syscall/zsyscall_netbsd_amd64.go
(両ファイルで同様の変更)
--- a/src/pkg/syscall/zsyscall_netbsd_386.go
+++ b/src/pkg/syscall/zsyscall_netbsd_386.go
@@ -263,6 +263,23 @@ func pipe(p *[2]_C_int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
if e1 != 0 {
src/pkg/syscall/ztypes_netbsd_386.go
および src/pkg/syscall/ztypes_netbsd_amd64.go
(両ファイルで同様の変更)
--- a/src/pkg/syscall/ztypes_netbsd_386.go
+++ b/src/pkg/syscall/ztypes_netbsd_386.go
@@ -127,11 +127,11 @@ type Flock_t struct {
}
type Dirent struct {
- Fileno uint32
+ Fileno uint64
Reclen uint16
+ Namlen uint16
Type uint8
- Namlen uint8
- Name [256]int8
+ Name [512]int8
}
type Fsid struct {
コアとなるコードの解説
syscall_netbsd.go
の変更
Getdirentries
の実装: 以前はTODO
コメントがあり、常にエラーを返していたGetdirentries
関数が、新しく定義された内部関数getdents
を呼び出すように変更されました。これにより、NetBSD上でのディレクトリエントリーの読み取りが可能になります。Sendfile
とGetdirentries
の位置入れ替え: これは機能的な変更ではなく、コードの配置の変更です。__getdents30
の削除: コメントリストから__getdents30
が削除されました。これは、getdents
システムコールが直接Goのラッパー関数として実装されたため、以前の参照が不要になったことを示しています。
zsyscall_netbsd_386.go
および zsyscall_netbsd_amd64.go
の変更
getdents
関数の追加: NetBSDのgetdents
システムコールをGoから呼び出すための具体的なラッパー関数getdents
が追加されました。この関数は、Syscall
関数を使用してSYS_GETDENTS
システムコールを実行し、ファイルディスクリプタ、バッファへのポインタ、バッファサイズを引数として渡します。これにより、GoプログラムがNetBSDカーネルから直接ディレクトリエントリーを取得できるようになります。
ztypes_netbsd_386.go
および ztypes_netbsd_amd64.go
の変更
Dirent
構造体の修正:Fileno
フィールドの型がuint32
からuint64
に変更されました。これは、NetBSDのdirent
構造体におけるd_fileno
(inode番号)が、特に64ビットシステムにおいてuint64_t
として定義されることに対応するためです。これにより、大きなファイルシステムや多数のファイルを持つシステムでも、inode番号が正しく扱えるようになります。Namlen
フィールドの型がuint8
からuint16
に変更されました。これは、NetBSDのdirent
構造体におけるd_namlen
(ファイル名の長さ)がuint16_t
として定義されることに対応するためです。これにより、ファイル名の長さが正確に表現されます。Name
配列のサイズが[256]int8
から[512]int8
に拡張されました。これは、NetBSDのMAXNAMLEN
が255より大きい場合や、将来的な互換性を考慮して、より長いファイル名を格納できるようにするためです。これにより、ファイル名が途中で切り詰められることなく、完全に読み取れるようになります。
これらの変更により、Goのsyscall
パッケージはNetBSDのシステムコールインターフェースと完全に一致し、NetBSD上でのディレクトリ操作が安定して行えるようになりました。
関連リンク
- Go言語
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - NetBSD
getdents
マニュアルページ (通常はman 2 getdents
で参照可能) - NetBSD
dirent
構造体定義 (通常は<sys/dirent.h>
で参照可能)
参考にした情報源リンク
- Web検索: "NetBSD getdents syscall Dirent struct"
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF3kDA3q2a7wJiA1eqT6IrGYtxWO36VUM4xfc63SDH20xFMsRYdDTKX_q_La2CAVPCRq36hWPXVUiHKnkvazb5o70a444574QABt70UicC1Ac_8JEcUBBcSXG7CAH0HWqlrmdCB9XsJLq3NOGV3Ch0=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHM8cbKz3MqfG7ThQ2ZrXl9JE_njLXVSKlXtHFCJ-XXe6R1XumFVdoLPrqTc0qNSDf71mHHLnMWigIDwFgwFIbJIYjzQfUU4CFQB8YCqAt10Rm4RLOHpjehZo8=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEpxxiRUgO7CsyjBQGukTiC1xm2lngLEOGWLpLwsrVOIbOAJYxlaGRrSkcs3hSDH-9XGGHh9kdi8qk_nx40tmNdZd98sEkxTj5y59UcZ-f-SI-YDQpPh2EzOb3UU3BmWFR-h0Rob3SsE2x8yQ==