C實現Linux之touch命令


Linux 的 touch 命令用來修改文件時間戳,或者新建一個不存在的文件,使用方式如下:

touch [-acm][-r ref_file(參照文件)|-t time(時間值)] file(文件名)  

本實驗基於C語言實現Linux touch命令的 [-acm]選項。

注:

touch file1.txt 更新 file1.txt 的存取和修改時間

touch -a file1.txt 改變 file1.txt 的讀取時間記錄

touch -c file1.txt 如果 file1.txt 不存在,不創建文件

touch -m file1.txt 改變 file1.txt 的修改時間記錄

 

touch命令就是修改文件或者目錄的時間屬性,包括存取時間和更改時間。若文件不存在,系統會建立一個新的文件。

 

getopt函數:解決參數處理的函數。

//頭文件
#include<unistd.h>
//函數原型:
int getopt(int argc,char * const argv[ ],const char * optstring);

函數介紹:分析命令參數。

返回值:參數字符。

 

open函數:

函數 open 是 UNIX 系統的系統調用函數,區別於 C 語言庫函數 fopen。

 

//頭文件:
#include<fcntl.h>
//函數原型
int open(constchar*pathname, int flags);    
int open(constchar*pathname, int flags, mode_t mode);

函數作用:打開和創建文件。

返回值:成功返回文件描述符,失敗返回-1。

參數說明:

對於 open 函數來說,第三個參數僅當創建新文件時(即使用了 O_CREAT 時)才使用,用於指定文件的訪問權限位(access permission bits)。pathname 是待打開/創建文件的 POSIX 路徑(如/home/user/a.cpp);flags 用於指定文件的打開/創建模式,這個參數可由以下常量(定義於fcntl.h)通過邏輯位或邏輯構成。

O_RDONLY 只讀模式

O_WRONLY 只寫模式

O_RDWR 讀寫模式

參數 mode 則有下列數種組合, 只有在建立新文件時才會生效, 此外真正建文件時的權限會受到 umask 值所影響, 因此該文件權限應該為 (mode-umaks).

S_IRWXU 00700 權限, 代表該文件所有者具有可讀、可寫及可執行的權限.

S_IRUSR 或S_IREAD, 00400 權限, 代表該文件所有者具有可讀取的權限.

S_IWUSR 或S_IWRITE, 00200 權限, 代表該文件所有者具有可寫入的權限.

S_IXUSR 或S_IEXEC, 00100 權限, 代表該文件所有者具有可執行的權限.

S_IRWXG 00070 權限, 代表該文件用戶組具有可讀、可寫及可執行的權限.

S_IRGRP 00040 權限, 代表該文件用戶組具有可讀的權限.

S_IWGRP 00020 權限, 代表該文件用戶組具有可寫入的權限.

S_IXGRP 00010 權限, 代表該文件用戶組具有可執行的權限.

S_IRWXO 00007 權限, 代表其他用戶具有可讀、可寫及可執行的權限.

S_IROTH 00004 權限, 代表其他用戶具有可讀的權限

S_IWOTH 00002 權限, 代表其他用戶具有可寫入的權限.

S_IXOTH 00001 權限, 代表其他用戶具有可執行的權限.

 

函數utimensat

//頭文件
#include<sys/stat.h>
//函數原型
int utimensat(int dirfd, const char *pathname,const struct timespec times[2], intflags);

作用:utimensat 是以納秒級的精度改變文件的時間戳。utimensat()通過文件的路徑(pathname)獲得文件。

 

這個系統調用函數都是通過一個時間數組 times 來改變時間戳的,times[0] 修改最后一次訪問的時間(access time),times[1] 修改最后修改的時間 (modify time)。該時間數組是由秒和納秒兩個部分組成,數據結構如下:

 

特別注意:

當 times[x].tv_sec = UTIME_OMIT; 相應的時間戳不變,times[x].tv_sec = UTIME_NOW; 相應的時間戳編程當前時間。

 

實例:

#include<stdio.h>
#include<getopt.h>
#include<sys/types.h>
#include<time.h>
#include<fcntl.h>
#include<stdlib.h>
#include<unistd.h>
#include<stdbool.h>
#include<sys/time.h>
#include<sys/stat.h>

#define CH_ATIME 1
#define CH_MTIME 2

//定義創建文件時的模式,此處對用戶,組,其他設置的權限都是可讀可寫。
#define MODE_RW_UGO (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |S_IWOTH)

//標志文件access time 和 modify time的改變情況
static int change_times;

// 如果有(-c)選項,並且不存在命令行中輸入的文件名,則不創建 
static bool no_create;

//當設置新的access time 和 modify time的時候使用
static struct timespec newtime[2];

//mytouch命令核心的核心模塊,用於創建或者更新文件的時間戳。
static bool mytouch(const char *file)
{
    bool ok;
    int fd = -1;
    if (!no_create)
    {
        fd = open(file, O_CREAT | O_WRONLY, MODE_RW_UGO);
    }    

    //在主函數中,如果沒有檢測到(-a)(-m),則change_times == (CH_ATIME | CH_MTIME),\
    否則按照選項只用改變其中一個時間戳。
    if (change_times !=(CH_ATIME | CH_MTIME))
    {
        //只設定其中一個時間值。
        
        /*如果change_times == CH_MTIME,即(-m),將對應的修改access time
        的timespec結構的tv_nsec設置為UTIME_OMIT;參考utimensat函數的用法*/
        if (change_times == CH_MTIME)
        {
            newtime[0].tv_nsec = UTIME_OMIT;
        }
        
        /*如果change_times == CH_MTIME,即(-a),將對應的修改modify time
        的timespec結構的tv_nsec設置為UTIME_OMIT;參考utimensat函數的用法*/
        else
        {
            //AT_FDCWD表示當前工作目錄。
            newtime[1].tv_nsec = UTIME_OMIT;
        }
    }
    ok = (utimensat(AT_FDCWD, file, newtime, 0) == 0);
    return true;
}

int main(int argc, char **argv)
{
    int c;
    bool ok = true;
    change_times = 0;
    no_create = false;

    //從命令行中得到命令的選項,即以'-'開頭的參數。目前只支持三種選型-a, -c, -m。
    while ((c = getopt(argc, argv, "acm")) != -1)
    {
        switch(c)
        {
            case 'a':
                change_times |= CH_ATIME;
                break;
            case 'c':
                no_create = true;
                break;
            case 'm':
                change_times |= CH_MTIME;
                break;
            default:
                printf("fault option!");
        }    
    }

    if (change_times == 0)
    {
        change_times =CH_ATIME | CH_MTIME;
    }

    newtime[0].tv_nsec = UTIME_NOW;
    newtime[1].tv_nsec = UTIME_NOW;
    
    //如果optind == argc,代表少輸入文件名字
    if (optind == argc)
    {
        printf("missing file operand\n");
    }    

    //針對多個文件名字調用mytouch函數
    for (; optind < argc; ++optind)
    {
        ok &= mytouch(argv[optind]);
    }
    exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}

 

運行結果:

 

touch 創建文件

 

touch -a 命令

 

touch -m

 

touch -c


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM