6.文件類型和文件權限管理


6.1.普通文件
(1)普通文件(- regular file)包括文本文件+二進制文件。
(2)文本文件即文件中的內容是由文本構成的,文本即經過某種編碼的字符(譬如ASCII碼字符);所有文件的內容本質上都是數字,而文本文件中的數字本身應理解爲該數字所對應的編碼字符(譬如ASCII碼對應的字符);常見的.c文件和.h文件和.txt文件等都是文本文件;文本文件的好處是可以被人輕鬆讀懂和編輯,則文本文件天生就是爲人類發明的。
(3)二進制文件即文件中存儲的內容本質上也是數字,但這些數字並非字符對應的數字編碼,而是真正的數字;常見的可執行程序文件(gcc編譯生成的a.out;arm-linux-gcc編譯生成的.bin)都是二進制文件。
(4)從本質上來看(刨除文件屬性和內容的理解)文本文件和二進制文件並沒有任何區別,都是1個文件裏面存放了數字;區別是理解方式不同,若把這些數字就當作數字處理則就是二進制文件,若把這些數字按照某種編碼格式去解碼成文本字符,則就是文本文件。
(5)在linux系統層面是不區分文本文件和二進制文件的,我們無法從文件本身準確知道該文件屬於哪種;我們只能事先就知道該文件的類型然後使用該種文件類型的用法去使用它;有時候也會用一些後綴名來人爲的標記文件的類型。
(6)使用文本文件時,常規做法是使用文本文件編輯器(vim、gedit、notepad++、SourceInsight)去打開並編輯它,編輯器會read讀出文件二進制數字內容,然後按照編碼格式去解碼將其還原成字符展現給我們;如果使用文本文件編輯器去打開某個二進制文件,則編輯器會以爲該二進制文件還是文本文件然後試圖去將其解碼成文字,但解碼過程很多數字並不對應有意義的字符所以成了亂碼;使用二進制閱讀工具去讀取文本文件,則呈現的是文本文件中字符所對應的二進制的數字編碼。


6.2.目錄文件和設備文件
(1)目錄文件(d directory)就是文件夾,文件夾在linux中是1種特殊文件;用vi打開某個文件夾,則裏面存的內容包括該目錄文件的路徑+目錄文件夾裏面的文件列表;目錄文件比較特殊,本身並不適合用普通的方式來讀寫,linux中使用特殊的一些API來專門讀寫目錄文件。
(2)設備文件包括字符設備文件(c character)+ 塊設備文件(b block);設備文件對應的是硬件設備,即該文件雖然在文件系統中存在,但並不是真正存在於硬盤上的某個文件,而是文件系統虛擬製造出來的(虛擬文件系統譬如如/dev /sys /proc等);虛擬文件系統中的文件大多數不能或者說不用直接讀寫的,而是用特殊的API產生或者使用的。
(3)管道文件(p pipe)+套接字文件(s socket)+符號鏈接文件(l link)後續用到的時候會詳細分析。


6.3.stat和fstat及lstat函數
(1)每個文件中都附帶了該文件的一些屬性信息(屬性信息是存在於文件本身中的,其只能被專用的API打開看到);文件屬性信息查看API有stat、fstat、lstat,其作用一樣,參數不同,細節略有不同;linux命令行下可以使用stat命令去查看文件屬性信息,實際上stat命令內部就是使用了stat系統調用來實現的(見圖1);struct stat是內核定義的1個結構體,在sys/stat.h中聲明,該結構體中的所有元素加起來就是文件屬性信息。
(2)stat該API的作用就是讓內核將我們要查找的目的文件的屬性信息結構體的值放入我們傳遞給stat函數的buf中,當stat該API調用從內核返回時buf中被填充了該文件的正確的屬性信息,然後我們通過查看buf這種結構體變量的元素即可得知該文件的各種屬性了。
(3)stat是從文件名出發得到文件屬性信息結構體,而fstat是從1個已打開的文件fd出發得到文件的屬性信息;則若文件沒有打開需要讀取文件信息即使用stat,若文件已經被打開需要讀取文件信息即使用fstat效率會更高;stat是從磁盤去讀取靜態文件,而fstat是從內存讀取動態文件;對於符號鏈接文件,stat和fstat查閱的是符號鏈接文件指向的文件的屬性,而lstat查閱的是符號鏈接文件本身的屬性。
(4)通過stat判斷文件具體類型(譬如-、d、l),文件屬性中的文件類型標誌在struct stat結構體的mode_t st_mode元素中,該元素中的每個bit位代表不同的含義,但這些位定義不容易記住,則linux系統事先定義多個宏來進行相應操作(譬如S_ISREG宏返回值是1表示該文件是普通文件,若該文件不是普通文件則返回0)。
(5)獨立判斷文件權限設置,st_mode記錄了文件權限信息,linux並沒有給文件權限測試提供宏操作,而只是提供了位掩碼,則我們只能用位掩碼來判斷文件是否具有相應權限。


6.4.文件的權限管理
(1)st_mode本質上是1個32位的數(類型unsinged int),該數中的每個位表示1個含義;文件類型和文件權限都記錄在st_mode中,我們使用專門的掩碼去取出相應的位即可得知相應的信息。
(2)ls-l打印出的權限列表中共9位分爲3組;第1組表示文件的屬主(owner、user)對該文件的可讀、可寫、可執行權限;第2組表示文件的屬主所在的組(group)對該文件的權限;第3組3個位表示其它用戶(others)對該文件的權限;屬主即該文件屬於誰,一般來說是創建該文件的用戶;但某個文件創建之後可用chown命令去修改該文件的屬主,也可用chgrp命令去修改該文件所在的組(見圖2)。
(3)文件操作時的權限檢查規則即當某個程序a.out被執行,a.out試圖去操作文件test.txt,判定a.out是否具有對test.txt的某種操作權限;首先test.txt具有9個權限位,規定了3種人(user、group、others)對該文件的操作權限;我們判定test.txt是否能被a.out來操作,關鍵先搞清楚a.out被誰執行,即當前程序(進程)是哪個用戶的進程。
(4)文本權限管控其實蠻複雜,我們很難輕易的確定當前用戶對某個文件是否具有某種權限;軟件應在操作某個文件之前先判斷當前用戶是否有權限做相應操作,若有相應權限即可進行操作,若沒有相應權限則提供錯誤信息給用戶;access函數可以測試得到當前執行程序的那個用戶在當前環境下對目標文件是否具有某種操作權限。
(5)chmod/fchmod與權限修改,chmod是1個linux命令,用來修改文件的各種權限屬性,chmod命令只有root用戶纔有權利去執行修改,chmod命令其實內部是用linux的1個叫chmod的API實現的。
(6)chown/fchown/lchown與屬主修改,linux中有個chown命令來修改文件屬主,需以root身份運行(譬如chown root test.txt),chown命令是用chown API實現的;linux中有個chgrp命令來修改文件屬主所在的組(譬如chgrp root test.txt)。
(7)umask與文件權限掩碼,文件權限掩碼是linux系統中維護的1個全局設置,umask的作用是用來設定我們系統中新創建的文件的默認權限的(譬如umask 0000即修改umask值;umask即查詢umask值),umask命令就是用umask API實現的。


6.5.讀取目錄文件
(1)opendir打開某個目錄後得到1個DIR類型的指針給readdir函數使用;readdir函數調用1次就會返回1個struct dirent類型的指針,該指針指向的結構體變量裏面記錄了1個目錄項(即目錄中的1個子文件);readdir函數調用1次只能讀出1個目錄項,要想讀出目錄中所有的目錄項必須多次調用readdir函數;readdir函數內部會記住哪個目錄項已經被讀過了哪個還沒讀,則多次調用後不會重複返回已經返回過的目錄項;當readdir函數返回NULL時就表示目錄中所有的目錄項已經讀完了。
(2)readdir函數和我們前面接觸的某些函數是不同的,首先readdir函數直接返回了1個結構體變量指針,因爲readdir內部申請了內存並且給我們返回了地址,多次調用readdir其實readir內部並不會重複申請內存而是使用第1次調用readdir時分配的那個內存,該設計方法是readdir不可重入的關鍵;readdir在多次調用時是有關聯的,該關聯也標明readdir函數是不可重入的。
(3)庫函數中有一些函數當年剛開始提供時都是不可重入的,後來意識到這種方式不安全,所以重新封裝了C庫,提供了對應的可重入版本;可重入函數的命名格式一般爲“不可重入版本函數名_r”(譬如readdir_r);關於可重入函數和不可重入函數的介紹請參考鏈接http://www.cnblogs.com/parrynee/archive/2010/01/29/1659071.html


