You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Unix EXT4系统中修改文件的所有时间戳(支持纳秒精度)?

如何在Unix EXT4系统中修改文件的所有时间戳(支持纳秒精度)?

嘿,我完全懂你现在的困扰——要在C程序里给EXT4文件改全时间戳还得支持纳秒精度,终端敲debugfs虽然能搞定,但集成到代码里确实得费点功夫。我给你整理了一套靠谱的方案,分步骤来:

一、先搞定访问/修改/状态时间(aTime、mTime、cTime)的纳秒级修改

这三个时间戳里,aTime(访问时间)和mTime(修改时间)用标准系统调用就能轻松实现纳秒精度修改,cTime的情况特殊点,我单独说明。

1. aTime和mTime的修改(普通用户权限即可)

用utimensat()这个POSIX标准函数,专门用来设置文件的访问和修改时间,原生支持纳秒。给你贴个实用的代码例子:

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <perror.h>

// 传入文件路径、新的aTime和mTime(纳秒级)
int update_am_times(const char *file_path, struct timespec new_atime, struct timespec new_mtime) {
    // AT_FDCWD表示以当前工作目录为基准解析文件路径
    int result = utimensat(AT_FDCWD, file_path, (struct timespec[]){new_atime, new_mtime}, 0);
    if (result == -1) {
        perror("Failed to update aTime and mTime");
    }
    return result;
}

这里的struct timespec结构体里,tv_sec是从Unix纪元开始的秒数,tv_nsec就是纳秒部分(范围0到999999999)。

2. cTime(状态时间)的特殊说明

划重点:普通情况下cTime会被内核自动更新为元数据修改的当前时间,因为它的核心作用就是记录文件元数据最后变化的时间。如果非要手动把cTime设为指定值,那只能像改创建时间那样用debugfs,而且必须要有root权限——毕竟这属于直接修改文件系统的底层元数据了。

二、修改EXT4专属的创建时间(crTime,纳秒级)

这个是最麻烦的,因为内核没有提供直接修改crTime的系统调用,只能通过debugfs直接操作EXT4的inode。要在C程序里实现,核心就是安全地调用debugfs命令,同时获取到必要的inode号和设备路径。

步骤1:获取文件的inode号和所在设备路径

debugfs需要这两个参数才能定位到目标文件的inode,直接上代码:

#include <sys/stat.h>
#include <mntent.h>
#include <stdio.h>
#include <string.h>
#include <perror.h>

// 获取目标文件的inode号
ino_t get_file_inode(const char *file_path) {
    struct stat file_stat;
    if (stat(file_path, &file_stat) == -1) {
        perror("Failed to get file stat");
        return (ino_t)-1;
    }
    return file_stat.st_ino;
}

// 根据文件的设备号,找到对应的挂载设备路径(比如/dev/sda1)
char *get_device_path(dev_t dev_num, char *buf, size_t buf_size) {
    FILE *mnt_file = setmntent("/etc/mtab", "r");
    if (!mnt_file) {
        perror("Failed to open mount table");
        return NULL;
    }

    struct mntent *mnt_entry;
    while ((mnt_entry = getmntent(mnt_file)) != NULL) {
        struct stat dir_stat;
        if (stat(mnt_entry->mnt_dir, &dir_stat) == 0 && dir_stat.st_dev == dev_num) {
            strncpy(buf, mnt_entry->mnt_fsname, buf_size - 1);
            buf[buf_size - 1] = '\0';
            endmntent(mnt_file);
            return buf;
        }
    }

    endmntent(mnt_file);
    fprintf(stderr, "Could not find device path\n");
    return NULL;
}

步骤2:在C程序中安全调用debugfs修改crTime

这里不推荐用system()函数——它会启动shell,有安全风险(比如路径里的特殊字符可能被恶意解析)。最好用fork()+execlp()的组合,直接执行debugfs命令,更可控也更安全:

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

// 封装执行debugfs命令的工具函数
int run_debugfs_command(const char *dev_path, const char *debugfs_cmd) {
    pid_t child_pid = fork();
    if (child_pid == -1) {
        perror("Fork failed");
        return -1;
    }

    if (child_pid == 0) {
        // 子进程执行debugfs命令
        execlp("debugfs", "debugfs", "-w", "-R", debugfs_cmd, dev_path, (char *)NULL);
        // 如果execlp返回,说明执行失败
        perror("Failed to execute debugfs");
        exit(EXIT_FAILURE);
    } else {
        // 父进程等待子进程结束,获取执行状态
        int status;
        waitpid(child_pid, &status, 0);
        if (WIFEXITED(status)) {
            return WEXITSTATUS(status);
        } else {
            fprintf(stderr, "Debugfs command terminated abnormally\n");
            return -1;
        }
    }
}

// 主函数:修改文件的crTime(纳秒级)
int update_crtime(const char *file_path, struct timespec new_crtime) {
    struct stat file_stat;
    if (stat(file_path, &file_stat) == -1) {
        perror("Failed to get file stat");
        return -1;
    }

    // 获取文件所在的设备路径
    char dev_path[256];
    if (!get_device_path(file_stat.st_dev, dev_path, sizeof(dev_path))) {
        return -1;
    }

    ino_t inode_num = file_stat.st_ino;
    char crtime_sec_cmd[256];
    char crtime_nsec_cmd[256];

    // 构造设置crTime秒部分的debugfs命令
    snprintf(crtime_sec_cmd, sizeof(crtime_sec_cmd), 
             "set_inode_field <%lu> crtime @%ld", 
             (unsigned long)inode_num, (long)new_crtime.tv_sec);
    if (run_debugfs_command(dev_path, crtime_sec_cmd) != 0) {
        fprintf(stderr, "Failed to set crtime seconds\n");
        return -1;
    }

    // 构造设置crTime纳秒部分的debugfs命令
    snprintf(crtime_nsec_cmd, sizeof(crtime_nsec_cmd), 
             "set_inode_field <%lu> crtime_extra %ld", 
             (unsigned long)inode_num, (long)new_crtime.tv_nsec);
    if (run_debugfs_command(dev_path, crtime_nsec_cmd) != 0) {
        fprintf(stderr, "Failed to set crtime nanoseconds\n");
        return -1;
    }

    return 0;
}

三、关键注意事项

  • 权限要求:修改crTime和手动设置cTime必须要有root权限(毕竟要直接操作文件系统inode);修改aTime和mTime只要对文件有写权限就行。
  • 文件系统限制:这套方案只适用于EXT4文件系统,crTime是EXT4的专属特性,其他文件系统(比如XFS)的创建时间修改方式完全不同。
  • 安全提示:尽量避免用system()或popen()执行命令,fork()+exec系列函数能避开shell注入的风险,更适合生产环境代码。

备注:内容来源于stack exchange,提问作者princess.strelka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 16:19:39