📄 pgpfilemod.c
字号:
/*
* File I/O modules.
*
* Written by: Derek Atkins <warlord@MIT.EDU>
*
* $Id: pgpFileMod.c,v 1.31 1998/02/07 00:42:14 heller Exp $
*/
#include "pgpConfig.h"
#include <string.h>
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if PGP_MACINTOSH
#include <unix.h>
#include <stat.h>
#else
#include <sys/types.h> /* required for Ultrix */
#include <sys/stat.h>
#endif
#include "pgpDebug.h"
#include "pgpFileMod.h"
#include "pgpAnnotate.h"
#include "pgpMem.h"
#include "pgpErrors.h"
#include "pgpFile.h"
#include "pgpPipeline.h"
#include "pgpContext.h"
#include "pgpKludge.h"
#define FILEMODMAGIC 0xfeedf11e
typedef struct FileModContext
{
PGPPipeline pipe;
PGPFile *file;
int closeFlag;
int in_newfile;
int scope_depth;
DEBUG_STRUCT_CONSTRUCTOR( FileModContext )
} FileModContext;
/*
* If we have a file, flush it. Then, if we are allowed to close
* it, then do so. If we successfully closed it, then set the file
* pointer to 0. Return from any error with the error number.
*/
static PGPError
fileModClose (FileModContext *context)
{
PGPError error = kPGPError_NoErr;
if (context->file) {
error = pgpFileFlush (context->file);
if (error)
return error;
if (context->closeFlag) {
error = pgpFileClose (context->file);
if (error)
return error;
context->file = 0;
}
}
return kPGPError_NoErr;
}
static PGPError
Flush (PGPPipeline *myself)
{
FileModContext *context;
pgpAssert (myself);
pgpAssert (myself->magic == FILEMODMAGIC);
context = (FileModContext *)myself->priv;
pgpAssert (context);
if (!context->file)
return kPGPError_NoErr;
return pgpFileFlush (context->file);
}
static size_t
fileWrite (PGPPipeline *myself, PGPByte const *buffer, size_t size,
PGPError *error)
{
FileModContext *context;
size_t retval;
pgpAssert (myself);
pgpAssert (myself->magic == FILEMODMAGIC);
context = (FileModContext *)myself->priv;
pgpAssert (context);
if (!context->file) {
if (error)
*error = kPGPError_CantOpenFile; /* No such file or directory*/
return 0;
}
retval = pgpFileWrite (buffer, size, context->file);
if (retval) {
if (error)
*error = kPGPError_NoErr;
return retval;
}
if (error && pgpFileError (context->file))
*error = kPGPError_FileOpFailed;
pgpFileClearError (context->file);
return 0;
}
/*
* We accept certain annotations to tell us that we should change
* the file we are writing. If we have an open file, then it is an
* assertion error if it doesn't have closeFlag true.
*
*/
static PGPError
fileAnnotate (PGPPipeline *myself, PGPPipeline *origin, int type,
PGPByte const *string, size_t size)
{
FileModContext *context;
FILE *fp;
char filename[FILENAME_MAX];
size_t len;
PGPError error;
PGPMemoryMgrRef memoryMgr;
pgpAssertAddrValid( myself, PGPPipeline );
memoryMgr = PGPGetContextMemoryMgr( myself->cdkContext );
(void)origin; /* Not used */
pgpAssert (myself);
pgpAssert (myself->magic == FILEMODMAGIC);
context = (FileModContext *)myself->priv;
pgpAssert (context);
switch (type) {
case PGPANN_NEWFILE_START:
pgpAssert(!context->file || context->closeFlag);
if (context->file) {
error = fileModClose (context);
if (error)
return error;
}
pgpAssert (!context->file);
{
PGPFile *pgpf;
len = pgpMin (size, sizeof (filename) - 1);
memcpy (filename, string, len);
filename[len] = '\0';
/* I need to know if this should be binary or not */
fp = fopen (filename, "wb");
if (!fp)
return kPGPError_CantOpenFile;
pgpf = pgpFileWriteOpen ( myself->cdkContext, fp, NULL);
if (!pgpf) {
fclose (fp);
return kPGPError_OutOfMemory;
}
context->file = pgpf;
context->closeFlag = 1;
}
context->in_newfile = 1;
break;
default:
; /* do nothing */
}
PGP_SCOPE_DEPTH_UPDATE(context->scope_depth, type);
pgpAssert(context->scope_depth != -1);
return kPGPError_NoErr;
}
static PGPError
fileSizeAdvise (PGPPipeline *myself, unsigned long bytes)
{
FileModContext *context;
pgpAssert (myself);
pgpAssert (myself->magic == FILEMODMAGIC);
context = (FileModContext *)myself->priv;
pgpAssert (context);
if (bytes || context->scope_depth)
return kPGPError_NoErr;
if (context->in_newfile && !context->closeFlag)
return kPGPError_NoErr;
return fileModClose (context);
}
static PGPError
fileTeardown (PGPPipeline *myself)
{
FileModContext *context;
pgpAssertAddrValid( myself, PGPPipeline );
pgpAssert (myself);
pgpAssert (myself->magic == FILEMODMAGIC);
context = (FileModContext *)myself->priv;
pgpAssert (context);
fileModClose (context);
pgpClearMemory( context, sizeof (*context));
PGPFreeData( context);
return( kPGPError_NoErr );
}
PGPPipeline *
pgpFileWriteCreate (
PGPContextRef cdkContext,
PGPPipeline **head,
PGPFile *file,
int closeFlag)
{
PGPPipeline *mod;
FileModContext *context;
PGPMemoryMgrRef memoryMgr = PGPGetContextMemoryMgr( cdkContext );
if (!head)
return NULL;
*head = 0;
context = (FileModContext *)PGPNewData(
memoryMgr, sizeof(*context), kPGPMemoryMgrFlags_Clear );
if ( IsNull( context ) )
return NULL;
mod = &context->pipe;
mod->magic = FILEMODMAGIC;
mod->write = fileWrite;
mod->flush = Flush;
mod->sizeAdvise = fileSizeAdvise;
mod->annotate = fileAnnotate;
mod->teardown = fileTeardown;
mod->name = "Write file";
mod->priv = context;
mod->cdkContext = cdkContext;
context->file = file;
context->closeFlag = closeFlag;
*head = mod;
return mod;
}
#if (BUFSIZ < 16384) && (PGP_MACINTOSH || PGP_WIN32)
#define kPGPReadBufSize 16384
#else
#define kPGPReadBufSize BUFSIZ
#endif
#if 0
/* Enable this for debugging - it stresses the hell out of the pipeline */
#undef kPGPReadBufSize
#define kPGPReadBufSize 1
#endif
struct PGPFileRead
{
PGPMemoryMgrRef memoryMgr;
PGPPipeline mod;
PGPFile * file;
PGPByte buffer[kPGPReadBufSize];
PGPByte * p;
off_t filesize;
off_t sizeleft;
size_t len;
PGPFileReadCallBack callBack;
void * callBackArg;
int annsent;
int sizesent;
int closeFlag;
} ;
PGPFileRead *
pgpFileReadCreate(
PGPContextRef cdkContext,
FILE * stdioFile,
int closeFlag)
{
/*
* XXX Potential space leak if <closeFlag> is false, although it's
* never called that way from anywhere except possibly on Un*x.
* never called that way from anywhere in PGP 5.0
*/
/* pgpFixBeforeShip("Potential space leak if <closeFlag> is false"); */
return pgpPGPFileReadCreate( cdkContext,
pgpFileReadOpen ( cdkContext, stdioFile, NULL, NULL), closeFlag);
}
PGPFileRead *
pgpPGPFileReadCreate(
PGPContextRef cdkContext,
PGPFile *input, int closeFlag)
{
PGPFileRead *context;
long sizeAdvise;
PGPMemoryMgrRef memoryMgr = PGPGetContextMemoryMgr( cdkContext );
pgpAssert (input);
context = (PGPFileRead *)PGPNewData( memoryMgr,
sizeof (*context), kPGPMemoryMgrFlags_Clear );
if (!context)
return NULL;
context->memoryMgr = memoryMgr;
sizeAdvise = pgpFileSizeAdvise (input);
context->file = input;
context->p = context->buffer;
if (sizeAdvise < 0)
{
/* Dont trust the size if its not a regular file */
context->filesize = 0;
context->sizesent = -1;
}
else
{
context->filesize = sizeAdvise;
context->sizesent = 0;
}
context->sizeleft = context->filesize;
context->callBack = NULL;
context->closeFlag = closeFlag;
context->mod.name = "File Read Module";
return context;
}
void
pgpFileReadSetCallBack (PGPFileRead *context, PGPFileReadCallBack callBack,
void *callBackArg)
{
context->callBack = callBack;
context->callBackArg = callBackArg;
}
PGPByte const *
pgpFileReadPeek (PGPFileRead *context, PGPSize *len)
{
pgpAssert (context);
/* Compress data to beginning of buffer */
if (context->p != context->buffer) {
pgpCopyMemory (context->p, context->buffer, context->len);
context->p = context->buffer;
}
/* Now try to fill the buffer */
if (!pgpFileEof (context->file))
context->len += pgpFileRead (context->p + context->len,
sizeof(context->buffer) - context->len,
context->file);
if (len)
*len = context->len;
return context->p;
}
void
pgpFileReadDestroy (PGPFileRead *context)
{
pgpAssert (context);
if (context->closeFlag)
(void) pgpFileClose (context->file);
PGPFreeData( context );
}
PGPError
pgpFileReadClose (PGPFileRead *context, PGPPipeline *head)
{
PGPError error = kPGPError_NoErr;
if (context->annsent < 2) {
error = head->annotate (head, &context->mod, PGPANN_FILE_END,
NULL, 0);
if (error)
return error;
context->annsent = 2;
}
return error;
}
PGPError
pgpFileReadPump (PGPFileRead *context, PGPPipeline *head)
{
PGPError error = kPGPError_NoErr;
size_t retlen;
pgpAssert (context);
pgpAssert (head);
/*
* Size should be sent outside scope. Also send it inside for consistency
* with past behavior; that is not necessary but should not hurt.
*/
if (!context->sizesent) {
error = head->sizeAdvise (head, context->sizeleft);
if (error)
return error;
}
if (!context->annsent) {
error = head->annotate (head, &context->mod, PGPANN_FILE_BEGIN,
NULL, 0);
if (error)
return error;
context->annsent = 1;
}
if (!context->sizesent) {
error = head->sizeAdvise (head, context->sizeleft);
if (error)
return error;
context->sizesent = 1;
}
do {
/* Write out anything in my buffer */
while (context->len) {
retlen = head->write (head, context->p,
context->len, &error);
context->len -= retlen;
context->p += retlen;
context->sizeleft -= retlen;
if (error)
return error;
if (context->callBack != NULL)
{
error = (*context->callBack) (context->callBackArg,
context->filesize - context->sizeleft,
context->filesize);
if (error != kPGPError_NoErr)
return error;
}
}
context->p = context->buffer;
if (pgpFileEof (context->file))
break;
context->len = pgpFileRead (context->p, sizeof(context->buffer),
context->file);
} while (context->len);
/* If I get here, then I'm at the end of the file */
if (context->sizeleft && context->sizesent > 0)
return kPGPError_SizeAdviseFailure;
error = head->sizeAdvise (head, 0);
if (error)
return error;
error = pgpFileReadClose (context, head);
if (error)
return error;
return kPGPError_NoErr;
}
/*
* Local Variables:
* tab-width: 4
* End:
* vi: ts=4 sw=4
* vim: si
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -