/****************************************************************/
/* */
/* fattab.c */
/* */
/* FAT File System Table Functions */
/* */
/* Copyright (c) 1995 */
/* Pasquale J. Villani */
/* All Rights Reserved */
/* */
/* This file is part of DOS-C. */
/* */
/* DOS-C is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU General Public License */
/* as published by the Free Software Foundation; either version */
/* 2, or (at your option) any later version. */
/* */
/* DOS-C is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
/* the GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public */
/* License along with DOS-C; see the file COPYING. If not, */
/* write to the Free Software Foundation, 675 Mass Ave, */
/* Cambridge, MA 02139, USA. */
/****************************************************************/
#include "../../hdr/portab.h"
#include "globals.h"
/* $Logfile: C:/dos-c/src/fs/fattab.c_v $ */
#ifndef IPL
static BYTE *RcsId = "$Header: C:/dos-c/src/fs/fattab.c_v 1.2 01 Sep 1995 17:48:42 patv $";
#endif
/*
* $Log: C:/dos-c/src/fs/fattab.c_v $
*
* Rev 1.2 01 Sep 1995 17:48:42 patv
* First GPL release.
*
* Rev 1.1 30 Jul 1995 20:50:26 patv
* Eliminated version strings in ipl
*
* Rev 1.0 02 Jul 1995 8:04:56 patv
* Initial revision.
*/
#ifdef PROTO
UCOUNT link_fat12(struct dpb *, UCOUNT, UCOUNT);
UCOUNT link_fat16(struct dpb *, UCOUNT, UCOUNT);
UWORD next_cl12(struct dpb *, UCOUNT);
UWORD next_cl16(struct dpb *, UCOUNT);
#else
UCOUNT link_fat12();
UCOUNT link_fat16();
UWORD next_cl12();
UWORD next_cl16();
#endif
/************************************************************************/
/* */
/* cluster/sector routines */
/* */
/************************************************************************/
/* */
/* The FAT file system is difficult to trace through FAT table. */
/* There are two kinds of FAT's, 12 bit and 16 bit. The 16 bit */
/* FAT is the easiest, since it is noting more than a series of */
/* UWORD's. The 12 bit FAT is difficult, because it packs 3 FAT */
/* entries into two BYTE's. The are packed as follows: */
/* */
/* 0x0003 0x0004 0x0005 0x0006 0x0007 0x0008 0x0009 ... */
/* */
/* are packed as */
/* */
/* 0x03 0x40 0x00 0x05 0x60 0x00 0x07 0x80 0x00 0x09 ... */
/* */
/* 12 bytes are compressed to 9 bytes */
/* */
UCOUNT
link_fat (struct dpb *dpbp, UCOUNT Cluster1, REG UCOUNT Cluster2)
{
if(ISFAT12(dpbp))
return link_fat12(dpbp, Cluster1, Cluster2);
else if(ISFAT16(dpbp))
return link_fat16(dpbp, Cluster1, Cluster2);
else
return DE_BLKINVLD;
}
UCOUNT
link_fat16 (struct dpb *dpbp, UCOUNT Cluster1, UCOUNT Cluster2)
{
UCOUNT idx;
struct buffer FAR *bp;
UWORD Cl2 = Cluster2;
/* Get the block that this cluster is in */
bp = getblock((LONG)(((LONG)Cluster1) * SIZEOF_CLST16) / dpbp -> dpb_secsize + dpbp -> dpb_fatstrt + 1,
dpbp -> dpb_unit);
if(bp == NULL)
return DE_BLKINVLD;
/* form an index so that we can read the block as a */
/* byte array */
idx = (((LONG)Cluster1) * SIZEOF_CLST16) % dpbp -> dpb_secsize;
/* Finally, put the word into the buffer and mark the */
/* buffer as dirty. */
fputword((WORD FAR *)&Cl2, (VOID FAR *)&(bp -> b_buffer[idx]));
bp -> b_update = TRUE;
/* Return successful. */
/* update the free space count */
if(Cluster2 == FREE)
{
/* update the free space count for returned */
/* cluster */
if(dpbp -> dpb_nfreeclst != UNKNCLUSTER)
++dpbp -> dpb_nfreeclst;
}
else
{
/* update the free space count for removed */
/* cluster */
if(dpbp -> dpb_nfreeclst != UNKNCLUSTER)
--dpbp -> dpb_nfreeclst;
}
return SUCCESS;
}
UCOUNT
link_fat12 (struct dpb *dpbp, UCOUNT Cluster1, UCOUNT Cluster2)
{
REG UBYTE FAR *fbp0, FAR *fbp1;
UCOUNT idx;
struct buffer FAR *bp, FAR *bp1;
/* Get the block that this cluster is in */
bp = getblock((LONG)((((Cluster1 << 1) + Cluster1) >> 1) / dpbp -> dpb_secsize + dpbp -> dpb_fatstrt + 1),
dpbp -> dpb_unit);
if(bp == NULL)
return DE_BLKINVLD;
/* form an index so that we can read the block as a */
/* byte array */
idx = (((Cluster1 << 1) + Cluster1) >> 1) % dpbp -> dpb_secsize;
/* Test to se if the cluster straddles the block. If it */
/* does, get the next block and use both to form the */
/* the FAT word. Otherwise, just point to the next */
/* block. */
if(idx >= dpbp -> dpb_secsize - 1)
{
bp1 = getblock((LONG)(dpbp -> dpb_fatstrt +
((((Cluster1 << 1) + Cluster1) >> 1) / dpbp -> dpb_secsize))
+ 2,
dpbp -> dpb_unit);
if(bp1 == (struct buffer *)0)
return DE_BLKINVLD;
bp1 -> b_update = TRUE;
fbp1 = (UBYTE FAR *)&(bp1 -> b_buffer[0]);
}
else
fbp1 = (UBYTE FAR *)&(bp -> b_buffer[idx + 1]);
fbp0 = (UBYTE FAR *)&(bp -> b_buffer[idx]);
bp -> b_update = TRUE;
/* Now pack the value in */
if (Cluster1 & 0x01)
{
*fbp0 = (*fbp0 & 0x0f) | ((Cluster2 & 0x0f) << 4);
*fbp1 = (Cluster2 >> 4) & 0xff;
}
else
{
*fbp0 = Cluster2 & 0xff;
*fbp1 = (*fbp1 & 0xf0) |(Cluster2 >> 8) & 0x0f;
}
/* update the free space count */
if(Cluster2 == FREE)
{
/* update the free space count for returned */
/* cluster */
if(dpbp -> dpb_nfreeclst != UNKNCLUSTER)
++dpbp -> dpb_nfreeclst;
}
else
{
/* update the free space count for removed */
/* cluster */
if(dpbp -> dpb_nfreeclst != UNKNCLUSTER)
--dpbp -> dpb_nfreeclst;
}
return SUCCESS;
}
UWORD
next_cluster (struct dpb *dpbp, REG UCOUNT ClusterNum)
{
if(ISFAT12(dpbp))
return next_cl12(dpbp, ClusterNum);
else if(ISFAT16(dpbp))
return next_cl16(dpbp, ClusterNum);
else
return LONG_LAST_CLUSTER;
}
UWORD
next_cl16 (struct dpb *dpbp, REG UCOUNT ClusterNum)
{
UCOUNT idx;
struct buffer FAR *bp;
UWORD RetCluster;
/* Get the block that this cluster is in */
bp = getblock((LONG)(((LONG)ClusterNum) * SIZEOF_CLST16) / dpbp -> dpb_secsize + dpbp -> dpb_fatstrt + 1,
dpbp -> dpb_unit);
if(bp == NULL)
return DE_BLKINVLD;
/* form an index so that we can read the block as a */
/* byte array */
idx = (((LONG)ClusterNum) * SIZEOF_CLST16) % dpbp -> dpb_secsize;
/* Get the cluster number, */
fgetword((VOID FAR *)&(bp -> b_buffer[idx]), (WORD FAR *)&RetCluster);
/* and return successful. */
return RetCluster;
}
UWORD
next_cl12 (struct dpb *dpbp, REG UCOUNT ClusterNum)
{
REG UBYTE FAR *fbp0, FAR *fbp1;
UCOUNT idx;
struct buffer FAR *bp, FAR *bp1;
/* Get the block that this cluster is in */
bp = getblock((LONG)((((ClusterNum << 1) + ClusterNum) >> 1) / dpbp -> dpb_secsize + dpbp -> dpb_fatstrt + 1),
dpbp -> dpb_unit);
if(bp == NULL)
return BAD;
/* form an index so that we can read the block as a */
/* byte array */
idx = (((ClusterNum << 1) + ClusterNum) >> 1) % dpbp -> dpb_secsize;
/* Test to se if the cluster straddles the block. If it */
/* does, get the next block and use both to form the */
/* the FAT word. Otherwise, just point to the next */
/* block. */
if(idx >= dpbp -> dpb_secsize - 1)
{
bp1 = getblock((LONG)(dpbp -> dpb_fatstrt +
((((ClusterNum << 1) + ClusterNum) >> 1) / dpbp -> dpb_secsize))
+ 2,
dpbp -> dpb_unit);
if(bp1 == (struct buffer *)0)
return BAD;
fbp1 = (UBYTE FAR *)&(bp1 -> b_buffer[0]);
}
else
fbp1 = (UBYTE FAR *)&(bp -> b_buffer[idx + 1]);
fbp0 = (UBYTE FAR *)&(bp -> b_buffer[idx]);
/* Now to unpack the contents of the FAT entry. Odd and */
/* even bytes are packed differently. */
if (ClusterNum & 0x01)
ClusterNum = ((*fbp0 & 0xf0) >> 4) | *fbp1 << 4;
else
ClusterNum = *fbp0 | ((*fbp1 & 0x0f) << 8);
if ((ClusterNum & MASK) == MASK)
ClusterNum = LAST_CLUSTER;
else if ((ClusterNum & BAD) == BAD)
ClusterNum = BAD;
return ClusterNum;
}