不调用fcntl函数实现dup2函数
问题描述
dup2函数头定义为int dup2(int fd, int fd2),返回值为fd2指定的文件描述符,指向fd指向的文件,如果fd2已经打开,则需先关闭;如果fd == fd2,则无需关闭fd2。
解题思路
1、寻找需要的文件描述符
不能调用fcntl,那么我们只能调用dup函数,这个函数会返回当前可用的文件描述符中的最小值,循环n次调用直到返回值等于fd2。2、调用dup的负面影响
这个时候我们打开了n-1个无用的文件,这些并不是我们需要或者预期的,返回前需关闭。否则不但会占用大量系统资源,使得系统无法打开新的文件,甚至这些预期之外的文件描述符也可以访问或者修改文件,形成安全隐患。3、消除dup造成的隐患
线性结构记录n-1个文件描述符,并依次关闭4、错误error处理
dup调用错误:包括指定的fd2过大,打开的文件描述符超出限制。在不考虑其他程序也调用此函数的情况下,我们可以通过sysconf函数来获取打开上限。5、测试问题
定义一个文件描述符x指向标准输出,并通过x写入一段特定的字符,查看是否会在标准输出是打印,也可以直接重定向到指定文件查看。
代码实现
本文采用c语言实现该逻辑:
#include "apue.h"
#include <myerr.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#ifdef OPEN_MAX
static long openmax = OPEN_MAX;
#else
static long openmax = 0;
#endif
int mydup(int fd, int fd2){
//获取系统允许的最大的文件数
errno = 0;
if (openmax == 0)
openmax = sysconf(_SC_OPEN_MAX);
if (openmax < 0){
if (errno != 0){ //这个值是不确定的
printf("OPEN_MAX这个值是不确定的,设为默认100\n");
openmax = 100;
}
else{ //获取OPEN_MAX错误
printf("获取OPEN_MAX错误,设为默认100\n");
openmax = 100;
}
}else
printf("OPEN_MAX获取成功,其值是%ld\n", openmax);
//关闭指定的fd2文件
errno = close(fd2);
//关闭文件不一定会成功,因为有可能这个文件本身就没有打开,所以错误也不退出
if (errno == -1)
printf("关闭fd2错误:%d",errno);
//获取待返回的文件描述符fd1
long fd1 = -1;
int arr[openmax-1], idx = 0,i;
for (i = 0; i < openmax - 1; i++){// 初始化线性结构
arr[i] = -1;
}
do{//循环调用dup函数直至返回的fd1 == fd2
fd1 = dup(fd);
if (fd1 > 0){//调用成功
if (fd1 == fd2){//如果调用成功,退出循环
break;
}else{
arr[idx] = fd1;
idx++;
}
}
}while(fd1 < fd2);
//关闭打开的多余的文件
for (i = 0; i < openmax - 1; i++){
if (arr[i] == -1)
break;
else{
errno = close(arr[i]);
if (errno == -1){
printf("关闭文件%ld错误",arr[i],stdout);
if (idx != i){
idx = i;
i--; //关闭失败回退再关闭一次
}
}
}
}
return fd1;
}
int main(void){
int fdtest = dup(1);
char buf[] = "hello, mydup for dup2!\n";
printf("打开的文件是:%d,buf长度是%d\n",fdtest,strlen(buf));
int fd = mydup(STDOUT_FIFLNO,fdtest);
printf("mydup返回的文件是:%d\n",fd);
//测试返回的文件符是否可以直接操作标准输出
if (write(fd, buf, strlen(buf)) != strlen(buf))
err_sys("buf write error\n");
exit(0);
}
在Linux环境下的运行结果如下:
打开的文件是:3,buf长度是23
OPEN_MAX获取成功,其值是102400
mydup返回的文件是:3
hello, mydup for dup2!
可见测试的buf成功通过获取的文件描述符写入到了标准输出中,至此测试完毕。