這裏寫圖片描述


這裏寫圖片描述


這裏寫圖片描述


6.filepropertyget
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:文件類型和文件權限管理
 * 功能:通過stat簡單讀取某個文件屬性信息並打印輸出;
 *       通過stat判斷某個文件類型;獨立判斷某個文件的權限。
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define PATHNAME "test.txt"

int main(int argc, char **argv)
{
    int ret = -1;
    struct stat buf;

    memset(&buf, 0, sizeof(buf));                       // 清零buf緩衝區
    ret = stat(PATHNAME, &buf);
    if (ret < 0)
    {
        perror("stat error");
        exit(-1);
    }

#if 0
    // 成功獲取了stat結構體,從中可以得到各種屬性信息了
    printf("inode = %d.\n", buf.st_ino);                // 靜態文件Inode編號st_ino
    printf("size = %d bytes.\n", buf.st_size);          // 文件大小st_size  
    printf("st_blksize = %d.\n", buf.st_blksize);       // 操作系統文件讀寫IO緩衝區大小st_blksize
    printf("st_blocks = %d.\n", buf.st_blocks);         // 佔用的塊數st_blocks
#endif  

#if 0
    // 通過stat判斷某個文件的類型
    ret = S_ISREG(buf.st_mode);                         
    printf("ret = %d.\n", ret);                         // ret = 1.
    ret = S_ISDIR(buf.st_mode);
    printf("ret = %d.\n", ret);                         // ret = 0.
#endif

#if 1
    // 獨立判斷某個文件的權限
    // 需在非共享目錄下更改文件權限
    // 增加文件屬主的可執行權限(chmod u+x test.txt)
    ret =  ((S_IRUSR & buf.st_mode) ? 1 : 0);           // 判斷文件的屬主是否有可讀權限,若有則返回1,若無則返回0
    printf("file owner = %d.\n", ret);
#endif

    return 0;
}

6.filepermission
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:文件類型和文件權限管理
 * 功能:驗證文件操作時的權限檢查規則。
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    int ret = -1;

    if (argc != 2)
    {
        printf("usage: %s filename.\n", argv[0]);
        exit(-1);
    }

    // 需在linux原生目錄(譬如“/home/gec/.”)下運行該程序
    // 需在普通用戶下手動新建某個文件,然後手動創建新用戶並來回切換用戶進行測試
    // 以“./a.out filename”格式運行程序
    ret = open(argv[1], O_RDONLY);
    if (ret > 0)
    {
        printf("can read.\n");
        close(ret);
    }
    else
    {
        perror("open O_RDONLY error");
    }

    ret = open(argv[1], O_WRONLY);
    if (ret > 0)
    {
        printf("can write.\n");
        close(ret);
    }
    else
    {
        perror("open O_WRONLY error");
    }

    return 0;
}

6.access
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:文件類型和文件權限管理
 * 功能:使用access函數判斷當前用戶是否對該文件有相應的操作權限。
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define PATHNAME "test.txt"

int main(int argc, char **argv)
{
    int ret = -1;

    ret = access(PATHNAME, F_OK);
    if (ret < 0)
    {
        printf("The file is not exit.\n");
        exit(-1);
    }
    else
    {
        printf("The file is exit.\n");
    }

    ret = access(PATHNAME, R_OK);
    if (ret < 0)
    {
        printf("The file can not read.\n");
    }
    else
    {
        printf("The file can read.\n");
    }

    return 0;
}

6.chmod
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:文件類型和文件權限管理
 * 功能:使用chmod函數修改文件權限。
 */

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

#define PATHNAME "test.txt"

int main(int argc, char **argv)
{
    int ret = -1;

    if (argc != 2)
    {
        printf("usage: %s filename.\n", argv[0]);
        exit(-1);
    }

    // -rwx------若沒特意指明的權限則默認被取消掉
    ret = chmod(PATHNAME,  S_IRUSR | S_IWUSR |S_IXUSR);
    if (ret < 0)
    {
        perror("chmod error");
        exit(-1);
    }

    return 0;
}

6.chown
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:文件類型和文件權限管理
 * 功能:chown函數修改文件屬主和屬主所在的組。
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define PATHNAME "test.txt"

int main(int argc, char **argv)
{
    int ret = -1;

    if (argc != 2)
    {
        printf("usage: %s filename.\n", argv[0]);
        exit(-1);
    }

    // 將test.txt的文件屬主和屬主所在的組均改爲root
    ret = chown(PATHNAME, 0, 0);
    if (ret < 0)
    {
        perror("chown error");
        exit(-1);
    }

    return 0;
}

6.umask
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:文件類型和文件權限管理
 * 功能:使用umask函數設置新建文件的默認權限。
 * Linux下設置新建文件時的默認權限掩碼由umask函數設置 
 * mode_t umask(mode_t umask) 傳入四位八進制數,返回系統原先的權限掩碼 
 * 0666對應文件權限中的0000 0444對應文件權限中的0222 
 *  
 * 系統原來的權限掩碼是:22.
 * 系統新的權限掩碼是:666.
 * 創建了文件test1.txt.
 * -r-xr-xr-x 1 root root 0 Jul 11  2016 test1.txt
 * 系統原來的權限掩碼是:666.
 * 系統新的權限掩碼是:444.
 * 創建了文件test2.txt.
 * -rwxrwxrwx 1 root root 0 Jul 11  2016 test2.txt
 */ 

#include <stdio.h>  
#include <stdlib.h>  
#include <sys/stat.h>  
#include <sys/types.h> 

int main(int argc, char **argv)
{
    mode_t new_umask, old_umask;  

    new_umask = 0666;  
    old_umask = umask(new_umask);  
    printf("系統原來的權限掩碼是:%o.\n",old_umask);  
    printf("系統新的權限掩碼是:%o.\n",new_umask);  
    system("touch test1.txt");  
    printf("創建了文件test1.txt.\n"); 
    system("ls test1.txt -l");

    new_umask = 0444;  
    old_umask = umask(new_umask);  
    printf("系統原來的權限掩碼是:%o.\n",old_umask);  
    printf("系統新的權限掩碼是:%o.\n",new_umask);  
    system("touch test2.txt");  
    printf("創建了文件test2.txt.\n");  
    system("ls test2.txt -l");  

    return 0;  
}

6.opendir_readdir
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 項目:文件類型和文件權限管理
 * 功能:讀取目錄文件並打印輸出並判斷文件類型和統計目錄下的文件項數目。   
 */

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    DIR *pDir = NULL;
    struct dirent *pEnt = NULL;
    unsigned int cnt = 0;               // 統計目錄文件下的文件項數目

    if (argc != 2)
    {
        printf("usage: %s dirname.\n", argv[0]);
        exit(-1);
    }

    pDir = opendir(argv[1]);
    if (NULL == pDir)
    {
        perror("opendir error");
        exit(-1);
    }

    while (1)
    {
        pEnt = readdir(pDir);
        if (pEnt != NULL)
        {
            // 打印輸出該目錄下的所有的文件項名字
            printf("name: [%s].\n", pEnt-> d_name);
            // 判斷某個文件項是否爲普通文件
            if (DT_REG == pEnt->d_type)
            {
                printf("%s is a regular file.\n", pEnt-> d_name);
            }
            else
            {
                printf("%s is not a regular file.\n", pEnt-> d_name);
            }
            // 統計該目錄下所有文件項個數
            cnt++;
        }
        else
        {
            break;
        }
    }
    printf("The cnts of fileobject is %d.\n", cnt);

    return 0;
}

發佈了104 篇原創文章 · 獲贊 29 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章