文件和目录之函数futimens、utimensat和utimes

一个文件的访问与修改时间可以通过以下几个函数进行修改。同时, futimensutimensat函数可以指定纳米级精度的时间戳。

#include <sys/stat.h>
int futimens(int fd, const struct timespec times[2]);
int utimensat(int fd, const char *path, const struct timespec times[2], int flag);
两个函数返回值: 若成功,返回 0;若出错,返回 -1。

结构体timespec

struct timespec{
   time_t tv_sec; // seconds 秒
   long tv_nsec;  // nanoseconds 纳秒
}

以上两个函数的times数组参数的第一个元素包含访问时间,第二个元素包含修改时间。这两个时间值均是日历时间,这是自特定时间(1970年1月1日 00:00:00)以来所经过的秒数。

时间戳可以按下列四种方式之一进行指定。

  1. 如果times参数是一个空指针,则访问时间和修改时间两者都设置为当前时间。
  2. 如果times参数指向两个timespec结构的数组,任一数组元素的tv_nsec字段的值为UTIME_NOW, 相应的时间戳就设置为当前时间,忽略相应的tv_sec字段。
  3. 如果times参数指向两个timespec结构的数组, 任一数组元素的tv_nsec字段的值为UTIME_OMIT, 相应的时间戳保持不变,忽略相应的tv_sec字段。
  4. 如果times参数指向两个timespec结构的数组,且tv_nsec字段的值既不是UTIME_NOW也不是UTIME_OMIT, 在这种情况下,相应的时间戳设置为相应的tv_sectv_nsec字段的值。

执行这些函数所要求的的优先权取决于times参数的值。

  • 如果times是一个空指针,或者任一tv_nsec字段设为UTIME_NOW,则进程的有效用户ID必须是该文件的所有者ID;进程对文件必须具有写权限,或者进程是一个超级用户进程。
  • 如果times是非空指针, 并且任一tv_nsec字段的值既不是UTIME_NOW也不是UTIME_OMIT,则进程的有效用户ID必须等于该文件的所有者ID,或者进程必须是一个超级用户进程,对文件只具有写权限是不够的。
  • 如果times是非空指针,并且两个tv_nsec字段的值都为UTIME_OMIT,就不执行任何的权限检查。

futimens函数通过打开文件来更改它的时间, utimensat函数通过提供文件名的方式来更改文件的时间。pathname参数相对于fd参数进行计算,fd要么是打开目录的文件描述符,要么设置为特殊值AT_FDCWD。如果pathname指定了绝对路径,那么fd参数被忽略。flag参数进一步修改默认行为,如果设置为AT_SYMLINK_NOFOLLOW标志,则符号链接本身的时间就会被修改。默认行为是跟随符号链接,并把文件的时间改成符号链接的时间。

测试样例如下:

void test1(){                                                                   
     int fd;                                                                     
     if((fd = open("fu_file", O_RDWR|O_TRUNC)) < 0)                              
         err_ret("fu_file: open error.");                                        
     if(futimens(fd, NULL) < 0)                                                  
         err_ret("fu_file: futimens error.");                                    
     printf("futimens changes.\n");                                              
     close(fd);                                                                  
 }                                                                               
 void test2(){                                                                   
     if(utimensat(AT_FDCWD, "ut_file", NULL, AT_SYMLINK_NOFOLLOW) < 0)           
         err_ret("ut_file: utimensat error.");                                   
     printf("utimensat changes.\n");                                         
}  

第三个要介绍的函数即是utimes

#include <sys/time.h>
int utimes(const char *pathname, const struct timeval times[2]);
函数返回值:若成功,返回0;若出错,返回 -1。

timeval结构体:

struct timeval{
    time_t tv_sec; // seconds 秒
    long tv_usec;  // microseconds 微秒
}

此函数不能对状态更改时间st_ctime指定一个值,因为调用utimes函数时,此字段会自动更新。

 #include "../../include/apue.h"                                                 
 #include <fcntl.h>                                                                                                                                           
 int main(int argc, char *argv[])                                                
 {                                                                               
     int i, fd;                                                                  
     struct stat statbuf;                                                        
     struct timespec times[2];                                                   
     for(i = 1; i < argc; i++){                                                  
         if(stat(argv[i], &statbuf) < 0){                                        
             err_ret("%s: stat error.", argv[i]);                                
             continue;                                                           
         }                                                                       
         if((fd = open(argv[i], O_RDWR | O_TRUNC)) < 0){                         
             err_ret("%s: open error.",argv[i]);                                 
             continue;                                                           
         }                                                                       
         times[0] = statbuf.st_atim;                                             
         times[1] = statbuf.st_mtim;                                             
         if(futimens(fd, times) < 0)                                             
             err_ret("%s: futimens error.", argv[i]);                            
         close(fd);                                                              
     }                                                                           
     return 0;                                                                                                                                                                              
}    

结果图如下:

如上图所见,最后修改时间和最后访问时间是未改变的,但是状态更改时间则更改为程序运行时的时间。

发布了229 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40073459/article/details/104401500