Linux中的stat函數只能訪問當前用戶所在目錄(提示stat-No such file or directory錯誤)


問題介紹

最近使用Linux C進行編程的時候,當遞歸讀取目錄的時候會發現stat函數一直再報錯(No such file or directory),經過一晚上的修改bug,發現我的代碼中的stat函數只能訪問用戶當前所在的路徑下的文件(即’pwd‘命令所提示的目錄)。

例如:此時我所在的路徑為:/home/mrzhi/Desktop/Linux-網絡編程/Unix_systems_programming/Chapter5_File_system

結果:可以發現該代碼可以正確訪問所在路徑下的文件,但是該路徑下的文件夾卻無法遞歸訪問。但是該代碼中的opendir和reddir函數可以正確打開和讀取該路徑下的文件夾。但是卻無法使用stat函數返回文件的屬性。

圖1. 結果描述

問題分析

這里我們先查看一下stat函數的定義

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
/* These  functions  return  information about a file, in the buffer pointed to by statbuf.
   No permissions are required on the file itself, **but—in the case of stat(), fstatat(),
   and lstat()—execute (search) permission is required on all of the directories in pathname that lead to the file.**
 * stat() and fstatat() retrieve information about the file pointed to by pathname;
   the differences for fstatat() are described below.
 */

可以發現其中有這樣一句話:but——in the case of stat, fstatat(), and lstat() - execute (search) permission is required on all of the directories in pathname that lead to the file。
這句話的意思是路徑名中指向該文件的所有目錄都必須具有執行(搜索權限)。也就是我所在目錄下的test必須具備執行或搜索權限。

錯誤原因:

只有文件為絕對路徑的情況下,才可以獲取文件的stat狀態。而剛開始的代碼中直接為./test/bbb.txt,此時pathname會直接訪問根目錄下的test/bbb.txt,但是我的根目錄下沒有這個文件,因此會報“No Such file or directory”的錯誤。要切記使用絕對路徑。

代碼示例

我的代碼示例如下:

**// 這個一個使用opendir,readdir和closedir等對目錄操作的函數
// 該程序顯示的是目錄中包含的文件名,其實這個目錄的路徑名被作為命令行參數傳送
// note:ls命令會按照字母順序對文件名進行排序,而readdir函數則按照起在目錄文件中出現的順序顯示文件名
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <limits.h>
#include <sys/stat.h>
int printDir (char *path) {
    DIR *dr;
    int ret;
    struct dirent *direntp;
    struct stat *statbuf;    // struct stat 用來保存stat和lstat函數中返回的信息
    // note: 如果statbuf使用指針,則需要使用malloc函數為其分配內存空間,不如直接使用statbuf(不加指針)方便
    //printf("sizeof(struct stat) = %d\n", sizeof(struct stat));
    
    // 使用opendir函數打開所指定的目錄
    dr = opendir(path);
    if(dr == NULL) {
        perror("Failed to open directory");
        return -1;
    }
    // 打印目錄中的文件
    statbuf = (struct stat*)malloc(sizeof(struct stat));
    while ( (direntp = readdir(dr)) != NULL) {
        // fprintf(stderr, "打印文件: ");
        // 調用stat函數查看文件的狀態
        fprintf(stderr, "%s", direntp->d_name);
        /* 在該函數中,stat只能訪問用戶所在的當前目錄-->當前的原因我也不清楚*/
        ret = stat(direntp->d_name, statbuf);
        if (ret == -1) {
            //fprintf(stderr, "errno is %d\n", errno);
            perror(" : Failed to get file status");
            //return -1;
        } else {
            // 其中st_atim表示最后一次訪問的時間,st_time表示最后一次數據修改的時間
            // st_ctime表示最后一次文件狀態改變的時間
            // ctime返回的字符串會以換行符結束,因此可以不用\n
            printf(" : last accessed at %s", ctime(&(statbuf->st_atim)) );
            // 如果該文件是個目錄,則遞歸打印目錄中的文件
            if (*direntp->d_name != '.' && S_ISDIR(statbuf->st_mode)) {
                printf("***************************%s is directory!***********\n", direntp->d_name);
                printDir(direntp->d_name);
                printf("***************************%s ********************\n", direntp->d_name);
            }
        }
    }
    while (direntp == NULL && errno == EINTR);
    // note:使用完畢后一定要關閉目錄
    closedir(dr);
}
int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s dir\n", argv[1]);
        return -1;
    }
    //printf("%s\n", argv[1]);
    int ret = printDir(argv[1]);
    return 0;
}**

修改后的代碼:

只有文件為絕對路徑的情況下,才可以獲取文件的stat狀態。因此這里對printDir函數中的while部分代碼進行修改即可。

// 打印目錄中的文件
    while ( (direntp = readdir(dr)) != NULL) {
        // fprintf(stderr, "打印文件: ");
        fprintf(stderr, "%s", direntp->d_name);

        char buf[1024] = {0};
        sprintf(buf, "%s/%s", path, direntp->d_name);

        // 調用stat函數查看文件的狀態
        /* 在該函數中,stat只能訪問用戶所在的當前目錄-->是路徑的問題, 需要絕對路徑才可以訪問*/
        ret = stat(buf, &statbuf);
        if (ret == -1) {
            perror(" : Failed to get file status");
            //return -1;
        } else {
            // 其中st_atim表示最后一次訪問的時間,st_time表示最后一次數據修改的時間
            // st_ctime表示最后一次文件狀態改變的時間
            // ctime返回的字符串會以換行符結束,因此可以不用\n
            printf(" : last accessed at %s", ctime(&statbuf.st_atim) );

            // 如果該文件是個目錄,則遞歸打印目錄中的文件
            if (*direntp->d_name != '.' && S_ISDIR(statbuf.st_mode)) {
                
                // 當遞歸打印目錄的時候,需要指定絕對路徑,此時為 ./test
                //sprintf(buf + strlen(buf), "/%s", direntp->d_name);

                printf("***************************%s is directory!***********\n", buf);

                printDir(buf);

                printf("***************************%s ********************\n", buf);
            }
        }

    }

note:以上問題是我在編程的時候遇到的,解決方法為經過百度和差異相關文獻(由於本人水平有限,可能解答有錯誤)。如有錯誤之處,請多多指正並諒解。


免責聲明!

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



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