VFAT、Linux:再起動後に無効なファイルタイムスタンプが表示される

VFAT、Linux:再起動後に無効なファイルタイムスタンプが表示される

ちょうど問題が発生しました。 Linuxシステムを再起動すると、マウントされたVFATファイルシステム内のすべてのファイルのタイムスタンプが間違った時間帯に表示されます。デバイスは現地時間がUTCであると考え始め、すべてのタイムスタンプをオフセットとともに表示します。

再現段階:

  • 小さなFAT形式の画像を作成します。

    dd if=/dev/zero of=small.img bs=1M seek=1 count=0

    mkfs.vfat small.img

  • このイメージをローカルにマウントします。

    mount -t vfat -o umask=0022,gid=1001,uid=1001 small.img mnt

  • タイムゾーンをUTC以外のタイムゾーンに設定します。

  • マウントされたファイルシステム(たとえばtouch mnt/newfile)にファイルを作成します。

  • ファイルの変更/変更タイムスタンプを観察してください。現在設定されているタイムスタンプに対して正しいです。

    stat mnt/newfile

    File: mnt/newfile
    Size: 0             Blocks: 0          IO Block: 16384  regular empty file
    Device: 700h/1792d  Inode: 40          Links: 1
    Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
    Access: 2021-03-22 12:19:56.000000000 +0100
    Modify: 2021-03-22 12:19:56.000000000 +0100
    Change: 2021-03-22 12:19:56.000000000 +0100
    Birth: -
    

    timedatectl

    Local time: Mon 2021-03-22 12:19:07 CET
    Universal time: Mon 2021-03-22 11:19:07 UTC
    RTC time: Mon 2021-03-22 11:19:07
    Time zone: Europe/Vienna (CET, +0100)
    System clock synchronized: yes
    NTP service: active
    RTC in local TZ: no
    
  • ファイルシステムをアンマウントして再マウントして、変更があるかどうかを確認します。 umount mnt; mount -t vfat -o umask=0022,gid=1001,uid=1001 small.img mnt; stat mnt/newfile

    File: mnt/newfile
    Size: 0          Blocks: 0          IO Block: 16384  regular empty file
    Device: 700h/1792d   Inode: 64          Links: 1
    Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
    Access: 2021-03-22 00:00:00.000000000 +0100
    Modify: 2021-03-22 12:19:56.000000000 +0100
    Change: 2021-03-22 12:19:56.000000000 +0100
    Birth: -
    
  • システムを再起動します。

  • 画像を再マウントして、生成されたファイルのタイムスタンプを確認してください。

    File: mnt/newfile
    Size: 0             Blocks: 0          IO Block: 16384  regular empty file
    Device: 700h/1792d  Inode: 26          Links: 1
    Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
    Access: 2021-03-22 01:00:00.000000000 +0100
    Modify: 2021-03-22 13:19:56.000000000 +0100
    Change: 2021-03-22 13:19:56.000000000 +0100
    Birth: -
    

時間が1時間(12:10から13:19)早くなったことがはっきりとわかりますが、時間帯は同じに+0100と表示されます。mountこれで、ファイルタイムスタンプがUTCとして記録されていると考えて、「正しい」オフセットを使用して表示しようとしているようです。

前のステートメントを検証するには、tz=UTCこのオプションを明示的に使用して同じファイルシステムを再マウントします。

mount -t vfat -o umask=0022,gid=1001,uid=1001,tz=UTC small.img mnt; stat mnt/newfile

File: mnt/newfile
Size: 0          Blocks: 0          IO Block: 16384  regular empty file
Device: 700h/1792d   Inode: 50          Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2021-03-22 01:00:00.000000000 +0100
Modify: 2021-03-22 13:19:56.000000000 +0100
Change: 2021-03-22 13:19:56.000000000 +0100
Birth: -

システムのタイムゾーンが実際にCETの場合でも:

date

Mon Mar 22 12:26:42 CET 2021

ポリスチレンhttps://stackoverflow.com/questions/10068855/how-do-i-get-the-Cordirect-modified-datetime-of-a-fat32-file-regardless-of-timezo回答が得られないため、この質問に対する回答ではありません。再インストール直後ではなく、コンピュータを再起動した直後にこの変更が表示されるのはなぜですか。 vfatがタイムスタンプを現地時間として保存する場合、再起動後のマウントでタイムスタンプが現地時間ではなくUTCであると仮定するのはなぜですか?

ベストアンサー1

Linuxカーネル自体に問題があるようですが、タイムゾーンは、(通常)カーネルとユーザー空間の間で異なる場合があります。。 Linuxカーネルソースツリーのファイルは、time.c保存(およびエクスポート)され、次にFAT時間<-> UNIX時間規則に従って使用されます。この構造のフィールドは、オプションが次の場合、現在のタイムゾーンとUTCの差を表示するために使用されます。kernel/timestruct timezone sys_tzfs/fat/misc.ctz_minuteswesttz=UTCいいえmount.vfatコマンドに渡されました。ただし、上記のフィールドは、説明したようにデフォルトで0に設定されています。ここ

Linuxでは、NULL以外のtzパラメータを使用した最初の呼び出しで(起動後)、tvパラメータがNULLで、tz_ Minuteswestフィールドがゼロです。 (この場合、tz_dsttimeフィールドは0でなければなりません。)この場合、CMOSクロックはローカル時間と見なされ、UTCシステム時間を取得するにはこの量だけ増加する必要があります。この機能を使用するのが悪い考えであることは間違いありません。

したがって、カーネル(および対応するドライバ)が常に正しいタイムゾーンを確認できるようにする唯一の方法は、UTC(たとえば-60 CETなど)に基づいて希望の時間オフセット「西」(時間単位)を使用してパラメータをsettimeofday()呼び出すことです。 。各システム起動後にゼロに設定されます。これは(何らかの方法で)システムタイムゾーンを設定することで達成できます。tztz.tz_minuteswesttz_dsttime現在のタイムゾーン他の値(UTCなど)に変更した後timedatectlコマンドラインツールsaは、通常、目的のタイムゾーンが現在のタイムゾーンと同じ場合、実際のタイムゾーン変更を実行しないためです。この概念を示すために、次のコードを作成します。

#include <sys/time.h>
#include <stdio.h>

int main()
{
    struct timeval tv;
    struct timezone tz;
    int ret = gettimeofday(&tv, &tz);
    printf("%d, %dr\n", tz.tz_minuteswest, tz.tz_dsttime);
    return ret;
}

コードは次のように実行されます。

$gcc testtz.cpp -o testtz
$./testtz
minuteswest: 0, dsttime: 0r
$timedatectl set-timezone Europe/Vienna
$./testtz
minuteswest: 0, dsttime: 0r
$timedatectl set-timezone UTC
$timedatectl set-timezone Europe/Vienna
$./testtz
minuteswest: -60, dsttime: 0r

timezone構造の使用は廃止とみなされますが、問題はすぐには消えません。だから私の問題については使用を検討します。time_offset=分オプションmount.vfat

おすすめ記事