📄 vfsfiles.c
字号:
/* FUNCTION: vfread()
*
* vfread() - fread for vfs. if vfd parm is a vfs handle, this gets
* data from the virtual file system, doing uncompression on the fly.
* If vfd is not in vfs, this can be ifdefed to fall to a native
* fread() call. Parameters and returns are identical to fread();
*
* PARAM1: char * buf
* PARAM2: unsigned size
* PARAM3: unsigned items
* PARAM4: VFILE * vfd
*
* RETURNS:
*/
int
vfread(char * buf, unsigned size, unsigned items, VFILE * vfd)
{
unsigned bcount; /* number of bytes put in caller's buffer */
IN_PROFILER(PF_FS, PF_ENTRY);
/* lock the VFS */
vfs_lock();
/* if the file is in our list of open files */
if (isvfile_locked(vfd))
{
#ifdef HT_RWVFS
/* the caller is trying to read a handle to a file that's been
deleted, so he gets 0 data back */
if (vfd->file == NULL)
{
vfs_unlock();
IN_PROFILER(PF_FS, PF_EXIT);
return 0;
}
#endif /* HT_RWVFS */
#ifdef HT_EXTDEV
/* if the file was created by an external file system */
if (vfd->file->method)
{
struct vfroutines * vfs = (struct vfroutines*) (vfd->file->method);
int rc;
/* call that system's fread() */
rc = vfs->r_fread(buf,size,items,vfd);
vfs_unlock();
IN_PROFILER(PF_FS, PF_EXIT);
return rc;
}
#endif /* HT_EXTDEV */
#ifdef HT_RWVFS
/* the data pointer can be NULL if somebody tries to read from
* a freshly created file, in which case there is no data in
* the file, so return 0
*/
if (!(vfd->file->data))
{
vfs_unlock();
IN_PROFILER(PF_FS, PF_EXIT);
return 0;
}
#endif /* HT_RWVFS */
bcount = items * size; /* number of bytes to transfer */
#ifdef HTML_COMPRESSION
if (vfd->file->flags & VF_HTMLCOMPRESSED)
{
int chr; /* next char to process */
while (bcount)
{
chr = vgetc_locked(vfd);
if (chr == EOF)
{
vfs_unlock();
IN_PROFILER(PF_FS, PF_EXIT);
return(((items*size)-bcount)/size);
}
*buf++ = (char)chr;
bcount--;
}
vfs_unlock();
IN_PROFILER(PF_FS, PF_EXIT);
return(items); /* filled user buffer, return # items copied */
}
else /* else fall to faster non-compression code */
#endif /* HTML_COMPRESSION */
{ /* get here to do simple uncompressed data read */
unsigned location = vfd->cmploc - vfd->file->data;
if (((unsigned long)location + bcount) > vfd->file->comp_size)
bcount = (unsigned)(vfd->file->comp_size - location);
MEMCPY(buf, vfd->cmploc, bcount);
vfd->cmploc += bcount;
}
vfs_unlock();
IN_PROFILER(PF_FS, PF_EXIT);
return (bcount/size);
}
vfs_unlock();
IN_PROFILER(PF_FS, PF_EXIT);
#ifdef HT_LOCALFS
/* default to call on local system */
return(fread(buf, size, items, (FILE*)vfd));
#else
return 0;
#endif /* HT_LOCALFS */
}
/* VFS_WRITE_BUF_INC defines how much the size of the buffer used to
store file system data is increased at a time */
#define VFS_WRITE_BUF_INC 8192
#define VFS_ROUND_UP(x) \
(((((x) - 1) / VFS_WRITE_BUF_INC) + 1) * VFS_WRITE_BUF_INC)
/* FUNCTION: vfwrite_locked()
*
* PARAM1: char * buf
* PARAM2: unsigned size
* PARAM3: unsigned items
* PARAM4: VFILE *vfd
*
* RETURNS:
*/
int
vfwrite_locked(char * buf, unsigned size, unsigned items, VFILE * vfd)
{
#ifndef HT_RWVFS
#ifndef HT_LOCALFS
#ifndef HT_EXTDEV
/* if the file is in our list of files */
if (isvfile_locked(vfd))
{
vfd->error = ENP_LOGIC;
return 0;
}
/* I know this is ugly but its the simplist way I can figure to
* suppress those annoying "parameter not used" compiler warnings.
* its a damned shame given that it results in the
* generation of superfluous code
*/
USE_ARG(buf);
USE_ARG(size);
USE_ARG(items);
return EBADF;
#endif /* HT_EXTDEV */
#endif /* HT_LOCALFS */
#endif /* HT_RWVFS */
#ifdef HT_RWVFS
unsigned int bcount; /* number of bytes to write */
unsigned long current_offset;
struct vfs_file * vfp;
#endif /* HT_RWVFS */
/* if the file is not in our list of files */
if (!isvfile_locked(vfd))
{
#ifdef HT_LOCALFS
/* default to call on local system */
return(fwrite(buf, size, items, (FILE*)vfd));
#else
return EBADF;
#endif /* HT_LOCALFS */
}
/* this file is in our list of files */
#ifdef HT_EXTDEV
/* if the file was created by an external file system */
if (vfd->file->method)
{
struct vfroutines * vfs = (struct vfroutines*) (vfd->file->method);
int rc;
/* call that system's fwrite() */
rc = vfs->r_fwrite(buf,size,items,vfd);
return rc;
}
#endif
/* if we don't support writes, set an error */
#ifndef HT_RWVFS
vfd->error = ENP_LOGIC;
return 0;
#else /* HT_RWVFS */
/* the caller is trying to write to a file that's been deleted,
so he writes 0 data */
if (vfd->file == NULL)
{
return 0;
}
vfp = vfd->file;
/* if the file is not writable, return error condition */
if (!(vfp->flags & VF_WRITE))
{
vfd->error = ENP_FILEIO;
return 0;
}
/* compute number of bytes to write */
bcount = size * items;
/* get rid of this degenerate case up front */
if (bcount == 0)
{
return 0;
}
/* if the file currently has no data buffer */
if (vfp->data == NULL)
{
/* compute the size of the buffer to be created */
/* we round up the size of the data to be written so we dont have
the overhead of a memory allocation on every write */
unsigned long buf_size = VFS_ROUND_UP((unsigned long)bcount);
/* allocate a buffer of that size */
vfp->data = vf_alloc_buffer(buf_size);
/* if the allocation failed */
if (!(vfp->data))
{
vfd->error = ENP_NOMEM;
return 0;
}
/* store the size of the allocated buffer */
vfp->buf_size = buf_size;
/* store the number of bytes written in the real and compressed
file sizes */
vfp->real_size = bcount;
vfp->comp_size = bcount;
/* set the file pointer to the first byte following the last
byte written */
vfd->cmploc = vfp->data + bcount;
/* turn off the compression flag */
vfp->flags &= ~VF_HTMLCOMPRESSED;
/* the data in the file is stale */
vfp->flags |= VF_STALE;
/* the buffer data was dynamically allocated */
vfp->flags |= VF_DYNAMICDATA;
/* copy the data to be written to the file buffer */
MEMCPY(vfp->data,buf,bcount);
/* return the number of "items" written */
return items;
}
/* compute the current offset into the file */
current_offset = vfd->cmploc - vfp->data;
/* if the data to be written wont fit into the file buffer */
if ((current_offset + bcount) > vfp->buf_size)
{
/* compute the size of a new buffer to hold the data */
unsigned long new_buf_size = VFS_ROUND_UP(current_offset + bcount);
unsigned char *new_buffer;
/* allocate a new buffer */
new_buffer = vf_alloc_buffer(new_buf_size);
/* check for allocation failure */
if (!new_buffer)
{
vfd->error = ENP_NOMEM;
return 0;
}
/* copy the old buffer contents to the new buffer */
MEMCPY(new_buffer,vfp->data,(unsigned int) (vfp->comp_size));
/* if the old buffer had been dynamically allocated */
if (vfp->flags & VF_DYNAMICDATA)
{
/* free it */
vf_free_buffer(vfp->data,vfp->buf_size);
}
/* store the new buffer in the file structure */
vfp->data = new_buffer;
/* store the new buffer size in the file structure */
vfp->buf_size = new_buf_size;
/* the new buffer was dynamically allocated */
vfp->flags |= VF_DYNAMICDATA;
/* set the current file pointer to point into the new data
* buffer note that this means the VFS does not support
* simultaneous opens of the same file, since for that to work,
* all the other cmploc's that point to this file would
* have to be updated also
*/
vfd->cmploc = vfp->data + current_offset;
}
/* copy the data to the current file pointer */
MEMCPY(vfd->cmploc,buf,bcount);
/* update the current file pointer */
vfd->cmploc += bcount;
/* if the resulting current offset is greater than the file size */
if (current_offset + bcount > vfp->comp_size)
{
/* update the "compressed" file size */
vfp->comp_size = current_offset + bcount;
}
/* since we turn off the compression bit below, the "real" size and
the compressed size must be the same */
vfp->real_size = vfp->comp_size;
/* turn off the compression flag */
vfp->flags &= ~VF_HTMLCOMPRESSED;
/* the data in the file is stale */
vfp->flags |= VF_STALE;
/* return the number of "items" written */
return items;
#endif /* HT_RWVFS */
}
/* FUNCTION: vfwrite()
*
* vfwrite() - This is included to support integration with native
* file systems. Parameters and returns are identical to fwrite();
* except that on some error conditions EBADF is returned instead of
* 0
*
* PARAM1: char * buf
* PARAM2: unsigned size
* PARAM3: unsigned items
* PARAM4: VFILE *vfd
*
* RETURNS:
*/
int
vfwrite(char * buf, unsigned size, unsigned items, VFILE * vfd)
{
int rc;
IN_PROFILER(PF_FS, PF_ENTRY);
/* lock the VFS */
vfs_lock();
/* do the write */
rc = vfwrite_locked(buf, size, items, vfd);
/* unlock the VFS */
vfs_unlock();
IN_PROFILER(PF_FS, PF_EXIT);
return rc;
}
/* FUNCTION: vfseek()
*
* vfseek : Returns 0 on success. Otherwise returns a nonzero value.
*
* PARAM1: VFILE * vfd
* PARAM2: long offset
* PARAM3: int mode
*
* RETURNS:
*/
int
vfseek(VFILE * vfd, long offset, int mode)
{
/* lock the VFS */
vfs_lock();
if (isvfile_locked(vfd))
{
#ifdef HT_RWVFS
/* the caller is trying to seek a file that's been deleted,
so return an error indication */
if (vfd->file == NULL)
{
vfs_unlock();
return -1;
}
#endif /* HT_RWVFS */
#ifdef HT_EXTDEV
if (vfd->file->method)
{
struct vfroutines * vfp = (struct vfroutines*) (vfd->file->method);
int rc;
rc = vfp->r_fseek(vfd,offset,mode);
vfs_unlock();
return rc;
}
#endif /* HT_EXTDEV */
/* this vfseek() currently only supports seek to exact
end or begining of file */
switch (mode)
{
case SEEK_SET:
vfd->cmploc = vfd->file->data + offset;
break;
case SEEK_CUR:
/* If the file is compressed, then the following
* adjustment is inaccurate. Currently we don't have
* any scenario where this happens. - handle later */
vfd->cmploc += offset;
break;
case SEEK_END:
vfd->cmploc = vfd->file->data + vfd->file->comp_size + offset;
break;
}
vfs_unlock();
return(0);
}
vfs_unlock();
#ifdef HT_LOCALFS
/* default to call on local system */
return(fseek((FILE*)vfd, offset, mode));
#else
return -1;
#endif /* HT_LOCALFS */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -