📄 vfsfiles.c
字号:
#ifdef VFS_VERBOSE
dprintf("file name too long in vfopen_locked()\n");
#endif /* VFS_VERBOSE */
return NULL;
}
/* allocate a vfs_file structure to hold the new file entry in */
vfp = VFS_VFS_FILE_ALLOC();
/* check for memory allocation failure */
if (!vfp)
{
set_vfopen_error(ENP_NOMEM);
#ifdef VFS_VERBOSE
dprintf("VFS_VFS_FILE_ALLOC() failed in vfopen_locked()\n");
#endif /* VFS_VERBOSE */
return NULL;
}
/* allocate a VFILE structure to represent the open file */
vop = vf_alloc_and_link_vop();
/* check for memory allocation failure */
if (!vop)
{
VFS_VFS_FILE_FREE(vfp); /* free the allocated vfs_file entry */
set_vfopen_error(ENP_NOMEM);
#ifdef VFS_VERBOSE
dprintf("vf_alloc_and_link_vop() failed 2\n");
#endif /* VFS_VERBOSE */
return NULL;
}
/* add the vfs_file structure to the head of the list */
vfp->next = vfsfiles;
vfsfiles = vfp;
/* increment count of total files */
vfs_total_dyna_files++;
/* remove leading directory separator before storing name */
if (*name == '/' || *name == '\\')
name++;
/* store the converted name in the directory entry structure */
strcpy(vfp->name,name);
/* set the flags */
vfp->flags = VF_DYNAMICINFO /* the directory entry was allocated */
| VF_WRITE /* the file is writable */
| VF_NONVOLATILE /* the file is non-volatile */
| VF_STALE; /* the file is stale */
/* the rest of the vfs_file structure fields remain with the
* zeroes that npalloc() is guaranteed to init its data with.
* note that this means the data pointer contains a null
* because we don't allocate any buffer to hold the data
* in until the first write
*/
/* link to the file's directory entry structure */
vop->file = vfp;
/* the cmploc and tag fields of the vop retain their NULLs from
* npalloc(). cmploc contains NULL because there is no data
* buffer to point to yet. tag contains NULL because no
* decompression operation has started yet
*/
return vop;
}
#endif /* HT_RWVFS */
#ifdef HT_LOCALFS
/* pass the open to the local file system */
return (VFILE *) fopen(name,mode);
#else
set_vfopen_error(ENP_NOFILE);
#ifdef VFS_VERBOSE
dprintf("fell thru to end of vfopen_locked()\n");
#endif /* VFS_VERBOSE */
return NULL;
#endif /* HT_LOCALFS */
}
/* FUNCTION: vfopen()
*
* PARAM1: char * name
* PARAM2: char * mode
*
* RETURNS:
*/
VFILE *
vfopen(char * name, char * mode)
{
VFILE *vfd;
#ifdef VFS_UNIT_TEST
if (vfs_log_file_name)
dprintf("vfopen() passed >%s<,%s\n",name,mode);
#endif /* VFS_UNIT_TEST */
/* lock the VFS */
vfs_lock();
vfd = vfopen_locked(name,mode);
vfs_unlock();
return vfd;
}
/* FUNCTION: vfclose_locked()
*
* PARAM1: VFILE * vfd
*
* RETURNS:
*/
void
vfclose_locked(VFILE * vfd)
{
VFILE * vtmp;
VFILE * vlast;
vlast = NULL;
/* see if vfd is in our list of open virtual files. We
can't use isvfile() since we need a pointer to last. */
vtmp = vfiles;
while (vtmp)
{
/* if this is the one we are looking for, exist search loop */
if (vfd == vtmp)
break;
/* bump the next and previous pointers along to try the next one */
vlast = vtmp;
vtmp = vtmp->next;
}
/* if the passed in handle was not in the list we maintain */
if (vfd != vtmp)
{
#ifdef HT_LOCALFS
/* default to call on local system */
fclose((FILE*)vfd);
#endif /* HT_LOCALFS */
return;
}
/* the passed in handle is in the list we maintain */
/* this not really a forever loop. it exists so we can break easily
and deal with all the ifdefs */
while (1)
{
struct vfs_file * vfp = vfd->file;
#ifdef HT_RWVFS
unsigned char *new_buffer;
/* vfd->file will be null if somebody unlinked the file after
* this handle was created to point to it. if the file itself
* is gone there is nothing left to do, so break to list
* deletion code at bottom of loop
*/
if (vfp == NULL)
break;
#endif /* HT_RWVFS */
#ifdef HT_EXTDEV
/* if the file was created by an external file system */
if (vfp->method)
{
/* call that file system's fclose() */
struct vfroutines * vfs = (struct vfroutines*)(vfp->method);
vfs->r_fclose(vfd);
break; /* break to list deletion code after end of phoney loop */
}
#endif /* HT_EXTDEV */
#ifdef HT_RWVFS
/* if the buffer containing the data was allocated dynamically,
* and there are VFS_CLOSE_FRAG_FLOOR bytes of unused data
* between the end of the file and the end of the buffer
*/
if ((vfp->flags & VF_DYNAMICDATA) &&
((vfp->buf_size - vfp->comp_size) > VFS_CLOSE_FRAG_FLOOR) &&
vfp->data) /* this last test is a sanity check */
{
/* try to reclaim the unused data */
/* allocate a new buffer just big enough for the data */
new_buffer = vf_alloc_buffer(vfp->comp_size);
/* if the allocation worked */
if (new_buffer)
{
/* copy the old buffer to the new one */
MEMCPY(new_buffer,vfp->data,(unsigned int) (vfp->comp_size));
/* free the old buffer */
vf_free_buffer(vfp->data,vfp->buf_size);
/* update the buffer pointer and size to reflect the
just big enough buffer */
vfp->data = new_buffer;
vfp->buf_size = vfp->comp_size;
}
}
#ifdef VFS_AUTO_SYNC
/* if the file's flags indicate that the file is non-volatile
and that it has been changed */
if ((vfp->flags & (VF_NONVOLATILE | VF_STALE)) ==
(VF_NONVOLATILE | VF_STALE))
{
/* store the non-volatile files to whatever backing store
* the system provides. note that it is up to the vfs_sync()
* function to clear the VF_STALE bits in whatever files it
* successfully stores. this way if a given attempt fails,
* the unsuccessfully saved files get another chance on the
* next call to vfs_sync(). note also that the sync function
* is passed the pointer to the vfs_file so that if all it
* does is sync the single file, then only that
* file's VF_STALE flag can be cleared.
*/
vfs_sync(vfp);
}
#endif /* VFS_AUTO_SYNC */
#endif /* HT_RWVFS */
/* break to list deletion code below */
break;
}
if (vlast) /* unlink from list of open files */
vlast->next = vtmp->next;
else
vfiles = vtmp->next;
/* free structure addressed by open handle */
VFS_VFS_OPEN_FREE(vtmp);
/* decrement the number of open files */
vfs_open_files--;
return;
}
/* FUNCTION: vfclose()
*
* PARAM1: VFILE *vfd
*
* RETURNS:
*/
void vfclose(VFILE * vfd)
{
vfs_lock();
vfclose_locked(vfd);
vfs_unlock();
}
#ifdef HT_RWVFS
/* FUNCTION: vunlink_flag_open_files()
*
* fix up references to deleted file in list of currently
* open VFILEs
*
* PARAM1: struct vfs_file *vfp
*
* RETURNS:
*/
void vunlink_flag_open_files(struct vfs_file * vfp)
{
VFILE * vtmp;
/* for all open files */
for (vtmp = vfiles; vtmp; vtmp = vtmp->next)
{
/* if the open file handle is referencing the file we are
deleting, set that reference to NULL */
if (vtmp->file == vfp)
vtmp->file = NULL;
}
}
#endif /* HT_RWVFS */
/* FUNCTION: vunlink()
*
* PARAM1: char *name
*
* RETURNS:
*/
int
vunlink(char * name)
{
struct vfs_file * vfp;
int rc = 0;
#ifdef VFS_AUTO_SYNC
int do_sync = 0;
#endif
#ifdef HT_RWVFS
struct vfs_file * vtmp;
struct vfs_file * vflast;
struct vfs_file * vfnext;
#endif
#ifdef VFS_UNIT_TEST
if (vfs_log_file_name)
dprintf("vunlink() passed >%s<\n",name);
#endif /* VFS_UNIT_TEST */
/* lock the VFS */
vfs_lock();
/* see if the converted name is one of the one's in our list */
/* if it isn't */
if ((vfp = vfslookup_locked(name)) == NULL)
{
vfs_unlock();
#ifdef HT_LOCALFS
/* default to call on local system */
return remove(name);
#else
/* no local file system, so return error condition */
return -1;
#endif /* HT_LOCALFS */
}
#ifdef HT_RWVFS
/* save the next link pointer since in one path through the code,
* the vfs_file structure gets freed before its unlinked from the
* list
*/
vfnext = vfp->next;
/* search list of files to determine predecessor in list */
vflast = NULL;
for (vtmp = vfsfiles; vtmp != NULL; vtmp = vtmp->next)
{
if (vtmp == vfp)
break;
vflast = vtmp;
}
/* this shouldn't happen since vfslookup_locked() already searched
the list, but just in case */
if (vtmp == NULL)
{
dtrap("vfsfiles 2\n");
vfs_unlock();
return -1;
}
/* this is not really a forever loop. it exists so we can break easily
and deal with all the ifdefs */
while (1)
{
#ifdef HT_EXTDEV
/* if the file was created by an external file system */
if (vfp->method)
{
/* call that file system's unlink() */
struct vfroutines * vfs = (struct vfroutines*) (vfp->method);
rc = vfs->r_unlink(name);
break; /* break to list deletion code after end of phoney loop */
}
#endif /* HT_EXTDEV */
/* if the file is not write enabled, return error condition */
if (!(vfp->flags & VF_WRITE))
{
vfs_unlock();
return -1;
}
/* if the data buffer containing the file's data was dynamically
allocated and is not null */
if ((vfp->flags & VF_DYNAMICDATA) && (vfp->data))
{
/* free the buffer */
vf_free_buffer(vfp->data,vfp->buf_size);
}
/* if the vfs_file structure itself was allocated dynamically */
if (vfp->flags & VF_DYNAMICINFO)
{
/* decrement count of total files */
vfs_total_dyna_files--;
/* free the vfs_file structure */
VFS_VFS_FILE_FREE(vfp);
}
/* since we modified the list we maintain, do a sync, but after
the vfs_file has been deleted from the list */
#ifdef VFS_AUTO_SYNC
do_sync = 1;
#endif
/* we were successful at our unlink */
rc = 0;
break;
}
/* delete the vfs_file structure from the list headed by vfsfiles */
if (vflast)
vflast->next = vfnext;
else
vfsfiles = vfnext;
/* fix up references to deleted file in list of currently open VFILEs */
vunlink_flag_open_files(vfp);
/* flag that the directory is stale so vfs_sync() knows it has to do
something */
vfs_dir_stale = TRUE;
#ifdef VFS_AUTO_SYNC
/* if we need to sync the backing store, call the function to do it */
if (do_sync)
{
/* a NULL passed to vfs_sync() means that only the directory
structure itself was changed */
vfs_sync(NULL);
}
#endif /* VFS_AUTO_SYNC */
#else /* HT_RWVFS */
/* unlinks not allowed on read-only VFS */
rc = -1;
#endif /* HT_RWVFS */
vfs_unlock();
return rc;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -