我们以 freopen
为例研究 glibc
打开一个新文件的过程(忽略宽字符处理,删除了部分对老 glibc的兼容代码),先检查传入的 fp
本身是否有active的fd,并将其关闭(_IO_file_close_it→_IO_new_file_close_it→_IO_SYSCLOSE
),然后将 fp
外面的 vtable
重新赋值为默认的 _IO_file_jumps
,_wide_data
的vtable被初始化为_IO_wfile_jumps
,再次 fopen
FILE *
freopen (const char *filename, const char *mode, FILE *fp)
{
FILE *result;
CHECK_FILE (fp, NULL);
if (!(fp->_flags & _IO_IS_FILEBUF))
return NULL;
_IO_acquire_lock (fp);
int fd = _IO_fileno (fp);
const char *gfilename = (filename == NULL && fd >= 0
? fd_to_filename (fd) : filename);
fp->_flags2 |= _IO_FLAGS2_NOCLOSE;
{
_IO_file_close_it (fp);
_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
result = _IO_file_fopen (fp, gfilename, mode, 1);
if (result != NULL)
result = __fopen_maybe_mmap (result);
}
fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
if (result != NULL)
{
/* unbound stream orientation */
result->_mode = 0;
if (fd != -1)
{
__dup3 (_IO_fileno (result), fd,
(result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0
? O_CLOEXEC : 0);
__close (_IO_fileno (result));
_IO_fileno (result) = fd;
}
}
else if (fd != -1)
__close (fd);
if (filename == NULL)
free ((char *) gfilename);
_IO_release_lock (fp);
return result;
}