Làm cách nào để tìm thời gian tạo tập tin?


64

Tôi cần tìm thời gian tạo tập tin, khi tôi đọc một số bài viết về vấn đề này, tất cả đều đề cập rằng không có giải pháp nào (như Site1 , Site2 ).

Khi tôi thử statlệnh, nó nói Birth: -.

Vì vậy, làm thế nào tôi có thể tìm thấy thời gian tạo của một tập tin?


2
Hãy nhớ rằng 'thời gian tạo' của tệp không được đảm bảo là chính xác. Có nhiều cách để 'đánh lừa' ngày tạo trên một tệp.
Thomas Ward

1
@ThomasWard Nhiều hơn những cách để làm mờ dữ liệu tệp khác?
Cees Timmerman

Câu trả lời:


67

Có một cách để biết ngày tạo của một thư mục, chỉ cần làm theo các bước sau:

  1. Biết inode của thư mục bằng ls -ilệnh (ví dụ: ví dụ X của nó )

  2. Biết phân vùng nào thư mục của bạn được lưu bằng df -T /pathlệnh (giả sử nó bật /dev/sda1)

  3. Bây giờ sử dụng lệnh này: sudo debugfs -R 'stat <X>' /dev/sda1

Bạn sẽ thấy trong đầu ra:

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

crtime là ngày tạo tập tin của bạn.

Những gì tôi đã thử nghiệm :

  1. Tạo một thư mục tại thời điểm cụ thể.
  2. Truy cập nó.
  3. Sửa đổi nó bằng cách tạo một tập tin.

  4. Tôi đã thử lệnh và nó đã cho một thời gian chính xác.

  5. Sau đó, tôi sửa đổi nó, và kiểm tra lại, thời gian chờ vẫn như cũ, nhưng sửa đổi và thời gian truy cập đã thay đổi.

Tôi đăng bài này, vì tôi muốn thảo luận vì vậy tôi có thể hiểu rõ hơn, tôi tự hỏi tại sao người ta nói rằng Linux không hỗ trợ tính năng này
nux

13
Vì bản thân Linux thì không. Hệ thống tập tin ext4 có thông tin này nhưng kernel không cung cấp API để truy cập. Rõ ràng, debugfstrích xuất nó trực tiếp từ hệ thống tập tin để nó không cần sử dụng API của kernel. Xem tại đây .
terdon

Tôi đã thử nó. Nó hoạt động hoàn hảo trên hệ thống tệp ext4
Fahim Babar Patel

1
Có vẻ như đây là ext4 cụ thể? Nó không hoạt động với XFS cho tôi.
Quantum7

Hạt nhân, glibc và coreutils hiện hỗ trợ statx()kể từ tháng 3 năm 2019.
hà mã

54

@Nux tìm thấy một giải pháp tuyệt vời cho việc này mà tất cả các bạn nên nâng cấp. Tôi quyết định viết một chức năng nhỏ có thể được sử dụng để chạy mọi thứ trực tiếp. Chỉ cần thêm điều này vào của bạn ~/.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
}

Bây giờ, bạn có thể chạy get_crtimeđể in ngày tạo của bao nhiêu tệp hoặc thư mục bạn muốn:

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

Lưu ý rằng ngày tạo không phải là ngày tạo file gốc nếu tập tin là một bản sao (như nó với ngày sửa đổi). Khi một tệp được sao chép, ngày sửa đổi là từ bản gốc, nhưng ngày tạo là từ bản sao. (theres một số hiểu lầm trong câu hỏi này: askubuntu.com/questions/529885/... )
Jacob Vlijm

1
@JacobVlijm tốt, vâng, tất nhiên. Điều đó không rõ ràng sao? Làm sao có thể khác được? Một bản sao là một tập tin mới chỉ có cùng nội dung với một nội dung khác. Thời gian sửa đổi cũng thay đổi cho một bản sao bằng cách này. Nó được đặt thành thời điểm bản sao được tạo trừ khi bạn rõ ràng chọn điều đó không xảy ra bằng cách sử dụng cp -phoặc tương tự.
terdon

Hoàn toàn, nhưng đồng thời, nó sẽ không hợp lý nếu như mod. ngày, một nơi nào đó trong tập tin ngày sẽ được lưu trữ khi nó bắt nguồn. Tôi phải thừa nhận rằng tôi đã không biết rằng đó không phải là trường hợp cho đến khi tôi trả lời câu hỏi được liên kết.
Jacob Vlijm

Chỉ cần thử bằng cách này, tôi chỉ sao chép các tập tin trong nautilus, ngày sửa đổi vẫn như cũ (m), m. ngày sớm hơn ngày tạo.
Jacob Vlijm

1
@demongolem có, phiên bản CentOS dfdường như không hỗ trợ --outputtùy chọn này. Trong trường hợp đó, bạn có thể thay thế dòng đó fs=$(df foo | awk '{a=$1}END{print a}'và chức năng cũng sẽ hoạt động. Tất cả những gì tôi thể hiện trong câu trả lời này là một cách để bọc lệnh từ câu trả lời được chấp nhận theo cách có thể chạy trực tiếp cho các mục tiêu tệp / thư mục.
terdon

11

Không thể stathiển thị thời gian tạo là do giới hạn của lệnh stat(2)gọi hệ thống , mà cấu trúc trả về không bao gồm một trường cho thời gian tạo. Tuy nhiên, bắt đầu với Linux 4.11 (tức là 17.10 và mới hơn *), cuộc gọi hệ thống mớistatx(2) khả dụng, bao gồm thời gian tạo trong cấu trúc trả về của nó.

* Và có thể trên các bản phát hành LTS cũ hơn bằng cách sử dụng hạt nhân ngăn xếp phần cứng (HWE). Kiểm tra uname -rxem nếu bạn đang sử dụng kernel ít nhất là 4.11 để xác nhận.

Thật không may, không dễ để gọi các cuộc gọi hệ thống trực tiếp trong một chương trình C. Thông thường glibc cung cấp một trình bao bọc giúp công việc trở nên dễ dàng, nhưng glibc chỉ thêm một trình bao bọc cho statx(2)tháng 8 năm 2018 (phiên bản 2.28 , có sẵn trong 18.10). May mắn thay, @whotwagner đã viết một chương trình C mẫu cho biết cách sử dụng lệnh statx(2)gọi hệ thống trên các hệ thống x86 và x86-64. Đầu ra của nó có cùng định dạng với statmặc định, không có bất kỳ tùy chọn định dạng nào, nhưng thật đơn giản để sửa đổi nó để chỉ in thời gian sinh.

Đầu tiên, sao chép nó:

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

Bạn có thể biên dịch statx.cmã, hoặc, nếu bạn chỉ muốn thời gian sinh, hãy tạo một birth.ctrong thư mục nhân bản với mã sau (đây là phiên bản tối thiểu của statx.cviệc in chỉ dấu thời gian tạo bao gồm độ chính xác nano giây)

#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;
}

Sau đó:

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

Về lý thuyết, điều này sẽ làm cho thời gian sáng tạo dễ tiếp cận hơn:

  • nhiều hệ thống tập tin nên được hỗ trợ hơn chỉ là hệ thống ext * ( debugfslà công cụ dành cho hệ thống tập tin ext2 / 3/4 và không thể sử dụng trên các hệ thống khác)
  • bạn không cần root để sử dụng cái này (ngoại trừ việc cài đặt một số gói bắt buộc, như makelinux-libc-dev).

Thử nghiệm hệ thống xfs, ví dụ:

$ 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: -

Tuy nhiên, điều này không hoạt động đối với NTFS và exfat. Tôi đoán hệ thống tập tin FUSE cho những người không bao gồm thời gian tạo.


Nếu, hay đúng hơn là khi nào, glibc bổ sung hỗ trợ cho statx(2)cuộc gọi hệ thống, statsẽ sớm xuất hiện và chúng tôi sẽ có thể sử dụng statlệnh cũ đơn giản cho việc này. Nhưng tôi không nghĩ rằng điều này sẽ được đưa vào các bản phát hành LTS ngay cả khi chúng có được các nhân mới hơn. Vì vậy, tôi không mong đợi stattrên bất kỳ LTS phát hành hiện tại (14.04, 16.04 hoặc 18,04) bao giờ in thời gian sáng tạo mà không cần can thiệp bằng tay.

Tuy nhiên, vào ngày 18.10, bạn có thể trực tiếp sử dụng statxchức năng như được mô tả trong man 2 statx(lưu ý rằng trang chủ 18.10 không chính xác khi nói rằng glibc chưa thêm trình bao bọc).


Cảm ơn đã liên kết với github. Tôi đã tìm kiếm vài tháng trước khi 4.11 xuất hiện và không tìm thấy gì và sau đó quên nó đi.
WinEunuuchs2Unix

@ WinEunuuchs2unix tha thứ bằng cách ping nhưng sẽ là khôn ngoan khi hỏi trên trang web meta tại sao tài khoản của muru có một đại diện chỉ 1?
George Udosen

@GeorgeUdosen Thật là sốc! Tôi có linh cảm tại sao mặc dù ...
WinEunuuchs2Unix

@GeorgeUdosen Có một câu hỏi meta gần đây về việc đình chỉ nói chung và họ sẽ không giải quyết một người dùng cụ thể: meta.askubfox.com/questions/18341/ Bây giờ tôi sẽ vào phòng trò chuyện để bạn có thể tiếp tục trò chuyện ở đó nếu bạn muốn.
WinEunuuchs2Unix

Bây giờ tính năng đã có sẵn, bạn có biết cách sửa đổi trường đó không? Tôi có thể cố gắng tạo một trình bao bọc ctypes để làm điều đó trong python. Cảm ơn.
Gringo Suave

3

TL; DR: Chỉ cần chạy: sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>

(Để tìm ra fs của bạn, hãy chạy df -T /path/to/your/file, rất có thể nó sẽ xảy ra /dev/sda1).

Phiên bản dài:

Chúng tôi sẽ chạy hai lệnh:

  1. Tìm ra tên của tên phân vùng cho tập tin của bạn.

    df -T /path/to/your/file

    Đầu ra sẽ trông như thế này (tên phân vùng là đầu tiên):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. Tìm ra thời gian tạo cho tập tin đó.

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

    Trong đầu ra, tìm kiếm ctime.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.