📄 file.c
字号:
{
long bytesRead = length;
if( FSRead( stream->refNum, &bytesRead, buffer ) != noErr )
return( CRYPT_ERROR_READ );
return( bytesRead );
}
int fileWrite( STREAM *stream, const void *buffer, const int length )
{
long bytesWritten = length;
if( FSWrite( stream->refNum, &bytesWritten, buffer ) != noErr || \
( int ) bytesWritten != length )
return( CRYPT_ERROR_WRITE );
return( CRYPT_OK );
}
/* Commit data in a file stream to backing storage */
int fileFlush( STREAM *stream )
{
FileParam paramBlock;
paramBlock.ioCompletion = NULL;
paramBlock.ioFRefNum = stream->refNum;
PBFlushFileSync( ( union ParamBlockRec * ) ¶mBlock );
return( CRYPT_OK );
}
/* Change the read/write position in a file */
int fileSeek( STREAM *stream, const long position )
{
if( SetFPos( stream->refNum, fsFromStart, position ) != noErr )
return( CRYPT_ERROR_WRITE );
return( CRYPT_OK );
}
/* Check whether a file is writeable */
BOOLEAN fileReadonly( 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 )
{
/* Wipe everything past the current position in the file */
while( length > 0 )
{
RESOURCE_DATA msgData;
BYTE buffer[ BUFSIZ * 2 ];
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 );
}
void fileClearToEOF( const STREAM *stream )
{
long eof, position, length;
assert( isReadPtr( stream, sizeof( STREAM ) ) );
assert( stream->type == STREAM_TYPE_FILE );
/* Wipe everything past the current position in the file */
if( GetFPos( stream->refNum, &position ) != noErr || \
GetEOF( stream->refNum, &eof ) != noErr )
return;
length = eof - position;
if( length <= 0 )
return; /* Nothing to do, exit */
eraseFile( stream, position, length );
}
void fileErase( const char *fileName )
{
STREAM stream;
BYTE buffer[ BUFSIZ ];
int 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_READ | FILE_WRITE | FILE_EXCLUSIVE_ACCESS );
if( cryptStatusError( status ) )
{
remove( fileName );
return;
}
/* Determine the size of the file and erase it */
SetFPos( stream.refNum, fsFromStart, 0 );
GetEOF( stream.refNum, &length );
eraseFile( stream, position, length );
/* Delete the file */
sFileClose( &stream );
FSpDelete( stream.fsspec );
}
/* Build the path to a file in the cryptlib directory */
void fileBuildCryptlibPath( char *path, const char *fileName,
const BUILDPATH_OPTION_TYPE option )
{
strcpy( path, ":" );
if( option == BUILDPATH_RNDSEEDFILE )
strcat( path, "randseed.dat" );
else
{
strcat( path, fileName );
strcat( path, ".p15" );
}
}
/****************************************************************************
* *
* Non-STDIO File Stream Functions *
* *
****************************************************************************/
#elif defined( CONFIG_NO_STDIO )
#if defined( __VMCMS__ ) || defined( __IBM4758__ )
/* Some environments place severe restrictions on what can be done with file
I/O, either having no filesystem at all or having one with characteristics
that don't fit the stdio model. For these systems we used our own in-
memory buffers and make them look like memory streams until they're
flushed, at which point they're written to backing store (flash RAM/
EEPROM/DASD/whatever non-FS storage is being used) in one go.
For streams with the sensitive bit set we don't expand the buffer size
because the original was probably in protected memory, for non-sensitive
streams we expand the size if necessary. This means that we have to
choose a suitably large buffer for sensitive streams (private keys), but
one that isn't too big. 16K is about right, since typical private key
files with cert chains are 2K */
#define STREAM_BUFSIZE 16384
#endif /* __VMCMS__ || __IBM4758__ */
/* Open/close a file stream */
int sFileOpen( STREAM *stream, const char *fileName, const int mode )
{
#ifdef __IBM4758__
const BOOLEAN useBBRAM = ( mode & FILE_SENSITIVE ) ? TRUE : FALSE;
#endif /* __IBM4758__ */
long length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( fileName != NULL );
assert( mode != 0 );
/* Initialise the stream structure */
memset( stream, 0, sizeof( STREAM ) );
stream->type = STREAM_TYPE_MEMORY;
if( ( mode & FILE_RW_MASK ) == FILE_READ )
stream->flags = STREAM_FLAG_READONLY;
#if defined( __IBM4758__ )
/* Make sure that the filename matches the 4758's data item naming
conventions and remember the filename. The best error code to return
if there's a problem is a file open error, since this is buried so
many levels down that a parameter error won't be meaningful to the
caller */
if( strlen( fileName ) > 8 )
return( CRYPT_ERROR_OPEN );
strcpy( stream->name, fileName );
/* If we're doing a read, fetch the data into memory */
if( mode & FILE_READ )
{
/* Find out how big the data item is and allocate a buffer for
it */
status = sccGetPPDLen( ( char * ) fileName, &length );
if( status != PPDGood )
return( ( status == PPD_NOT_FOUND ) ? CRYPT_ERROR_NOTFOUND : \
( status == PPD_NOT_AUTHORIZED ) ? CRYPT_ERROR_PERMISSION : \
CRYPT_ERROR_OPEN );
if( ( stream->buffer = clAlloc( "sFileOpen", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
stream->bufSize = stream->bufEnd = length;
stream->isIOStream = TRUE;
/* Fetch the data into the buffer so it can be read as a memory
stream */
status = sccGetPPD( ( char * ) fileName, stream->buffer, length );
return( ( status != PPDGood ) ? CRYPT_ERROR_READ : CRYPT_OK );
}
/* We're doing a write, make sure that there's enough room available.
This doesn't guarantee that there'll be enough when the data is
committed, but it makes sense to at least check when the "file" is
opened */
status = sccQueryPPDSpace( &length, useBBRAM ? PPD_BBRAM : PPD_FLASH );
if( status != PPDGood || length < STREAM_BUFSIZE )
return( CRYPT_ERROR_OPEN );
/* Allocate the initial I/O buffer for the data */
if( ( stream->buffer = clAlloc( "sFileOpen", STREAM_BUFSIZE ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
stream->bufSize = STREAM_BUFSIZE;
stream->isSensitive = useBBRAM;
return( CRYPT_OK );
#elif defined( __VMCMS__ )
/* If we're going to be doing a write either now or later, we can't open
the file until we have all of the data that we want to write to it
available since the open arg has to include the file format
information, so all we can do at this point is remember the name for
later use */
strcpy( stream->name, fileName );
asciiToEbcdic( stream->name, strlen( stream->name ) );
/* If we're doing a read, fetch the data into memory */
if( mode & FILE_READ )
{
FILE *filePtr;
fldata_t fileData;
char fileBuffer[ MAX_PATH_LENGTH ];
int count;
/* Open the file and determine how large it is */
filePtr = fopen( fileName, "rb" );
if( filePtr == NULL )
return( CRYPT_ERROR_OPEN );
status = fldata( filePtr, fileBuffer, &fileData );
if( status )
{
fclose( filePtr );
return( CRYPT_ERROR_OPEN );
}
length = fileData.__maxreclen;
/* Fetch the data into a buffer large enough to contain the entire
stream */
if( ( stream->buffer = clAlloc( "sFileOpen", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
stream->bufSize = stream->bufEnd = length;
status = fread( stream->buffer, length, 1, filePtr );
fclose( filePtr );
return( ( status != 1 ) ? CRYPT_ERROR_READ : CRYPT_OK );
}
/* Allocate the initial I/O buffer for the data */
if( ( stream->buffer = clAlloc( "sFileOpen", STREAM_BUFSIZE ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
stream->bufSize = STREAM_BUFSIZE;
return( CRYPT_OK );
#else
#error Need to add mechanism to connect stream to backing store
return( CRYPT_ERROR_OPEN );
#endif /* Nonstandard I/O enviroments */
}
int sFileClose( STREAM *stream )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( stream->type != STREAM_TYPE_NULL );
#if defined( __IBM4758__ )
/* Close the file and clear the stream structure */
zeroise( stream->buffer, stream->bufSize );
clFree( "sFileClose", stream->buffer );
zeroise( stream, sizeof( STREAM ) );
return( CRYPT_OK );
#elif defined( __VMCMS__ )
/* Close the file and clear the stream structure */
zeroise( stream->buffer, stream->bufSize );
clFree( "sFileClose", stream->buffer );
zeroise( stream, sizeof( STREAM ) );
return( CRYPT_OK );
#else
#error Need to add mechanism to disconnect stream from backing store
zeroise( stream, sizeof( STREAM ) );
return( CRYPT_OK );
#endif /* Nonstandard I/O enviroments */
}
/* Read/write a block of data from/to a file stream */
int fileRead( STREAM *stream, void *buffer, const int length )
{
#if defined( __IBM4758__ ) || defined( __VMCMS__ )
/* These environments move all data into an in-memory buffer when the
file is opened, so there's never any need to read more data from the
stream */
return( CRYPT_ERROR_READ );
#else
#error Need to add mechanism to read data from backing store
return( CRYPT_ERROR_READ );
#endif /* Nonstandard I/O enviroments */
}
int fileWrite( STREAM *stream, const void *buffer, const int length )
{
#if defined( __IBM4758__ ) || defined( __VMCMS__ )
/* Expand the write buffer on demand when it fills up. If it's a small
buffer allocated when we initially read a file and it doesn't look
like we'll be overflowing a standard-size buffer, we first expand it
up to STREAM_BUFSIZE before increasing it in STREAM_BUFSIZE steps.
The following routine does a safe realloc() that wipes the original
buffer */
void *newBuffer;
const int newSize = ( stream->bufSize < STREAM_BUFSIZE && \
stream->bufPos + length < STREAM_BUFSIZE - 1024 ) ? \
STREAM_BUFSIZE : stream->bufSize + STREAM_BUFSIZE;
/* Allocate the buffer and copy the new data across. If the malloc
fails we return CRYPT_ERROR_OVERFLOW rather than CRYPT_ERROR_MEMORY
since the former is more appropriate for the emulated-I/O environment */
if( ( newBuffer = clDynAlloc( "expandBuffer", \
stream->bufSize + STREAM_BUFSIZE ) ) == NULL )
return( CRYPT_ERROR_OVERFLOW );
memcpy( newBuffer, stream->buffer, stream->bufSize );
zeroise( stream->buffer, stream->bufSize );
clFree( "expandBuffer", stream->buffer );
stream->buffer = newBuffer;
stream->bufSize = newSize;
return( CRYPT_OK );
#else
#error Need to add mechanism to write data to backing store
return( CRYPT_ERROR_WRITE );
#endif /* Nonstandard I/O enviroments */
}
/* Commit data in a file stream to backing storage */
int fileFlush( STREAM *stream )
{
#if defined( __IBM4758__ )
/* Write the data to flash or BB memory as appropriate */
if( sccSavePPD( stream->name, stream->buffer, stream->bufEnd,
( stream->isSensitive ? PPD_BBRAM : PPD_FLASH ) | PPD_TRIPLE ) != PPDGood )
return( CRYPT_ERROR_WRITE );
return( CRYPT_OK );
#elif defined( __VMCMS__ )
/* Under CMS, MVS, TSO, etc the only consistent way to handle writes is
to write a fixed-length single-record file containing all the data in
one record, so we can't really do anything until the data is flushed */
FILE *filePtr;
char formatBuffer[ 64 ];
int count;
sprintf( formatBuffer, "wb, recfm=F, lrecl=%d, noseek", stream->bufPos );
filePtr = fopen( stream->name, formatBuffer );
if( filePtr == NULL )
return( CRYPT_ERROR_WRITE );
count = fwrite( stream->buffer, stream->bufEnd, 1, filePtr );
fclose( filePtr );
return( ( count != 1 ) ? CRYPT_ERROR_WRITE : CRYPT_OK );
#else
#error Need to add mechanism to commit data to backing store
return( CRYPT_ERROR_WRITE );
#endif /* Nonstandard I/O enviroments */
}
/* Change the read/write position in a file */
int fileSeek( STREAM *stream, const long position )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -