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 커널 소스 트리 의 파일은 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()호출 하는 것 입니다. 각 시스템 시작 후 0으로 설정됩니다. 이는 (어떤 방식으로든) 시스템 시간대를 설정하여 달성할 수 있습니다.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.

관련 정보