twl_wrapsdk/build/libraries/fatfs/ARM7/rtdrobj.c
Shirait 4fe5688d29 add SD driver and FATFS library (tentative)
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/twl_wrapsdk/trunk@96 4ee2a332-4b2b-5046-8439-1ba90f034370
2007-05-30 10:22:28 +00:00

1425 lines
45 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
pc_get_cwd - Get the current working directory DROBJ for a drive,
pc_fndnode - Find a file or directory on disk and return a DROBJ.
pc_get_inode - Find a filename within a subdirectory
static pc_findin - Find a filename in the same directory as argument.
pc_get_mom - Find the parent inode of a subdirectory.
pc_mkchild - Allocate a DROBJ and fill in based on parent object.
pc_mknode - Create an empty subdirectory or file.
pc_insert_inode - Called only by pc_mknode
pc_rmnode - Delete an inode unconditionally.
pc_update_inode - Flush an inode to disk
pc_read_obj - Assign an initialized BLKBUFF to a DROBJ
pc_write_obj - Write a DROBJ s BLKBUFF to disk
pc_get_root - Create the special ROOT object for a drive.
pc_firstblock - Return the absolute block number of a directory
pc_next_block - Calculate the next block owned by an object.
pc_l_next_block - Calculate the next block in a chain.
We keep a shared image of directory entries around. These routines
keep track of them for us.
pc_marki - Set dr:sec:index, + stitch FINODE into the inode list
pc_scani - Search for an inode in the internal inode list.
Heap management routines
pc_allocobj -
pc_alloci -
pc_free_all_i -
pc_freei -
pc_freeobj -
Simple helper routines
pc_dos2inode -
pc_ino2dos -
pc_init_inode -
pc_isadir -
*/
#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_cwd(DDRIVE *pdrive) /*__fn__*/
{
DROBJ *pcwd;
DROBJ *pobj;
pcwd = (DROBJ *)(rtfs_get_system_user()->lcwd[pdrive->driveno]);
/* If no current working dir set it to the root */
if (!pcwd)
{
pcwd = pc_get_root(pdrive);
rtfs_get_system_user()->lcwd[pdrive->driveno] = pcwd;
}
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);
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) /*__fn__*/
{
DROBJ *pobj;
DROBJ *pmom;
DROBJ *pchild;
int driveno;
DDRIVE *pdrive;
byte *filename;
byte fileext[4];
byte *pf0,*pf1;
BLKBUFF *scratch;
/* Get past D: plust get drive number if there */
path = pc_parsedrive( &driveno, path );
if (!path)
{
rtfs_set_errno(PEINVALIDDRIVEID); /* pc_fndnode: parsedrive failed */
return (0);
}
/* Find the drive */
pdrive = pc_drno2dr(driveno);
if (!pdrive)
{
rtfs_set_errno(PEINVALIDDRIVEID); /* pc_fndnode: pc_drno2dr failed */
return (0);
}
/* Get the top of the current path */
if (CS_OP_CMP_ASCII(path, '\\'))
{
CS_OP_INC_PTR(path);
pobj = pc_get_root(pdrive);
}
else
{
pobj = pc_get_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))
{
path = pc_nibbleparse(filename,fileext, path );
if (!path)
{
pc_free_scratch_blk(scratch);
rtfs_set_errno(PENOENT); /* pc_fndnode: no match */
pc_freeobj(pobj);
return (0);
}
#if (RTFS_SUBDIRS)
pf1 = pf0 = filename;
CS_OP_INC_PTR(pf1);
#if (VFAT)
if (CS_OP_CMP_ASCII(pf0,'.') && CS_OP_IS_EOS(pf1)) /* DOT */
;
#else
/* Tomo */
if (CS_OP_CMP_ASCII(pf0,'.') && CS_OP_CMP_ASCII(pf1,' ')) /* DOT-in NON-VFAT it is space filled */
;
#endif
#endif
else
{
/* Find Filename in pobj. and initialize lpobj with result */
pchild = pc_get_inode(0, pobj, filename, fileext, GET_INODE_MATCH);
if (!pchild)
{ /* get_inode set errno */
pc_free_scratch_blk(scratch);
pc_freeobj(pobj);
return (0);
}
#if (RTFS_SUBDIRS)
/* 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);
if (CS_OP_CMP_ASCII(pf0,'.') && CS_OP_CMP_ASCII(pf1,'.'))
{
/* 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 */
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
#endif /* SUBDIRS */
{
/* We are done with pobj for now */
pc_freeobj(pobj);
/* Make sure pobj points at the next inode */
pobj = pchild;
#if (RTFS_SUBDIRS)
#else
/* No subdirectory support. Return the one we found */
pc_free_scratch_blk(scratch);
return (pobj);
#endif
}
}
}
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) /*__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) >= INOPBLOCK )
{
rtfs_set_errno(0); /* Clear errno to be safe */
if (!pc_next_block(pobj)) /* Will set errno illegal block id encountered */
{
if (!get_errno())
rtfs_set_errno(PENOENT); /* 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))
{
return (pobj);
}
else
{
/* pc_findin set errno */
if (starting)
pc_freeobj(pobj);
return (0);
}
}
/**************************************************************************
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.
****************************************************************************/
#if (RTFS_SUBDIRS)
/*
* 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;
BLOCKT 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);
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->maxfindex) )
{
pc_freeobj(pmom);
rtfs_set_errno(PEINVALIDCLUSTER);
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[0];
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);
}
}
#endif
/**************************************************************************
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); /* pc_mkchild: Internal error, parent dir provided */
return(0);
}
/* init the object - */
pobj = pc_allocobj();
if (!pobj)
return (0);
pd = &pobj->blkinfo;
pobj->isroot = FALSE; /* Child can not be root */
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 (!pd->my_block)
{
pc_freeobj(pobj);
return (0);
}
return (pobj);
}
/**************************************************************************
PC_MKNODE - Create an empty subdirectory or file.
Description
Creates a file or subdirectory inode depending on the flag values in
attributes. A pointer to an inode is returned for further processing. See
po_open(),po_close(), pc_mkdir() et al for examples.
Note: After processing, the DROBJ must be released by calling pc_freeobj.
Returns
Returns a pointer to a DROBJ structure for further use, or NULL if the
inode name already exists or path not found.
**************************************************************************/
/* Make a node from path and attribs create and fill in pobj */
/* Note: the parent directory is locked before this routine is called */
DROBJ *pc_mknode(DROBJ *pmom ,byte *filename, byte *fileext, byte attributes, CLUSTERTYPE incluster) /*__fn__*/
{
DROBJ *pobj;
BOOLEAN ret_val;
DOSINODE *pdinodes;
FINODE lfinode;
CLUSTERTYPE cluster;
CLUSTERTYPE cltemp;
DATESTR crdate;
BLKBUFF *pbuff;
DDRIVE *pdrive;
byte attr;
#if (RTFS_SUBDIRS)
byte dot_str[4]; /* Make DOT and DOTDOT strings */
byte null_str[4];
#endif
ret_val = TRUE;
if (!pmom || !pmom->pdrive)
{
rtfs_set_errno(PEINTERNAL); /* pc_mknode: Internal error*/
return (0);
}
/* Make sure the file/directory name is legal */
if (!validate_filename(filename, fileext))
{
rtfs_set_errno(PEINVALIDPATH);
return (0);
}
pdrive = pmom->pdrive;
cluster = incluster;
#if (RTFS_SUBDIRS)
if (attributes & ADIRENT)
{
/*Unless renaming a directory we grab a cluster for a new dir and */
/* clear it */
if (!incluster)
{
/* pc_alloc_dir will set errno */
cluster = pc_alloc_dir(pdrive,pmom);
if (!cluster)
ret_val = FALSE;
else if (!pc_clzero( pdrive , cluster ) )
{
/* clzero will set errno */
FATOP(pdrive)->fatop_clrelease_dir(pdrive , cluster);
ret_val = FALSE;
}
}
}
#endif
if (!ret_val)
{
return (0);
}
/* For a subdirectory. First make it a simple file. We will change the
attribute after all is clean */
attr = attributes;
#if (RTFS_SUBDIRS)
if (attr & ADIRENT)
attr = ANORMAL;
#endif
/* Allocate an empty DROBJ and FINODE to hold the new file */
pobj = pc_allocobj();
if (!pobj)
{
return (0);
}
/* Set up the drive link */
pobj->pdrive = pmom->pdrive;
/* Load the inode copy name,ext,attr,cluster, size,datetime */
/* Convert pobj to native and stitch it in to mom */
if (!pc_insert_inode(pobj , pmom, attr, cluster, filename, fileext))
{
if (cluster && !incluster)
FATOP(pdrive)->fatop_clrelease_dir(pdrive , cluster);
pc_freeobj(pobj);
return (0);
}
#if (RTFS_SUBDIRS)
/* Now if we are creating subdirectory we have to make the DOT and DOT DOT
inodes and then change pobj s attribute to ADIRENT
The DOT and DOTDOT are not buffered inodes. We are simply putting
the to disk */
if ( attributes & ADIRENT)
{
if (incluster)
{
pbuff = pc_read_blk( pdrive , pc_cl2sector(pdrive , incluster));
if (!pbuff)
{
pc_freeobj(pobj);
return (0);
}
}
else
{
/* Set up a buffer to do surgery */
pbuff = pc_init_blk( pdrive , pc_cl2sector(pdrive , cluster));
if (!pbuff)
{
pc_freeobj(pobj);
FATOP(pdrive)->fatop_clrelease_dir(pdrive , cluster);
return (0);
}
}
pdinodes = (DOSINODE *) &pbuff->data[0];
/* Load DOT and DOTDOT in native form */
/* DOT first. It points to the begining of this sector */
dot_str[0] = CS_OP_ASCII('.');dot_str[1]=CS_OP_ASCII('\0');
null_str[0] = CS_OP_ASCII('\0');
/* Load the time and date stamp to be used for "." and ".."
from the subdirectory that we are creating. In this way
the three directory entries will all have the same timestamp
value */
crdate.time = pobj->finode->ftime;
crdate.date = pobj->finode->fdate;
pc_init_inode( &lfinode, dot_str,null_str, ADIRENT|ARCHIVE,
cluster, /*size*/ 0L , &crdate);
/* And to the buffer in intel form */
pc_ino2dos (pdinodes, &lfinode);
/* Now DOTDOT points to mom s cluster */
cltemp = pc_get_parent_cluster(pdrive, pobj);
dot_str[0] = CS_OP_ASCII('.');dot_str[1] = CS_OP_ASCII('.');
dot_str[2] = CS_OP_ASCII('\0');
null_str[0] = CS_OP_ASCII('\0');
pc_init_inode( &lfinode, dot_str, null_str, ADIRENT|ARCHIVE, cltemp,
/*size*/ 0L , &crdate);
/* And to the buffer in intel form */
pc_ino2dos (++pdinodes, &lfinode );
/* Write the cluster out */
if ( !pc_write_blk ( pbuff ) )
{
pc_discard_buf(pbuff);
pc_freeobj(pobj);
if (!incluster)
FATOP(pdrive)->fatop_clrelease_dir(pdrive , cluster);
return (0);
}
else
pc_release_buf(pbuff);
/* And write the node out with the original attributes */
pobj->finode->fattribute = (byte)(attributes|ARCHIVE);
/* Convert to native. Overwrite the existing inode.Set archive/date */
if (!pc_update_inode(pobj, TRUE, TRUE))
{
pc_freeobj(pobj);
if (!incluster)
FATOP(pdrive)->fatop_clrelease_dir(pdrive , cluster);
return (0);
}
}
#endif
ret_val = FATOP(pdrive)->fatop_flushfat(pdrive->driveno);
if (ret_val)
{
return (pobj);
}
else
{
pc_freeobj(pobj);
return (0);
}
}
/***************************************************************************
PC_RMNODE - Delete an inode unconditionally.
Description
Delete the inode at pobj and flush the file allocation table. Does not
check file permissions or if the file is already open. (see also pc_unlink
and pc_rmdir). The inode is marked deleted on the disk and the cluster
chain associated with the inode is freed. (Un-delete wo not work)
Returns
Returns TRUE if it successfully deleted the inode an flushed the fat.
*****************************************************************************/
/* Delete a file / dir or volume. Do not check for write access et al */
/* Note: the parent directory is locked before this routine is called */
BOOLEAN pc_rmnode( DROBJ *pobj) /*__fn__*/
{
CLUSTERTYPE cluster;
DDRIVE *pdrive;
/* Do not delete anything that has multiple links */
if (pobj->finode->opencount > 1)
{
rtfs_set_errno(PEACCES); /* pc_rmnode() - directory entry is in use */
err_ex:
pc_report_error(PCERR_REMINODE);
return (FALSE);
}
pdrive = pobj->pdrive;
/* Mark it deleted and unlink the cluster chain */
pobj->finode->fname[0] = PCDELETEESCAPE;
cluster = pc_finode_cluster(pdrive,pobj->finode);
if (!pc_delete_lfn_info(pobj)) /* Delete lonf file name info associated with DROBJ */
goto err_ex;
/* We free up store right away. Do not leave cluster pointer
hanging around to cause problems. */
pc_pfinode_cluster(pdrive,pobj->finode,0);
/* Convert to native. Overwrite the existing inode.Set archive/date */
if (pc_update_inode(pobj, TRUE, TRUE))
{
/* If there is no cluster chain to delete don't call freechain */
if (!cluster)
return(TRUE);
/* And clear up the space */
/* Tomo */
/* Make sure the blocks contained within the cluster chain
are flushed from the block buffer pool */
pc_flush_chain_blk(pdrive, cluster);
/* Set min to 0 and max to 0xffffffff to eliminate range checking on the
cluster chain and force removal of all clusters */
if (!FATOP(pdrive)->fatop_freechain(pdrive, cluster, 0, 0xffffffff))
{
/* If freechain failed still flush the fat in INVALID CLUSTER
was the failure condition */
if (get_errno() == PEINVALIDCLUSTER)
FATOP(pdrive)->fatop_flushfat(pobj->pdrive->driveno);
return(FALSE);
}
else if ( FATOP(pdrive)->fatop_flushfat(pobj->pdrive->driveno) )
return (TRUE);
}
/* If it gets here we had a problem */
return(FALSE);
}
/**************************************************************************
PC_UPDATE_INODE - Flush an inode to disk
Summary
Description
Read the disk inode information stored in pobj and write it to
the block and offset on the disk where it belongs. The disk is
first read to get the block and then the inode info is merged in
and the block is written. (see also pc_mknode() )
Returns
Returns TRUE if all went well, no on a write error.
*****************************************************************************
*/
/* Take a DROBJ that contains correct my_index & my_block. And an inode.
Load the block. Copy the inode in and write it back out */
BOOLEAN pc_update_inode(DROBJ *pobj, BOOLEAN set_archive, BOOLEAN set_date) /*__fn__*/
{
BLKBUFF *pbuff;
DOSINODE *pi;
int i;
DIRBLK *pd;
DATESTR crdate;
pd = &pobj->blkinfo;
i = pd->my_index;
if ( i >= INOPBLOCK || i < 0 ) /* Index into block */
{
rtfs_set_errno(PEINTERNAL); /* pc_update_inode: Internal error, illegal inode index */
return (FALSE);
}
OS_CLAIM_FSCRITICAL()
/* Set the archive bit and the date */
if (set_archive)
pobj->finode->fattribute |= ARCHIVE;
if (set_date)
{
pc_getsysdate(&crdate);
pobj->finode->ftime = crdate.time;
pobj->finode->fdate = crdate.date;
}
OS_RELEASE_FSCRITICAL()
/* Read the data */
pobj->pblkbuff = pbuff = pc_read_blk(pobj->pdrive, pobj->blkinfo.my_block);
if (pbuff)
{
pi = (DOSINODE *) &pbuff->data[0];
/* Copy it off and write it */
pc_ino2dos( (pi+i), pobj->finode );
if (!pc_write_blk(pbuff))
{
pc_discard_buf(pbuff);
return (FALSE);
}
else
{
pc_release_buf(pbuff);
return (TRUE);
}
}
return (FALSE);
}
#if (RTFS_WRITE)
/* Load an in memory inode up with user supplied values */
void pc_init_inode(FINODE *pdir, KS_CONSTANT byte *filename, /*__fn__*/
KS_CONSTANT byte *fileext, byte attr,
CLUSTERTYPE cluster, dword size, DATESTR *crdate) /*__fn__*/
{
/* Copy the file names and pad with spaces */
pc_cppad(pdir->fname,(byte*)filename,8);
pc_cppad(pdir->fext,(byte*)fileext,3);
pdir->fattribute = attr;
rtfs_memset(&pdir->resarea[0],(byte) 0,8);
pdir->ftime = crdate->time;
pdir->fdate = crdate->date;
/* Note: fclusterhi is of resarea in fat 16 system and cluster>>16 is 0*/
pdir->fclusterhi = (word)(cluster >> 16);
pdir->fcluster = (word) cluster;
pdir->fsize = size;
pc_zero_lfn_info(pdir);
}
/***************************************************************************
PC_INO2DOS - Convert an in memory inode to a dos disk entry.
Description
Take in memory native format inode information and copy it to a
buffer. Translate the inode to INTEL byte ordering during the transfer.
Returns
Nothing
***************************************************************************/
/* Un-Make a disk directory entry */
/* Convert an inmem inode to dos form. */
void pc_ino2dos (DOSINODE *pbuff, FINODE *pdir) /*__fn__*/
{
pc_ascii_strn2upper((byte *)&pbuff->fname[0],(byte *)&pdir->fname[0],8); /*X*/
pc_ascii_strn2upper((byte *)&pbuff->fext[0],(byte *)&pdir->fext[0],3); /*X*/
pbuff->fattribute = pdir->fattribute; /*X*/
/* If the first character is 0xE5 (valid kanji) convert it to 0x5 */
if (pdir->fname[0] == PCDELETE) /* 0XE5 */
pbuff->fname[0] = 0x5;
/* If rmnode wants us to delete the file set it to 0xE5 */
if (pdir->fname[0] == PCDELETEESCAPE)
pbuff->fname[0] = PCDELETE;
copybuff(&pbuff->resarea[0],&pdir->resarea[0], 8); /*X*/
#if (KS_LITTLE_ENDIAN)
pbuff->ftime = pdir->ftime;
pbuff->fdate = pdir->fdate;
pbuff->fcluster = pdir->fcluster;
/* Note: fclusterhi is of resarea in fat 16 system */
pbuff->fclusterhi = pdir->fclusterhi;
pbuff->fsize = pdir->fsize;
#else
fr_WORD((byte *) &pbuff->ftime,pdir->ftime); /*X*/
fr_WORD((byte *) &pbuff->fdate,pdir->fdate); /*X*/
fr_WORD((byte *) &pbuff->fcluster,pdir->fcluster); /*X*/
/* Note: fclusterhi is of resarea in fat 16 system */
fr_WORD((byte *) &pbuff->fclusterhi,pdir->fclusterhi); /*X*/
fr_DWORD((byte *) &pbuff->fsize,pdir->fsize); /*X*/
#endif
}
#endif
/*************************************************************************
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;
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->rootblock;
pd->my_block = pdrive->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 */
BLOCKT pc_firstblock( DROBJ *pobj) /*__fn__*/
{
dword clno;
if (!pc_isadir(pobj))
{
rtfs_set_errno(PEINTERNAL); /* pc_firstblock: Internal error */
return (BLOCKEQ0);
}
/* Root dir ? */
#if (RTFS_SUBDIRS)
if (!pobj->isroot)
{
clno = pc_finode_cluster(pobj->pdrive, pobj->finode);
if ((clno < 2) || (clno > pobj->pdrive->maxfindex) )
{
rtfs_set_errno(PEINVALIDCLUSTER);
return (0);
}
return (pc_cl2sector(pobj->pdrive , clno));
}
else
#endif
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__*/
{
BLOCKT 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 */
BLOCKT pc_l_next_block(DDRIVE *pdrive, BLOCKT curblock) /*__fn__*/
{
CLUSTERTYPE cluster;
/* If the block is in the root area */
if (curblock < pdrive->firstclblock)
{
if (curblock < pdrive->rootblock)
{
rtfs_set_errno(PEINVALIDBLOCKNUMBER); /* pc_l_next_block: Internal error */
return (BLOCKEQ0);
}
else if (++curblock < pdrive->firstclblock)
return (curblock);
else
return (BLOCKEQ0);
}
else /* In cluster space */
{
if (curblock >= pdrive->numsecs)
{
rtfs_set_errno(PEINVALIDBLOCKNUMBER); /* pc_l_next_block: Internal error */
return (BLOCKEQ0);
}
/* 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->maxfindex) )
{
rtfs_set_errno(PEINVALIDBLOCKNUMBER); /* pc_l_next_block: Internal error */
return (BLOCKEQ0);
}
/* Consult the fat for the next cluster */
cluster = FATOP(pdrive)->fatop_clnext(pdrive, cluster); /* Directory */
if (cluster == 0xffffffff)
return (BLOCKEQ0); /* End of chain */
else if (cluster == 0) /* clnext detected error */
{
return (BLOCKEQ0);
}
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, BLOCKT 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, BLOCKT sectorno, int index) /*__fn__*/
{
FINODE *pfi;
OS_CLAIM_FSCRITICAL()
pfi = prtfs_cfg->inoroot;
while (pfi)
{
if ( (pfi->my_drive == pdrive) &&
(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
****************************************************************************/
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)
{
/* Set the opencount to 1 so freei releases the inode */
pfi->opencount = 1;
pc_freei(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()
}
}
}
/*****************************************************************************
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()
return;
}
else
{
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()
/* release the core */
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*/
copybuff(&pdir->resarea[0],&pbuff->resarea[0], 8); /*X*/
#if (!KS_LITTLE_ENDIAN)
pdir->ftime = to_WORD((byte *) &pbuff->ftime); /*X*/
pdir->fdate = to_WORD((byte *) &pbuff->fdate); /*X*/
/* 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->fsize = to_DWORD((byte *) &pbuff->fsize); /*X*/
#else
pdir->ftime = pbuff->ftime; /*X*/
pdir->fdate = pbuff->fdate; /*X*/
/* Note: fclusterhi is of resarea in fat 16 system */
pdir->fclusterhi = pbuff->fclusterhi; /*X*/
pdir->fcluster = pbuff->fcluster; /*X*/
pdir->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);
}