为什么 stat return 结果错误?

Why does stat return wrong result?

我想使用 stat 检查给定的参数是否是目录。该程序有 2 个参数:当第一个参数不是目录或它不存在时,代码可以正常工作。

但是当第一个参数是一个目录并且存在,而第二个参数不存在时,程序说它们都存在——错误的结果。我想知道为什么它不起作用。

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


int main(int n, char **argv)
{
    char *dir_1=argv[1], *dir_2=argv[2];


    if (is_dir(dir_1) == 0)
            printf("Directory %s exists.\n", dir_1);
    else
            printf("Directory %s does not exist.\n", dir_1);

    if (is_dir(dir_2) == 0)
            printf("Directory  %s exists.\n", dir_2);
    else
            printf("Directory  %s does not exist.\n", dir_2);

}


int is_dir(char *file)
{
        struct stat file_stat;
        stat(file, &file_stat);
        return( (S_ISDIR(file_stat.st_mode)) ? 0 : -1);
}

如果文件不存在,stat自己returns -1,并设置errnoENOENT。但是由于第一个目录存在并且是一个目录,所以struct stat填充的是一个目录的信息;这恰好位于堆栈中第二次 stat 调用的完全相同位置。第二个 staterrno ENOENT 失败,但随后 is_dir 解释了第一次调用留下的值。


is_dir 更正确的实现可能是:

int is_dir(char *file)
{
    struct stat file_stat;

    // if an error occurs, we return 0 for false
    if (stat(file, &file_stat) < 0) {
        return 0;
    }

    // otherwise we return whatever the S_ISDIR returns
    return S_ISDIR(file_stat.st_mode);
}

请注意,我也更改了 return 值;诸如 is_dir 之类的函数应 return 一个布尔值,在函数名称说明真实事实的情况下为真(非零),否则为零。

你会像这样使用它:

if (is_dir(dir_1)) {
        printf("Directory %s exists.\n", dir_1);
}
else {
        printf("Directory %s does not exist.\n", dir_1);
}

if (is_dir(dir_2)) {
        printf("Directory  %s exists.\n", dir_2);
}
else {
        printf("Directory  %s does not exist.\n", dir_2);
}

请注意,本例中的 return 值 0 并不意味着一定不存在具有该名称的目录; stat 系统调用也可能由于权限不足等原因而失败;扩展逻辑(解释 errno 的值)超出了这个答案的范围。

这个答案是一个又一个被采纳的。 S_ISDIR 在 MSVC 中不存在,而是有 _S_IFDIR。替换后,编译器通知 is_dir() 不是 return 值。原因是 _S_IFDIR 是掩码,而不是函数。因此,在对代码进行了一些调整之后,我得到了它。

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

int is_dir(char *file)
{
    struct stat file_stat;
    if (stat(file, &file_stat) == 0)                    // check it worked
        return file_stat.st_mode & _S_IFDIR;            // it's a status mask
    return 0;
}

int main(int argc, char **argv)                         // conventional ids
{
    char *dir_1, *dir_2;
    if (argc < 3) return 0;                             // check silliness
    dir_1=argv[1];
    dir_2=argv[2];

    if (is_dir(dir_1))                                  // reversed the logic
        printf("%s is a Directory.\n", dir_1);
    else
        printf("%s is not a Directory.\n", dir_1);      // better text

    if (is_dir(dir_2))
        printf("%s is a Directory.\n", dir_2);
    else
        printf("%s is not a Directory.\n", dir_2);
    return 0;
}

程序输出:

>test test.c wtest
test.c is not a Directory.
wtest is a Directory.

反过来:

>test wtest test.c
wtest is a Directory.
test.c is not a Directory.