struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. 标志着这个结构的状态,请往下看*/ #define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ 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; //文件描述符 #if 0 int _blksize; #else int _flags2; //第二个文件标志 #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. 过去的文件偏移(已弃用) */
#define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsignedshort _cur_column; //当前列号(用于支持列计算) signedchar _vtable_offset; //虚函数表偏移量 char _shortbuf[1]; //短缓冲区
_IO_size_t _IO_fwrite (constvoid *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp) { _IO_size_t request = size * count; _IO_size_t written = 0; CHECK_FILE (fp, 0); if (request == 0) return0; _IO_acquire_lock (fp); if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1) written = _IO_sputn (fp, (constchar *) buf, request);//调用_IO_sputn _IO_release_lock (fp); /* We have written all of the input in case the return value indicates this or EOF is returned. The latter is a special case where we simply did not manage to flush the buffer. But the data is in the buffer and therefore written as far as fwrite is concerned. */ if (written == request || written == EOF) return count; else return written / size; } libc_hidden_def (_IO_fwrite)
void _IO_new_file_init (struct _IO_FILE_plus *fp) { /* POSIX.1 allows another file handle to be used to change the position of our file descriptor. Hence we actually don't know the actual position before we do the first fseek (and until a following fflush). */ fp->file._offset = _IO_pos_BAD; fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS;
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) /* We desperately try to help programs which are using streams in a strange way and mix old and new functions. Detect old streams here. */ if (_IO_vtable_offset (fp) != 0) return _IO_old_fclose (fp); #endif
/* First unlink the stream. */ if (fp->_IO_file_flags & _IO_IS_FILEBUF) _IO_un_link ((struct _IO_FILE_plus *) fp);//调用_IO_un_link函数释放链表
_IO_acquire_lock (fp); if (fp->_IO_file_flags & _IO_IS_FILEBUF) status = _IO_file_close_it (fp);//关闭文件流 else status = fp->_flags & _IO_ERR_SEEN ? -1 : 0; _IO_release_lock (fp); _IO_FINISH (fp);//调用vtable中_IO_FINISH if (fp->_mode > 0) { #if _LIBC /* This stream has a wide orientation. This means we have to free the conversion functions. */ struct _IO_codecvt *cc = fp->_codecvt;
/* Check if unknown vtable pointers are permitted; otherwise, terminate the process. */ void _IO_vtable_check (void) attribute_hidden;
/* Perform vtable pointer validation. If validation fails, terminate the process. */ staticinlineconststruct _IO_jump_t * IO_validate_vtable(conststruct _IO_jump_t *vtable) { /* Fast path: The vtable pointer is within the __libc_IO_vtables section. 第一步,检测虚表指针是否位于_IO_vtable段中*/ uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables; constchar *ptr = (constchar *) vtable; uintptr_t offset = ptr - __start___libc_IO_vtables; if (__glibc_unlikely (offset >= section_length))//通过偏移是否大于段的大小来判断 /* The vtable pointer is not in the expected section. Use the slow path, which will terminate the process if necessary. 如果不在对应段中,调用_IO_vtable_check进行进一步检查*/ _IO_vtable_check (); return vtable; }
/* In case this libc copy is in a non-default namespace, we always need to accept foreign vtables because there is always a possibility that FILE * objects are passed across the linking boundary. */ { Dl_info di; structlink_map *l; if (_dl_open_hook != NULL || (_dl_addr (_IO_vtable_check, &di, &l, NULL) != 0 && l->l_ns != LM_ID_BASE)) return; }
#else/* !SHARED */ /* We cannot perform vtable validation in the static dlopen case because FILE * handles might be passed back and forth across the boundary. Therefore, we disable checking in this case. */ if (__dlopen != NULL) return; #endif
__libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n"); }