C中的chmod分配错误的权限

Posted

技术标签:

【中文标题】C中的chmod分配错误的权限【英文标题】:Chmod in C assigning wrong permissions 【发布时间】:2017-08-10 23:12:33 【问题描述】:

以下是我的方法的代码,该方法将文件从路径复制到文件到作为目标提供的目录。副本工作得很好,但是我的 chmod 调用为目标中的复制文件分配了错误的权限。如果源中权限为644,则复制的文件权限为170或120。

我已经尝试调试了好几个小时,这让我有点发疯,因此非常感谢任何帮助。

void copy_file(char* src, char* dest) 

    char a;
    //extract file name through a duplicate ptr
    char* fname = strdup(src);
    char* dname = basename(fname);
    //open read and write streams
    FILE* read;
    FILE* write;

    read = fopen(src, "r");
    chdir(dest);
    write = fopen(dname, "w");

    //error checking
    if (read == NULL) //|| (write == NULL))
       
        perror("Read Error: ");
        exit(0);
    

    else if (write == NULL)
    
        perror("Write Error: ");
        exit(0);
    

    //write from src to dest char by char
    while (1)
        a = fgetc(read);
        if (a == EOF) 
        
            break;
        
        fputc(a, write);
    

    //close files
    fclose(read);
    fclose(write);

    // this is where I attempt to assign source file permissions
    //and it goes horribly wrong    
    struct stat src_st;
    if(stat(src, &src_st))
        perror("stat: ");
    

    chmod(dname, src_st.st_mode);
    printf("%o\n", src_st.st_mode & 0777);

【问题讨论】:

请阅读minimal reproducible example。 char a; ... a = fgetc(read); 是错误的。 fgetc 返回 int 是有原因的。 fname = strdup(src); 是内存泄漏。你永远不会释放fname 如果fopen(src, "r")fopen(dname, "w") 均失败,您的代码将显示来自dname 的错误,但声称它来自读取src exit(0) 表示终止成功。使用exit(EXIT_FAILURE) 处理错误。 【参考方案1】:

fopen(src, "r"),然后你chdir(dest)。这意味着当您稍后调用stat(src, &src_st) 时,没有理由认为stat 将访问与fopen 相同的文件,或者实际上stat 将访问任何文件。

如果stat 失败,您仍然继续调用chmod,因此您将src_st.st_mode 中的任何随机垃圾传递给chmod

您应该在调用fclose(src) 之前使用fstat(fileno(read), &src_st),而不是调用stat(src, &src_st)

【讨论】:

这行得通,非常感谢仍在努力使用 C 的人!【参考方案2】:

基本问题是您必须立即检查fopenchdirstat 等系统调用

例如,我尝试的第一件事是copy_file( "test.data", "test2.data" ) 没有意识到它需要一个目标目录

char* fname = strdup(src);
char* dname = basename(fname);

dname 现在是test.data,与源相同。

read = fopen(src, "r");     // succeeds
chdir(dest);                // fails
write = fopen(dname, "w");  // blows away test.data, the source

您最终确实会检查 readwrite,但要在损坏完成之后。

吹走你的源文件真的很糟糕。您的代码处理失败的系统调用很重要。如果你不这样做,它会继续航行,造成混乱和破坏。


C 中的大多数系统调用都返回 0 表示成功。这是一种反模式,其中返回值是错误标志,因此 false 表示失败,其他任何内容都表示错误类型(尽管 stat 不使用它,但它使用 errno)。

当它失败时,stat 返回 -1,这是真的。所以这是错误的方法。

struct stat src_st;
if(stat(src, &src_st))
    perror("stat: ");

相反,您必须检查非零。

    struct stat src_st;
    if(stat(src, &src_st) != 0 )
        // Note that I don't use perror, it doesn't provide enough information.
        fprintf(stderr, "Could not stat %s: %s\n", src, strerror(errno));
        exit(1);
    

您可以猜到,这会变得非常乏味,而且您会忘记,或者每次都略有不同。您需要围绕这些函数编写包装器来为您进行错误处理。

FILE *fopen_checked( const char *file, const char *mode ) 
    FILE *fp = fopen(file, mode);
    if( file == NULL ) 
        fprintf(stderr, "Could not open '%s' for '%s': %s", file, mode, strerror(errno));
        exit(1);
    

    return fp;

这不是最好的错误处理,但它至少可以确保您的代码适当地停止并着火。


关于chdir 的注释:如果可以避免,请不要使用它chdir 会影响程序的全局状态、当前工作目录,而全局变量会增加一切的复杂性。一个函数非常非常容易改变目录而不是像你的那样改回来。现在你的进程处于一个奇怪的状态。

例如,如果有人做了copy_file( "somefile", "foo" ),这会将程序留在foo/。如果他们随后执行copy_file( "otherfile", "foo" ),他们会尝试将 foo/otherfile 复制到 foo/foo/otherfile。

并且,作为@robmayoff pointed out,您的stat 失败,因为该进程现在位于不同的目录中。所以即使是执行chdir 的函数也会被它弄糊涂。

确保你的函数总是chdir 回到像 C 这样的语言的原始目录是非常困难的,并且会使错误处理变得非常复杂。相反,请留在您的原始目录中并使用 basename 之类的函数将路径连接在一起。


最后,避免混合文件操作。使用文件名或文件描述符,但尽量不要同时使用。这意味着如果您使用fopen,请使用fstatfchmod。您可能必须使用 fileno 从 FILE 指针中获取文件描述符。

这避免了携带并保持同步两条数据,文件描述符和文件名。它还避免了chdir 或文件被重命名甚至删除的问题,只要文件描述符保持打开状态,它仍然可以工作。

【讨论】:

【参考方案3】:

这也是个问题:

char a;

...

while (1)
    a = fgetc(read);
    if (a == EOF) 
    
        break;
    
    fputc(a, write);

fgetc() 返回int,而不是char。每the C Standard,7.21.7.1 The fgetc function

7.21.7.1 fgetc 函数

概要

#include <stdio.h>
int fgetc(FILE *stream);

假设sizeof( int ) &gt; sizeof( char )char 值是有符号的、2s 补码整数,并且EOF 是一个定义为int-1(所有非常常见的值),读取带有char a = fgetc( stream ); 的文件将读取有效的0xFF 字符值时失败。如果您的实现的默认 char 值是 unsigned charchar a = fgetc( stream ); 将永远不会生成与 EOF 匹配的值。

【讨论】:

以上是关于C中的chmod分配错误的权限的主要内容,如果未能解决你的问题,请参考以下文章

4412 chmod权限

linux文件共享分配只读+禁止复制文件怎么分配权限?

linux 系统 chmod 误操作权限异常修复方式

linux中的权限管理命令

金蝶客户端使用

shell脚本--权限分配