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

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

このコミットは、Go言語の標準ライブラリにディレクトリ変更機能(Chdir)を導入するものです。具体的には、osパッケージにプラットフォーム非依存のChdir関数を追加し、その内部で各OS(Darwin/macOSおよびLinux)のsyscallパッケージを介して実際のシステムコールを呼び出すように実装されています。これにより、Goプログラムから現在の作業ディレクトリを変更する機能が提供されます。

コミット

commit 61ba160120bcb5b5141fc95fa3ec232d577b9bfb
Author: Russ Cox <rsc@golang.org>
Date:   Tue Apr 7 00:40:36 2009 -0700

    Chdir
    
    R=r
    DELTA=17  (17 added, 0 deleted, 0 changed)
    OCL=27146
    CL=27153

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

https://github.com/golang/go/commit/61ba160120bcb5b5141fc95fa3ec232d577b9bfb

元コミット内容

Chdir

R=r
DELTA=17  (17 added, 0 deleted, 0 changed)
OCL=27146
CL=27153

変更の背景

このコミットが行われた2009年4月は、Go言語がまだ一般に公開される前の初期開発段階にありました。当時のGo言語は、システムプログラミングを効率的に行うための新しい言語として設計されており、OSとのインタラクションを抽象化しつつも、その機能にアクセスできる必要がありました。

Chdir(Change Directory)は、オペレーティングシステムにおいて現在の作業ディレクトリを変更するための基本的なシステムコールです。ファイルパスの解決や相対パスの基準となるため、多くのアプリケーションで必要とされる機能です。このコミット以前のGo言語には、このChdir機能が標準ライブラリに直接提供されていなかったと考えられます。

この変更の背景には、Go言語が提供するべき基本的なOS機能の網羅と、プラットフォーム間の差異を吸収し、開発者がより簡単にシステムプログラミングを行えるようにするという設計思想があります。osパッケージは、このようなOS関連の一般的な操作を抽象化して提供する役割を担っており、Chdirはその重要な一部として追加されました。

前提知識の解説

1. システムコール (System Call)

システムコールは、コンピュータプログラムがオペレーティングシステム(OS)のカーネルにサービスを要求するためのメカニズムです。ファイル操作(読み書き、ディレクトリ変更)、プロセス管理(プロセスの作成、終了)、メモリ管理など、OSが提供する低レベルな機能にアクセスするために使用されます。Go言語のsyscallパッケージは、これらのシステムコールを直接呼び出すためのインターフェースを提供します。

2. osパッケージとsyscallパッケージ

  • syscallパッケージ: Go言語のsyscallパッケージは、OSが提供する低レベルなシステムコールへの直接的なインターフェースを提供します。これにより、GoプログラムはOSの特定の機能にアクセスできますが、そのAPIはOSに依存し、プラットフォーム間で異なる場合があります。このパッケージは、より高度なOS機能の実装の基盤として使用されることが多いです。
  • osパッケージ: osパッケージは、syscallパッケージの上に構築された、より高レベルでプラットフォーム非依存のOS機能を提供します。ファイルシステム操作、プロセス管理、環境変数へのアクセスなど、一般的なOS関連のタスクを抽象化し、開発者が異なるOS環境でも同じコードで動作するように設計されています。通常、GoアプリケーションでOS機能を利用する際には、syscallパッケージではなくosパッケージを使用することが推奨されます。

3. Chdirシステムコール

Chdirは、Unix系OSやWindowsなど、ほとんどのOSに存在するシステムコールで、プロセスの現在の作業ディレクトリを変更します。現在の作業ディレクトリは、相対パスの解決の基準となります。例えば、プログラムが/home/userで実行されており、Chdir("/tmp")を呼び出すと、その後の相対パス(例: open("file.txt"))は/tmp/file.txtとして解決されるようになります。

4. エラーハンドリング (ErrnoToError)

システムコールが失敗した場合、OSは通常、エラーコード(errno)を返します。これは整数値で、特定のエラー条件(例: ファイルが見つからない、パーミッションがないなど)を示します。Go言語では、これらの数値エラーコードをGoの標準エラーインターフェース(error型)に変換する必要があります。このコミットで登場するErrnoToError関数は、syscallパッケージから返される数値エラーコードを、Goのos.Error(当時のエラー型)に変換する役割を担っています。これにより、Goの統一されたエラーハンドリングメカニズムを通じてシステムエラーを処理できるようになります。

技術的詳細

このコミットの技術的なポイントは、Go言語の標準ライブラリにおけるOSインタラクションの設計パターンを示している点です。

  1. osパッケージによる抽象化: src/lib/os/file.goos.Chdir関数が追加されています。この関数は、dir stringを引数に取り、*os.Errorを返します。これは、Goのユーザーがプラットフォームの違いを意識せずにディレクトリ変更を行えるようにするための高レベルなAPIです。
  2. syscallパッケージによるOS固有の実装: os.Chdirの内部では、syscall.Chdirが呼び出されています。このsyscall.Chdirは、src/lib/syscall/file_darwin.gosrc/lib/syscall/file_linux.goでそれぞれ異なる実装を持っています。
    • Darwin (macOS): Syscall(SYS_CHDIR, ...)を使用して、Darwinカーネルのchdirシステムコールを直接呼び出しています。SYS_CHDIRは、chdirシステムコールに対応する数値定数です。StringBytePtr(dir)は、Goの文字列をC言語の文字列(ヌル終端バイト配列)に変換するためのヘルパー関数です。
    • Linux: 同様にSyscall(SYS_CHDIR, ...)を使用して、Linuxカーネルのchdirシステムコールを呼び出しています。実装パターンはDarwinと非常に似ており、OS間の差異をsyscallパッケージ内で吸収しています。
  3. エラー変換 (ErrnoToError): syscall.Chdirは、成功時にはret int64errno int64を返します。errnoはOSが返す数値エラーコードです。os.Chdirでは、このerrnoErrnoToError(e)という関数でGoの*os.Error型に変換しています。これにより、システムコールレベルの数値エラーが、Goの慣用的なエラー型として扱えるようになります。これは、Goのエラーハンドリングの初期の設計を示しています。

この多層的なアプローチにより、Go言語はOSの低レベルな機能にアクセスしつつも、開発者には統一された高レベルなインターフェースを提供しています。

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

src/lib/os/file.go

 // Chdir changes the current working directory to the named directory.
 func Chdir(dir string) *os.Error {
 	r, e := syscall.Chdir(dir);
 	return ErrnoToError(e);
 }

src/lib/syscall/file_darwin.go

 func Chdir(dir string) (ret int64, errno int64) {
 	namebuf := StringBytePtr(dir);
 	r1, r2, err := Syscall(SYS_CHDIR, int64(uintptr(unsafe.Pointer(namebuf))), 0, 0);
 	return r1, err;
 }

src/lib/syscall/file_linux.go

 func Chdir(dir string) (ret int64, errno int64) {
 	namebuf := StringBytePtr(dir);
 	r1, r2, err := Syscall(SYS_CHDIR, int64(uintptr(unsafe.Pointer(namebuf))), 0, 0);
 	return r1, err;
 }

コアとなるコードの解説

src/lib/os/file.goChdir 関数

この関数は、Go言語のosパッケージに新しく追加された、ユーザーが直接呼び出すためのChdir関数です。

  • func Chdir(dir string) *os.Error: dirという文字列(変更したいディレクトリのパス)を引数に取り、*os.Error型(当時のGoのエラー型)を返します。
  • r, e := syscall.Chdir(dir);: 実際のディレクトリ変更処理は、syscallパッケージのChdir関数に委譲されています。syscall.Chdirは、成功時には戻り値rとエラーコードeを返します。
  • return ErrnoToError(e);: syscall.Chdirから返された数値エラーコードeを、ErrnoToErrorヘルパー関数を使ってGoの*os.Error型に変換し、呼び出し元に返します。これにより、OS固有の数値エラーがGoの統一されたエラーとして扱われます。

src/lib/syscall/file_darwin.go および src/lib/syscall/file_linux.goChdir 関数

これらの関数は、それぞれのOS(Darwin/macOSおよびLinux)に特化したsyscallパッケージ内のChdir関数です。

  • func Chdir(dir string) (ret int64, errno int64): dirという文字列を引数に取り、システムコールの戻り値retとOSのエラーコードerrnoint64型で返します。
  • namebuf := StringBytePtr(dir);: Goの文字列dirを、C言語のシステムコールが期待する形式(ヌル終端されたバイト配列へのポインタ)に変換しています。StringBytePtrは、この変換を行うためのユーティリティ関数です。
  • r1, r2, err := Syscall(SYS_CHDIR, int64(uintptr(unsafe.Pointer(namebuf))), 0, 0);: ここが最も重要な部分で、実際のシステムコールを呼び出しています。
    • Syscall: syscallパッケージが提供する汎用的なシステムコール呼び出し関数です。
    • SYS_CHDIR: 呼び出すシステムコールの識別子(chdirシステムコールに対応する数値定数)です。
    • int64(uintptr(unsafe.Pointer(namebuf))): namebuf(ディレクトリパスのバイト配列へのポインタ)をシステムコールに渡すための引数として準備しています。unsafe.Pointeruintptrは、ポインタを整数に変換し、システムコールに渡せる形式にするためのGoの低レベルな機能です。
    • 0, 0: chdirシステムコールは通常1つの引数しか取らないため、残りの引数は0で埋められています。
  • return r1, err;: システムコールの戻り値r1と、システムコールが設定したエラーコードerr(これはerrnoとして返される)を返します。

これらの実装により、os.Chdirはプラットフォーム非依存のインターフェースを提供しつつ、内部では各OSのネイティブなchdirシステムコールを効率的に呼び出しています。

関連リンク

参考にした情報源リンク