📄 vfsfiles.c
字号:
/*
* FILENAME: vfsfiles.c
*
* Copyright 1997- 2000 By InterNiche Technologies Inc. All rights reserved
*
*
* MODULE: VFS
*
* ROUTINES: vfopen(), set_vfopen_error(), get_vfopen_error(),
* ROUTINES: vf_alloc_and_link_vop(), *vf_alloc_buffer(), vf_free_buffer(),
* ROUTINES: vfopen_locked(), vfclose_locked(), vunlink_flag_open_files(),
* ROUTINES: vfread(), vfwrite_locked(), vfseek(), vftell(), vgetc_locked(),
* ROUTINES: vfslookup_locked(), (), vfslookup(), strippath(),
* ROUTINES: isvfile_locked(), (), isvfile(), vferror(), vclearerr(),
*
* PORTABLE: yes
*/
/* Additional Copyrights: */
/* vfsfiles.c
* Portions Copyright 1996 by NetPort Software. All rights reserved.
* InterNIche virtual file system. This implements the vfopen(),
* vfread(), etc, calls the Embedded WEB servers and similar devices
* to do file IO. These calls lookup names, descriptors, etc, to see
* if the file is a "virtual" file in RAM/ROM/FLASH, or if it should
* fall through to the local disk system (if any)
* 7/24/96 - Created by John Bartas
* 12/10/98 - Added RWVFS hooks for writable file support -JB-
* 12/26/98 - Separated from WebPort sources.
*/
#include "ipport.h"
#ifdef VFS_FILES
#include "vfsport.h" /* per-port include */
#include "vfsfiles.h" /* overlay vfs stuff on system file IO */
#include "profiler.h" /* InterNiche profile utility */
/* if this sort of thing is needed, it should probably be in ipport.h */
#ifdef NOTDEF
#ifdef HT_LOCALFS
#include <fcntl.h> /* Standard lib stuff for file IO */
#include <io.h>
#endif /* HT_LOCALFS */
#endif /* NOTDEF */
#ifdef WEBPORT
#include "httpd.h" /* local NetPort HTML includes */
#include "cgi.h"
#endif /* WEBPORT */
#ifdef HTML_COMPRESSION
#include "htcmptab.h" /* tag table, for compression */
#endif /* HTML_COMPRESSION */
/* path to file system root. This must use UNIX slashes, and should not
be NULL. A single slash is OK. */
#ifdef HT_LOCALFS
/* if there's a local FS (e.g. a disk), force vfs created files to
* live in a special directory. This can be changed at startup
* time.
*/
char vfs_root_path[HTPATHMAX] = { "/vfs/" };
#else /* the vfs is the whole file system */
char vfs_root_path[HTPATHMAX] = { "/" };
#endif /* HT_LOCALFS */
#ifdef VFS_STRIPPATH
/* preserve compatibility with old-style webport path */
char * http_root_path = &vfs_root_path[0];
#endif /* VFS_STRIPPATH */
#ifdef HT_EXTDEV
/* list of alternate file IO routine sets */
struct vfroutines * vfsystems = NULL;
#endif /* HT_EXTDEV */
#ifdef HT_RWVFS
/* this counts the number of bytes that have been allocated for
* buffers for the read/write file system so that the above maximum
* can be enforced
*/
unsigned long vfs_total_rw_space;
/* this counts the number of dynamically allocated files in the file
system so that the above maximum can be enforced */
unsigned long vfs_total_dyna_files;
/* this flag gets set during successful unlink operations so that
* vfs_sync() knows to sync the file system even though none of the
* files in it show that they are stale
*/
int vfs_dir_stale;
#endif /* HT_RWVFS */
/* this counts the number of open files in the file system so that
the above maximum can be enforced */
unsigned long vfs_open_files;
#ifdef VFS_STRIPPATH
char * strippath(char * name);
#endif /* VFS_STRIPPATH */
VFILE * vfiles = NULL; /* list of open files */
/* list of files */
struct vfs_file * vfsfiles = NULL;
#ifdef VFS_UNIT_TEST
/* this flag determines whether the VFS logs the file names that are
passed to it */
int vfs_log_file_name = 0;
#endif /* VFS_UNIT_TEST */
/* vfopen_error is used as a place to store errors that occur in vfopen() */
/* the porting engineer might want to replace this with a macro that
defines vfopen to be errno, depending on his target system */
int vfopen_error = 0;
/* FUNCTION: set_vfopen_error()
*
* this function sets the vfopen() error indication. it is called from
* vfopen() when errors occur
*
* PARAM1: int error
*
* RETURNS:
*/
void set_vfopen_error(int error)
{
vfopen_error = error;
}
/* FUNCTION: get_vfopen_error()
*
* this function returns the last error that occurred in a call to
* vfopen(). the porting engineer might want to define errno to be
* equal to this function, depending on his target system
*
* PARAM1:
*
* RETURNS:
*/
int get_vfopen_error()
{
return vfopen_error;
}
/* FUNCTION: vf_alloc_and_link_vop()
*
* this function allocates a VFILE structure and links it to the
* beginning of the linked list of open files
*
* PARAM1:
*
* RETURNS:
*/
VFILE * vf_alloc_and_link_vop()
{
struct vfs_open * vop;
/* enforce maximum number of simultaneously open files */
if (vfs_open_files >= VFS_MAX_OPEN_FILES)
{
#ifdef VFS_VERBOSE
dprintf("vfs_open_files too big (%ld) in vf_alloc_and_link_vop()\n",
vfs_open_files);
#endif /* VFS_VERBOSE */
return NULL;
}
/* allocate a structure to represent the open file */
vop = VFS_VFS_OPEN_ALLOC();
/* if the allocation succeeded */
if (vop)
{
/* add to the beginning of the list of open files */
vop->next = vfiles;
vfiles = vop;
/* increment the count of open files */
vfs_open_files++;
}
#ifdef VFS_VERBOSE
else
dprintf("VFS_VFS_OPEN_ALLOC() failed in vf_alloc_and_link_vop()\n");
#endif /* VFS_VERBOSE */
return vop;
}
#ifdef HT_RWVFS
/* FUNCTION: *vf_alloc_buffer()
*
* PARAM1: unsigned long size
*
* RETURNS:
*/
unsigned char * vf_alloc_buffer(unsigned long size)
{
unsigned char *buffer;
#ifdef MUTE_WARNS
unsigned int long_size,int_size;
#endif /* MUTE_WARNS */
/* make sure the requested allocation does not exceed the total
memory space reserved for file buffers */
if ((vfs_total_rw_space + size) > VFS_MAX_TOTAL_RW_SPACE)
return NULL;
/* the file sizes in the vfs_file structures are all unsigned
* longs, but npalloc() only can allocate sizes expressed in
* unsigned ints, so if your longs are bigger than your ints, you
* can't allocate memory
* any bigger than what will fit in an unsigned int
*/
#ifdef MUTE_WARNS
/* the idiotic hoops you got to jump through to suppress compiler
warnings */
long_size = sizeof(unsigned long);
int_size = sizeof(unsigned int);
if (long_size > int_size)
#else
if (sizeof(unsigned long) > sizeof (unsigned int))
#endif /* MUTE_WARNS */
{
unsigned long mem_mask;
/* what this does is create a mem_mask containing 0xffff0000 on
* most systems where this "if" expression will evaluate to
* true (2 byte ints, 4 byte longs). if any of those upper bits
* are on in your requested size, you otta luck.
*/
#ifdef MUTE_WARNS
switch (int_size)
#else
switch (sizeof(unsigned int))
#endif /* MUTE_WARNS */
{
case 2 :
mem_mask = 0xffff0000;
break;
default :
dtrap("vfsfiles 0\n"); /* you have a weird compiler */
return NULL;
}
if (size & mem_mask)
return NULL;
}
/* try to allocate a buffer of the requested size */
buffer = (unsigned char *) npalloc((unsigned int) size);
/* if the allocation succeeded */
if (buffer)
{
/* add size to the count of total buffer space allocated */
vfs_total_rw_space += size;
}
return buffer;
}
/* FUNCTION: vf_free_buffer()
*
* PARAM1: unsigned char *buffer
* PARAM2: unsigned long size
*
* RETURNS:
*/
void vf_free_buffer(unsigned char * buffer, unsigned long size)
{
/* free the buffer */
if (buffer)
npfree(buffer);
/* and subtract its size from the total buffer space count */
vfs_total_rw_space -= size;
}
#endif /* HT_RWVFS */
/* FUNCTION: vfopen_locked()
*
* PARAM1: char * name
* PARAM2: char * mode
*
* RETURNS:
*/
VFILE *
vfopen_locked(char * name, char * mode)
{
struct vfs_file * vfp;
struct vfs_open * vop;
/* clear any previous vfopen() error */
set_vfopen_error(0);
/* the old code used to do special handling of '?' in files for
* the benefit of the web server. the web server should be doing
* this now. this is here to make sure that its doing it
*/
if (strchr(name,'?'))
{
dtrap("vfsfiles 1\n");
return NULL;
}
/* determine if the file exists */
/* if the directory exists, vfp will point to its directory entry
structure else vfp will be NULL */
vfp = vfslookup_locked(name);
/* if the file exists */
if (vfp)
{
#ifdef HT_RWVFS
/* if mode begins with 'w' we will truncate to end of file */
/* make sure the file is writable before proceeding */
if ((*mode == 'w') && !(vfp->flags & VF_WRITE))
{
set_vfopen_error(ENP_FILEIO);
#ifdef VFS_VERBOSE
dprintf("mode w with no VF_WRITE\n");
#endif /* VFS_VERBOSE */
return NULL;
}
#endif /* HT_RWVFS */
/* allocate a VFILE structure to represent the open file */
vop = vf_alloc_and_link_vop();
/* check for failure */
if (!vop)
{
set_vfopen_error(ENP_NOMEM);
#ifdef VFS_VERBOSE
dprintf("vf_alloc_and_link_vop() failed 1\n");
#endif /* VFS_VERBOSE */
return NULL;
}
/* link to the file's directory entry structure */
vop->file = vfp;
/* by default start at the beginning of the file */
/* note that vfp->data could be NULL at this point since empty
files might have no data buffer allocated to them */
vop->cmploc = vfp->data; /* start at beginning of file */
#ifdef HT_RWVFS
/* if mode begins with 'a', seek to end of file */
if (*mode == 'a')
{
if (vfp->data)
{
vop->cmploc = vfp->data + vfp->comp_size;
}
}
/* if mode begins with 'w', truncate to end of file */
if (*mode == 'w')
{
/* set the size of the file before compression to 0 */
vfp->real_size = 0;
/* set the size of the compressed data to 0 */
vfp->comp_size = 0;
/* note we leave the pointer to the file buffer and its length
alone since first writes will go to it */
/* flag that the file has been modified */
vfp->flags |= VF_STALE;
/* turn off the compression flag */
vfp->flags &= ~VF_HTMLCOMPRESSED;
}
#endif /* HT_RWVFS */
return vop;
}
#ifdef HT_EXTDEV
/* if the mode implies that the file should be created if it
does not exist */
if (*mode != 'r')
{
/* see if one of the other systems wants to create this file */
/* if none of the below devices can open the file, continue on */
struct vfroutines * vfs;
for (vfs = vfsystems; vfs; vfs = vfs->next)
{
if ((vop = vfs->r_fopen(name, mode)) != NULL)
{
return vop;
}
}
}
#endif /* HT_EXTDEV */
#ifdef HT_LOCALFS
/* compare the passed name to a vfs_root_path. if the name does
* not begin with it, pass it to the native file
* system fopen()
*/
if (strncmp(name, vfs_root_path, strlen(vfs_root_path)))
{
return (VFILE *) fopen(name, mode);
}
#endif /* HT_LOCALFS */
#ifdef HT_RWVFS
/* if the mode implies that the file should be created if it
does not exist */
if (*mode != 'r')
{
/* enforce maximum number of files */
if (vfs_total_dyna_files >= VFS_MAX_DYNA_FILES)
{
set_vfopen_error(ENP_NOMEM);
#ifdef VFS_VERBOSE
dprintf("vf_total_dyna_files too big in vfopen_locked()\n");
#endif /* VFS_VERBOSE */
return NULL;
}
/* make sure the file name is not too long for the VFS */
if (strlen(name) > FILENAMEMAX)
{
set_vfopen_error(ENP_PARAM);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -