【问题标题】:How can I swap contents of two text files with kernel system calls如何使用内核系统调用交换两个文本文件的内容
【发布时间】:2020-04-29 17:50:22
【问题描述】:

这是我糟糕的尝试:

//open:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//raad, write, exit:
#include <unistd.h>
#include <stdlib.h>
//renameat2:
#include<stdio.h>

int main(){
        int fd1, fd2;
        //do I need those ifs?
        if((fd1 = open("foo", O_RDWR)) == -1){
            write(2, "File failed to open in read/write mode\n", 33);
            exit(-1);
        }

        if((fd2 = open("bar", O_RDWR)) == -1 ){
            write(2, "File failed to open in read/write mode\n", 34);
            exit(-1);
        }

        renameat2(AT_FDCWD,fd1,AT_FDCWD,fd2, RENAME_EXCHANGE);

        close(fd1);
        close(fd2);
        exit(0);
}

我正在尝试使用系统调用函数“renameat2”,但它给了我错误:

main.c:24:3: 警告:函数“renameat2”的隐式声明;你的意思是“重命名”吗?

main.c:24:13: error: 'AT_FDCWD' undeclared(首次在此函数中使用)

main.c:24:40: 错误:'RENAME_EXCHANGE' 未声明(在此函数中首次使用)

【问题讨论】:

  • 是否在最顶部添加#define _GNU_SOURCE,尤其是#includes,修复它吗?
  • 是的,它有帮助。但它递归地打开了另外两个问题:为什么它有帮助,现在如何处理:main.c:22:28: 警告:从不兼容的指针类型传递 'renameat2' 的参数 2 [-Wincompatible-pointer-types]
  • 好的,我明白了。我发现了错误并对其进行了编辑。现在,为什么这有帮助? #define _GNU_SOURCE

标签: c kernel system-calls


【解决方案1】:

两个问题:

首先,由于renameat2 不是任何标准的一部分,因此您需要在包含任何头文件之前使用#define _GNU_SOURCE 才能使用它。请参阅man 7 feature_test_macros 以获得更详细的说明。

其次,renameat2 不支持 AT_EMPTY_PATH 就像其他系统调用一样(即使支持,这也不是您使用它的方式),因此您需要将您想要的文件的名称传递给它重命名,而不是 FD。由此可见,您不需要打开文件。

这是您修复了这两个问题的代码:

#define _GNU_SOURCE

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

int main(){
        renameat2(AT_FDCWD,"foo",AT_FDCWD,"bar", RENAME_EXCHANGE);

        exit(0);
}

这是一个更灵活的版本,具有更好的错误处理能力:

#define _GNU_SOURCE

#include <fcntl.h>
#include <stdio.h>

int main(int argc, char *argv[]){
    if(argc != 3) {
        fputs("Wrong number of arguments\n", stderr);
        return 1;
    }
    if(renameat2(AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_EXCHANGE)) {
        perror("renameat2");
        return 1;
    }
    return 0;
}

【讨论】:

  • 也许会更好:exit(renameat2(AT_FDCWD,"foo",AT_FDCWD,"bar", RENAME_EXCHANGE)); ?
  • 可以,但是在renameat2前面加一个负号,因为如果失败,它会返回-1,但是你的进程应该返回1。实际上使用if 语句也可能是值得的,这样您就可以使用perror 来说明它失败的原因。
  • 你能告诉我怎么做吗?并感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
相关资源
最近更新 更多