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

📄 stream.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
		default:
			retIntError_Stream( stream );
		}

	ENSURES_S( sanityCheck( stream ) );

	return( ch );
	}

RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int sread( INOUT STREAM *stream, 
		   OUT_BUFFER_FIXED( length ) void *buffer, 
		   IN_LENGTH const int length )
	{
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( stream->type == STREAM_TYPE_NETWORK || \
			isReadPtr( stream->buffer, stream->bufSize ) );
	assert( isWritePtr( buffer, length ) );

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

	REQUIRES_S( sanityCheck( stream ) );
	REQUIRES_S( stream->type == STREAM_TYPE_MEMORY || \
				stream->type == STREAM_TYPE_FILE || \
				stream->type == STREAM_TYPE_NETWORK );
	REQUIRES_S( length > 0 && length < 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_MEMORY:
			{
			int localLength = length;

#ifdef VIRTUAL_FILE_STREAM 
			/* If partial reads are allowed return whatever's left in the
			   stream buffer.  This only occurs for virtual file streams  
			   that have been translated into memory streams */
			if( stream->flags & STREAM_FLAG_PARTIALREAD )
				{
				REQUIRES_S( sIsVirtualFileStream( stream ) );

				localLength = stream->bufEnd - stream->bufPos;
				}
#endif /* VIRTUAL_FILE_STREAM */
			
			/* Read the data from the stream buffer */
			if( stream->bufPos + localLength > stream->bufEnd )
				{
				memset( buffer, 0, min( 16, length ) );	/* Clear output buffer */
				return( sSetError( stream, CRYPT_ERROR_UNDERFLOW ) );
				}
			memcpy( buffer, stream->buffer + stream->bufPos, localLength );
			stream->bufPos += localLength;

			/* Usually reads are atomic so we just return an all-OK 
			   indicator, however if we're performing partial reads we need
			   to return an exact byte count */
			status = ( stream->flags & STREAM_FLAG_PARTIALREAD ) ? \
					 localLength : CRYPT_OK;
			break;
			}

		case STREAM_TYPE_FILE:
			{
			BYTE *bufPtr = buffer;
			int dataLength, bytesCopied = 0, iterationCount;

			REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );

			/* Read the data from the file */
			for( dataLength = length, iterationCount = 0;
				 dataLength > 0 && iterationCount < FAILSAFE_ITERATIONS_LARGE;
				 iterationCount++ )
				{
				const int oldDataLength = dataLength;
				int bytesToCopy;

				/* If the stream buffer is empty try and refill it */
				if( stream->bufPos >= stream->bufEnd || \
					( stream->flags & STREAM_FFLAG_POSCHANGED ) )
					{
					status = refillStream( stream );
					if( cryptStatusError( status ) )
						return( ( status == OK_SPECIAL ) ? \
								bytesCopied : status );
					}

				/* Copy as much data as we can out of the stream buffer */
				bytesToCopy = min( dataLength, \
								   stream->bufEnd - stream->bufPos );
				memcpy( bufPtr, stream->buffer + stream->bufPos, 
						bytesToCopy );
				stream->bufPos += bytesToCopy;
				bufPtr += bytesToCopy;
				bytesCopied += bytesToCopy;
				dataLength -= bytesToCopy;
				ENSURES_S( dataLength < oldDataLength );
				}
			ENSURES_S( iterationCount < FAILSAFE_ITERATIONS_LARGE );

			/* Usually reads are atomic so we just return an all-OK 
			   indicator, however if we're performing partial reads we need
			   to return an exact byte count */
			status = ( stream->flags & STREAM_FLAG_PARTIALREAD ) ? \
					 bytesCopied : CRYPT_OK;
			break;
			}

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

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

			/* Read the data from the network.  Reads are normally atomic
			   but if the partial-write flag is set can be restarted after
			   a timeout */
			status = netStream->readFunction( stream, buffer, length, 
											  &bytesRead );
			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;

				/* If it's not a special-case CRYPT_ERROR_COMPLETE status,
				   exit.  We don't make the error persistent since unlike
				   memory or file stream reads, most errors on network reads 
				   are recoverable */
				if( status != CRYPT_ERROR_COMPLETE )
					return( status );

				/* If we get a CRYPT_ERROR_COMPLETE status this means that
				   the other side has closed the connection.  This status is 
				   returned when there are intermediate protocol layers such 
				   as HTTP or tunnelling over a cryptlib session involved.
				   When this occurs we update the stream state and map the 
				   status to a standard read error.  The exact code to 
				   return here is a bit uncertain, it isn't specifically a 
				   read error because either the other side is allowed to 
				   close the connection after it's said its bit (and so it's 
				   not a read error), or it has to perform a 
				   cryptographically protected close (in which case any 
				   non-OK status indicates a problem).  The most sensible 
				   status is probably a read error */
				sioctl( stream, STREAM_IOCTL_CONNSTATE, NULL, FALSE );
				return( CRYPT_ERROR_READ );
				}
			if( bytesRead < length && \
				!( ( stream->flags & STREAM_FLAG_PARTIALREAD ) || \
				   ( netStream->nFlags & STREAM_NFLAG_ENCAPS ) ) )
				{
				/* If we didn't read all of the data and partial reads 
				   aren't allowed report a read timeout.  The situation
				   for HTTP streams is a bit special because what we're
				   sending to the read 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, 
							  "Read timed out with %d of %d bytes read",
							  httpDataInfo->bytesTransferred, 
							  httpDataInfo->bytesAvail ) );
					}
				retExt( CRYPT_ERROR_TIMEOUT,
						( CRYPT_ERROR_TIMEOUT, NETSTREAM_ERRINFO, 
						  "Read timed out with %d of %d bytes read",
						  bytesRead, length ) );
				}

			/* This is an ugly case where we have to follow the Posix 
			   semantics of returning a read-bytes count as the return 
			   status rather than a by-reference parameter.  If we didn't
			   do this then every trivial memory-stream read would need to
			   pass in a dummy parameter for the read-byte-count value just
			   to handle the one or two calls to a network stream read that
			   needs to return a length */
			status = bytesRead;
			break;
			}
#endif /* USE_TCP */

		default:
			retIntError_Stream( stream );
		}

	ENSURES_S( sanityCheck( stream ) );

	return( status );
	}

/****************************************************************************
*																			*
*							Stream Write Functions							*
*																			*
****************************************************************************/

/* Write data to a stream */

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sputc( INOUT STREAM *stream, IN_BYTE const int ch )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( stream->type == STREAM_TYPE_NULL || \
			isWritePtr( 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_NULL || \
				stream->type == STREAM_TYPE_MEMORY || \
				stream->type == STREAM_TYPE_FILE );
	REQUIRES_S( !( stream->flags & STREAM_FLAG_READONLY ) );
	REQUIRES( ch >= 0 && ch <= 0xFF );

	/* 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 );

	switch( stream->type )
		{
		case STREAM_TYPE_NULL:
			/* It's a null stream, just record the write and return */
			stream->bufPos++;
			if( stream->bufEnd < stream->bufPos )
				stream->bufEnd = stream->bufPos;
			break;

		case STREAM_TYPE_MEMORY:
			/* Write the data to the stream buffer */
			if( stream->bufPos >= stream->bufSize )
				{
#ifdef VIRTUAL_FILE_STREAM 
				if( sIsVirtualFileStream( stream ) )
					{
					int status;

					status = expandVirtualFileStream( stream, 1 );
					if( cryptStatusError( status ) )
						return( status );
					}
				else
#endif /* VIRTUAL_FILE_STREAM */
					return( sSetError( stream, CRYPT_ERROR_OVERFLOW ) );
				}
			stream->buffer[ stream->bufPos++ ] = ch;
			if( stream->bufEnd < stream->bufPos )
				stream->bufEnd = stream->bufPos;
#ifdef VIRTUAL_FILE_STREAM 
			if( sIsVirtualFileStream( stream ) )
				{
				/* This is a memory stream emulating a file stream, set the
				   dirty bit */
				stream->flags |= STREAM_FLAG_DIRTY;
				}
#endif /* VIRTUAL_FILE_STREAM */
			break;

		case STREAM_TYPE_FILE:
			REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );

			/* Write the data to the file */
			if( stream->bufPos >= stream->bufSize )
				{
				int status;

				status = emptyStream( stream, FALSE );
				if( cryptStatusError( status ) )
					return( status );
				}
			stream->buffer[ stream->bufPos++ ] = ch;
			stream->flags |= STREAM_FLAG_DIRTY;
			break;

		default:
			retIntError_Stream( stream );
		}

	ENSURES_S( sanityCheck( stream ) );

	return( CRYPT_OK );
	}

RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int swrite( INOUT STREAM *stream, 
		    IN_BUFFER( length ) const void *buffer, 
			IN_LENGTH const int length )
	{
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( stream->type == STREAM_TYPE_NULL || \
			stream->type == STREAM_TYPE_NETWORK || \
			isWritePtr( stream->buffer, stream->bufSize ) );
	assert( isReadPtr( buffer, length ) );

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

	REQUIRES_S( sanityCheck( stream ) );
	REQUIRES_S( stream->type == STREAM_TYPE_NULL || \
				stream->type == STREAM_TYPE_MEMORY || \
				stream->type == STREAM_TYPE_FILE || \
				stream->type == STREAM_TYPE_NETWORK );
	REQUIRES_S( length > 0 && length < MAX_INTLENGTH );
	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 );

	switch( stream->type )
		{
		case STREAM_TYPE_NULL:
			/* It's a null stream, just record the write and return */
			stream->bufPos += length;
			if( stream->bufEnd < stream->bufPos )
				stream->bufEnd = stream->bufPos;
			status = CRYPT_OK;
			break;

		case STREAM_TYPE_MEMORY:
			/* Write the data to the stream buffer */
			if( stream->bufPos + length > stream->bufSize )
				{
#ifdef VIRTUAL_FILE_STREAM 
				if( sIsVirtualFileStream( stream ) )
					{
					status = expandVirtualFileStream( stream, length );
					if( cryptStatusError( status ) )
						return( status );
					}
				else
#endif /* VIRTUAL_FILE_STREAM */
					return( sSetError( stream, CRYPT_ERROR_OVERFLOW ) );
				}
			memcpy( stream->buffer + stream->bufPos, buffer, length );
			stream->bufPos += length;
			if( stream->bufEnd < stream->bufPos )
				stream->bufEnd = stream->bufPos;
#ifdef VIRTUAL_FILE_STREAM 
			if( sIsVirtualFileStream( stream ) )
				{
				/* This is a memory stream emulating a file stream, set the
				   dirty bit */
				stream->flags |= STREAM_FLAG_DIRTY;
				}
#endif /* VIRTUAL_FILE_STREAM */
			status = CRYPT_OK;
			break;

		case STREAM_TYPE_FILE:
			{
			const BYTE *bufPtr = buffer;
			int dataLength, iterationCount;

			REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );

⌨️ 快捷键说明

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