ฉันจะค้นหาเวลาสร้างไฟล์ได้อย่างไร


64

ฉันต้องการค้นหาเวลาในการสร้างไฟล์เมื่อฉันอ่านบทความเกี่ยวกับปัญหานี้ทุกคนกล่าวถึงว่าไม่มีวิธีแก้ปัญหา (เช่นไซต์ 1 , ไซต์ 2 )

เมื่อฉันพยายามคำสั่งมันฯstat Birth: -

ดังนั้นฉันจะหาเวลาสร้างไฟล์ได้อย่างไร


2
โปรดทราบว่า 'เวลาการสร้าง' ของไฟล์ไม่รับประกันว่าจะถูกต้อง มีหลายวิธีในการ 'เหลวไหล' วันที่สร้างไฟล์
Thomas Ward

1
@ThomasWard มีหลายวิธีที่จะทำให้เหลวไหลข้อมูลไฟล์อื่น ๆ
Cees Timmerman

คำตอบ:


67

มีวิธีรู้วันที่สร้างของไดเรกทอรีเพียงทำตามขั้นตอนเหล่านี้:

  1. รู้จักinodeของไดเร็กตอรี่โดยls -iคำสั่ง (ตัวอย่างเช่นX )

  2. ทราบว่าพาร์ทิชันของคุณจะได้รับการบันทึกโดยdf -T /pathคำสั่ง (ให้พูดใน /dev/sda1)

  3. ตอนนี้ใช้คำสั่งนี้: sudo debugfs -R 'stat <X>' /dev/sda1

คุณจะเห็นในผลลัพธ์:

crtime: 0x4e81cacc:966104fc -- mon Sep 27 14:38:28 2013

crtime คือวันที่สร้างไฟล์ของคุณ

สิ่งที่ฉันทดสอบ :

  1. สร้างไดเรกทอรีในเวลาที่กำหนด
  2. เข้าถึงได้แล้ว
  3. แก้ไขโดยการสร้างไฟล์

  4. ฉันลองใช้คำสั่งและให้เวลาที่แน่นอน

  5. จากนั้นฉันจะแก้ไขและทดสอบอีกครั้งcrtimeยังคงเหมือนเดิม แต่แก้ไขและเข้าถึงเวลาเปลี่ยน

ผมโพสต์นี้เพราะผมต้องการที่จะหารือเพื่อให้สามารถเข้าใจผมสงสัยว่าทำไมคนบอกว่า Linux ไม่สนับสนุนคุณสมบัตินี้
Nux

13
เพราะลีนุกซ์เองนั้นไม่ ระบบไฟล์ ext4 มีข้อมูลนี้ แต่เคอร์เนลไม่ได้จัดเตรียม API เพื่อเข้าถึง เห็นได้ชัดว่าdebugfsแยกมันโดยตรงจากระบบไฟล์จึงไม่จำเป็นต้องใช้ API ของเคอร์เนล ดูที่นี่
terdon

ฉันทดสอบมัน มันทำงานได้อย่างสมบูรณ์แบบในระบบไฟล์ ext4
Fahim Babar Patel

1
ดูเหมือนว่าจะเป็นเฉพาะ ext4? มันไม่ทำงานกับ XFS สำหรับฉัน
Quantum7

เคอร์เนล glibc และ coreutils ทั้งหมดในขณะนี้สนับสนุนstatx()ณ เดือนมีนาคม 2019
hippietrail

54

@Nux พบทางออกที่ดีสำหรับสิ่งนี้ซึ่งคุณควร upvote ทั้งหมด ฉันตัดสินใจที่จะเขียนฟังก์ชั่นเล็ก ๆ น้อย ๆ ที่สามารถใช้เพื่อเรียกใช้ทุกอย่างโดยตรง ~/.bashrcเพียงแค่เพิ่มนี้เพื่อคุณ

get_crtime() {

    for target in "${@}"; do
        inode=$(stat -c '%i' "${target}")
        fs=$(df  --output=source "${target}"  | tail -1)
        crtime=$(sudo debugfs -R 'stat <'"${inode}"'>' "${fs}" 2>/dev/null | 
        grep -oP 'crtime.*--\s*\K.*')
        printf "%s\t%s\n" "${target}" "${crtime}"
    done
}

ตอนนี้คุณสามารถget_crtimeพิมพ์วันที่สร้างไฟล์หรือไดเรกทอรีได้มากเท่าที่คุณต้องการ:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014

โปรดทราบว่าวันที่สร้างไม่ได้เป็นวันที่สร้างของไฟล์ต้นฉบับหากไฟล์ที่เป็นสำเนา (เช่นมันเป็นที่มีวันที่แก้ไข) เมื่อไฟล์ถูกคัดลอกวันที่แก้ไขจะมาจากต้นฉบับ แต่วันที่สร้างนั้นมาจากการคัดลอก (มีบางคนเข้าใจผิดในคำถามนี้: askubuntu.com/questions/529885/ … )
Jacob Vlijm

1
@JacobVlijm ใช่แล้วแน่นอน ไม่ชัดเจนเหรอ? มันจะเป็นอย่างอื่นได้อย่างไร? สำเนาเป็นไฟล์ใหม่ที่เพิ่งมีเนื้อหาเหมือนกัน เวลาในการแก้ไขยังเปลี่ยนแปลงสำหรับการทำสำเนาโดยวิธี มันถูกกำหนดเป็นช่วงเวลาที่สำเนาถูกสร้างขึ้นเว้นแต่ว่าคุณจะเลือกอย่างชัดเจนว่าจะไม่เกิดขึ้นโดยใช้cp -pหรือคล้ายกัน
terdon

แน่นอน แต่มันในเวลาเดียวกันมันจะไม่เป็นการผิดถ้าหากเช่น mod วันที่บางแห่งในไฟล์วันที่จะถูกเก็บไว้เมื่อมันมา ฉันต้องยอมรับว่าไม่รู้ว่าไม่ได้เกิดขึ้นจนกว่าฉันจะตอบคำถามที่เชื่อมโยง
Jacob Vlijm

เพียงแค่พยายามฉันยังได้คัดลอกไฟล์ใน nautilus วันที่แก้ไขจะยังคงอยู่เหมือนเดิม (คือ), m วันที่ก่อนหน้าวันที่สร้าง
Jacob Vlijm

1
@dongongolem ใช่แล้ว CentOS เวอร์ชันdfดูเหมือนจะไม่รองรับ--outputตัวเลือกนี้ ในกรณีนั้นคุณสามารถแทนที่บรรทัดนั้นด้วยfs=$(df foo | awk '{a=$1}END{print a}'และฟังก์ชั่นจะทำงานได้เช่นกัน ทั้งหมดที่ฉันแสดงในคำตอบนี้เป็นวิธีการห่อคำสั่งจากคำตอบที่ได้รับการยอมรับในวิธีที่สามารถเรียกใช้โดยตรงสำหรับเป้าหมายไฟล์ / ไดเรกทอรี
terdon

11

การไม่สามารถstatแสดงเวลาการสร้างได้เนื่องจากข้อ จำกัด ของการstat(2)เรียกระบบซึ่งโครงสร้างการส่งคืนไม่ได้รวมฟิลด์สำหรับเวลาการสร้าง เริ่มต้นด้วย Linux 4.11 (เช่น 17.10 และใหม่กว่า *) การstatx(2)เรียกระบบใหม่พร้อมใช้งานซึ่งรวมถึงเวลาการสร้างในโครงสร้างการส่งคืน

* และอาจใช้กับ LTS รุ่นเก่าโดยใช้เคอร์เนลการเปิดใช้งานฮาร์ดแวร์ (HWE) ตรวจสอบuname -rเพื่อดูว่าคุณใช้เคอร์เนลอย่างน้อย 4.11 เพื่อยืนยัน

น่าเสียดายที่การโทรออกด้วยระบบโดยตรงในโปรแกรม C นั้นไม่ใช่เรื่องง่าย โดยทั่วไปแล้ว glibc จะให้ wrapper ที่ทำให้งานง่ายขึ้น แต่ glibc จะเพิ่ม wrapper สำหรับstatx(2)ในเดือนสิงหาคม 2018 (รุ่น2.28มีใน 18.10) โชคดีที่ @whotwagner เขียนโปรแกรมตัวอย่าง Cที่แสดงวิธีใช้การstatx(2)เรียกระบบบนระบบ x86 และ x86-64 เอาท์พุทมันเป็นรูปแบบเดียวกับstatค่าเริ่มต้นโดยไม่มีตัวเลือกการจัดรูปแบบใด ๆ แต่มันง่ายในการปรับเปลี่ยนเพื่อพิมพ์เพียงเวลาเกิด

ก่อนอื่นโคลนมัน:

git clone https://github.com/whotwagner/statx-fun

คุณสามารถรวบรวมstatx.cรหัสหรือถ้าคุณต้องการเวลาเกิดให้สร้างbirth.cไดเรกทอรีในโคลนด้วยรหัสต่อไปนี้ (ซึ่งเป็นรุ่นที่น้อยที่สุดของstatx.cการพิมพ์เพียงแค่การประทับเวลาการสร้างรวมถึงความแม่นยำระดับนาโนวินาที):

#define _GNU_SOURCE
#define _ATFILE_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include "statx.h"
#include <time.h>
#include <getopt.h>
#include <string.h>

// does not (yet) provide a wrapper for the statx() system call
#include <sys/syscall.h>

/* this code works ony with x86 and x86_64 */
#if __x86_64__
#define __NR_statx 332
#else
#define __NR_statx 383
#endif

#define statx(a,b,c,d,e) syscall(__NR_statx,(a),(b),(c),(d),(e))

int main(int argc, char *argv[])
{
    int dirfd = AT_FDCWD;
    int flags = AT_SYMLINK_NOFOLLOW;
    unsigned int mask = STATX_ALL;
    struct statx stxbuf;
    long ret = 0;

    int opt = 0;

    while(( opt = getopt(argc, argv, "alfd")) != -1)
    {
        switch(opt) {
            case 'a':
                flags |= AT_NO_AUTOMOUNT;
                break;
            case 'l':
                flags &= ~AT_SYMLINK_NOFOLLOW;
                break;
            case 'f':
                flags &= ~AT_STATX_SYNC_TYPE;
                flags |= AT_STATX_FORCE_SYNC;
                break;
            case 'd':
                flags &= ~AT_STATX_SYNC_TYPE;
                flags |= AT_STATX_DONT_SYNC;
                break;
            default:
                exit(EXIT_SUCCESS);
                break;
        }
    }

    if (optind >= argc) {
        exit(EXIT_FAILURE);
    }

    for (; optind < argc; optind++) {
        memset(&stxbuf, 0xbf, sizeof(stxbuf));
        ret = statx(dirfd, argv[optind], flags, mask, &stxbuf);
        if( ret < 0)
        {
            perror("statx");
            return EXIT_FAILURE;
        }
        printf("%lld.%u\n", *&stxbuf.stx_btime.tv_sec, *&stxbuf.stx_btime.tv_nsec);
    }
    return EXIT_SUCCESS;
}

แล้ว:

$ make birth
$ ./birth ./birth.c
1511793291.254337149
$ ./birth ./birth.c | xargs -I {} date -d @{}
Mon Nov 27 14:34:51 UTC 2017

ในทางทฤษฎีสิ่งนี้ควรทำให้เวลาในการสร้างเข้าถึงได้มากขึ้น:

  • ควรสนับสนุนระบบไฟล์มากกว่าระบบไฟล์ ext * ( debugfsเป็นเครื่องมือสำหรับระบบไฟล์ ext2 / 3/4 และไม่สามารถใช้กับผู้อื่นได้)
  • คุณไม่จำเป็นต้องรูทเพื่อใช้สิ่งนี้ (ยกเว้นสำหรับการติดตั้งแพ็กเกจที่จำเป็นเช่นmakeและlinux-libc-dev)

ทดสอบระบบ xfs ตัวอย่างเช่น:

$ truncate -s 1G temp; mkfs -t xfs temp; mkdir foo; sudo mount temp foo; sudo chown $USER foo
$ touch foo/bar
$ # some time later
$ echo > foo/bar
$ chmod og-w foo/bar
$ ./birth foo/bar | xargs -I {} date -d @{}
Mon Nov 27 14:43:21 UTC 2017
$ stat foo/bar                             
  File: foo/bar
  Size: 1           Blocks: 8          IO Block: 4096   regular file
Device: 700h/1792d  Inode: 99          Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/ muru)      Gid: ( 1000/ muru)
Access: 2017-11-27 14:43:32.845579010 +0000
Modify: 2017-11-27 14:44:38.809696644 +0000
Change: 2017-11-27 14:44:45.536112317 +0000
 Birth: -

อย่างไรก็ตามสิ่งนี้ใช้ไม่ได้กับ NTFS และ exfat ฉันเดาว่าระบบไฟล์ของ FUSE สำหรับผู้ที่ไม่มีเวลาสร้าง


หากหรือมากกว่าเมื่อ glibc เพิ่มการสนับสนุนสำหรับการstatx(2)เรียกของระบบstatจะตามมาในไม่ช้าและเราจะสามารถใช้statคำสั่งเก่าแบบธรรมดาสำหรับสิ่งนี้ แต่ฉันไม่คิดว่านี่จะ backported เพื่อ LTS รุ่นแม้ว่าพวกเขาจะได้รับเมล็ดใหม่ ดังนั้นฉันไม่ได้คาดหวังstatกับการเปิดตัว LTS ใด ๆ ในปัจจุบัน (14.04, 16.04 หรือ 18.04) เพื่อพิมพ์เวลาการสร้างโดยไม่ต้องมีการแทรกแซงด้วยตนเอง

อย่างไรก็ตามในวันที่ 18.10 คุณสามารถใช้งานstatxฟังก์ชั่นได้โดยตรงตามที่อธิบายไว้ในman 2 statx(หมายเหตุว่า 18.10 manpage นั้นไม่ถูกต้องในการระบุว่า glibc ยังไม่ได้เพิ่ม wrapper)


ขอบคุณที่เชื่อมโยงไปยัง GitHub ฉันค้นหาไม่กี่เดือนที่ผ่านมาเมื่อ 4.11 ออกมาและไม่พบอะไรเลยแล้วก็ลืมมันไป
WinEunuuchs2Unix

@ WinEunuuchs2unix ให้อภัยโดยกระตุก แต่มันจะฉลาดที่จะถามในเว็บไซต์เมตาสาเหตุที่บัญชี Muru มีตัวแทนเพียง1?
George Udosen

@ GeorgeUdosen นั่นมันช่างน่าตกใจ! ฉันมีลางสังหรณ์ว่าทำไม ...
WinEunuuchs2Unix

@GeorgeUdosen มีคำถามเมตาเมื่อเร็ว ๆ นี้เกี่ยวกับการระงับโดยทั่วไปและพวกเขาจะไม่พูดกับผู้ใช้ที่เฉพาะเจาะจง: meta.askubuntu.com/questions/18341/…ฉันจะเข้าห้องสนทนาตอนนี้เพื่อให้คุณสามารถสนทนาต่อไปได้ถ้าคุณ ประสงค์.
WinEunuuchs2Unix

เมื่อคุณสมบัติพร้อมใช้งานแล้วคุณจะรู้วิธีแก้ไขฟิลด์ดังกล่าวหรือไม่ ฉันอาจลองสร้าง wrapper ctypes เพื่อทำมันในไพ ธ อน ขอบคุณ
Gringo Suave

3

TL; DR: เพิ่งรัน: sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>

(หากต้องการหาค่า fs ของคุณให้เรียกใช้df -T /path/to/your/fileโดยส่วนใหญ่จะเป็นไปได้/dev/sda1)

รุ่นยาว:

เราจะเรียกใช้สองคำสั่ง:

  1. ค้นหาชื่อพาร์ติชั่นสำหรับไฟล์ของคุณ

    df -T /path/to/your/file

    ผลลัพธ์จะมีลักษณะเช่นนี้ (ชื่อพาร์ติชันเป็นอันดับแรก)

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. ค้นหาเวลาสร้างไฟล์นั้น

    sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>
    

    ctimeในการส่งออกให้มองหา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.