📄 lowl.c
字号:
Description
Given a DDRIVE and a cluster number. Get the value in the fat at clusterno
(the next cluster in a chain.) Handle 16 and 12 bit fats correctly.
Returns
Returns the the value at clno. In pvalue.
If any error occured while FAT swapping return NO else return YES.
Note: If fat buffering is disabled, always returns yes
***************************************************************************/
/* Retrieve a value from the fat */
BOOL pc_faxx(DDRIVE *pdr, UCOUNT clno, UCOUNT *pvalue) /*__fn__*/
{
UCOUNT wtry;
ULONG ltry;
UCOUNT result;
UTINY wrdbuf[2]; /* Temp storage area */
UTINY FAR *fat_data = pdr->fat_swap_structure.data_array;
if (pdr->fasize == 3) /* 3 nibble ? */
{
wtry = (UCOUNT) (clno + (UCOUNT) (clno >> 1)); /* multiply by 1.5 */
/* And use the product as index */
wrdbuf[0] = fat_data[wtry]; /* Use a temp variable since in */
wrdbuf[1] = fat_data[wtry+1]; /* small model we can't call with
fat_data (it's a far pointer) */
result = to_WORD(wrdbuf); /* And use the product as index */
if ( ((clno << 1) + clno) == (wtry << 1) ) /* If whole number */
result &= 0xfff; /* Return it */
else
result =(UCOUNT) ((UCOUNT) (result >> 4) & 0xfff ); /* shift right 4 */
}
else /* 16 BIT fat. ret the value at 2 * clno */
{
if (pdr->use_fatbuf)
{
if ( pc_pfgword( pdr, clno, (UCOUNT *) &wrdbuf[0] ))
result = to_WORD(&wrdbuf[0]); /* And use the product as index */
else
return (NO);
}
else
{
ltry = (ULONG) clno;
ltry <<= 1;
wrdbuf[0] = fat_data[ltry]; /* Use a temp variable since in */
wrdbuf[1] = fat_data[ltry+1]; /* intel small model we can't call
with fat_data (it's a far pointer) */
result = to_WORD(wrdbuf); /* And use the product as index */
}
}
*pvalue = result;
return (YES);
}
/****************************************************************************
PC_FLUSHFAT - Write any dirty FAT blocks to disk
Description
Given a valid drive number. Write any fat blocks to disk that
have been modified. Updates all copies of the fat.
Returns
Returns NO if driveno is not an open drive. Or a write failed.
****************************************************************************/
/* Consult the dirty fat block list and write any. write all copies
of the fat */
BOOL pc_flushfat(COUNT driveno) /*__fn__*/
{
UTINY FAR *pf;
UTINY *pd;
UCOUNT i;
UCOUNT j;
BLOCKT baseblock;
DDRIVE *pdr;
BOOL is_last;
pdr = pc_drno2dr(driveno);
if (!pdr)
{
return(NO);
}
if (!pdr->fat_is_dirty)
return(YES);
if (pdr->use_fatbuf)
{
if (pc_pfflush(pdr) )
{
pdr->fat_is_dirty = NO;
return(YES);
}
else
return(NO);
}
/* else ... */
PC_DRIVE_IO_ENTER(pdr->driveno)
for (j = 0; j < pdr->numfats;j++)
{
baseblock = (BLOCKT) j;
baseblock *= pdr->secpfat;
baseblock += pdr->fatblock;
if (j == (UCOUNT) (pdr->numfats - 1) )
is_last = YES;
else
is_last = NO;
/* NOTE: data_array is the fat data. data_map is a byte map of dirty
fat blocks */
pf = pdr->fat_swap_structure.data_array;
pd = pdr->fat_swap_structure.data_map;
if (!pf)
{
PC_DRIVE_IO_EXIT(pdr->driveno)
pc_report_error(PCERR_FAT_NULLP);
return (NO);
}
/* Check each block in the fat */
for (i = 0; i < pdr->secpfat; i++,pd++,baseblock++)
{
/* If the block is dirty */
if (*pd)
{
/* Write it */
if(!pc_bdevsw[pdr->driveno].io_proc(pdr->driveno,baseblock,pf,1,NO))
{
PC_DRIVE_IO_EXIT(pdr->driveno)
pc_report_error(PCERR_FAT_FLUSH);
return(NO);
}
if (is_last)
*pd = (UTINY) 0;
}
pf += 512;
}
}
pdr->fat_is_dirty = NO;
PC_DRIVE_IO_EXIT(pdr->driveno)
return (YES);
}
/****************************************************************************
PC_FREECHAIN - Free a cluster chain associated with an inode.
Description
Trace the cluster chain starting at cluster and return all the clusters to
the free state for re-use. The FAT is not flushed.
Returns
Nothing.
****************************************************************************/
VOID pc_freechain(DDRIVE *pdr, UCOUNT cluster) /*__fn__*/
{
UCOUNT nextcluster;
nextcluster = pc_clnext(pdr , cluster);
while (cluster)
{
pc_clrelease(pdr , cluster);
cluster = nextcluster;
nextcluster = pc_clnext(pdr , nextcluster);
}
}
/******************************************************************************
PC_GET_CHAIN - Return as many contiguous clusters as possible.
Description
Starting at start_cluster return the number of contiguous clusters
allocated in the chain containing start_cluster or n_clusters,
whichever is less.
Returns
Returns the number of contiguous clusters found. Or zero on an error.
This function should always return at least one. (start_cluster). Unless
an error occurs.
The word at *pnext_cluster is filled with on of the following:
. If we went beyond a contiguous section it contains
the first cluster in the next segment of the chain.
. If we are still in a section it contains
the next cluster in the current segment of the chain.
. If we are at the end of the chain it contains the last cluster
in the chain.
****************************************************************************/
UCOUNT pc_get_chain(DDRIVE *pdr, UCOUNT start_cluster, UCOUNT *pnext_cluster, UCOUNT n_clusters) /*__fn__*/
{
UCOUNT clno;
UCOUNT n_contig;
UCOUNT value;
COUNT nibs_per_entry;
if (start_cluster < 2)
return (0);
if (start_cluster > pdr->maxfindex)
return (0);
nibs_per_entry = pdr->fasize;
clno = start_cluster;
n_contig = 1;
*pnext_cluster = 0;
/* Get each FAT entry. If its value points to the next contiguous entry
continue. Otherwise we have reached the end of the contiguous chain.
At which point we return the number of contig's found and by reference
the address of the FAT entry beginning the next chain segment.
*/
while(YES)
{
if (!pc_faxx(pdr, clno, &value))
return(0);
/* check for a bad cluster and skip it if we see it */
if ( ( value == 0xff7 && nibs_per_entry == 3)
|| (value == 0xfff7 && nibs_per_entry == 4) )
{
clno += 1;
}
/* check for end markers set next cluster to the last
cluster in the chain if we are at the end */
else if ( ( value > 0xff7 && nibs_per_entry == 3)
|| (value > 0xfff7 && nibs_per_entry == 4) )
{
value = clno;
break;
}
else if (value == ++clno)
{
if (n_contig >= n_clusters)
break;
n_contig++;
}
else
break;
}
*pnext_cluster = value;
return (n_contig);
}
/******************************************************************************
PC_PFAXX - Write a value to the FAT at clno.
Description
Given a DDRIVE,cluster number and value. Write the value in the fat
at clusterno. Handle 16 and 12 bit fats correctly.
Returns
No if an io error occurred during fat swapping, else YES.
*****************************************************************************/
/* Given a clno & fatval Put the value in the table at the index (clno) */
BOOL pc_pfaxx(DDRIVE *pdr, UCOUNT clno, UCOUNT value) /*__fn__*/
{
UCOUNT wtry;
ULONG ltry;
UTINY wrdbuf[2]; /* Temp storage area */
UTINY FAR *fat_data = pdr->fat_swap_structure.data_array;
pdr->fat_is_dirty = YES;
if (!pdr->use_fatbuf)
{
/* Using the in-memory FAT Buffers */
if (pdr->fasize == 3) /* 3 nibble ? */
{
value &= 0x0fff; /* 3 nibble clusters */
wtry = (UCOUNT) (clno + (UCOUNT) (clno >> 1)); /* multiply by 1.5 */
if ( ((clno << 1) + clno) == (wtry << 1) ) /* If whole number */
{
fat_data[wtry] = (UTINY)((UTINY)value & 0xff); /* Low Byte to NIBBLE 1 & 2 */
fat_data[wtry+1] &= 0xf0; /* clr low NIBBLE of next byte */
/* Put the high nibble of value in the low nibble ofnext byte */
fat_data[wtry+1] |= ( ((UTINY)(value>>8)) & 0x0f );
}
else
{
fat_data[wtry+1]= (UTINY)((UTINY)(value>>4) & 0xff); /* high to NIB 2 & 3*/
fat_data[wtry] &= 0x0f; /* clr high NIBBLE of byte */
/* Put the low nibble of value in the high nibble of byte */
fat_data[wtry] |= ( ((UTINY)(value & 0xf) << 4) & 0xf0 );
}
/* Now mark the dirty flags block == index/512 */
/* Note try>>9 and try+1 >> 9 are usually the same */
/* NOTE: data_map is a byte map of dirty fat blocks */
pdr->fat_swap_structure.data_map[(wtry>>9)] = (UTINY) 1;
pdr->fat_swap_structure.data_map[(wtry+1)>>9] = (UTINY) 1;
}
else /* 16 BIT entries */
{
/* Byte offset in fat ==s cluster number * 2 */
ltry = (ULONG) clno;
ltry <<= 1;
/* Use temp buffer since fat_data is far , can't call fr word with
it directly in intel small model */
fr_WORD(&wrdbuf[0],value);
fat_data[ltry] = wrdbuf[0];
fat_data[ltry+1] = wrdbuf[1];
/* Now mark the dirty flags block == index/512 */
/* NOTE: data_map is a byte map of dirty fat blocks */
pdr->fat_swap_structure.data_map[(ltry>>9)] = (UTINY) 1;
}
}
else
{
/* fat swapping. Always 16 bit entries */
fr_WORD(&wrdbuf[0],value);
/* Now put the values back into the FAT */
if (!pc_pfpword( pdr, clno, (UCOUNT *) &wrdbuf[0] ))
{
return (NO);
}
}
return (YES);
}
/***************************************************************************
PC_FATSW - FAT Access code when fat buffering is enabled.
Summary
Free all core associated with the drive's fat
VOID pc_pfclose( DDRIVE *pdr);
Flush the current page (if needed. And read in a new page such that
"index" is contained therein. (Called by pc_pfpbyte() and pc_pfgbyte())
BOOL pc_pfswap( DDRIVE *pdr, UCOUNT index);
Put a byte (value) into the FAT at index. Return YES if everything worked.
Note: FAT page swaps will occur if they are needed. Called by pc_pfaxx().
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -