* ファイルシステムとタイムスタンプ [#e41c69af]

** そもそもの疑問 [#y52839a4]

Linux で FAT フォーマットの SD カードを mount し,ls -l でディレクトリの中身を覗いていて

> 何で Linux 上で FAT filesystem のタイムスタンプが正常に表示できるんだろう

と,すごく気になりだしたのである.

というわけで追っかけてみた.

** epoch と timezone [#abe51c4f]

「何でそんなこと気にするんだ」と話のとっかかりとして,まずはここらへんから.

まず,epoch とは「1970 年 1 月 1 日 UTC からの経過秒数」のことである.
UTC とは協定世界時のことで,サマータイムが適用されていないグリニッジ標準時と同じ時刻である.
UNIX では,カーネルが持っている時計の現在時刻を time(2) システムコールで取得することができる.

次に timezone について.
timezone とは要するに「現地時間の UTC からの時差」である.
たとえば日本時間は,UTC に対して 9 時間進んだ時刻である.

** ls -l コマンドを実行すると… [#meee1fa6]

まず,ディレクトリ内のファイル名・ディレクトリ名の一覧を取得する.
そして,各ファイル・ディレクトリに対して stat(2) システムコールを発行する.

stat(2) が返す構造体の形式は以下のとおりである.

          struct stat {
              dev_t     st_dev;     /* ファイルがあるデバイスの ID */
              ino_t     st_ino;     /* inode 番号 */
              mode_t    st_mode;    /* アクセス保護 */
              nlink_t   st_nlink;   /* ハードリンクの数 */
              uid_t     st_uid;     /* 所有者のユーザ ID */
              gid_t     st_gid;     /* 所有者のグループ ID */
              dev_t     st_rdev;    /* デバイス ID (特殊ファイルの場合) */
              off_t     st_size;    /* 全体のサイズ (バイト単位) */
              blksize_t st_blksize; /* ファイルシステム I/O での
                                       ブロックサイズ */
              blkcnt_t  st_blocks;  /* 割り当てられたブロック数 */
              time_t    st_atime;   /* 最終アクセス時刻 */
              time_t    st_mtime;   /* 最終修正時刻 */
              time_t    st_ctime;   /* 最終状態変更時刻 */
          };

ファイルのタイムスタンプは time_t 型であり,つまり epoch 形式である.

この epoch 形式を現地時間の「年月日時分秒」に変換するのは libc の仕事である.
libc は /etc/localtime ファイルにある時差情報に基づいて epoch を現地時間に変換する.
かくして ls -l のタイムスタンプは現地時間で表示されるわけである.

あ,そうそう,ext3 などの UNIX / Linux native のファイルシステムでは,タイムスタンプは epoch 形式のまま HDD に保存されている.

 HDD
       epoch
         |
         |
 --------|----------
 kernel  |
         |
 --------|---------- stat(2)
 user    |
         +---- /etc/localtime
         #
         #
         V
  yy/mm/dd hh:mm:ss JST


** FAT の場合 [#mea1bd8a]

FAT filesystem の場合,少々話が違ってくる.
「[http://www.geocities.co.jp/SiliconValley-PaloAlto/2038/fat.html FAT FS フォーマットの実装についての覚え書き]」あたりを見てみると,FAT では「年月日時分秒」形式で時刻が保存されているが,''timezone という概念は存在しない''.
つまり「どこの現地時間か UTC かは知らないけど,そういう時刻」ということでタイムスタンプが打たれているわけである.

しかし,strace をかけてみても ls -l ではやはり stat(2) でファイル情報を取得していており,ext3 上のディレクトリの処理と一緒である.
ということは,
> カーネル内部で年月日時分秒形式を epoch 形式に変換している

ということになる.
ところが,これには timezone 情報が必要であるのだが,timezone 情報は /etc/localtime ファイルに保存されている.
/etc/* のファイルは,ユーザランドプログラムやライブラリが設定ファイルを慣習的に配置しているだけであり,カーネルがここのファイルを直接参照することは,普通はない.

(つづく)

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS