mirror of
https://github.com/peteratebs/rtfsprorelease.git
synced 2025-06-19 01:05:39 -04:00
1137 lines
35 KiB
C
1137 lines
35 KiB
C
/*
|
|
* EBS - RTFS (Real Time File Manager)
|
|
*
|
|
* Copyright EBS Inc 1987-2003
|
|
* All rights reserved.
|
|
* This code may not be redistributed in source or linkable object form
|
|
* without the consent of its author.
|
|
*/
|
|
/* RTDROBJ.C - Directory object manipulation routines */
|
|
|
|
#include "rtfs.h"
|
|
|
|
|
|
/***************************************************************************
|
|
PC_GET_CWD - Get the current working directory for a drive,
|
|
|
|
Description
|
|
Return the current directory inode for the drive represented by ddrive.
|
|
|
|
***************************************************************************/
|
|
|
|
/* Get the current working directory and copy it into pobj */
|
|
DROBJ *_pc_get_user_cwd(DDRIVE *pdrive) /*__fn__*/
|
|
{
|
|
DROBJ *pcwd;
|
|
DROBJ *pobj;
|
|
RTFS_SYSTEM_USER *pu;
|
|
|
|
pu = rtfs_get_system_user();
|
|
pcwd = rtfs_get_user_pwd(pu, pdrive->driveno,FALSE); /* Get cwd for driveno, don't clear it */
|
|
|
|
/* If no current working dir set it to the root */
|
|
|
|
if (!pcwd)
|
|
{
|
|
pcwd = pc_get_root(pdrive);
|
|
rtfs_set_user_pwd(pu, pcwd); /* Set cwd to pobj */
|
|
}
|
|
|
|
if (pcwd)
|
|
{
|
|
pobj = pc_allocobj();
|
|
if (!pobj)
|
|
{
|
|
return (0);
|
|
}
|
|
/* Free the inode that comes with allocobj */
|
|
pc_freei(pobj->finode);
|
|
OS_CLAIM_FSCRITICAL()
|
|
copybuff(pobj, pcwd, sizeof(DROBJ));
|
|
pobj->finode->opencount += 1;
|
|
OS_RELEASE_FSCRITICAL()
|
|
return (pobj);
|
|
}
|
|
else /* If no cwd is set error */
|
|
{
|
|
rtfs_set_errno(PEINTERNAL, __FILE__, __LINE__);
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
PC_FNDNODE - Find a file or directory on disk and return a DROBJ.
|
|
|
|
Description
|
|
Take a full path name and traverse the path until we get to the file
|
|
or subdir at the end of the path spec. When found allocate and init-
|
|
ialize (OPEN) a DROBJ.
|
|
|
|
Returns
|
|
Returns a pointer to a DROBJ if the file was found, otherwise 0.
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
/* Find path and create a DROBJ structure if found */
|
|
DROBJ *pc_fndnode(byte *path, int use_charset) /*__fn__*/
|
|
{
|
|
DROBJ *pobj;
|
|
DROBJ *pmom;
|
|
DROBJ *pchild;
|
|
int driveno;
|
|
DDRIVE *pdrive;
|
|
byte *filename;
|
|
byte fileext[4];
|
|
byte *pf0,*pf1;
|
|
BLKBUFF *scratch;
|
|
BLKBUFF *exfatscratch = 0;
|
|
#if (INCLUDE_EXFATORFAT64)
|
|
byte *exFatPathbuff = 0;
|
|
#endif
|
|
/* Get past D: plust get drive number if there */
|
|
path = pc_parsedrive( &driveno, path, use_charset);
|
|
if (!path)
|
|
{
|
|
rtfs_set_errno(PEINVALIDDRIVEID, __FILE__, __LINE__); /* pc_fndnode: parsedrive failed */
|
|
return (0);
|
|
}
|
|
/* Find the drive */
|
|
pdrive = pc_drno2dr(driveno);
|
|
if (!pdrive)
|
|
{
|
|
rtfs_set_errno(PEINVALIDDRIVEID, __FILE__, __LINE__); /* pc_fndnode: pc_drno2dr failed */
|
|
return (0);
|
|
}
|
|
#if (INCLUDE_EXFATORFAT64)
|
|
if (ISEXFATORFAT64(pdrive))
|
|
{
|
|
exfatscratch = pc_scratch_blk();
|
|
if (!exfatscratch)
|
|
{
|
|
return(0);
|
|
}
|
|
exFatPathbuff = (byte *)exfatscratch->data;
|
|
|
|
if (!pcexfat_parse_path(pdrive, exFatPathbuff, path, use_charset))
|
|
{
|
|
pc_free_scratch_blk(exfatscratch);
|
|
return(0);
|
|
}
|
|
path = exFatPathbuff;
|
|
pobj = pc_get_root(pdrive);
|
|
if (CS_OP_IS_NOT_EOS(path, use_charset))
|
|
{
|
|
CS_OP_INC_PTR(path, use_charset);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
/* Get the top of the current path */
|
|
if (CS_OP_CMP_ASCII(path, '\\', use_charset))
|
|
{
|
|
CS_OP_INC_PTR(path, use_charset);
|
|
pobj = pc_get_root(pdrive);
|
|
}
|
|
else
|
|
{
|
|
pobj = _pc_get_user_cwd(pdrive);
|
|
}
|
|
}
|
|
if (!pobj)
|
|
return (0);
|
|
scratch = pc_scratch_blk();
|
|
if (!scratch)
|
|
return(0);
|
|
filename = (byte *)scratch->data;
|
|
|
|
|
|
/* Search through the path til exausted */
|
|
while (CS_OP_IS_NOT_EOS(path, use_charset))
|
|
{
|
|
path = pc_nibbleparse(filename,fileext, path, use_charset);
|
|
if (!path)
|
|
{
|
|
if (exfatscratch)
|
|
pc_free_scratch_blk(exfatscratch);
|
|
pc_free_scratch_blk(scratch);
|
|
rtfs_set_errno(PENOENT, __FILE__, __LINE__); /* pc_fndnode: no match */
|
|
pc_freeobj(pobj);
|
|
return (0);
|
|
}
|
|
pf1 = pf0 = filename;
|
|
CS_OP_INC_PTR(pf1, use_charset);
|
|
#if (INCLUDE_VFAT)
|
|
if (CS_OP_CMP_ASCII(pf0,'.', use_charset) && CS_OP_IS_EOS(pf1, use_charset)) /* DOT */
|
|
;
|
|
#else
|
|
/* Tomo */
|
|
if (CS_OP_CMP_ASCII(pf0,'.', use_charset) && CS_OP_CMP_ASCII(pf1,' ', use_charset)) /* DOT-in NON-VFAT it is space filled */
|
|
;
|
|
#endif
|
|
else
|
|
{
|
|
/* Find Filename in pobj. and initialize lpobj with result */
|
|
pchild = pc_get_inode(0, pobj, filename, fileext, GET_INODE_MATCH, use_charset);
|
|
if (!pchild)
|
|
{ /* get_inode set errno */
|
|
if (exfatscratch)
|
|
pc_free_scratch_blk(exfatscratch);
|
|
pc_free_scratch_blk(scratch);
|
|
pc_freeobj(pobj);
|
|
return (0);
|
|
}
|
|
/* We found it. We have one special case. if DOTDOT we need
|
|
to shift up a level so we are not the child of mom
|
|
but of grand mom. */
|
|
pf1 = pf0 = filename;
|
|
CS_OP_INC_PTR(pf1, use_charset);
|
|
if (CS_OP_CMP_ASCII(pf0,'.', use_charset) && CS_OP_CMP_ASCII(pf1,'.', use_charset))
|
|
{
|
|
/* Find pobj s parent. By looking back from DOTDOT */
|
|
pmom = pc_get_mom(pchild);
|
|
/* We are done with pobj for now */
|
|
pc_freeobj(pobj);
|
|
|
|
if (!pmom)
|
|
{ /* Get mom set errno */
|
|
if (exfatscratch)
|
|
pc_free_scratch_blk(exfatscratch);
|
|
pc_free_scratch_blk(scratch);
|
|
pc_freeobj(pchild);
|
|
return (0);
|
|
}
|
|
else
|
|
{
|
|
/* We found the parent now free the child */
|
|
pobj = pmom;
|
|
pc_freeobj(pchild);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* We are done with pobj for now */
|
|
pc_freeobj(pobj);
|
|
/* Make sure pobj points at the next inode */
|
|
pobj = pchild;
|
|
#if (INCLUDE_EXFATORFAT64) /* Found a directory, update drobj */
|
|
if (ISEXFATORFAT64(pdrive) && pc_isadir(pobj))
|
|
{
|
|
dword fcluster,sectorno;
|
|
fcluster = pc_finode_cluster(pobj->pdrive,pobj->finode);
|
|
sectorno = pc_cl2sector(pobj->pdrive,fcluster);
|
|
pobj->blkinfo.my_frstblock = sectorno;
|
|
pobj->blkinfo.my_block = sectorno;
|
|
pobj->blkinfo.my_index = 0;
|
|
#if (INCLUDE_EXFAT) /* FAT64 does not require exNOFATCHAIN */
|
|
pobj->blkinfo.my_exNOFATCHAINfirstcluster = pcexfat_getexNOFATCHAINfirstcluster(pobj);
|
|
pobj->blkinfo.my_exNOFATCHAINlastcluster = pcexfat_getexNOFATCHAINlastcluster(pobj);
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
if (exfatscratch)
|
|
pc_free_scratch_blk(exfatscratch);
|
|
pc_free_scratch_blk(scratch);
|
|
return (pobj);
|
|
}
|
|
|
|
/***************************************************************************
|
|
PC_GET_INODE - Find a filename within a subdirectory
|
|
|
|
Description
|
|
Search the directory pmom for the pattern or name in filename:ext and
|
|
return the an initialized object. If pobj is NULL start the search at
|
|
the top of pmom (getfirst) and allocate pobj before returning it.
|
|
Otherwise start the search at pobj (getnext). (see also pc_gfirst,
|
|
pc_gnext)
|
|
|
|
|
|
Note: Filename and ext must be right filled with spaces to 8 and 3 bytes
|
|
respectively. Null termination does not matter.
|
|
|
|
Note the use of the action variable. This is used so we do not have to
|
|
use match patterns in the core code like *.* and ..
|
|
GET_INODE_MATCH Must match the pattern exactly
|
|
GET_INODE_WILD Pattern may contain wild cards
|
|
GET_INODE_STAR Like he passed *.* (pattern will be null)
|
|
GET_INODE_DOTDOT Like he past .. (pattern will be null
|
|
|
|
|
|
Returns
|
|
Returns a drobj pointer or NULL if file not found.
|
|
***************************************************************************/
|
|
|
|
/* Give a directory mom. And a file name and extension.
|
|
Find find the file or dir and initialize pobj.
|
|
If pobj is NULL. We allocate and initialize the object otherwise we get the
|
|
next item in the chain of dirents.
|
|
*/
|
|
DROBJ *pc_get_inode( DROBJ *pobj, DROBJ *pmom, byte *filename, byte *fileext, int action, int use_charset) /*__fn__*/
|
|
{
|
|
BOOLEAN starting = FALSE;
|
|
/* Create the child if just starting */
|
|
if (!pobj)
|
|
{
|
|
starting = TRUE;
|
|
pobj = pc_mkchild(pmom); /* If failure sets errno */
|
|
if (!pobj)
|
|
return(0);
|
|
}
|
|
else /* If doing a gnext do not get stuck in and endless loop */
|
|
{
|
|
if ( ++(pobj->blkinfo.my_index) >= pobj->pdrive->drive_info.inopblock)
|
|
{
|
|
rtfs_clear_errno(); /* Clear errno to be safe */
|
|
if (!pc_next_block(pobj)) /* Will set errno illegal block id encountered */
|
|
{
|
|
if (!get_errno())
|
|
rtfs_set_errno(PENOENT, __FILE__, __LINE__); /* pc_get_inode: end of dir */
|
|
if (starting)
|
|
pc_freeobj(pobj);
|
|
return(0);
|
|
}
|
|
else
|
|
pobj->blkinfo.my_index = 0;
|
|
}
|
|
}
|
|
if (pc_findin(pobj, filename, fileext,action, use_charset))
|
|
{
|
|
DROBJ *proot;
|
|
if (pobj->isroot)
|
|
{
|
|
proot = pc_get_root(pobj->pdrive);
|
|
if (!proot || proot->finode != pobj->finode)
|
|
{
|
|
pobj->isroot = FALSE;
|
|
}
|
|
if (proot)
|
|
pc_freeobj(proot);
|
|
}
|
|
return (pobj);
|
|
}
|
|
else
|
|
{
|
|
/* pc_findin set errno */
|
|
if (starting)
|
|
pc_freeobj(pobj);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
#if (INCLUDE_REVERSEDIR)
|
|
/* Give a directory mom. And a file name and extension.
|
|
Search backwards and find the file or dir and initialize pobj.
|
|
If pobj is NULL. We allocate and initialize the object otherwise we get the
|
|
next item in the chain of dirents.
|
|
*/
|
|
DROBJ *pc_rget_inode( DROBJ *pobj, DROBJ *pmom, byte *filename, byte *fileext, int action, int use_charset) /*__fn__*/
|
|
{
|
|
#if (INCLUDE_VFAT)
|
|
BOOLEAN starting = FALSE;
|
|
RTFS_ARGSUSED_PVOID((void *) fileext);
|
|
/* Create the child if just starting */
|
|
if (!pobj)
|
|
{
|
|
starting = TRUE;
|
|
pobj = pc_mkchild(pmom); /* If failure sets errno */
|
|
if (!pobj)
|
|
return(0);
|
|
}
|
|
if (pc_rfindin(pobj, filename, action, use_charset, starting))
|
|
{
|
|
DROBJ *proot;
|
|
if (pobj->isroot)
|
|
{
|
|
proot = pc_get_root(pobj->pdrive);
|
|
if (!proot || proot->finode != pobj->finode)
|
|
{
|
|
pobj->isroot = FALSE;
|
|
}
|
|
if (proot)
|
|
pc_freeobj(proot);
|
|
}
|
|
return (pobj);
|
|
}
|
|
else
|
|
{
|
|
/* pc_findin set errno */
|
|
if (starting)
|
|
pc_freeobj(pobj);
|
|
return (0);
|
|
}
|
|
#else
|
|
/* reverse directory not supported for 8.3 only */
|
|
return 0;
|
|
#endif
|
|
}
|
|
#endif
|
|
/**************************************************************************
|
|
PC_GET_MOM - Find the parent inode of a subdirectory.
|
|
|
|
Description
|
|
Given a DROBJ initialized with the contents of a subdirectory s DOTDOT
|
|
entry, initialize a DROBJ which is the parent of the current directory.
|
|
|
|
Returns
|
|
Returns a DROBJ pointer or NULL if could something went wrong.
|
|
|
|
|
|
****************************************************************************/
|
|
/*
|
|
* Get mom:
|
|
* if (!dotodot->cluster) Mom is root.
|
|
* getroot()
|
|
* else cluster points to mom.
|
|
* find .. in mom
|
|
* then search through the directory pointed to by moms .. until
|
|
* you find mom. This will be current block startblock etc for mom.
|
|
*/
|
|
|
|
DROBJ *pc_get_mom(DROBJ *pdotdot) /*__fn__*/
|
|
{
|
|
DROBJ *pmom;
|
|
DDRIVE *pdrive = pdotdot->pdrive;
|
|
dword sectorno;
|
|
BLKBUFF *rbuf;
|
|
DIRBLK *pd;
|
|
DOSINODE *pi;
|
|
FINODE *pfi;
|
|
dword clno;
|
|
/* We have to be a subdir */
|
|
if (!pc_isadir(pdotdot))
|
|
{
|
|
rtfs_set_errno(PEINVALIDDIR, __FILE__, __LINE__);
|
|
return(0);
|
|
}
|
|
|
|
/* If ..->cluster is zero then parent is root */
|
|
if (!pc_finode_cluster(pdrive,pdotdot->finode))
|
|
return(pc_get_root(pdrive));
|
|
|
|
/* Otherwise : cluster points to the beginning of our parent.
|
|
we also need the position of our parent in its parent */
|
|
pmom = pc_allocobj();
|
|
if (!pmom)
|
|
return (0);
|
|
|
|
pmom->pdrive = pdrive;
|
|
/* Find .. in our parent s directory */
|
|
clno = pc_finode_cluster(pdrive,pdotdot->finode);
|
|
if ((clno < 2) || (clno > pdrive->drive_info.maxfindex) )
|
|
{
|
|
pc_freeobj(pmom);
|
|
rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__);
|
|
return (0);
|
|
}
|
|
sectorno = pc_cl2sector(pdrive,clno);
|
|
/* We found .. in our parents dir. */
|
|
pmom->pdrive = pdrive;
|
|
pmom->blkinfo.my_frstblock = sectorno;
|
|
pmom->blkinfo.my_block = sectorno;
|
|
pmom->blkinfo.my_index = 0;
|
|
pmom->isroot = FALSE;
|
|
pd = &pmom->blkinfo;
|
|
|
|
pmom->pblkbuff = rbuf = pc_read_blk(pdrive, pmom->blkinfo.my_block);
|
|
if (rbuf)
|
|
{
|
|
pi = (DOSINODE *) rbuf->data;
|
|
OS_CLAIM_FSCRITICAL()
|
|
pc_dos2inode(pmom->finode , pi );
|
|
OS_RELEASE_FSCRITICAL()
|
|
|
|
pc_release_buf(rbuf);
|
|
|
|
/* See if the inode is in the buffers */
|
|
pfi = pc_scani(pdrive, sectorno, 0);
|
|
if (pfi)
|
|
{
|
|
pc_freei(pmom->finode);
|
|
pmom->finode = pfi;
|
|
}
|
|
else
|
|
{
|
|
pc_marki(pmom->finode , pmom->pdrive , pd->my_block,
|
|
pd->my_index);
|
|
}
|
|
return (pmom);
|
|
|
|
}
|
|
else /* Error, something did not work */
|
|
{
|
|
pc_freeobj(pmom);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
PC_MKCHILD - Allocate a DROBJ and fill in based on parent object.
|
|
|
|
Description
|
|
Allocate an object and fill in as much of the the block pointer section
|
|
as possible based on the parent.
|
|
|
|
Returns
|
|
Returns a partially initialized DROBJ if enough core available and
|
|
pmom was a valid subdirectory.
|
|
|
|
****************************************************************************/
|
|
|
|
DROBJ *pc_mkchild( DROBJ *pmom) /*__fn__*/
|
|
{
|
|
DROBJ *pobj;
|
|
DIRBLK *pd;
|
|
|
|
/* Mom must be a directory */
|
|
if (!pc_isadir(pmom))
|
|
{
|
|
rtfs_set_errno(PEINVALIDDIR, __FILE__, __LINE__); /* pc_mkchild: Internal error, parent dir provided */
|
|
return(0);
|
|
}
|
|
/* init the object - */
|
|
pobj = pc_allocobj();
|
|
if (!pobj)
|
|
return (0);
|
|
|
|
pd = &pobj->blkinfo;
|
|
|
|
pobj->isroot = pmom->isroot; /* Child inherets mom's root status. Changed above us */
|
|
pobj->pdrive = pmom->pdrive; /* Child inherets moms drive */
|
|
|
|
/* Now initialize the fields storing where the child inode lives */
|
|
pd->my_index = 0;
|
|
pd->my_block = pd->my_frstblock = pc_firstblock(pmom);
|
|
#if (INCLUDE_EXFAT) /* FAT64 does not require exNOFATCHAIN */
|
|
if (ISEXFAT(pmom->pdrive))
|
|
{
|
|
pd->my_exNOFATCHAINfirstcluster = pcexfat_getexNOFATCHAINfirstcluster(pmom);
|
|
pd->my_exNOFATCHAINlastcluster = pcexfat_getexNOFATCHAINlastcluster(pmom);
|
|
}
|
|
#endif
|
|
if (!pd->my_block)
|
|
{
|
|
pc_freeobj(pobj);
|
|
return (0);
|
|
}
|
|
return (pobj);
|
|
}
|
|
|
|
/*************************************************************************
|
|
PC_GET_ROOT - Create the special ROOT object for a drive.
|
|
Description
|
|
Use the information in pdrive to create a special object for accessing
|
|
files in the root directory.
|
|
|
|
Returns
|
|
Returns a pointer to a DROBJ, or NULL if no core available.
|
|
****************************************************************************/
|
|
|
|
/* Initialize the special root object
|
|
Note: We do not read any thing in here we just set up
|
|
the block pointers. */
|
|
|
|
DROBJ *pc_get_root( DDRIVE *pdrive) /*__fn__*/
|
|
{
|
|
DIRBLK *pd;
|
|
DROBJ *pobj;
|
|
FINODE *pfi;
|
|
#if (INCLUDE_EXFATORFAT64)
|
|
if (ISEXFATORFAT64(pdrive)) /* Treat Exfat root more like normal directories */
|
|
return(pcexfat_get_root(pdrive));
|
|
#endif
|
|
pobj = pc_allocobj();
|
|
if (!pobj)
|
|
return (0);
|
|
pobj->pdrive = pdrive;
|
|
pfi = pc_scani(pdrive, 0, 0);
|
|
|
|
if (pfi)
|
|
{
|
|
pc_freei(pobj->finode);
|
|
pobj->finode = pfi;
|
|
}
|
|
else /* No inode in the inode list. Copy the data over
|
|
and mark where it came from */
|
|
{
|
|
pc_marki(pobj->finode , pdrive , 0, 0);
|
|
}
|
|
|
|
|
|
/* Add a TEST FOR DRIVE INIT Here later */
|
|
pobj->pdrive = pdrive;
|
|
/* Set up the tree stuf so we know it is the root */
|
|
pd = &pobj->blkinfo;
|
|
pd->my_frstblock = pdrive->drive_info.rootblock;
|
|
pd->my_block = pdrive->drive_info.rootblock;
|
|
pd->my_index = 0;
|
|
pobj->isroot = TRUE;
|
|
return (pobj);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
PC_FIRSTBLOCK - Return the absolute block number of a directory s
|
|
contents.
|
|
Description
|
|
Returns the block number of the first inode in the subdirectory. If
|
|
pobj is the root directory the first block of the root will be returned.
|
|
|
|
Returns
|
|
Returns 0 if the obj does not point to a directory, otherwise the
|
|
first block in the directory is returned.
|
|
|
|
*****************************************************************************/
|
|
|
|
/* Get the first block of a root or subdir */
|
|
dword pc_firstblock( DROBJ *pobj) /*__fn__*/
|
|
{
|
|
dword clno;
|
|
if (!pc_isadir(pobj))
|
|
{
|
|
rtfs_set_errno(PEINTERNAL, __FILE__, __LINE__); /* pc_firstblock: Internal error */
|
|
return (0);
|
|
}
|
|
/* Root dir ? */
|
|
if (!pobj->isroot)
|
|
{
|
|
clno = pc_finode_cluster(pobj->pdrive, pobj->finode);
|
|
if ((clno < 2) || (clno > pobj->pdrive->drive_info.maxfindex) )
|
|
{
|
|
rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__);
|
|
return (0);
|
|
}
|
|
return (pc_cl2sector(pobj->pdrive , clno));
|
|
}
|
|
else
|
|
return (pobj->blkinfo.my_frstblock);
|
|
}
|
|
|
|
/***************************************************************************
|
|
PC_NEXT_BLOCK - Calculate the next block owned by an object.
|
|
|
|
Description
|
|
Find the next block owned by an object in either the root or a cluster
|
|
chain and update the blockinfo section of the object.
|
|
|
|
Returns
|
|
Returns TRUE or FALSE on end of chain.
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
/* Calculate the next block in an object */
|
|
BOOLEAN pc_next_block( DROBJ *pobj) /*__fn__*/
|
|
{
|
|
dword nxt;
|
|
|
|
nxt = pc_l_next_block(pobj->pdrive, pobj->blkinfo.my_block);
|
|
|
|
if (nxt)
|
|
{
|
|
pobj->blkinfo.my_block = nxt;
|
|
return (TRUE);
|
|
}
|
|
else
|
|
return (FALSE);
|
|
}
|
|
|
|
/**************************************************************************
|
|
PC_L_NEXT_BLOCK - Calculate the next block in a chain.
|
|
|
|
Description
|
|
Find the next block in either the root or a cluster chain.
|
|
|
|
Returns
|
|
Returns 0 on end of root dir or chain.
|
|
|
|
****************************************************************************/
|
|
|
|
/* Return the next block in a chain */
|
|
dword pc_l_next_block(DDRIVE *pdrive, dword curblock) /*__fn__*/
|
|
{
|
|
dword cluster;
|
|
/* If the block is in the root area */
|
|
if (curblock < pdrive->drive_info.firstclblock)
|
|
{
|
|
if (curblock < pdrive->drive_info.rootblock)
|
|
{
|
|
rtfs_set_errno(PEINTERNAL, __FILE__, __LINE__); /* pc_l_next_block: Internal error */
|
|
return (0);
|
|
}
|
|
else if (++curblock < pdrive->drive_info.firstclblock)
|
|
return (curblock);
|
|
else
|
|
return (0);
|
|
}
|
|
else /* In cluster space */
|
|
{
|
|
if (curblock >= pdrive->drive_info.numsecs)
|
|
{
|
|
rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__); /* pc_l_next_block: Internal error */
|
|
return (0);
|
|
}
|
|
/* Get the next block */
|
|
curblock += 1;
|
|
|
|
/* If the next block is not on a cluster edge then it must be
|
|
in the same cluster as the current. - otherwise we have to
|
|
get the firt block from the next cluster in the chain */
|
|
if (pc_sec2index(pdrive, curblock))
|
|
return (curblock);
|
|
else
|
|
{
|
|
curblock -= 1;
|
|
/* Get the old cluster number */
|
|
cluster = pc_sec2cluster(pdrive,curblock);
|
|
if ((cluster < 2) || (cluster > pdrive->drive_info.maxfindex) )
|
|
{
|
|
rtfs_set_errno(PEINVALIDCLUSTER, __FILE__, __LINE__); /* pc_l_next_block: Internal error */
|
|
return (0);
|
|
}
|
|
/* Consult the fat for the next cluster. */
|
|
cluster = fatop_next_cluster(pdrive, cluster);
|
|
if (cluster == FAT_EOF_RVAL)
|
|
return (0); /* End of chain */
|
|
else if (cluster == 0) /* clnext detected error */
|
|
{
|
|
return (0);
|
|
}
|
|
else
|
|
return (pc_cl2sector(pdrive, cluster));
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
PC_MARKI - Set dr:sec:index info and stitch a FINODE into the inode list
|
|
|
|
|
|
Description
|
|
Each inode is uniquely determined by DRIVE, BLOCK and Index into that
|
|
block. This routine takes an inode structure assumed to contain the
|
|
equivalent of a DOS directory entry. And stitches it into the current
|
|
active inode list. Drive block and index are stored for later calls
|
|
to pc_scani and the inode s opencount is set to one.
|
|
|
|
Returns
|
|
Nothing
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/* Take an unlinked inode and link it in to the inode chain. Initialize
|
|
the open count and sector locater info. */
|
|
void pc_marki( FINODE *pfi, DDRIVE *pdrive, dword sectorno, int index)/*__fn__*/
|
|
{
|
|
OS_CLAIM_FSCRITICAL()
|
|
|
|
pfi->my_drive = pdrive;
|
|
pfi->my_block = sectorno;
|
|
pfi->my_index = index;
|
|
pfi->opencount = 1;
|
|
|
|
/* Stitch the inode at the front of the list */
|
|
if (prtfs_cfg->inoroot)
|
|
prtfs_cfg->inoroot->pprev = pfi;
|
|
|
|
pfi->pprev = 0;
|
|
pfi->pnext = prtfs_cfg->inoroot;
|
|
prtfs_cfg->inoroot = pfi;
|
|
OS_RELEASE_FSCRITICAL()
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
PC_SCANI - Search for an inode in the internal inode list.
|
|
|
|
Description
|
|
Each inode is uniquely determined by DRIVE, BLOCK and Index into that
|
|
block. This routine searches the current active inode list to see
|
|
if the inode is in use. If so the opencount is changed and a pointer is
|
|
returned. This guarantees that two processes will work on the same
|
|
information when manipulating the same file or directory.
|
|
|
|
Returns
|
|
A pointer to the FINODE for pdrive:sector:index or NULL if not found
|
|
|
|
****************************************************************************/
|
|
|
|
/* See if the inode for drive,sector , index is in the list. If so..
|
|
bump its open count and return it. Else return NULL */
|
|
|
|
FINODE *pc_scani( DDRIVE *pdrive, dword sectorno, int index) /*__fn__*/
|
|
{
|
|
FINODE *pfi;
|
|
OS_CLAIM_FSCRITICAL()
|
|
pfi = prtfs_cfg->inoroot;
|
|
while (pfi)
|
|
{
|
|
if (pfi->my_drive == pdrive)
|
|
{
|
|
if ( (pfi->my_block == sectorno) &&
|
|
(pfi->my_index == index) )
|
|
{
|
|
pfi->opencount += 1;
|
|
OS_RELEASE_FSCRITICAL()
|
|
return (pfi);
|
|
}
|
|
}
|
|
pfi = pfi->pnext;
|
|
}
|
|
OS_RELEASE_FSCRITICAL()
|
|
return (0);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
PC_ALLOCOBJ - Allocate a DROBJ structure
|
|
Description
|
|
Allocates and zeroes the space needed to store a DROBJ structure. Also
|
|
allocates and zeroes a FINODE structure and links the two via the
|
|
finode field in the DROBJ structure.
|
|
|
|
Returns
|
|
Returns a valid pointer or NULL if no more core.
|
|
|
|
*****************************************************************************/
|
|
|
|
DROBJ *pc_allocobj(void) /*__fn__*/
|
|
{
|
|
DROBJ *pobj;
|
|
|
|
/* Alloc a DROBJ */
|
|
pobj = pc_memory_drobj(0);
|
|
if (pobj)
|
|
{
|
|
pobj->finode = pc_alloci();
|
|
if (!pobj->finode)
|
|
{
|
|
/* Free the DROBJ */
|
|
pc_memory_drobj(pobj);
|
|
pobj = 0;
|
|
}
|
|
}
|
|
return (pobj);
|
|
}
|
|
|
|
/**************************************************************************
|
|
PC_ALLOCI - Allocate a FINODE structure
|
|
|
|
Description
|
|
Allocates and zeroes a FINODE structure.
|
|
|
|
Returns
|
|
Returns a valid pointer or NULL if no more core.
|
|
|
|
****************************************************************************/
|
|
|
|
FINODE *pc_alloci(void) /*__fn__*/
|
|
{
|
|
FINODE *p;
|
|
p = pc_memory_finode(0);
|
|
return(p);
|
|
}
|
|
|
|
/**************************************************************************
|
|
PC_FREE_ALL_DROBJ - Release all drobj buffers associated with a drive.
|
|
Description
|
|
For each internally buffered drobj structure associated with pdrive
|
|
Returns
|
|
Nothing
|
|
****************************************************************************/
|
|
|
|
void pc_free_all_drobj( DDRIVE *pdrive) /*__fn__*/
|
|
{
|
|
int i;
|
|
DROBJ *pobj;
|
|
pobj = prtfs_cfg->mem_drobj_pool;
|
|
for (i = 0; i < prtfs_cfg->cfg_NDROBJS; i++,pobj++)
|
|
{
|
|
if (pobj->pdrive == pdrive)
|
|
pc_memory_drobj(pobj);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
PC_FREE_ALL_I - Release all inode buffers associated with a drive.
|
|
Description
|
|
For each internally buffered finode (dirent) check if it exists on
|
|
pdrive. If so delete it. In debug mode print a message since all
|
|
finodes should be freed before pc_dskclose is called.
|
|
Returns
|
|
Nothing
|
|
****************************************************************************/
|
|
|
|
static void pc_discardi(FINODE *pfi);
|
|
|
|
void pc_free_all_i( DDRIVE *pdrive) /*__fn__*/
|
|
{
|
|
FINODE *pfi;
|
|
OS_CLAIM_FSCRITICAL()
|
|
pfi = prtfs_cfg->inoroot;
|
|
OS_RELEASE_FSCRITICAL()
|
|
while (pfi)
|
|
{
|
|
if (pfi->my_drive == pdrive)
|
|
{
|
|
pc_discardi(pfi);
|
|
/* Since we changed the list go back to the top */
|
|
OS_CLAIM_FSCRITICAL()
|
|
pfi = prtfs_cfg->inoroot;
|
|
OS_RELEASE_FSCRITICAL()
|
|
}
|
|
else
|
|
{
|
|
OS_CLAIM_FSCRITICAL()
|
|
pfi = pfi->pnext;
|
|
OS_RELEASE_FSCRITICAL()
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#if (INCLUDE_RTFS_PROPLUS) /* ProPlus finode extensions */
|
|
void pc_discardi_extended(FINODE *pfi);
|
|
void pc_freei_extended(FINODE *pfi);
|
|
#endif
|
|
|
|
/* return finode memory to the free list without processing */
|
|
static void pc_discardi(FINODE *pfi)
|
|
{
|
|
OS_CLAIM_FSCRITICAL()
|
|
{ /* Unlink from the shared finode list */
|
|
if (pfi->pprev) /* Pont the guy behind us at the guy in front*/
|
|
pfi->pprev->pnext = pfi->pnext;
|
|
else
|
|
prtfs_cfg->inoroot = pfi->pnext; /* No prev, we were at the front so
|
|
make the next guy the front */
|
|
if (pfi->pnext) /* Make the next guy point behind */
|
|
pfi->pnext->pprev = pfi->pprev;
|
|
}
|
|
OS_RELEASE_FSCRITICAL()
|
|
#if (INCLUDE_RTFS_PROPLUS) /* ProPlus finode extensions */
|
|
/* Free resources used in extended mode */
|
|
pc_discardi_extended(pfi);
|
|
#endif
|
|
pc_memory_finode(pfi);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
PC_FREEI - Release an inode from service
|
|
|
|
Description
|
|
If the FINODE structure is only being used by one file or DROBJ, unlink it
|
|
from the internal active inode list and return it to the heap; otherwise
|
|
reduce its open count.
|
|
|
|
Returns
|
|
Nothing
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
void pc_freei(FINODE *pfi) /*__fn__*/
|
|
{
|
|
if (!pfi)
|
|
return;
|
|
OS_CLAIM_FSCRITICAL()
|
|
if (pfi->opencount)
|
|
{
|
|
if (--pfi->opencount) /* Decrement opencount and return if non zero */
|
|
{
|
|
OS_RELEASE_FSCRITICAL()
|
|
#if (INCLUDE_RTFS_PROPLUS) /* ProPlus finode extensions */
|
|
pc_freei_extended(pfi); /* If ProPlus, reduce extension opencounts */
|
|
#endif
|
|
return;
|
|
}
|
|
else
|
|
{ /* Unlink from the shared finode list */
|
|
|
|
if (pfi->pprev) /* Pont the guy behind us at the guy in front*/
|
|
{
|
|
pfi->pprev->pnext = pfi->pnext;
|
|
}
|
|
else
|
|
{
|
|
|
|
prtfs_cfg->inoroot = pfi->pnext; /* No prev, we were at the front so
|
|
make the next guy the front */
|
|
}
|
|
|
|
if (pfi->pnext) /* Make the next guy point behind */
|
|
{
|
|
pfi->pnext->pprev = pfi->pprev;
|
|
}
|
|
}
|
|
}
|
|
OS_RELEASE_FSCRITICAL()
|
|
/* If the finode contains a fragment list for use in basic file io then release it */
|
|
if (pfi->pbasic_fragment)
|
|
pc_fraglist_free_list(pfi->pbasic_fragment);
|
|
pfi->pbasic_fragment = 0;
|
|
|
|
#if (INCLUDE_RTFS_PROPLUS) /* ProPlus finode extensions */
|
|
/* pc_freei_entended() tests if the finode is an ProPlus extended Inode.
|
|
If so it release the extensions */
|
|
pc_freei_extended(pfi);
|
|
#endif
|
|
pc_memory_finode(pfi);
|
|
|
|
}
|
|
|
|
/***************************************************************************
|
|
PC_FREEOBJ - Free a DROBJ structure
|
|
|
|
Description
|
|
Return a drobj structure to the heap. Calls pc_freei to reduce the
|
|
open count of the finode structure it points to and return it to the
|
|
heap if appropriate.
|
|
|
|
Returns
|
|
Nothing
|
|
|
|
|
|
****************************************************************************/
|
|
|
|
void pc_freeobj( DROBJ *pobj) /*__fn__*/
|
|
{
|
|
if (pobj)
|
|
{
|
|
pc_freei(pobj->finode);
|
|
/* Release the core */
|
|
pc_memory_drobj(pobj);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
PC_DOS2INODE - Convert a dos disk entry to an in memory inode.
|
|
|
|
Description
|
|
Take the data from pbuff which is a raw disk directory entry and copy
|
|
it to the inode at pdir. The data goes from INTEL byte ordering to
|
|
native during the transfer.
|
|
|
|
Returns
|
|
Nothing
|
|
****************************************************************************/
|
|
|
|
/* Convert a dos inode to in mem form. */
|
|
void pc_dos2inode (FINODE *pdir, DOSINODE *pbuff) /*__fn__*/
|
|
{
|
|
copybuff(&pdir->fname[0],&pbuff->fname[0],8); /*X*/
|
|
/* If the on disk representation is 0x5, change it to 0xE5, a valid
|
|
kanji character */
|
|
if (pdir->fname[0] == 0x5)
|
|
pdir->fname[0] = PCDELETE;
|
|
copybuff(&pdir->fext[0],&pbuff->fext[0],3); /*X*/
|
|
pdir->fattribute = pbuff->fattribute; /*X*/
|
|
|
|
pdir->reservednt = pbuff->reservednt;
|
|
pdir->create10msincrement = pbuff->create10msincrement;
|
|
|
|
#if (!KS_LITTLE_ENDIAN)
|
|
pdir->ftime = to_WORD((byte *) &pbuff->ftime); /*X*/
|
|
pdir->fdate = to_WORD((byte *) &pbuff->fdate); /*X*/
|
|
pdir->ctime = to_WORD((byte *) &pbuff->ctime);
|
|
pdir->cdate = to_WORD((byte *) &pbuff->cdate);
|
|
pdir->adate = to_WORD((byte *) &pbuff->adate);
|
|
pdir->atime = pdir->ftime; /* Access time not supported for FAT32, set it to last modified */
|
|
/* Note: fclusterhi is of resarea in fat 16 system */
|
|
pdir->fclusterhi = to_WORD((byte *) &pbuff->fclusterhi);
|
|
pdir->fcluster = to_WORD((byte *) &pbuff->fcluster); /*X*/
|
|
pdir->fsizeu.fsize = to_DWORD((byte *) &pbuff->fsize); /*X*/
|
|
#else
|
|
pdir->ftime = pbuff->ftime; /*X*/
|
|
pdir->fdate = pbuff->fdate; /*X*/
|
|
pdir->ctime = pbuff->ctime;
|
|
pdir->cdate = pbuff->cdate;
|
|
pdir->adate = pbuff->adate;
|
|
pdir->atime = pdir->ftime; /* Access time not supported for FAT32, set it to last modified */
|
|
/* Note: fclusterhi is of resarea in fat 16 system */
|
|
pdir->fclusterhi = pbuff->fclusterhi; /*X*/
|
|
pdir->fcluster = pbuff->fcluster; /*X*/
|
|
pdir->fsizeu.fsize = pbuff->fsize; /*X*/
|
|
#endif
|
|
}
|
|
|
|
/**************************************************************************
|
|
PC_INIT_INODE - Load an in memory inode up with user supplied values.
|
|
|
|
Description
|
|
Take an uninitialized inode (pdir) and fill in some fields. No other
|
|
processing is done. This routine simply copies the arguments into the
|
|
FINODE structure.
|
|
|
|
Note: filename & fileext do not need null termination.
|
|
|
|
Returns
|
|
Nothing
|
|
****************************************************************************/
|
|
/**************************************************************************
|
|
PC_ISAVOL - Test a DROBJ to see if it is a volume
|
|
|
|
Description
|
|
Looks at the appropriate elements in pobj and determines if it is a root
|
|
or subdirectory.
|
|
|
|
Returns
|
|
Returns FALSE if the obj does not point to a directory.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOLEAN pc_isavol( DROBJ *pobj) /*__fn__*/
|
|
{
|
|
if (pobj->finode->fattribute & AVOLUME)
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
PC_ISADIR - Test a DROBJ to see if it is a root or subdirectory
|
|
|
|
Description
|
|
Looks at the appropriate elements in pobj and determines if it is a root
|
|
or subdirectory.
|
|
|
|
Returns
|
|
Returns FALSE if the obj does not point to a directory.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOLEAN pc_isadir( DROBJ *pobj) /*__fn__*/
|
|
{
|
|
if ( (pobj->isroot) || (pobj->finode->fattribute & ADIRENT) )
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
PC_ISROOT - Test a DROBJ to see if it is the root directory
|
|
|
|
Description
|
|
Looks at the appropriate elements in pobj and determines if it is a root
|
|
directory.
|
|
|
|
Returns
|
|
Returns NO if the obj does not point to the root directory.
|
|
|
|
****************************************************************************/
|
|
|
|
/* Get the first block of a root or subdir */
|
|
BOOLEAN pc_isroot( DROBJ *pobj) /*__fn__*/
|
|
{
|
|
return(pobj->isroot);
|
|
}
|