758 lines
21 KiB
C
758 lines
21 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla Communicator.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1999
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Daniel Veditz <dveditz@netscape.com>
|
|
* Edward Kandrot <kandrot@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/*------------------------------------------------------------------------
|
|
* nr_bufio
|
|
*
|
|
* Buffered I/O routines to improve registry performance
|
|
* the routines mirror fopen(), fclose() et al
|
|
*
|
|
* Inspired by the performance gains James L. Nance <jim_nance@yahoo.com>
|
|
* got using NSPR memory-mapped I/O for the registry. Unfortunately NSPR
|
|
* doesn't support mmapio on the Mac.
|
|
*-----------------------------------------------------------------------*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#if defined(XP_MAC) || defined(XP_MACOSX)
|
|
#include <Errors.h>
|
|
#endif
|
|
|
|
#if defined(SUNOS4)
|
|
#include <unistd.h> /* for SEEK_SET */
|
|
#endif /* SUNOS4 */
|
|
|
|
#include "prerror.h"
|
|
#include "prlog.h"
|
|
|
|
#include "vr_stubs.h"
|
|
#include "nr_bufio.h"
|
|
|
|
|
|
#define BUFIO_BUFSIZE_DEFAULT 0x2000
|
|
|
|
#define STARTS_IN_BUF(f) ((f->fpos >= f->datastart) && \
|
|
(f->fpos < (f->datastart+f->datasize)))
|
|
|
|
#define ENDS_IN_BUF(f,c) (((f->fpos + c) > (PRUint32)f->datastart) && \
|
|
((f->fpos + c) <= (PRUint32)(f->datastart+f->datasize)))
|
|
|
|
#if DEBUG_dougt
|
|
static num_reads = 0;
|
|
#endif
|
|
|
|
|
|
struct BufioFileStruct
|
|
{
|
|
FILE *fd; /* real file descriptor */
|
|
PRInt32 fsize; /* total size of file */
|
|
PRInt32 fpos; /* our logical position in the file */
|
|
PRInt32 datastart; /* the file position at which the buffer starts */
|
|
PRInt32 datasize; /* the amount of data actually in the buffer*/
|
|
PRInt32 bufsize; /* size of the in memory buffer */
|
|
PRBool bufdirty; /* whether the buffer been written to */
|
|
PRInt32 dirtystart;
|
|
PRInt32 dirtyend;
|
|
PRBool readOnly; /* whether the file allows writing or not */
|
|
#ifdef DEBUG_dveditzbuf
|
|
PRUint32 reads;
|
|
PRUint32 writes;
|
|
#endif
|
|
char *data; /* the data buffer */
|
|
};
|
|
|
|
|
|
static PRBool _bufio_loadBuf( BufioFile* file, PRUint32 count );
|
|
static int _bufio_flushBuf( BufioFile* file );
|
|
|
|
#ifdef XP_OS2
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <share.h>
|
|
#include <io.h>
|
|
|
|
FILE* os2_fileopen(const char* name, const char* mode)
|
|
{
|
|
int access = O_RDWR;
|
|
int descriptor;
|
|
int pmode = 0;
|
|
|
|
/* Fail if only one character is passed in - this shouldn't happen */
|
|
if (mode[1] == '\0') {
|
|
return NULL;
|
|
}
|
|
/* Only possible options are wb+, rb+, wb and rb */
|
|
if (mode[0] == 'w' && mode[1] == 'b') {
|
|
access |= (O_TRUNC | O_CREAT);
|
|
if (mode[2] == '+') {
|
|
access |= O_RDWR;
|
|
pmode = S_IREAD | S_IWRITE;
|
|
} else {
|
|
access |= O_WRONLY;
|
|
pmode = S_IWRITE;
|
|
}
|
|
}
|
|
if (mode[0] == 'r' && mode[1] == 'b') {
|
|
if (mode[2] == '+') {
|
|
access |= O_RDWR;
|
|
pmode = S_IREAD | S_IWRITE;
|
|
} else {
|
|
access = O_RDONLY;
|
|
pmode = S_IREAD;
|
|
}
|
|
}
|
|
|
|
descriptor = sopen(name, access, SH_DENYNO, pmode);
|
|
if (descriptor != -1) {
|
|
return fdopen(descriptor, mode);
|
|
}
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* like fopen() this routine takes *native* filenames, not NSPR names.
|
|
*/
|
|
BufioFile* bufio_Open(const char* name, const char* mode)
|
|
{
|
|
FILE *fd;
|
|
BufioFile *file = NULL;
|
|
|
|
#ifdef XP_OS2
|
|
fd = os2_fileopen( name, mode );
|
|
#else
|
|
fd = fopen( name, mode );
|
|
#endif
|
|
|
|
if ( fd )
|
|
{
|
|
/* file opened successfully, initialize the bufio structure */
|
|
|
|
file = PR_NEWZAP( BufioFile );
|
|
if ( file )
|
|
{
|
|
file->fd = fd;
|
|
file->bufsize = BUFIO_BUFSIZE_DEFAULT; /* set the default buffer size */
|
|
|
|
file->data = (char*)PR_Malloc( file->bufsize );
|
|
if ( file->data )
|
|
{
|
|
/* get file size to finish initialization of bufio */
|
|
if ( !fseek( fd, 0, SEEK_END ) )
|
|
{
|
|
file->fsize = ftell( fd );
|
|
|
|
file->readOnly = strcmp(mode,XP_FILE_READ) == 0 ||
|
|
strcmp(mode,XP_FILE_READ_BIN) == 0;
|
|
}
|
|
else
|
|
{
|
|
PR_Free( file->data );
|
|
PR_DELETE( file );
|
|
}
|
|
}
|
|
else
|
|
PR_DELETE( file );
|
|
}
|
|
|
|
/* close file if we couldn't create BufioFile */
|
|
if (!file)
|
|
{
|
|
fclose( fd );
|
|
PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* couldn't open file. Figure out why and set NSPR errors */
|
|
|
|
switch (errno)
|
|
{
|
|
/* file not found */
|
|
#if defined(XP_MAC) || defined(XP_MACOSX)
|
|
case fnfErr:
|
|
#else
|
|
case ENOENT:
|
|
#endif
|
|
PR_SetError(PR_FILE_NOT_FOUND_ERROR,0);
|
|
break;
|
|
|
|
/* file in use */
|
|
#if defined(XP_MAC) || defined(XP_MACOSX)
|
|
case opWrErr:
|
|
#else
|
|
case EACCES:
|
|
#endif
|
|
PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR,0);
|
|
break;
|
|
|
|
default:
|
|
PR_SetError(PR_UNKNOWN_ERROR,0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return file;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* close the buffered file and destroy BufioFile struct
|
|
*/
|
|
int bufio_Close(BufioFile* file)
|
|
{
|
|
int retval = -1;
|
|
|
|
if ( file )
|
|
{
|
|
if ( file->bufdirty )
|
|
_bufio_flushBuf( file );
|
|
|
|
retval = fclose( file->fd );
|
|
|
|
if ( file->data )
|
|
PR_Free( file->data );
|
|
|
|
PR_DELETE( file );
|
|
#if DEBUG_dougt
|
|
printf(" --- > Buffered registry read fs hits (%d)\n", num_reads);
|
|
#endif
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* change the logical position in the file. Equivalent to fseek()
|
|
*/
|
|
int bufio_Seek(BufioFile* file, PRInt32 offset, int whence)
|
|
{
|
|
if (!file)
|
|
return -1;
|
|
|
|
switch(whence)
|
|
{
|
|
case SEEK_SET:
|
|
file->fpos = offset;
|
|
break;
|
|
case SEEK_END:
|
|
file->fpos = file->fsize + offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
file->fpos = file->fpos + offset;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
if ( file->fpos < 0 )
|
|
file->fpos = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* like ftell() returns the current position in the file, or -1 for error
|
|
*/
|
|
PRInt32 bufio_Tell(BufioFile* file)
|
|
{
|
|
if (file)
|
|
return file->fpos;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
PRUint32 bufio_Read(BufioFile* file, char* dest, PRUint32 count)
|
|
{
|
|
PRInt32 startOffset;
|
|
PRInt32 endOffset;
|
|
PRInt32 leftover;
|
|
PRUint32 bytesCopied;
|
|
PRUint32 bytesRead;
|
|
PRUint32 retcount = 0;
|
|
|
|
/* sanity check arguments */
|
|
if ( !file || !dest || count == 0 || file->fpos >= file->fsize )
|
|
return 0;
|
|
|
|
/* Adjust amount to read if we're near EOF */
|
|
if ( (file->fpos + count) > (PRUint32)file->fsize )
|
|
count = file->fsize - file->fpos;
|
|
|
|
|
|
/* figure out how much of the data we want is already buffered */
|
|
|
|
startOffset = file->fpos - file->datastart;
|
|
endOffset = startOffset + count;
|
|
|
|
if ( startOffset >= 0 && startOffset < file->datasize )
|
|
{
|
|
/* The beginning of what we want is in the buffer */
|
|
/* so copy as much as is available of what we want */
|
|
|
|
if ( endOffset <= file->datasize )
|
|
bytesCopied = count;
|
|
else
|
|
bytesCopied = file->datasize - startOffset;
|
|
|
|
memcpy( dest, file->data + startOffset, bytesCopied );
|
|
retcount = bytesCopied;
|
|
file->fpos += bytesCopied;
|
|
#ifdef DEBUG_dveditzbuf
|
|
file->reads++;
|
|
#endif
|
|
|
|
/* Was that all we wanted, or do we need to get more? */
|
|
|
|
leftover = count - bytesCopied;
|
|
PR_ASSERT( leftover >= 0 ); /* negative left? something's wrong! */
|
|
|
|
if ( leftover )
|
|
{
|
|
/* need data that's not in the buffer */
|
|
|
|
/* if what's left fits in a buffer then load the buffer with the */
|
|
/* new area before giving the data, otherwise just read right */
|
|
/* into the user's dest buffer */
|
|
|
|
if ( _bufio_loadBuf( file, leftover ) )
|
|
{
|
|
startOffset = file->fpos - file->datastart;
|
|
|
|
/* we may not have been able to load as much as we wanted */
|
|
if ( startOffset > file->datasize )
|
|
bytesRead = 0;
|
|
else if ( startOffset+leftover <= file->datasize )
|
|
bytesRead = leftover;
|
|
else
|
|
bytesRead = file->datasize - startOffset;
|
|
|
|
if ( bytesRead )
|
|
{
|
|
memcpy( dest+bytesCopied, file->data+startOffset, bytesRead );
|
|
file->fpos += bytesRead;
|
|
retcount += bytesRead;
|
|
#ifdef DEBUG_dveditzbuf
|
|
file->reads++;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* we need more than we could load into a buffer, so */
|
|
/* skip buffering and just read the data directly */
|
|
|
|
if ( fseek( file->fd, file->fpos, SEEK_SET ) == 0 )
|
|
{
|
|
#if DEBUG_dougt
|
|
++num_reads;
|
|
#endif
|
|
bytesRead = fread(dest+bytesCopied, 1, leftover, file->fd);
|
|
file->fpos += bytesRead;
|
|
retcount += bytesRead;
|
|
}
|
|
else
|
|
{
|
|
/* XXX seek failed, couldn't load more data -- help! */
|
|
/* should we call PR_SetError() ? */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* range doesn't start in the loaded buffer but it might end there */
|
|
if ( endOffset > 0 && endOffset <= file->datasize )
|
|
bytesCopied = endOffset;
|
|
else
|
|
bytesCopied = 0;
|
|
|
|
leftover = count - bytesCopied;
|
|
|
|
if ( bytesCopied )
|
|
{
|
|
/* the tail end of the range we want is already buffered */
|
|
/* first copy the buffered data to the dest area */
|
|
memcpy( dest+leftover, file->data, bytesCopied );
|
|
#ifdef DEBUG_dveditzbuf
|
|
file->reads++;
|
|
#endif
|
|
}
|
|
|
|
/* now pick up the part that's not already in the buffer */
|
|
|
|
if ( _bufio_loadBuf( file, leftover ) )
|
|
{
|
|
/* we were able to load some data */
|
|
startOffset = file->fpos - file->datastart;
|
|
|
|
/* we may not have been able to read as much as we wanted */
|
|
if ( startOffset > file->datasize )
|
|
bytesRead = 0;
|
|
else if ( startOffset+leftover <= file->datasize )
|
|
bytesRead = leftover;
|
|
else
|
|
bytesRead = file->datasize - startOffset;
|
|
|
|
if ( bytesRead )
|
|
{
|
|
memcpy( dest, file->data+startOffset, bytesRead );
|
|
#ifdef DEBUG_dveditzbuf
|
|
file->reads++;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* leftover data doesn't fit so skip buffering */
|
|
if ( fseek( file->fd, file->fpos, SEEK_SET ) == 0 )
|
|
{
|
|
bytesRead = fread(dest, 1, leftover, file->fd);
|
|
#if DEBUG_dougt
|
|
++num_reads;
|
|
#endif
|
|
}
|
|
else
|
|
bytesRead = 0;
|
|
}
|
|
|
|
/* if we couldn't read all the leftover, don't tell caller */
|
|
/* about the tail end we copied from the first buffer */
|
|
if ( bytesRead == (PRUint32)leftover )
|
|
retcount = bytesCopied + bytesRead;
|
|
else
|
|
retcount = bytesRead;
|
|
|
|
file->fpos += retcount;
|
|
}
|
|
|
|
return retcount;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Buffered writes
|
|
*/
|
|
PRUint32 bufio_Write(BufioFile* file, const char* src, PRUint32 count)
|
|
{
|
|
const char* newsrc;
|
|
PRInt32 startOffset;
|
|
PRInt32 endOffset;
|
|
PRUint32 leftover;
|
|
PRUint32 retcount = 0;
|
|
PRUint32 bytesWritten = 0;
|
|
PRUint32 bytesCopied = 0;
|
|
|
|
/* sanity check arguments */
|
|
if ( !file || !src || count == 0 || file->readOnly )
|
|
return 0;
|
|
|
|
/* Write to the current buffer if we can, otherwise load a new buffer */
|
|
|
|
startOffset = file->fpos - file->datastart;
|
|
endOffset = startOffset + count;
|
|
|
|
if ( startOffset >= 0 && startOffset < file->bufsize )
|
|
{
|
|
/* the area we want to write starts in the buffer */
|
|
|
|
if ( endOffset <= file->bufsize )
|
|
bytesCopied = count;
|
|
else
|
|
bytesCopied = file->bufsize - startOffset;
|
|
|
|
memcpy( file->data + startOffset, src, bytesCopied );
|
|
file->bufdirty = PR_TRUE;
|
|
endOffset = startOffset + bytesCopied;
|
|
file->dirtystart = PR_MIN( startOffset, file->dirtystart );
|
|
file->dirtyend = PR_MAX( endOffset, file->dirtyend );
|
|
#ifdef DEBUG_dveditzbuf
|
|
file->writes++;
|
|
#endif
|
|
|
|
if ( endOffset > file->datasize )
|
|
file->datasize = endOffset;
|
|
|
|
retcount = bytesCopied;
|
|
file->fpos += bytesCopied;
|
|
|
|
/* was that all we had to write, or is there more? */
|
|
leftover = count - bytesCopied;
|
|
newsrc = src+bytesCopied;
|
|
}
|
|
else
|
|
{
|
|
/* range doesn't start in the loaded buffer but it might end there */
|
|
if ( endOffset > 0 && endOffset <= file->bufsize )
|
|
bytesCopied = endOffset;
|
|
else
|
|
bytesCopied = 0;
|
|
|
|
leftover = count - bytesCopied;
|
|
newsrc = src;
|
|
|
|
if ( bytesCopied )
|
|
{
|
|
/* the tail end of the write range is already in the buffer */
|
|
memcpy( file->data, src+leftover, bytesCopied );
|
|
file->bufdirty = PR_TRUE;
|
|
file->dirtystart = 0;
|
|
file->dirtyend = PR_MAX( endOffset, file->dirtyend );
|
|
#ifdef DEBUG_dveditzbuf
|
|
file->writes++;
|
|
#endif
|
|
|
|
if ( endOffset > file->datasize )
|
|
file->datasize = endOffset;
|
|
}
|
|
}
|
|
|
|
/* if we only wrote part of the request pick up the leftovers */
|
|
if ( leftover )
|
|
{
|
|
/* load the buffer with the new range, if possible */
|
|
if ( _bufio_loadBuf( file, leftover ) )
|
|
{
|
|
startOffset = file->fpos - file->datastart;
|
|
endOffset = startOffset + leftover;
|
|
|
|
memcpy( file->data+startOffset, newsrc, leftover );
|
|
file->bufdirty = PR_TRUE;
|
|
file->dirtystart = startOffset;
|
|
file->dirtyend = endOffset;
|
|
#ifdef DEBUG_dveditzbuf
|
|
file->writes++;
|
|
#endif
|
|
if ( endOffset > file->datasize )
|
|
file->datasize = endOffset;
|
|
|
|
bytesWritten = leftover;
|
|
}
|
|
else
|
|
{
|
|
/* request didn't fit in a buffer, write directly */
|
|
if ( fseek( file->fd, file->fpos, SEEK_SET ) == 0 )
|
|
bytesWritten = fwrite( newsrc, 1, leftover, file->fd );
|
|
else
|
|
bytesWritten = 0; /* seek failed! */
|
|
}
|
|
|
|
if ( retcount )
|
|
{
|
|
/* we already counted the first part we wrote */
|
|
retcount += bytesWritten;
|
|
file->fpos += bytesWritten;
|
|
}
|
|
else
|
|
{
|
|
retcount = bytesCopied + bytesWritten;
|
|
file->fpos += retcount;
|
|
}
|
|
}
|
|
|
|
if ( file->fpos > file->fsize )
|
|
file->fsize = file->fpos;
|
|
|
|
return retcount;
|
|
}
|
|
|
|
|
|
|
|
int bufio_Flush(BufioFile* file)
|
|
{
|
|
if ( file->bufdirty )
|
|
_bufio_flushBuf( file );
|
|
|
|
return fflush(file->fd);
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* internal helper functions
|
|
*---------------------------------------------------------------------------*/
|
|
/**
|
|
* Attempts to load the buffer with the requested amount of data.
|
|
* Returns PR_TRUE if it was able to load *some* of the requested
|
|
* data, but not necessarily all. Returns PR_FALSE if the read fails
|
|
* or if the requested amount wouldn't fit in the buffer.
|
|
*/
|
|
static PRBool _bufio_loadBuf( BufioFile* file, PRUint32 count )
|
|
{
|
|
PRInt32 startBuf;
|
|
PRInt32 endPos;
|
|
PRInt32 endBuf;
|
|
PRUint32 bytesRead;
|
|
|
|
/* no point in buffering more than the physical buffer will hold */
|
|
if ( count > (PRUint32)file->bufsize )
|
|
return PR_FALSE;
|
|
|
|
/* Is caller asking for data we already have? */
|
|
if ( STARTS_IN_BUF(file) && ENDS_IN_BUF(file,count) )
|
|
{
|
|
PR_ASSERT(0);
|
|
return PR_TRUE;
|
|
}
|
|
|
|
/* if the buffer's dirty make sure we successfully flush it */
|
|
if ( file->bufdirty && _bufio_flushBuf(file) != 0 )
|
|
return PR_FALSE;
|
|
|
|
/* For now we're not trying anything smarter than simple paging. */
|
|
/* Slide over if necessary to fit the entire request */
|
|
startBuf = ( file->fpos / file->bufsize ) * file->bufsize;
|
|
endPos = file->fpos + count;
|
|
endBuf = startBuf + file->bufsize;
|
|
if ( endPos > endBuf )
|
|
startBuf += (endPos - endBuf);
|
|
|
|
if ( fseek( file->fd, startBuf, SEEK_SET ) != 0 )
|
|
return PR_FALSE;
|
|
else
|
|
{
|
|
#if DEBUG_dougt
|
|
++num_reads;
|
|
#endif
|
|
bytesRead = fread( file->data, 1, file->bufsize, file->fd );
|
|
file->datastart = startBuf;
|
|
file->datasize = bytesRead;
|
|
file->bufdirty = PR_FALSE;
|
|
file->dirtystart = file->bufsize;
|
|
file->dirtyend = 0;
|
|
#ifdef DEBUG_dveditzbuf
|
|
printf("REG: buffer read %d (%d) after %d reads\n",startBuf,file->fpos,file->reads);
|
|
file->reads = 0;
|
|
file->writes = 0;
|
|
#endif
|
|
return PR_TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int _bufio_flushBuf( BufioFile* file )
|
|
{
|
|
PRUint32 written;
|
|
PRUint32 dirtyamt;
|
|
PRInt32 startpos;
|
|
|
|
PR_ASSERT(file);
|
|
if ( !file || !file->bufdirty )
|
|
return 0;
|
|
|
|
startpos = file->datastart + file->dirtystart;
|
|
if ( !fseek( file->fd, startpos, SEEK_SET ) )
|
|
{
|
|
dirtyamt = file->dirtyend - file->dirtystart;
|
|
written = fwrite( file->data+file->dirtystart, 1, dirtyamt, file->fd );
|
|
if ( written == dirtyamt )
|
|
{
|
|
#ifdef DEBUG_dveditzbuf
|
|
printf("REG: buffer flush %d - %d after %d writes\n",startpos,startpos+written,file->writes);
|
|
file->writes = 0;
|
|
#endif
|
|
file->bufdirty = PR_FALSE;
|
|
file->dirtystart = file->bufsize;
|
|
file->dirtyend = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* sets the file buffer size to bufsize, clearing the buffer in the process.
|
|
*
|
|
* accepts bufsize of -1 to mean default buffer size, defined by BUFIO_BUFSIZE_DEFAULT
|
|
* returns new buffers size, or -1 if error occured
|
|
*/
|
|
|
|
int bufio_SetBufferSize(BufioFile* file, int bufsize)
|
|
{
|
|
char *newBuffer;
|
|
int retVal = -1;
|
|
|
|
PR_ASSERT(file);
|
|
if (!file)
|
|
return retVal;
|
|
|
|
if (bufsize == -1)
|
|
bufsize = BUFIO_BUFSIZE_DEFAULT;
|
|
if (bufsize == file->bufsize)
|
|
return bufsize;
|
|
|
|
newBuffer = (char*)PR_Malloc( bufsize );
|
|
if (newBuffer)
|
|
{
|
|
/* if the buffer's dirty make sure we successfully flush it */
|
|
if ( file->bufdirty && _bufio_flushBuf(file) != 0 )
|
|
{
|
|
PR_Free( newBuffer );
|
|
return -1;
|
|
}
|
|
|
|
|
|
file->bufsize = bufsize;
|
|
if ( file->data )
|
|
PR_Free( file->data );
|
|
file->data = newBuffer;
|
|
file->datasize = 0;
|
|
file->datastart = 0;
|
|
retVal = bufsize;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/* EOF nr_bufio.c */
|