file.c

来自「cryptlib安全工具包」· C语言 代码 · 共 2,036 行 · 第 1/5 页

C
2,036
字号
	REQUIRES( stream->type == STREAM_TYPE_FILE );
	REQUIRES( length > 0 && length < MAX_INTLENGTH );

	return( sSetError( stream, CRYPT_ERROR_WRITE ) );
	}

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int fileFlush( INOUT STREAM *stream )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES( stream->type == STREAM_TYPE_FILE );

	return( sSetError( stream, CRYPT_ERROR_WRITE ) );
	}

/* Change the read/write position in a file */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int fileSeek( INOUT STREAM *stream, IN_LENGTH_Z const long position )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES( stream->type == STREAM_TYPE_FILE );
	REQUIRES( position >= 0 && position < MAX_INTLENGTH );

	return( sSetError( stream, CRYPT_ERROR_READ ) );
	}

/* Check whether a file is writeable */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN fileReadonly( IN_STRING const char *fileName )
	{
	return( TRUE );
	}

/* File deletion functions: Wipe a file from the current position to EOF,
   and wipe and delete a file (although it's not terribly rigorous).
   Vestigia nulla retrorsum */

static void eraseFile( const STREAM *stream, long position, long length )
	{
	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES_V( stream->type == STREAM_TYPE_FILE );
	REQUIRES_V( position >= 0 && position < MAX_INTLENGTH );
	REQUIRES_V( length > 0 && length < MAX_INTLENGTH );

	/* Wipe everything past the current position in the file */
	while( length > 0 )
		{
		MESSAGE_DATA msgData;
		BYTE buffer[ ( BUFSIZ * 2 ) + 8 ];
		int bytesToWrite = min( length, BUFSIZ * 2 );

		/* We need to make sure that we fill the buffer with random data for
		   each write, otherwise compressing filesystems will just compress
		   it to nothing */
		setMessageData( &msgData, buffer, bytesToWrite );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
		if( fwrite( buffer, 1, bytesToWrite, stream->filePtr ) == 0 )
			break;	/* An error occurred while writing, exit */
		length -= bytesToWrite;
		}
	fflush( stream->filePtr );

	/* Truncate the file and if we're erasing the entire file, reset the
	   timestamps.  This is only possible through a file handle on some
	   systems, on others the caller has to do it via the filename */
	chsize( fileno( stream->filePtr ), position );
	if( position <= 0 )
		{
		struct ftime fileTime;

		memset( &fileTime, 0, sizeof( struct ftime ) );
		setftime( fileno( stream->filePtr ), &fileTime );
		}
	}

STDC_NONNULL_ARG( ( 1 ) ) \
void fileClearToEOF( const STREAM *stream )
	{
	long position, length;

	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES_V( stream->type == STREAM_TYPE_FILE );

	/* Wipe everything past the current position in the file */
	position = ftell( stream->filePtr );
	fseek( stream->filePtr, 0, SEEK_END );
	length = ftell( stream->filePtr ) - position;
	fseek( stream->filePtr, position, SEEK_SET );
	eraseFile( stream, position, length );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
void fileErase( IN_STRING const char *fileName )
	{
	STREAM stream;
	int fileHandle, length, status;

	assert( fileName != NULL );

	/* Try and open the file so that we can erase it.  If this fails, the
	   best that we can do is a straight unlink */
	status = sFileOpen( &stream, fileName,
						FILE_FLAG_READ | FILE_FLAG_WRITE | \
						FILE_FLAG_EXCLUSIVE_ACCESS );
	if( cryptStatusError( status ) )
		{
		remove( fileName );
		return;
		}

	/* Determine the size of the file and erase it */
	fileHandle = fileno( stream.filePtr );
	fseek( stream.filePtr, 0, SEEK_END );
	length = ( int ) ftell( stream.filePtr );
	fseek( stream.filePtr, 0, SEEK_SET );
	eraseFile( stream, 0, length );

	/* Truncate the file to 0 bytes if we couldn't do it in eraseFile, reset
	   the time stamps, and delete it */
	sFileClose( &stream );

	/* Finally, delete the file */
	remove( fileName );
	}

/* Build the path to a file in the cryptlib directory */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int fileBuildCryptlibPath( OUT_BUFFER( pathMaxLen, pathLen ) char *path, 
						   IN_LENGTH_SHORT const int pathMaxLen, 
						   OUT_LENGTH_SHORT_Z int *pathLen,
						   IN_BUFFER( fileNameLen ) const char *fileName, 
						   IN_LENGTH_SHORT const int fileNameLen,
						   IN_ENUM( BUILDPATH_OPTION ) \
						   const BUILDPATH_OPTION_TYPE option )
	{
	assert( isWritePtr( path, pathMaxLen ) );
	assert( isWritePtr( pathLen, sizeof( int ) ) );
	assert( isReadPtr( fileName, fileNameLen ) );

	REQUIRES( pathMaxLen > 8 && pathMaxLen < MAX_INTLENGTH );
	REQUIRES( fileNameLen > 0 && fileNameLen < MAX_INTLENGTH );
	REQUIRES( ( ( option == BUILDPATH_CREATEPATH || \
				  option == BUILDPATH_GETPATH ) && fileName != NULL ) || \
			  ( option == BUILDPATH_RNDSEEDFILE && fileName == NULL ) );

	/* Make sure that the open fails if we can't build the path */
	*path = '\0';

	/* Make sure that the path buffer meets the minimum-length
	   requirements */
	REQUIRES( pathMaxLen >= 64 );

	/* Add the filename to the path */
	return( appendFilename( path, pathMaxLen, pathLen, fileName, 
							fileNameLen, option ) );
	}

/****************************************************************************
*																			*
*							Macintosh File Stream Functions					*
*																			*
****************************************************************************/

#elif defined( __MAC__ )

/* Convert a C to a Pascal string */

static void CStringToPString( const char *cstring, StringPtr pstring )
	{
	short len = min( strlen( cstring ), 255 );

	memmove( pstring + 1, cstring, len );
	*pstring = len;
	}

/* Open/close a file stream */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int sFileOpen( INOUT STREAM *stream, IN_STRING const char *fileName, 
			   IN_FLAGS( FILE ) const int mode )
	{
	Str255 pFileName;
	OSErr err;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( fileName != NULL );

	REQUIRES( mode != 0 );

	/* Initialise the stream structure */
	memset( stream, 0, sizeof( STREAM ) );
	stream->type = STREAM_TYPE_FILE;
	if( ( mode & FILE_FLAG_RW_MASK ) == FILE_FLAG_READ )
		stream->flags = STREAM_FLAG_READONLY;

	CStringToPString( fileName, pFileName );
	err = FSMakeFSSpec( 0, 0, pFileName, &stream->fsspec );
	if( err == dirNFErr || err == nsvErr )
		{
		/* Volume or parent directory not found */
		return( CRYPT_ERROR_NOTFOUND );
		}
	if( err != noErr && err != fnfErr )
		{
		/* fnfErr is OK since the fsspec is still valid */
		return( CRYPT_ERROR_OPEN );
		}

	if( mode & FILE_FLAG_WRITE )
		{
		/* Try and create the file, specifying its type and creator.  The
		   wierd string-looking constants are Mac compiler-specific and
		   evaluate to 32-bit unsigned type and creator IDs.  Unfortunately
		   the type value, which should be '????', triggers warnings about
		   trigraphs in unnecessarily pedantic compilers so we have to use
		   the hex equivalent instead */
		err = FSpCreate( &stream->fsspec, 0x3F3F3F3F /* '????' */, 'CLib', 
						 smSystemScript );
		if( err == wPrErr || err == vLckdErr || err == afpAccessDenied )
			return( CRYPT_ERROR_PERMISSION );
		if( err != noErr && err != dupFNErr && err != afpObjectTypeErr )
			return( CRYPT_ERROR_OPEN );
		}

	err = FSpOpenDF( &stream->fsspec, mode & FILE_FLAG_RW_MASK, 
					 &stream->refNum );
	if( err == nsvErr || err == dirNFErr || err == fnfErr )
		return( CRYPT_ERROR_NOTFOUND );
	if( err == opWrErr || err == permErr || err == afpAccessDenied )
		return( CRYPT_ERROR_PERMISSION );
	if( err != noErr )
		return( CRYPT_ERROR_OPEN );

	return( CRYPT_OK );
	}

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sFileClose( INOUT STREAM *stream )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( stream->type == STREAM_TYPE_FILE );

	/* Close the file and clear the stream structure */
	FSClose( stream->refNum );
	zeroise( stream, sizeof( STREAM ) );

	return( CRYPT_OK );
	}

/* Read/write a block of data from/to a file stream */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
int fileRead( INOUT STREAM *stream, 
			  OUT_BUFFER( length, *bytesRead ) void *buffer, 
			  IN_LENGTH const int length, 
			  OUT_LENGTH_Z int *bytesRead )
	{
    long byteCount = length;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( buffer, length ) );
	assert( isWritePtr( bytesRead, sizeof( int ) ) );

	REQUIRES( stream->type == STREAM_TYPE_FILE );
	REQUIRES( length > 0 && length < MAX_INTLENGTH );

	/* Clear return value */
	*bytesRead = 0;

	if( FSRead( stream->refNum, &bytesRead, buffer ) != noErr )
		return( sSetError( stream, CRYPT_ERROR_READ ) );
	*bytesRead = byteCount;

	return( CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int fileWrite( INOUT STREAM *stream, 
			   IN_BUFFER( length ) const void *buffer, 
			   IN_LENGTH const int length )
	{
	long bytesWritten = length;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( buffer, length ) );

	REQUIRES( stream->type == STREAM_TYPE_FILE );
	REQUIRES( length > 0 && length < MAX_INTLENGTH );

	if( FSWrite( stream->refNum, &bytesWritten, buffer ) != noErr || \
		( int ) bytesWritten != length )
		return( sSetError( stream, CRYPT_ERROR_WRITE ) );
	return( CRYPT_OK );
	}

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int fileFlush( INOUT STREAM *stream )
	{
	FileParam paramBlock;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES( stream->type == STREAM_TYPE_FILE );

	paramBlock.ioCompletion = NULL;
	paramBlock.ioFRefNum = stream->refNum;
	PBFlushFileSync( ( union ParamBlockRec * ) &paramBlock );
	return( CRYPT_OK );
	}

/* Change the read/write position in a file */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int fileSeek( INOUT STREAM *stream, IN_LENGTH_Z const long position )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES( stream->type == STREAM_TYPE_FILE );
	REQUIRES( position >= 0 && position < MAX_INTLENGTH );

	if( SetFPos( stream->refNum, fsFromStart, position ) != noErr )
		return( sSetError( stream, CRYPT_ERROR_READ ) );
	return( CRYPT_OK );
	}

/* Check whether a file is writeable */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN fileReadonly( IN_STRING const char *fileName )
	{
	Str255 pFileName;
	FSSpec fsspec;
	OSErr err;
	short refnum;

	assert( fileName != NULL );

	CStringToPString( fileName, pFileName );

	err = FSMakeFSSpec( 0, 0, pFileName, &fsspec );
	if ( err == noErr )
		err = FSpOpenDF( &fsspec, fsRdWrPerm, &refnum );
	if ( err == noErr )
		FSClose( refnum );

	if ( err == opWrErr || err == permErr || err == afpAccessDenied )
		return( TRUE );

	return( FALSE );
	}

/* File deletion functions: Wipe a file from the current position to EOF,
   and wipe and delete a file (although it's not terribly rigorous).
   Vestigia nulla retrorsum */

static void eraseFile( const STREAM *stream, long position, long length )
	{
	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES_V( stream->type == STREAM_TYPE_FILE );
	REQUIRES_V( position >= 0 && position < MAX_INTLENGTH );
	REQUIRES_V( length > 0 && length < MAX_INTLENGTH );

	/* Wipe everything past the current position in the file */
	while( length > 0 )
		{
		MESSAGE_DATA msgData;
		BYTE buffer[ ( BUFSIZ * 2 ) + 8 ];
		int bytesToWrite = min( length, BUFSIZ * 2 );

		/* We need to make sure that we fill the buffer with random data for
		   each write, otherwise compressing filesystems will just compress
		   it to nothing */
		setMessageData( &msgData, buffer, bytesToWrite );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
		if( FSWrite( stream->refNum, &bytesWritten, buffer ) != noErr )
			break;	/* An error occurred while writing, exit */
		length -= bytesToWrite;
		}

	SetFPos( stream->refNum, fsFromStart, position );
	SetEOF( stream->refNum, position );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
void fileClearToEOF( const STREAM *stream )
	{
	long eof, position, length;

	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES_V( stream->type == STREAM_TYPE_FILE );

	/* Wipe everything past the current position in the file */
	if( GetFPos( stream->refNum, &position ) != noErr || \

⌨️ 快捷键说明

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