file.c
来自「cryptlib安全工具包」· C语言 代码 · 共 2,036 行 · 第 1/5 页
C
2,036 行
filePtr = fopen( stream->name, "wb" );
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 */
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 defined( __IBM4758__ ) || defined( __VMCMS__ ) || defined( __TESTIO__ )
/* These environments move all data into an in-memory buffer when the
file is opened, so there's never any need to move around in the
stream */
return( sSetError( stream, CRYPT_ERROR_READ ) );
#else
#error Need to add mechanism to perform virtual seek on backing store
return( sSetError( stream, CRYPT_ERROR_READ ) );
#endif /* Nonstandard I/O enviroments */
}
/* Check whether a file is writeable */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN fileReadonly( IN_STRING const char *fileName )
{
assert( fileName != NULL );
#if defined( __IBM4758__ ) || defined( __VMCMS__ ) || defined( __TESTIO__ )
/* Since there's no filesystem, there's no concept of a read-only
file - all data items are always accessible */
return( FALSE );
#else
#error Need to add mechanism to determine readability of data in backing store
return( FALSE );
#endif /* Nonstandard I/O enviroments */
}
/* 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 */
STDC_NONNULL_ARG( ( 1 ) ) \
void fileClearToEOF( const STREAM *stream )
{
assert( isReadPtr( stream, sizeof( STREAM ) ) );
REQUIRES_V( stream->type == STREAM_TYPE_FILE );
#if defined( __IBM4758__ ) || defined( __VMCMS__ ) || defined( __TESTIO__ )
/* Data updates on these systems are atomic so there's no remaining data
left to clear */
UNUSED_ARG( stream );
#else
#error Need to add clear-to-EOF function for data in backing store
#endif /* Nonstandard I/O enviroments */
}
STDC_NONNULL_ARG( ( 1 ) ) \
void fileErase( IN_STRING const char *fileName )
{
#if defined( __IBM4758__ )
sccDeletePPD( ( char * ) fileName );
#elif defined( __VMCMS__ )
FILE *filePtr;
int length = CRYPT_ERROR;
assert( fileName != NULL );
/* Determine how large the file is */
filePtr = fopen( fileName, "rb+" );
if( filePtr != NULL )
{
fldata_t fileData;
char fileBuffer[ MAX_PATH_LENGTH + 8 ];
if( fldata( filePtr, fileBuffer, &fileData ) == 0 )
length = fileData.__maxreclen;
}
/* If we got a length, overwrite the data. Since the file contains a
single record we can't perform the write-until-done overwrite used
on other OS'es, however since we're only going to be deleting short
private key files using the default stream buffer is OK for this */
if( length > 0 )
{
MESSAGE_DATA msgData;
BYTE buffer[ STREAM_VFILE_BUFSIZE + 8 ];
length = max( length, STREAM_VFILE_BUFSIZE );
setMessageData( &msgData, buffer, length );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
fwrite( buffer, 1, length, filePtr );
}
if( filePtr != NULL )
{
fflush( filePtr );
fclose( filePtr );
}
remove( fileName );
#elif defined( __TESTIO__ )
FILE *filePtr;
int length = CRYPT_ERROR;
assert( fileName != NULL );
/* Determine how large the file is */
filePtr = fopen( fileName, "rb+" );
if( filePtr != NULL )
{
fseek( filePtr, 0, SEEK_END );
length = ( int ) ftell( filePtr );
fseek( filePtr, 0, SEEK_SET );
}
/* If we got a length, overwrite the data. Since the file contains a
single record we can't perform the write-until-done overwrite used
on other OS'es, however since we're only going to be deleting short
private key files using the default stream buffer is OK for this */
if( length > 0 )
{
MESSAGE_DATA msgData;
BYTE buffer[ STREAM_VFILE_BUFSIZE + 8 ];
length = max( length, STREAM_VFILE_BUFSIZE );
setMessageData( &msgData, buffer, length );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
fwrite( buffer, 1, length, filePtr );
}
if( filePtr != NULL )
{
fflush( filePtr );
fclose( filePtr );
}
remove( fileName );
#else
#error Need to add erase function for data in backing store
#endif /* Nonstandard I/O enviroments */
}
/* 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 );
/* Build the path to the configuration file if necessary */
#if defined( __IBM4758__ )
if( option == BUILDPATH_RNDSEEDFILE )
{
/* Unlikely to really be necessary since we have a hardware RNG */
strlcpy_s( path, pathMaxLen, "RANDSEED" );
}
else
strlcpy_s( path, pathMaxLen, fileName );
return( CRYPT_OK );
#elif defined( __VMCMS__ )
return( appendFilename( path, pathMaxLen, pathLen, fileName,
fileNameLen, option ) );
#elif defined( __TESTIO__ )
return( appendFilename( path, pathMaxLen, pathLen, fileName,
fileNameLen, option ) );
#else
#error Need to add function to build path to config data in backing store
return( CRYPT_ERROR_OPEN );
#endif /* OS-specific file path creation */
}
/****************************************************************************
* *
* Palm OS File Stream Functions *
* *
****************************************************************************/
#elif defined( __PALMOS__ )
#include <FeatureMgr.h>
/* In theory it's possible for a system not to have the VFS Manager
available, although this seems highly unlikely we check for it just
in case using the Feature Manager */
static BOOLEAN checkVFSMgr( void )
{
uint32_t vfsMgrVersion;
return( ( FtrGet( sysFileCVFSMgr, vfsFtrIDVersion,
&vfsMgrVersion ) == errNone ) ? TRUE : FALSE );
}
/* 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 )
{
static const int modes[] = {
vfsModeRead, vfsModeRead,
vfsModeCreate | vfsModeExclusive | vfsModeWrite,
vfsModeReadWrite
};
uint32_t volIterator = vfsIteratorStart;
uint16_t volRefNum, openMode;
status_t 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;
openMode = modes[ mode & FILE_FLAG_RW_MASK ];
/* Make sure that VFS services are available and get the default volume
to open the file on */
if( !checkVFSMgr() )
return( CRYPT_ERROR_OPEN );
if( VFSVolumeEnumerate( &volRefNum, &volIterator ) != errNone )
return( CRYPT_ERROR_OPEN );
/* If we're trying to write to the file, check whether we've got
permission to do so */
if( ( mode & FILE_FLAG_WRITE ) && fileReadonly( fileName ) )
return( CRYPT_ERROR_PERMISSION );
/* Try and open the file */
err = VFSFileOpen( volRefNum, fileName, openMode, &stream->fileRef );
if( err == vfsErrFilePermissionDenied || err == vfsErrIsADirectory || \
err == vfsErrVolumeFull )
return( CRYPT_ERROR_PERMISSION );
if( err == vfsErrFileNotFound )
return( CRYPT_ERROR_NOTFOUND );
if( err != errNone )
return( CRYPT_ERROR_OPEN );
return( CRYPT_OK );
}
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sFileClose( INOUT STREAM *stream )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
REQUIRES( stream->type == STREAM_TYPE_FILE );
/* Close the file and clear the stream structure */
VFSFileClose( stream->fileRef );
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 )
{
uint32_t byteCount;
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( VFSFileRead( stream->fileRef, length, buffer,
&byteCount ) != errNone )
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 )
{
uint32_t bytesWritten;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( buffer, length ) );
REQUIRES( stream->type == STREAM_TYPE_FILE );
REQUIRES( length > 0 && length < MAX_INTLENGTH );
if( VFSFileWrite( stream->fileRef, length, buffer,
&bytesWritten ) != errNone || \
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 )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
REQUIRES( stream->type == STREAM_TYPE_FILE );
/* There doesn't seem to be any way to force data to be written do
backing store, probably because the concept of backing store is
somewhat hazy in a system that's never really powered down.
Probably for removable media data is committed fairly quickly to
handle media removal while for fixed media it's committed as
required since it can be retained in memory more or less
indefinitely */
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( VFSFileSeek( stream->fileRef, vfsOriginBeginning,
position ) != errNone )
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 )
{
FileRef fileRef;
uint32_t volIterator = vfsIteratorStart;
uint16_t volRefNum;
status_t err;
assert( fileName != NULL );
if( VFSVolumeEnumerate( &volRefNum, &volIterator ) != errNone )
return( TRUE );
err = VFSFileOpen( volRefNum, fileName, vfsModeRead, &fileRef );
if( err == errNone )
VFSFileClose( fileRef );
return( ( err == vfsErrFilePermissionDenied ) ? TRUE : 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 )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?