2000-05-06 21:34:20 +02:00
|
|
|
/****************************************************************/
|
|
|
|
/* */
|
|
|
|
/* 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 "portab.h"
|
|
|
|
#include "globals.h"
|
|
|
|
|
|
|
|
#ifdef VERSION_STRINGS
|
|
|
|
static BYTE *RcsId = "$Id$";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* $Log$
|
2001-11-14 00:36:45 +01:00
|
|
|
* Revision 1.10 2001/11/13 23:36:45 bartoldeman
|
|
|
|
* Kernel 2025a final changes.
|
|
|
|
*
|
2001-11-04 20:47:39 +01:00
|
|
|
* Revision 1.9 2001/11/04 19:47:39 bartoldeman
|
|
|
|
* kernel 2025a changes: see history.txt
|
|
|
|
*
|
2001-09-23 22:39:44 +02:00
|
|
|
* Revision 1.8 2001/09/23 20:39:44 bartoldeman
|
|
|
|
* FAT32 support, misc fixes, INT2F/AH=12 support, drive B: handling
|
|
|
|
*
|
2001-07-10 00:19:33 +02:00
|
|
|
* Revision 1.7 2001/07/09 22:19:33 bartoldeman
|
|
|
|
* LBA/FCB/FAT/SYS/Ctrl-C/ioctl fixes + memory savings
|
|
|
|
*
|
2001-06-03 16:16:18 +02:00
|
|
|
* Revision 1.6 2001/06/03 14:16:17 bartoldeman
|
|
|
|
* BUFFERS tuning and misc bug fixes/cleanups (2024c).
|
|
|
|
*
|
2001-04-22 00:32:53 +02:00
|
|
|
* Revision 1.5 2001/04/21 22:32:53 bartoldeman
|
|
|
|
* Init DS=Init CS, fixed stack overflow problems and misc bugs.
|
|
|
|
*
|
2001-04-15 05:21:50 +02:00
|
|
|
* Revision 1.4 2001/04/15 03:21:50 bartoldeman
|
|
|
|
* See history.txt for the list of fixes.
|
|
|
|
*
|
2000-05-25 22:56:23 +02:00
|
|
|
* Revision 1.3 2000/05/25 20:56:21 jimtabor
|
|
|
|
* Fixed project history
|
|
|
|
*
|
2000-05-08 06:30:00 +02:00
|
|
|
* Revision 1.2 2000/05/08 04:30:00 jimtabor
|
|
|
|
* Update CVS to 2020
|
2000-05-06 21:34:20 +02:00
|
|
|
*
|
2000-05-25 22:56:23 +02:00
|
|
|
* Revision 1.1.1.1 2000/05/06 19:34:53 jhall1
|
|
|
|
* The FreeDOS Kernel. A DOS kernel that aims to be 100% compatible with
|
|
|
|
* MS-DOS. Distributed under the GNU GPL.
|
|
|
|
*
|
2000-05-06 21:34:20 +02:00
|
|
|
* Revision 1.6 1999/08/10 18:03:42 jprice
|
|
|
|
* ror4 2011-03 patch
|
|
|
|
*
|
|
|
|
* Revision 1.5 1999/05/03 06:25:45 jprice
|
|
|
|
* Patches from ror4 and many changed of signed to unsigned variables.
|
|
|
|
*
|
|
|
|
* Revision 1.4 1999/04/16 00:53:33 jprice
|
|
|
|
* Optimized FAT handling
|
|
|
|
*
|
|
|
|
* Revision 1.3 1999/04/11 04:33:38 jprice
|
|
|
|
* ror4 patches
|
|
|
|
*
|
|
|
|
* Revision 1.1.1.1 1999/03/29 15:42:09 jprice
|
|
|
|
* New version without IPL.SYS
|
|
|
|
*
|
|
|
|
* Revision 1.4 1999/02/09 02:54:23 jprice
|
|
|
|
* Added Pat's 1937 kernel patches
|
|
|
|
*
|
|
|
|
* Revision 1.3 1999/02/01 01:43:28 jprice
|
|
|
|
* Fixed findfirst function to find volume label with Windows long filenames
|
|
|
|
*
|
|
|
|
* Revision 1.2 1999/01/22 04:15:28 jprice
|
|
|
|
* Formating
|
|
|
|
*
|
|
|
|
* Revision 1.1.1.1 1999/01/20 05:51:00 jprice
|
|
|
|
* Imported sources
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Rev 1.7 09 Feb 1998 5:41:08 patv
|
|
|
|
* Eliminated FAT12 EOF and error returns.
|
|
|
|
*
|
|
|
|
* Rev 1.6 04 Jan 1998 23:14:38 patv
|
|
|
|
* Changed Log for strip utility
|
|
|
|
*
|
|
|
|
* Rev 1.5 16 Jan 1997 12:46:22 patv
|
|
|
|
* pre-Release 0.92 feature additions
|
|
|
|
*
|
|
|
|
* Rev 1.4 29 May 1996 21:15:14 patv
|
|
|
|
* bug fixes for v0.91a
|
|
|
|
*
|
|
|
|
* Rev 1.3 19 Feb 1996 3:20:08 patv
|
|
|
|
* Added NLS, int2f and config.sys processing
|
|
|
|
*
|
|
|
|
* 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
|
2001-09-23 22:39:44 +02:00
|
|
|
UCOUNT link_fat12(struct dpb FAR *, CLUSTER, CLUSTER);
|
|
|
|
UCOUNT link_fat16(struct dpb FAR *, CLUSTER, CLUSTER);
|
|
|
|
UCOUNT link_fat32(struct dpb FAR *, CLUSTER, CLUSTER);
|
|
|
|
CLUSTER next_cl12(struct dpb FAR *, CLUSTER);
|
|
|
|
CLUSTER next_cl16(struct dpb FAR *, CLUSTER);
|
|
|
|
CLUSTER next_cl32(struct dpb FAR *, CLUSTER);
|
2000-05-06 21:34:20 +02:00
|
|
|
#else
|
|
|
|
UCOUNT link_fat12();
|
|
|
|
UCOUNT link_fat16();
|
2001-09-23 22:39:44 +02:00
|
|
|
UCOUNT link_fat32();
|
|
|
|
CLUSTER next_cl12();
|
|
|
|
CLUSTER next_cl16();
|
|
|
|
CLUSTER next_cl32();
|
2000-05-06 21:34:20 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* cluster/sector routines */
|
|
|
|
/* */
|
|
|
|
/************************************************************************/
|
|
|
|
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifndef ISFAT32
|
|
|
|
int ISFAT32(struct dpb FAR *dpbp)
|
|
|
|
{
|
|
|
|
return _ISFAT32(dpbp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
struct buffer FAR *getFATblock(CLUSTER cluster, struct dpb FAR *dpbp)
|
2001-06-03 16:16:18 +02:00
|
|
|
{
|
|
|
|
ULONG sector;
|
|
|
|
struct buffer FAR *bp;
|
2001-09-23 22:39:44 +02:00
|
|
|
|
2001-06-03 16:16:18 +02:00
|
|
|
if (ISFAT12(dpbp))
|
|
|
|
{
|
|
|
|
sector = ((cluster << 1) + cluster) >> 1;
|
2001-09-23 22:39:44 +02:00
|
|
|
}
|
|
|
|
#ifdef WITHFAT32
|
|
|
|
else if (ISFAT32(dpbp))
|
|
|
|
{
|
|
|
|
sector = (ULONG)cluster * SIZEOF_CLST32;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else
|
2001-06-03 16:16:18 +02:00
|
|
|
{
|
|
|
|
sector = (ULONG)cluster * SIZEOF_CLST16;
|
|
|
|
}
|
|
|
|
sector = sector / dpbp->dpb_secsize + dpbp->dpb_fatstrt;
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
|
|
|
if (ISFAT32(dpbp) && (dpbp->dpb_xflags & FAT_NO_MIRRORING)) {
|
|
|
|
/* we must modify the active fat,
|
|
|
|
it's number is in the 0-3 bits of dpb_xflags */
|
2001-11-04 20:47:39 +01:00
|
|
|
sector += (dpbp->dpb_xflags & 0xf) * dpbp->dpb_xfatsize;
|
2001-09-23 22:39:44 +02:00
|
|
|
}
|
|
|
|
#endif
|
2001-06-03 16:16:18 +02:00
|
|
|
|
|
|
|
bp = getblock(sector, dpbp->dpb_unit);
|
|
|
|
|
|
|
|
if (bp)
|
2001-11-04 20:47:39 +01:00
|
|
|
{
|
|
|
|
bp->b_flag &= ~(BFR_DATA | BFR_DIR);
|
|
|
|
bp->b_flag |= BFR_FAT | BFR_VALID;
|
|
|
|
bp->b_copies = dpbp->dpb_fats;
|
|
|
|
bp->b_offset = dpbp->dpb_fatsize;
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
2001-11-04 20:47:39 +01:00
|
|
|
if (ISFAT32(dpbp))
|
|
|
|
{
|
|
|
|
if (dpbp->dpb_xflags & FAT_NO_MIRRORING)
|
|
|
|
bp->b_copies = 1;
|
|
|
|
bp->b_offset = dpbp->dpb_xfatsize;
|
2001-06-03 16:16:18 +02:00
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
#endif
|
|
|
|
}
|
2001-06-03 16:16:18 +02:00
|
|
|
return bp;
|
|
|
|
}
|
2001-09-23 22:39:44 +02:00
|
|
|
|
|
|
|
#ifdef WITHFAT32
|
|
|
|
void read_fsinfo(struct dpb FAR *dpbp)
|
|
|
|
{
|
|
|
|
struct buffer FAR *bp;
|
|
|
|
struct fsinfo FAR *fip;
|
|
|
|
|
|
|
|
bp = getblock(dpbp->dpb_xfsinfosec, dpbp->dpb_unit);
|
|
|
|
bp->b_flag &= ~(BFR_DATA | BFR_DIR | BFR_FAT | BFR_DIRTY);
|
|
|
|
bp->b_flag |= BFR_VALID;
|
|
|
|
|
|
|
|
fip = (struct fsinfo FAR *) & bp->b_buffer[0x1e4];
|
2001-11-04 20:47:39 +01:00
|
|
|
dpbp->dpb_xnfreeclst = fip->fi_nfreeclst;
|
|
|
|
dpbp->dpb_xcluster = fip->fi_cluster;
|
2001-09-23 22:39:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void write_fsinfo(struct dpb FAR *dpbp)
|
|
|
|
{
|
|
|
|
struct buffer FAR *bp;
|
|
|
|
struct fsinfo FAR *fip;
|
|
|
|
|
|
|
|
bp = getblock(dpbp->dpb_xfsinfosec, dpbp->dpb_unit);
|
|
|
|
bp->b_flag &= ~(BFR_DATA | BFR_DIR | BFR_FAT);
|
|
|
|
bp->b_flag |= BFR_VALID | BFR_DIRTY;
|
|
|
|
|
|
|
|
fip = (struct fsinfo FAR *) & bp->b_buffer[0x1e4];
|
2001-11-04 20:47:39 +01:00
|
|
|
fip->fi_nfreeclst = dpbp->dpb_xnfreeclst;
|
|
|
|
fip->fi_cluster = dpbp->dpb_xcluster;
|
2001-09-23 22:39:44 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* */
|
|
|
|
/* 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 */
|
|
|
|
/* */
|
|
|
|
|
2001-09-23 22:39:44 +02:00
|
|
|
UCOUNT link_fat(struct dpb FAR *dpbp, CLUSTER Cluster1, REG CLUSTER Cluster2)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-07-10 00:19:33 +02:00
|
|
|
UCOUNT res;
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
if (ISFAT12(dpbp))
|
2001-07-10 00:19:33 +02:00
|
|
|
res = link_fat12(dpbp, Cluster1, Cluster2);
|
2000-05-06 21:34:20 +02:00
|
|
|
else if (ISFAT16(dpbp))
|
2001-07-10 00:19:33 +02:00
|
|
|
res = link_fat16(dpbp, Cluster1, Cluster2);
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
|
|
|
else if (ISFAT32(dpbp))
|
|
|
|
res = link_fat32(dpbp, Cluster1, Cluster2);
|
|
|
|
#endif
|
2000-05-06 21:34:20 +02:00
|
|
|
else
|
|
|
|
return DE_BLKINVLD;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
|
|
|
|
2001-09-23 22:39:44 +02:00
|
|
|
/* update the free space count */
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if (res == SUCCESS && Cluster2 == FREE)
|
|
|
|
{
|
|
|
|
#ifdef WITHFAT32
|
|
|
|
if (ISFAT32(dpbp) && dpbp->dpb_xnfreeclst != XUNKNCLSTFREE)
|
|
|
|
{
|
|
|
|
/* update the free space count for returned */
|
|
|
|
/* cluster */
|
|
|
|
++dpbp->dpb_xnfreeclst;
|
|
|
|
write_fsinfo(dpbp);
|
|
|
|
} else
|
|
|
|
#endif
|
2001-07-10 00:19:33 +02:00
|
|
|
if (dpbp->dpb_nfreeclst != UNKNCLSTFREE)
|
2001-11-04 20:47:39 +01:00
|
|
|
++dpbp->dpb_nfreeclst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*if (Cluster2 == FREE)
|
|
|
|
{ */
|
2001-09-23 22:39:44 +02:00
|
|
|
/* update the free space count for returned */
|
|
|
|
/* cluster */
|
2001-11-04 20:47:39 +01:00
|
|
|
/* ++dpbp->dpb_nfreeclst;
|
|
|
|
}*/
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-09-23 22:39:44 +02:00
|
|
|
/* update the free space count for removed */
|
2001-07-10 00:19:33 +02:00
|
|
|
/* cluster */
|
|
|
|
/* BUG: was counted twice for 2nd,.. cluster. moved to find_fat_free() */
|
2001-11-04 20:47:39 +01:00
|
|
|
/* BO: don't completely understand this yet - leave here for now as
|
|
|
|
a comment */
|
2001-09-23 22:39:44 +02:00
|
|
|
/* else
|
|
|
|
{
|
|
|
|
--dpbp->dpb_nfreeclst;
|
|
|
|
} */
|
2001-07-10 00:19:33 +02:00
|
|
|
return res;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-09-23 22:39:44 +02:00
|
|
|
#ifdef WITHFAT32
|
|
|
|
UCOUNT link_fat32(struct dpb FAR *dpbp, CLUSTER Cluster1, CLUSTER Cluster2)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
UCOUNT idx;
|
|
|
|
struct buffer FAR *bp;
|
|
|
|
|
|
|
|
/* Get the block that this cluster is in */
|
2001-09-23 22:39:44 +02:00
|
|
|
bp = getFATblock(Cluster1, dpbp);
|
|
|
|
|
|
|
|
if (bp == NULL)
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
|
|
|
|
/* form an index so that we can read the block as a */
|
|
|
|
/* byte array */
|
|
|
|
idx = (UWORD)((Cluster1 * SIZEOF_CLST32) % dpbp->dpb_secsize);
|
|
|
|
|
|
|
|
/* Finally, put the word into the buffer and mark the */
|
|
|
|
/* buffer as dirty. */
|
|
|
|
fputlong((DWORD FAR *) & Cluster2, (VOID FAR *) & (bp->b_buffer[idx]));
|
|
|
|
bp->b_flag |= BFR_DIRTY | BFR_VALID;
|
|
|
|
|
|
|
|
/* Return successful. */
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
UCOUNT link_fat16(struct dpb FAR *dpbp, CLUSTER Cluster1, CLUSTER Cluster2)
|
|
|
|
{
|
|
|
|
UCOUNT idx;
|
|
|
|
struct buffer FAR *bp;
|
|
|
|
|
|
|
|
/* Get the block that this cluster is in */
|
|
|
|
bp = getFATblock(Cluster1, dpbp);
|
2001-06-03 16:16:18 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
if (bp == NULL)
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
|
|
|
|
/* form an index so that we can read the block as a */
|
|
|
|
/* byte array */
|
2001-06-03 16:16:18 +02:00
|
|
|
idx = (UWORD)(( Cluster1 * SIZEOF_CLST16) % dpbp->dpb_secsize);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Finally, put the word into the buffer and mark the */
|
|
|
|
/* buffer as dirty. */
|
2001-06-03 16:16:18 +02:00
|
|
|
fputword((WORD FAR *) & Cluster2, (VOID FAR *) & (bp->b_buffer[idx]));
|
|
|
|
bp->b_flag |= BFR_DIRTY | BFR_VALID;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Return successful. */
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2001-09-23 22:39:44 +02:00
|
|
|
UCOUNT link_fat12(struct dpb FAR *dpbp, CLUSTER Cluster1, CLUSTER Cluster2)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
REG UBYTE FAR *fbp0,
|
|
|
|
FAR * fbp1;
|
|
|
|
UCOUNT idx;
|
|
|
|
struct buffer FAR *bp,
|
|
|
|
FAR * bp1;
|
|
|
|
|
|
|
|
/* Get the block that this cluster is in */
|
2001-06-03 16:16:18 +02:00
|
|
|
bp = getFATblock(Cluster1 , dpbp);
|
2000-05-06 21:34:20 +02:00
|
|
|
if (bp == NULL)
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
|
|
|
|
/* form an index so that we can read the block as a */
|
|
|
|
/* byte array */
|
2001-09-23 22:39:44 +02:00
|
|
|
idx = (UCOUNT)(((Cluster1 << 1) + Cluster1) >> 1) % dpbp->dpb_secsize;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Test to see 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)
|
|
|
|
{
|
2001-06-03 16:16:18 +02:00
|
|
|
bp1 = getFATblock(Cluster1 + 1,dpbp);
|
|
|
|
if (bp1 == 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_BLKINVLD;
|
2001-06-03 16:16:18 +02:00
|
|
|
|
|
|
|
bp1->b_flag |= BFR_DIRTY | BFR_VALID;
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
fbp1 = (UBYTE FAR *) & (bp1->b_buffer[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fbp1 = (UBYTE FAR *) & (bp->b_buffer[idx + 1]);
|
|
|
|
fbp0 = (UBYTE FAR *) & (bp->b_buffer[idx]);
|
2001-06-03 16:16:18 +02:00
|
|
|
bp->b_flag |= BFR_DIRTY | BFR_VALID;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Now pack the value in */
|
|
|
|
if (Cluster1 & 0x01)
|
|
|
|
{
|
|
|
|
*fbp0 = (*fbp0 & 0x0f) | ((Cluster2 & 0x0f) << 4);
|
|
|
|
*fbp1 = (Cluster2 >> 4) & 0xff;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*fbp0 = Cluster2 & 0xff;
|
2001-04-15 05:21:50 +02:00
|
|
|
*fbp1 = (*fbp1 & 0xf0) | ((Cluster2 >> 8) & 0x0f);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given the disk parameters, and a cluster number, this function
|
|
|
|
looks at the FAT, and returns the next cluster in the clain. */
|
2001-09-23 22:39:44 +02:00
|
|
|
CLUSTER next_cluster(struct dpb FAR *dpbp, CLUSTER ClusterNum)
|
|
|
|
{
|
|
|
|
struct buffer FAR *bp;
|
2001-11-14 00:36:45 +01:00
|
|
|
#ifdef DEBUG
|
2001-11-04 20:47:39 +01:00
|
|
|
if (ClusterNum == LONG_LAST_CLUSTER) printf("fatal error: trying to do next_cluster(dpbp, EOC)!\n");
|
2001-11-14 00:36:45 +01:00
|
|
|
if (ClusterNum == 0) printf("fatal error: trying to do next_cluster(dpbp, 0)!\n");
|
|
|
|
#endif
|
2001-09-23 22:39:44 +02:00
|
|
|
|
|
|
|
/* Get the block that this cluster is in */
|
|
|
|
bp = getFATblock(ClusterNum, dpbp);
|
|
|
|
|
|
|
|
if (bp == NULL)
|
|
|
|
return DE_BLKINVLD;
|
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if (ISFAT12(dpbp))
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
UBYTE bytes[2];
|
|
|
|
UCOUNT word;
|
|
|
|
} clusterbuff;
|
|
|
|
|
|
|
|
UCOUNT idx;
|
2001-06-03 16:16:18 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* form an index so that we can read the block as a */
|
|
|
|
/* byte array */
|
|
|
|
idx = (UCOUNT)(((ClusterNum << 1) + ClusterNum) >> 1) % dpbp->dpb_secsize;
|
2001-04-22 00:32:53 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
clusterbuff.bytes[0] = bp->b_buffer[idx];
|
2001-04-22 00:32:53 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
clusterbuff.bytes[1] = bp->b_buffer[idx+1]; /* next byte, will be overwritten,
|
|
|
|
if not valid */
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* Test to see 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)
|
|
|
|
{
|
|
|
|
bp = getFATblock(ClusterNum +1, dpbp);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if (bp == 0)
|
|
|
|
return LONG_BAD;
|
2001-09-23 22:39:44 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
clusterbuff.bytes[1] = bp->b_buffer[0];
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* Now to unpack the contents of the FAT entry. Odd and */
|
|
|
|
/* even bytes are packed differently. */
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
#ifndef I86 /* the latter assumes byte ordering */
|
|
|
|
if (ClusterNum & 0x01)
|
|
|
|
idx = ((clusterbuff.byte[0] & 0xf0) >> 4) | (clusterbuff.byte[1] << 4);
|
|
|
|
else
|
|
|
|
idx = clusterbuff.byte[0] | ((clusterbuff.byte[0] & 0x0f) << 8);
|
|
|
|
#else
|
2001-06-03 16:16:18 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if (ClusterNum & 0x01)
|
|
|
|
idx = (unsigned short)clusterbuff.word >> 4;
|
|
|
|
else
|
|
|
|
idx = clusterbuff.word & 0x0fff;
|
|
|
|
#endif
|
2001-06-03 16:16:18 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
if (idx >= MASK12)
|
|
|
|
return LONG_LAST_CLUSTER;
|
|
|
|
if (idx == BAD12)
|
2000-05-06 21:34:20 +02:00
|
|
|
return LONG_BAD;
|
2001-11-04 20:47:39 +01:00
|
|
|
return idx;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
else if (ISFAT16(dpbp))
|
|
|
|
{
|
|
|
|
UWORD res;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
#ifndef I86
|
|
|
|
UCOUNT idx;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* form an index so that we can read the block as a */
|
|
|
|
/* byte array */
|
|
|
|
idx = (ClusterNum * SIZEOF_CLST16) % dpbp->dpb_secsize;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
/* Get the cluster number, */
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
fgetword((VOID FAR *) & (bp->b_buffer[idx]), (WORD FAR *) & res);
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
#else
|
|
|
|
/* this saves 2 WORDS of stack :-) */
|
|
|
|
|
|
|
|
res = *(UWORD FAR *)&(bp->b_buffer[(UCOUNT)((ClusterNum * SIZEOF_CLST16) % dpbp->dpb_secsize)]);
|
|
|
|
#endif
|
|
|
|
if (res >= MASK16) return LONG_LAST_CLUSTER;
|
|
|
|
if (res == BAD16) return LONG_BAD;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#ifdef WITHFAT32
|
|
|
|
else if (ISFAT32(dpbp))
|
2001-07-10 00:19:33 +02:00
|
|
|
{
|
2001-11-04 20:47:39 +01:00
|
|
|
UDWORD res;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
res = *(UDWORD FAR *)&(bp->b_buffer[(UCOUNT)((ClusterNum * SIZEOF_CLST32) % dpbp->dpb_secsize)]);
|
|
|
|
if (res > LONG_BAD) return LONG_LAST_CLUSTER;
|
2001-07-10 00:19:33 +02:00
|
|
|
|
2001-11-04 20:47:39 +01:00
|
|
|
return res;
|
2001-07-10 00:19:33 +02:00
|
|
|
}
|
|
|
|
#endif
|
2001-11-04 20:47:39 +01:00
|
|
|
return LONG_LAST_CLUSTER;
|
|
|
|
}
|
|
|
|
|