int FSEEK(register FILE *stream, OFFSET_TYPE offset, int whence) { #if defined(__UCLIBC_HAS_LFS__) && !defined(__DO_LARGEFILE) return fseeko64(stream, offset, whence); #else __offmax_t pos = offset; int retval = -1; __STDIO_AUTO_THREADLOCK_VAR; if (((unsigned int) whence) > 2) { __set_errno(EINVAL); } else { __STDIO_AUTO_THREADLOCK(stream); __STDIO_STREAM_VALIDATE(stream); if ((!__STDIO_STREAM_IS_WRITING(stream) || !__STDIO_COMMIT_WRITE_BUFFER(stream)) && ((whence != SEEK_CUR) || (__stdio_adjust_position(stream, &pos) >= 0)) && (__SEEK(stream, &pos, whence) >= 0) ) { /* Clear reading/writing modes, EOF, and ungots. */ stream->__modeflags &= ~(__MASK_READING|__FLAG_WRITING|__FLAG_EOF); /* Make sure all pointers are reset. */ __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream); __STDIO_STREAM_DISABLE_GETC(stream); __STDIO_STREAM_DISABLE_PUTC(stream); /* We reinitialize the mbstate object. Doing so is * implementation defined behavior. */ #ifdef __STDIO_MBSTATE __INIT_MBSTATE(&(stream->__state)); #endif #ifdef __UCLIBC_HAS_WCHAR__ stream->__ungot_width[0] = 0; #endif retval = 0; } __STDIO_STREAM_VALIDATE(stream); __STDIO_AUTO_THREADUNLOCK(stream); } return retval; #endif }
* auto-transition via fseek() is a configurable option. * Returns 0 on success and EOF otherwise. * * Notes: * There are two function signatures, depending on wchar support, * since with no wchar support the orientation is narrow by default. */ #ifdef __UCLIBC_HAS_WCHAR__ int __stdio_trans2w_o(FILE * __restrict stream, int oflag) #else int __stdio_trans2w(FILE * __restrict stream) #endif { __STDIO_STREAM_VALIDATE(stream); assert(!__STDIO_STREAM_IS_WRITING(stream)); #ifdef __UCLIBC_HAS_WCHAR__ if (!(stream->__modeflags & oflag)) { if (stream->__modeflags & (__FLAG_NARROW|__FLAG_WIDE)) { __UNDEFINED_OR_NONPORTABLE; goto DO_EBADF; } stream->__modeflags |= oflag; } #endif if (stream->__modeflags & __FLAG_READONLY) { DO_EBADF: __set_errno(EBADF); ERROR:
size_t attribute_hidden __stdio_WRITE(register FILE *stream, register const unsigned char *buf, size_t bufsize) { size_t todo; ssize_t rv, stodo; __STDIO_STREAM_VALIDATE(stream); assert(stream->__filedes >= -1); assert(__STDIO_STREAM_IS_WRITING(stream)); assert(!__STDIO_STREAM_BUFFER_WUSED(stream)); /* Buffer must be empty. */ todo = bufsize; do { if (todo == 0) { /* Done? */ __STDIO_STREAM_VALIDATE(stream); return bufsize; } stodo = (todo <= SSIZE_MAX) ? todo : SSIZE_MAX; if ((rv = __WRITE(stream, (char *) buf, stodo)) >= 0) { #ifdef __UCLIBC_MJN3_ONLY__ #warning TODO: Make custom stream write return check optional. #endif #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ assert(rv <= stodo); if (rv > stodo) { /* Wrote more than stodo! */ /* abort(); */ } #endif todo -= rv; buf += rv; } else #ifdef __UCLIBC_MJN3_ONLY__ #warning EINTR? #endif /* if (errno != EINTR) */ { __STDIO_STREAM_SET_ERROR(stream); #ifdef __STDIO_BUFFERS if ((stodo = __STDIO_STREAM_BUFFER_SIZE(stream)) != 0) { unsigned char *s; if (stodo > todo) { stodo = todo; } s = stream->__bufstart; do { if (((*s = *buf) == '\n') && __STDIO_STREAM_IS_LBF(stream) ) { break; } ++s; ++buf; } while (--stodo); stream->__bufpos = s; todo -= (s - stream->__bufstart); } #endif /* __STDIO_BUFFERS */ __STDIO_STREAM_VALIDATE(stream); return bufsize - todo; } } while (1); }
int fflush_unlocked(register FILE *stream) { #ifdef __STDIO_BUFFERS int retval = 0; #ifdef __UCLIBC_MJN3_ONLY__ #warning REMINDER: should probably define a modeflags type #endif unsigned short bufmask = __FLAG_LBF; #ifndef NDEBUG if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) { __STDIO_STREAM_VALIDATE(stream); /* debugging only */ } #endif if (stream == (FILE *) &_stdio_openlist) { /* Flush all lbf streams. */ stream = NULL; bufmask = 0; } if (!stream) { /* Flush all (lbf) writing streams. */ __STDIO_OPENLIST_INC_USE; __STDIO_THREADLOCK_OPENLIST_ADD; stream = _stdio_openlist; __STDIO_THREADUNLOCK_OPENLIST_ADD; while(stream) { /* We only care about currently writing streams and do not want to * block trying to obtain mutexes on non-writing streams. */ #warning fix for nonatomic #warning unnecessary check if no threads if (__STDIO_STREAM_IS_WRITING(stream)) { /* ONLY IF ATOMIC!!! */ __MY_STDIO_THREADLOCK(stream); /* Need to check again once we have the lock. */ if (!(((stream->__modeflags | bufmask) ^ (__FLAG_WRITING|__FLAG_LBF) ) & (__FLAG_WRITING|__MASK_BUFMODE)) ) { if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) { __STDIO_STREAM_DISABLE_PUTC(stream); __STDIO_STREAM_CLEAR_WRITING(stream); } else { retval = EOF; } } __MY_STDIO_THREADUNLOCK(stream); } stream = stream->__nextopen; } __STDIO_OPENLIST_DEC_USE; } else if (__STDIO_STREAM_IS_WRITING(stream)) { if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) { __STDIO_STREAM_DISABLE_PUTC(stream); __STDIO_STREAM_CLEAR_WRITING(stream); } else { retval = EOF; } } #if 0 else if (stream->__modeflags & (__MASK_READING|__FLAG_READONLY)) { /* ANSI/ISO says behavior in this case is undefined but also says you * shouldn't flush a stream you were reading from. As usual, glibc * caters to broken programs and simply ignores this. */ __UNDEFINED_OR_NONPORTABLE; __STDIO_STREAM_SET_ERROR(stream); __set_errno(EBADF); retval = EOF; } #endif #ifndef NDEBUG if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) { __STDIO_STREAM_VALIDATE(stream); /* debugging only */ } #endif return retval; #else /* __STDIO_BUFFERS --------------------------------------- */ #ifndef NDEBUG if ((stream != NULL) #ifdef __STDIO_HAS_OPENLIST && (stream != (FILE *) &_stdio_openlist) #endif ) { __STDIO_STREAM_VALIDATE(stream); /* debugging only */ } #endif #if 0 if (stream && (stream->__modeflags & (__MASK_READING|__FLAG_READONLY))) { /* ANSI/ISO says behavior in this case is undefined but also says you * shouldn't flush a stream you were reading from. As usual, glibc * caters to broken programs and simply ignores this. */ __UNDEFINED_OR_NONPORTABLE; __STDIO_STREAM_SET_ERROR(stream); __set_errno(EBADF); return EOF; } #endif return 0; #endif /* __STDIO_BUFFERS */ }
void _stdio_validate_FILE(const FILE *stream) { #ifdef __UCLIBC_HAS_THREADS__ assert(((unsigned int)(stream->__user_locking)) <= 2); #endif #warning Define a constant for minimum possible valid __filedes? assert(stream->__filedes >= -3); if (stream->__filedes < 0) { /* assert((stream->__filedes != -1) */ /* #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */ /* || (stream->__cookie == &stream->__filedes) /\* custom *\/ */ /* #endif */ /* ); */ /* assert((stream->__filedes == -1) || __STDIO_STREAM_IS_FBF(stream)); */ assert(!__STDIO_STREAM_IS_FAKE_VSNPRINTF(stream) || __STDIO_STREAM_IS_NARROW(stream)); assert(!__STDIO_STREAM_IS_FAKE_VSSCANF(stream) || __STDIO_STREAM_IS_NARROW(stream)); #ifdef __STDIO_STREAM_IS_FAKE_VSWPRINTF assert(!__STDIO_STREAM_IS_FAKE_VSWPRINTF(stream) || __STDIO_STREAM_IS_WIDE(stream)); #endif #ifdef __STDIO_STREAM_IS_FAKE_VSWSCANF assert(!__STDIO_STREAM_IS_FAKE_VSWSCANF(stream) || __STDIO_STREAM_IS_WIDE(stream)); #endif } #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ if (stream->__cookie != &stream->__filedes) { /* custom */ assert(stream->__filedes == -1); } #endif /* Can not be both narrow and wide oriented at the same time. */ assert(!(__STDIO_STREAM_IS_NARROW(stream) && __STDIO_STREAM_IS_WIDE(stream))); /* The following impossible case is used to disable a stream. */ if ((stream->__modeflags & (__FLAG_READONLY|__FLAG_WRITEONLY)) == (__FLAG_READONLY|__FLAG_WRITEONLY) ) { assert(stream->__modeflags == (__FLAG_READONLY|__FLAG_WRITEONLY)); assert(stream->__filedes == -1); #ifdef __STDIO_BUFFERS assert(stream->__bufpos == stream->__bufstart); assert(stream->__bufread == stream->__bufstart); # ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ assert(stream->__bufputc_u == stream->__bufstart); # endif # ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ assert(stream->__bufgetc_u == stream->__bufstart); # endif #endif } if (__STDIO_STREAM_IS_READONLY(stream)) { /* assert(!__STDIO_STREAM_IS_WRITEONLY(stream)); */ assert(!__STDIO_STREAM_IS_WRITING(stream)); if (stream->__modeflags & __FLAG_UNGOT) { assert(((unsigned)(stream->__ungot[1])) <= 1); assert(!__FEOF_UNLOCKED(stream)); } } if (__STDIO_STREAM_IS_WRITEONLY(stream)) { /* assert(!__STDIO_STREAM_IS_READONLY(stream)); */ assert(!__STDIO_STREAM_IS_READING(stream)); assert(!(stream->__modeflags & __FLAG_UNGOT)); } if (__STDIO_STREAM_IS_NBF(stream)) { /* We require that all non buffered streams have no buffer. */ assert(!__STDIO_STREAM_BUFFER_SIZE(stream)); } assert((stream->__modeflags & __MASK_BUFMODE) <= __FLAG_NBF); #ifdef __STDIO_BUFFERS /* Ensure __bufstart <= __bufpos <= __bufend. */ assert(stream->__bufpos >= stream->__bufstart); assert(stream->__bufpos <= stream->__bufend); /* Ensure __bufstart <= __bufread <= __bufend. */ assert(stream->__bufread >= stream->__bufstart); assert(stream->__bufread <= stream->__bufend); #endif /* If EOF, then we must have no buffered readable or ungots. */ if (__FEOF_UNLOCKED(stream)) { #ifdef __STDIO_BUFFERS assert(stream->__bufpos == stream->__bufread); #endif assert(!(stream->__modeflags & __FLAG_UNGOT)); } if (!__STDIO_STREAM_IS_WRITING(stream)) { #ifdef __STDIO_BUFFERS /* If not writing, then putc macro must be disabled. */ # ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ assert(stream->__bufputc_u == stream->__bufstart); # endif #endif } if (!__STDIO_STREAM_IS_READING(stream)) { /* If not reading, then can not have ungots. */ assert(!(stream->__modeflags & __FLAG_UNGOT)); #ifdef __STDIO_BUFFERS /* Ensure __bufread == __bufstart. */ assert(stream->__bufread == stream->__bufstart); /* If not reading, then getc macro must be disabled. */ # ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ assert(stream->__bufgetc_u == stream->__bufstart); # endif #endif } if (__STDIO_STREAM_IS_READING(stream)) { assert(!__STDIO_STREAM_IS_WRITING(stream)); #ifdef __STDIO_BUFFERS /* Ensure __bufpos <= __bufread. */ assert(stream->__bufpos <= stream->__bufread); /* Ensure __bufgetc_u is valid. */ # ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ assert(stream->__bufgetc_u >= stream->__bufstart); assert(stream->__bufgetc_u <= stream->__bufread); # endif #endif } if (__STDIO_STREAM_IS_WRITING(stream)) { assert(!__STDIO_STREAM_IS_READING(stream)); #ifdef __STDIO_BUFFERS # ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ assert(stream->__bufputc_u >= stream->__bufstart); assert(stream->__bufputc_u <= stream->__bufend); # endif #endif } /* If have an ungotten char, then getc (and putc) must be disabled. */ /* Also, wide streams must have the getc/putc macros disabled. */ if ((stream->__modeflags & __FLAG_UNGOT) || __STDIO_STREAM_IS_WIDE(stream) ) { #ifdef __STDIO_BUFFERS # ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ assert(stream->__bufputc_u == stream->__bufstart); # endif # ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ assert(stream->__bufgetc_u == stream->__bufstart); # endif #endif } /* TODO -- filepos? ungot_width? filedes? nextopen? */ }
/* We assume here that we are the only remaining thread. */ void attribute_hidden _stdio_term(void) { #if defined(__STDIO_BUFFERS) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__) register FILE *ptr; #ifdef __UCLIBC_HAS_THREADS__ /* First, make sure the open file list is unlocked. If it was * locked, then I suppose there is a chance that a pointer in the * chain might be corrupt due to a partial store. */ __stdio_init_mutex(&_stdio_openlist_add_lock); #warning check #ifdef __STDIO_BUFFERS __stdio_init_mutex(&_stdio_openlist_del_lock); #endif /* Next we need to worry about the streams themselves. If a stream * is currently locked, then it may be in an invalid state. So we * 'disable' it in case a custom stream is stacked on top of it. * Then we reinitialize the locks. */ for (ptr = _stdio_openlist ; ptr ; ptr = ptr->__nextopen ) { if (__STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(ptr)) { /* The stream is already locked, so we don't want to touch it. * However, if we have custom streams, we can't just close it * or leave it locked since a custom stream may be stacked * on top of it. So we do unlock it, while also disabling it. */ ptr->__modeflags = (__FLAG_READONLY|__FLAG_WRITEONLY); __STDIO_STREAM_DISABLE_GETC(ptr); __STDIO_STREAM_DISABLE_PUTC(ptr); __STDIO_STREAM_INIT_BUFREAD_BUFPOS(ptr); } ptr->__user_locking = 1; /* Set locking mode to "by caller". */ __stdio_init_mutex(&ptr->__lock); /* Shouldn't be necessary, but... */ } #endif /* Finally, flush all writing streams and shut down all custom streams. * NOTE: We assume that any stacking by custom streams is done on top * of streams previously allocated, and hence further down the * list. Otherwise we have no way of knowing the order in which * to shut them down. * Remember that freopen() counts as a new allocation here, even * though the stream is reused. That's because it moves the * stream to the head of the list. */ for (ptr = _stdio_openlist ; ptr ; ptr = ptr->__nextopen ) { #ifdef __STDIO_BUFFERS /* Write any pending buffered chars. */ if (__STDIO_STREAM_IS_WRITING(ptr)) { __STDIO_COMMIT_WRITE_BUFFER(ptr); } #endif #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ /* Actually close all custom streams to perform any special cleanup. */ if (ptr->__cookie != &ptr->__filedes) { __CLOSE(ptr); } #endif } #endif }
int fclose(register FILE *stream) { int rv = 0; __STDIO_AUTO_THREADLOCK_VAR; #ifdef __STDIO_HAS_OPENLIST #if !defined(__UCLIBC_HAS_THREADS__) || !defined(__STDIO_BUFFERS) /* First, remove the file from the open file list. */ { FILE *ptr; __STDIO_THREADLOCK_OPENLIST_DEL; __STDIO_THREADLOCK_OPENLIST_ADD; ptr = _stdio_openlist; if ((ptr = _stdio_openlist) == stream) { _stdio_openlist = stream->__nextopen; } else { while (ptr) { if (ptr->__nextopen == stream) { ptr->__nextopen = stream->__nextopen; break; } ptr = ptr->__nextopen; } } __STDIO_THREADUNLOCK_OPENLIST_ADD; __STDIO_THREADUNLOCK_OPENLIST_DEL; } #endif #endif __STDIO_AUTO_THREADLOCK(stream); __STDIO_STREAM_VALIDATE(stream); #ifdef __STDIO_BUFFERS /* Write any pending buffered chars. */ if (__STDIO_STREAM_IS_WRITING(stream)) { rv = fflush_unlocked(stream); } #endif if (__CLOSE(stream) < 0) { /* Must close even if fflush failed. */ rv = EOF; } stream->__filedes = -1; /* We need a way for freopen to know that a file has been closed. * Since a file can't be both readonly and writeonly, that makes * an effective signal. It also has the benefit of disabling * transitions to either reading or writing. */ #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS) /* Before we mark the file as closed, make sure we increment the openlist use count * so it isn't freed under us while still cleaning up. */ __STDIO_OPENLIST_INC_USE; #endif stream->__modeflags &= (__FLAG_FREEBUF|__FLAG_FREEFILE); stream->__modeflags |= (__FLAG_READONLY|__FLAG_WRITEONLY); #ifndef NDEBUG __STDIO_STREAM_RESET_GCS(stream); /* Reinitialize everything (including putc since fflush could fail). */ __STDIO_STREAM_DISABLE_GETC(stream); __STDIO_STREAM_DISABLE_PUTC(stream); __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream); # ifdef __UCLIBC_HAS_WCHAR__ stream->__ungot_width[0] = 0; # endif # ifdef __STDIO_MBSTATE __INIT_MBSTATE(&(stream->__state)); # endif #endif __STDIO_AUTO_THREADUNLOCK(stream); __STDIO_STREAM_FREE_BUFFER(stream); #ifdef __UCLIBC_MJN3_ONLY__ #warning REMINDER: inefficient - locks and unlocks twice and walks whole list #endif #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS) /* inefficient - locks/unlocks twice and walks whole list */ __STDIO_OPENLIST_INC_DEL_CNT; __STDIO_OPENLIST_DEC_USE; /* This with free the file if necessary. */ #else __STDIO_STREAM_FREE_FILE(stream); #endif return rv; }