[インデックス 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 uint64NetBSDのdirent構造体におけるd_filenoフィールドはino_t型であり、64ビットシステムではuint64_tとして定義されることが一般的です。この変更により、GoのDirent構造体がNetBSDのino_tのサイズと一致し、ファイル番号の正確な表現が可能になります。
- 変更前:
-
Namlenフィールドの型変更:- 変更前:
Namlen uint8 - 変更後:
Namlen uint16NetBSDのdirent構造体におけるd_namlenフィールドはuint16_t型です。この変更により、ファイル名の長さが正しく表現されるようになります。
- 変更前:
-
Name配列のサイズ変更:- 変更前:
Name [256]int8 - 変更後:
Name [512]int8NetBSDの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==