int _IO_new_fclose (_IO_FILE *fp) { int status; CHECK_FILE(fp, EOF); #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_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); 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; __libc_lock_lock (__gconv_lock); __gconv_release_step (cc->__cd_in.__cd.__steps); __gconv_release_step (cc->__cd_out.__cd.__steps); __libc_lock_unlock (__gconv_lock); #endif } else { if (_IO_have_backup (fp)) _IO_free_backup_area (fp); } if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr) { fp->_IO_file_flags = 0; free(fp); } return status; }
FILE * freopen64 (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, 0); fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE; if (result != NULL) result = __fopen_maybe_mmap (result); if (result != NULL) { /* unbound stream orientation */ result->_mode = 0; if (fd != -1) { #ifdef O_CLOEXEC # ifndef __ASSUME_DUP3 int newfd; if (__have_dup3 < 0) newfd = -1; else newfd = # endif __dup3 (_IO_fileno (result), fd, (result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 ? O_CLOEXEC : 0); #else # define newfd 1 #endif #ifndef __ASSUME_DUP3 if (newfd < 0) { if (errno == ENOSYS) __have_dup3 = -1; __dup2 (_IO_fileno (result), fd); if ((result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0) __fcntl (fd, F_SETFD, FD_CLOEXEC); } #endif __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; }
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; #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) if (&_IO_stdin_used == NULL) { /* If the shared C library is used by the application binary which was linked against the older version of libio, we just use the older one even for internal use to avoid trouble since a pointer to the old libio may be passed into shared C library and wind up here. */ _IO_old_file_close_it (fp); _IO_JUMPS_FILE_plus (fp) = &_IO_old_file_jumps; result = _IO_old_file_fopen (fp, gfilename, mode); } else #endif { _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) { #ifdef O_CLOEXEC # ifndef __ASSUME_DUP3 int newfd; if (__have_dup3 < 0) newfd = -1; else newfd = # endif __dup3 (_IO_fileno (result), fd, (result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 ? O_CLOEXEC : 0); #else # define newfd 1 #endif #ifndef __ASSUME_DUP3 if (newfd < 0) { if (errno == ENOSYS) __have_dup3 = -1; __dup2 (_IO_fileno (result), fd); if ((result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0) __fcntl (fd, F_SETFD, FD_CLOEXEC); } #endif __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; }
FILE * freopen64 (const char *filename, const char *mode, FILE *fp) { FILE *result = NULL; char fdfilename[FD_TO_FILENAME_SIZE]; CHECK_FILE (fp, NULL); _IO_acquire_lock (fp); /* First flush the stream (failure should be ignored). */ _IO_SYNC (fp); if (!(fp->_flags & _IO_IS_FILEBUF)) goto end; int fd = _IO_fileno (fp); const char *gfilename = filename != NULL ? filename : fd_to_filename (fd, fdfilename); 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, 0); fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE; if (result != NULL) result = __fopen_maybe_mmap (result); if (result != NULL) { /* unbound stream orientation */ result->_mode = 0; if (fd != -1 && _IO_fileno (result) != fd) { /* At this point we have both file descriptors already allocated, so __dup3 will not fail with EBADF, EINVAL, or EMFILE. But we still need to check for EINVAL and, due Linux internal implementation, EBUSY. It is because on how it internally opens the file by splitting the buffer allocation operation and VFS opening (a dup operation may run when a file is still pending 'install' on VFS). */ if (__dup3 (_IO_fileno (result), fd, (result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 ? O_CLOEXEC : 0) == -1) { _IO_file_close_it (result); result = NULL; goto end; } __close (_IO_fileno (result)); _IO_fileno (result) = fd; } } else if (fd != -1) __close (fd); end: _IO_release_lock (fp); return result; }