IO_FILE源码学习:

发布于 2024-06-25  90 次阅读


1.IO_FILE概述:

IO_FILE就是来描述IO文件结构体的,首先我们来看一下源码(2.35)

IO_FILE的相关源码是在libioP.h文件里面的:

/* We always allocate an extra word following an _IO_FILE.
  This contains a pointer to the function jump table used.
  This is for compatibility with C++ streambuf; the word can
  be used to smash to a pointer to a virtual function table. */

struct _IO_FILE_plus
{
 FILE file;
     // 这里是常量指针 请记住和指针常量的区别
 // 指针常量本质是常量 存储的是指针 也就是说其记录的指针不能被修改 但是指针指向的内容是可以修改的
 // 常量指针是指针 只不过指针所指向的地址得是个常量 所以指针本身值可以被修改 但是其内容不可被修改
 // 所以在开发者最初设想中 这里的vtable的值可以改变 但是它指向的内容是不可变的
 // vtable指向的是类型为_IO_jump_t的常量数据
 const struct _IO_jump_t *vtable;
};

我们最终描述文件流的数据结构是_IO_FILE_plus,这里面有FILE file结构体和 常量 _IO_jump_t,我们可以推断出来file成员应该是包含的该文件的关键数据,而vtable(虚表)就是各种操作函数的指针

每一个_IO_FILE结构体里面都有一个 _chain指针,指向下一个 _IO_FILE_plus结构体,通常情况下是这个样子的:​



_IO_lsit_all -->IO_2_1_stderr     .---->IO_2_1_stdout     .----->IO_2_1_stdin
                  ..........     |       ..........       |       ..........
                  ..........     |       ..........       |      ..........
                  chain     ___|     chain   ___|       chain
                  ..........             ..........               ..........

当有新的文件被打开的时候,对应的_IO_FILE_plus结构体就会被插入到链首

2._IO_FILE:

下面就是_IO_FILE的源码:

struct _IO_FILE
{
 int _flags; /* High-order word is _IO_MAGIC; rest is flags. */

 /* The following pointers correspond to the C++ streambuf protocol. */
 char *_IO_read_ptr; /* Current read pointer */
 char *_IO_read_end; /* End of get area. */
 char *_IO_read_base; /* Start of putback+get area. */
 char *_IO_write_base; /* Start of put area. */
 char *_IO_write_ptr; /* Current put pointer. */
 char *_IO_write_end; /* End of put area. */
 char *_IO_buf_base; /* Start of reserve area. */
 char *_IO_buf_end; /* End of reserve area. */

 /* The following fields are used to support backing up and undo. */
 char *_IO_save_base; /* Pointer to start of non-current get area. */
 char *_IO_backup_base;  /* Pointer to first valid character of backup area */
 char *_IO_save_end; /* Pointer to end of non-current get area. */

 struct _IO_marker *_markers;

 struct _IO_FILE *_chain;

 int _fileno;
 int _flags2;
 __off_t _old_offset; /* This used to be _offset but it's too small. */

 /* 1+column number of pbase(); 0 is unknown. */
 unsigned short _cur_column;
 signed char _vtable_offset;
 char _shortbuf[1];

 _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

struct _IO_FILE_complete
{
 struct _IO_FILE _file;
#endif
 __off64_t _offset;
 /* Wide character stream stuff. */
 struct _IO_codecvt *_codecvt;
 struct _IO_wide_data *_wide_data;
 struct _IO_FILE *_freeres_list;
 void *_freeres_buf;
 size_t __pad5;
 int _mode;
 /* Make sure we don't get into trouble again. */
 char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
};

_IO_FILE_complete可以理解为_IO_FILE的豪华加长版,其中的_wide_data需要关注一下,有些手法会用到。

3._IO_jump_t:

vtable是一个指向_IO_jump_t结构体的指针。当打开一个文件的时候,相应的_IO_FIEL结构体会被创建并将其vtable字段指向对应文件类型的_IO_jump_t的地址。当我们需要执行文件操作的时候,可以通过_IO_FILE结构体里面的vtable字段获取相应的_IO_jump_t结构体。通常一个_IO_jump_t结构体包含了以下的函数指针:

struct _IO_jump_t
{
   JUMP_FIELD(size_t, __dummy);
   JUMP_FIELD(size_t, __dummy2);
   JUMP_FIELD(_IO_finish_t, __finish);
   JUMP_FIELD(_IO_overflow_t, __overflow);
   JUMP_FIELD(_IO_underflow_t, __underflow);
   JUMP_FIELD(_IO_underflow_t, __uflow);
   JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
   /* showmany */
   JUMP_FIELD(_IO_xsputn_t, __xsputn);
   JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
   JUMP_FIELD(_IO_seekoff_t, __seekoff);
   JUMP_FIELD(_IO_seekpos_t, __seekpos);
   JUMP_FIELD(_IO_setbuf_t, __setbuf);
   JUMP_FIELD(_IO_sync_t, __sync);
   JUMP_FIELD(_IO_doallocate_t, __doallocate);
   JUMP_FIELD(_IO_read_t, __read);
   JUMP_FIELD(_IO_write_t, __write);
   JUMP_FIELD(_IO_seek_t, __seek);
   JUMP_FIELD(_IO_close_t, __close);
   JUMP_FIELD(_IO_stat_t, __stat);
   JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
   JUMP_FIELD(_IO_imbue_t, __imbue);
};

注意,程序里面有很多的_IO_jump_t结构体,不同的_IO_FILE_plus可能会采用不同的_IO_jump_t,比如我们的stdin/stdout/stderr使用_IO_file_jumps


The world's full of lonely people afraid to make the first move.