⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stream.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:

			/* Write the data to the file */
			for( dataLength = length, iterationCount = 0;
				 dataLength > 0 && iterationCount < FAILSAFE_ITERATIONS_LARGE;
				 iterationCount++ )
				{
				const int bytesToCopy = \
						min( dataLength, stream->bufSize - stream->bufPos );

				if( bytesToCopy > 0 )
					{
					memcpy( stream->buffer + stream->bufPos, bufPtr, 
							bytesToCopy );
					stream->bufPos += bytesToCopy;
					bufPtr += bytesToCopy;
					dataLength -= bytesToCopy;
					}
				if( stream->bufPos >= stream->bufSize )
					{
					status = emptyStream( stream, FALSE );
					if( cryptStatusError( status ) )
						return( status );
					}
				}
			ENSURES_S( iterationCount < FAILSAFE_ITERATIONS_LARGE );
			stream->flags |= STREAM_FLAG_DIRTY;
			status = CRYPT_OK;
			break;
			}

#ifdef USE_TCP
		case STREAM_TYPE_NETWORK:
			{
			NET_STREAM_INFO *netStream = \
					( NET_STREAM_INFO * ) stream->netStreamInfo;
			int bytesWritten;

			REQUIRES_S( netStream->protocol != STREAM_PROTOCOL_HTTP || \
						( netStream->protocol == STREAM_PROTOCOL_HTTP && \
						  length == sizeof( HTTP_DATA_INFO ) ) );

			/* Write the data to the network.  Writes are normally atomic
			   but if the partial-write flag is set can be restarted after
			   a timeout */
			status = netStream->writeFunction( stream, buffer, length, 
											   &bytesWritten );
			if( cryptStatusError( status ) )
				{
				/* If the lower-level code has indicated that the error 
				   condition is fatal, make it persistent for the stream */
				if( cryptStatusError( netStream->persistentStatus ) )
					stream->status = netStream->persistentStatus;

				return( status );
				}
			if( bytesWritten < length && \
				!( stream->flags & STREAM_FLAG_PARTIALWRITE ) )
				{
				/* If we didn't write all of the data and partial writes 
				   aren't allowed report a write timeout.  The situation
				   for HTTP streams is a bit special because what we're
				   sending to the write function is an HTTP_DATA_INFO
				   structure so we have to extract the actual length
				   information from that */
				if( netStream->protocol == STREAM_PROTOCOL_HTTP )
					{
					const HTTP_DATA_INFO *httpDataInfo = \
									( HTTP_DATA_INFO * ) buffer;

					retExt( CRYPT_ERROR_TIMEOUT, 
							( CRYPT_ERROR_TIMEOUT, NETSTREAM_ERRINFO, 
							  "Write timed out with %d of %d bytes written",
							  httpDataInfo->bytesTransferred,
							  httpDataInfo->bufSize ) );
					}
				retExt( CRYPT_ERROR_TIMEOUT, 
						( CRYPT_ERROR_TIMEOUT, NETSTREAM_ERRINFO, 
						  "Write timed out with %d of %d bytes written",
						  bytesWritten, length ) );
				}
			status = bytesWritten;
			break;
			}
#endif /* USE_TCP */

		default:
			retIntError_Stream( stream );
		}

	ENSURES_S( sanityCheck( stream ) );

	return( status );
	}

/* Commit data in a stream to backing storage */

int sflush( STREAM *stream )
	{
	int status = CRYPT_OK, flushStatus;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( stream->buffer, stream->bufSize ) );

	/* Check that the input parameters are in order */
	if( !isWritePtr( stream, sizeof( STREAM ) ) )
		retIntError();

	if( !isReadPtr( stream->buffer, stream->bufSize ) )
		retIntError_Stream( stream );

	REQUIRES_S( sanityCheck( stream ) && \
				stream->flags & STREAM_FFLAG_BUFFERSET );
	REQUIRES_S( stream->type == STREAM_TYPE_FILE || \
				sIsVirtualFileStream( stream ) );
	REQUIRES_S( !( stream->flags & STREAM_FLAG_READONLY ) );

	/* If there's a problem with the stream don't try to do anything until
	   the error is cleared */
	if( cryptStatusError( stream->status ) )
		return( stream->status );

	/* If the data in the stream buffer is unchanged there's nothing to do */
	if( !( stream->flags & STREAM_FLAG_DIRTY ) )
		return( CRYPT_OK );

	/* If there's data still in the stream buffer and it's not a virtual 
	   file stream that's handled via a memory stream (for which the data 
	   is committed in an atomic operation when the file is flushed), write 
	   it to disk.  If there's an error at this point we still try and flush 
	   whatever data we have to disk so we don't bail out immediately if 
	   there's a problem */
	if( stream->bufPos > 0 && !sIsVirtualFileStream( stream ) )
		status = emptyStream( stream, TRUE );

	/* Commit the data */
	flushStatus = fileFlush( stream );
	stream->flags &= ~STREAM_FLAG_DIRTY;

	return( cryptStatusOK( status ) ? flushStatus : status );
	}

/****************************************************************************
*																			*
*								Meta-data Functions							*
*																			*
****************************************************************************/

/* Set/clear the error status of a stream.  sSetError() returns the error 
   status that it's passed so that it can be called using
   'return( sSetError( stream, status ) );' */

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sSetError( INOUT STREAM *stream, IN_ERROR const int status )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES_S( cryptStatusError( status ) );

	/* Check that the input parameters are in order */
	if( !isWritePtr( stream, sizeof( STREAM ) ) )
		retIntError();

	/* If there's already an error status set don't try and override it */
	if( cryptStatusError( stream->status ) )
		return( stream->status );

	stream->status = status;

	return( status );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
void sClearError( STREAM *stream )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	/* Check that the input parameters are in order */
	if( !isWritePtr( stream, sizeof( STREAM ) ) )
		retIntError_Void();

	stream->status = CRYPT_OK;
	}

/* Determine whether a stream is a null stream */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN sIsNullStream( const STREAM *stream )
	{
	assert( isReadPtr( stream, sizeof( STREAM ) ) );

	/* Check that the input parameters are in order */
	if( !isReadPtr( stream, sizeof( STREAM ) ) )
		retIntError_Boolean();

	return( ( stream->type == STREAM_TYPE_NULL ) ? TRUE : FALSE );
	}


/* Move to an absolute position in a stream */

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sseek( INOUT STREAM *stream, IN_LENGTH_Z const long position )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	/* Check that the input parameters are in order */
	if( !isWritePtr( stream, sizeof( STREAM ) ) )
		retIntError();

	REQUIRES_S( sanityCheck( stream ) );
	REQUIRES_S( stream->type == STREAM_TYPE_NULL || \
				stream->type == STREAM_TYPE_MEMORY || \
				stream->type == STREAM_TYPE_FILE );
	REQUIRES_S( position >= 0 && position < MAX_INTLENGTH );

	/* If there's a problem with the stream don't try to do anything */
	if( cryptStatusError( stream->status ) )
		return( stream->status );

	switch( stream->type )
		{
		case STREAM_TYPE_NULL:
			/* Move to the position in the stream buffer.  We never get 
			   called directly with an sseek on a memory stream, but end up 
			   here via a translated sSkip() call */
			stream->bufPos = ( int ) position;
			if( stream->bufEnd < stream->bufPos )
				stream->bufEnd = stream->bufPos;
			break;

		case STREAM_TYPE_MEMORY:
			/* Move to the position in the stream buffer */
			if( ( int ) position > stream->bufSize )
				{
				stream->bufPos = stream->bufSize;
				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
				}
			stream->bufPos = ( int ) position;
			if( stream->bufEnd < stream->bufPos )
				stream->bufEnd = stream->bufPos;
			break;

		case STREAM_TYPE_FILE:
			{
			int newBufCount;

			/* If it's a currently-disconnected file stream then all we can 
			   do is rewind the stream.  This occurs when we're doing an 
			   atomic flush of data to disk and we rewind the stream prior 
			   to writing the new/updated data.  The next buffer-connect 
			   operation will reset the stream state so there's nothing to 
			   do at this point */
			if( !( stream->flags & STREAM_FFLAG_BUFFERSET ) )
				{
				REQUIRES_S( position == 0 );

				return( CRYPT_OK );
				}

			/* It's a file stream, remember the new position in the file */
			newBufCount = position / stream->bufSize;
			if( newBufCount != stream->bufCount )
				{
				/* We're not within the current buffer any more, remember 
				   that we have to explicitly update the file position on
				   the next read */
				stream->flags |= STREAM_FFLAG_POSCHANGED;

				/* If we're already positioned to read the next bufferful 
				   of data we don't have to explicitly skip ahead to it */
				if( newBufCount == stream->bufCount + 1 ) 
					stream->flags |= STREAM_FFLAG_POSCHANGED_NOSKIP;

				stream->bufCount = newBufCount;
				}
			stream->bufPos = position % stream->bufSize;
			break;
			}

		default:
			retIntError_Stream( stream );
		}

	ENSURES_S( sanityCheck( stream ) );

	return( CRYPT_OK );
	}

/* Return the current posision in a stream */

CHECK_RETVAL_RANGE( 0, MAX_INTLENGTH ) STDC_NONNULL_ARG( ( 1 ) ) \
int stell( const STREAM *stream )
	{
	assert( isReadPtr( stream, sizeof( STREAM ) ) );

	/* Check that the input parameters are in order */
	if( !isReadPtr( stream, sizeof( STREAM ) ) )
		retIntError();

	/* We can't use REQUIRE_S( sanityCheck() ) in this case because the 
	   stream is a const parameter.  Since stell() is expected to return a 
	   value in the range 0...stream->bufSize we don't use REQUIRES() either 
	   but simply return an offset of zero */
	REQUIRES_EXT( sanityCheck( stream ), 0 );
	REQUIRES_EXT( ( stream->type == STREAM_TYPE_NULL || \
					stream->type == STREAM_TYPE_MEMORY || \
					stream->type == STREAM_TYPE_FILE ), 0 );

	/* If there's a problem with the stream don't try to do anything */
	if( cryptStatusError( stream->status ) )
		{
		assert( DEBUG_WARN );
		return( 0 );
		}

	switch( stream->type )
		{
		case STREAM_TYPE_NULL:
		case STREAM_TYPE_MEMORY:
			return( stream->bufPos );

		case STREAM_TYPE_FILE:
			return( ( stream->bufCount * stream->bufSize ) + \
					stream->bufPos );
		}

	retIntError();
	}

/* Skip a number of bytes in a stream */

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sSkip( INOUT STREAM *stream, IN_LENGTH const long offset )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	/* Check that the input parameters are in order */
	if( !isWritePtr( stream, sizeof( STREAM ) ) )
		retIntError();

	REQUIRES_S( sanityCheck( stream ) );
	REQUIRES_S( stream->type == STREAM_TYPE_NULL || \
				stream->type == STREAM_TYPE_MEMORY || \
				stream->type == STREAM_TYPE_FILE );
	REQUIRES_S( offset > 0 && offset < MAX_INTLENGTH );

	/* If there's a problem with the stream don't try to do anything */
	if( cryptStatusError( stream->status ) )
		return( stream->status );

	return( sseek( stream, stream->bufPos + offset ) );
	}

/* Peek at the next data value in a stream */

CHECK_RETVAL_RANGE( MAX_ERROR, 0xFF ) STDC_NONNULL_ARG( ( 1 ) ) \
int sPeek( INOUT STREAM *stream )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( stream->buffer, stream->bufSize ) );

	/* Check that the input parameters are in order */
	if( !isWritePtr( stream, sizeof( STREAM ) ) )
		retIntError();

	REQUIRES_S( sanityCheck( stream ) );
	REQUIRES_S( stream->type == STREAM_TYPE_MEMORY || \
				stream->type == STREAM_TYPE_FILE );

	/* If there's a problem with the stream don't try to do anything until
	   the error is cleared */
	if( cryptStatusError( stream->status ) )
		return( stream->status );

	/* Read the data from the buffer, but without advancing the read pointer
	   like sgetc() does */
	switch( stream->type )
		{
		case STREAM_TYPE_MEMORY:
			/* Read the data from the stream buffer */
			if( stream->bufPos >= stream->bufEnd )
				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
			return( stream->buffer[ stream->bufPos ] );

		case STREAM_TYPE_FILE:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -