be2ae12b54
git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/trunk@196 6ac86273-5f31-0410-b378-82cca8765d1b
1131 lines
30 KiB
C
1131 lines
30 KiB
C
/****************************************************************/
|
|
/* */
|
|
/* fcbfns.c */
|
|
/* */
|
|
/* Old CP/M Style Function Handlers for Kernel */
|
|
/* */
|
|
/* 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$
|
|
* Revision 1.9 2001/04/15 03:21:50 bartoldeman
|
|
* See history.txt for the list of fixes.
|
|
*
|
|
* Revision 1.8 2001/03/30 22:27:42 bartoldeman
|
|
* Saner lastdrive handling.
|
|
*
|
|
* Revision 1.7 2001/03/21 02:56:26 bartoldeman
|
|
* See history.txt for changes. Bug fixes and HMA support are the main ones.
|
|
*
|
|
* Revision 1.6 2000/08/06 05:50:17 jimtabor
|
|
* Add new files and update cvs with patches and changes
|
|
*
|
|
* Revision 1.5 2000/06/21 18:16:46 jimtabor
|
|
* Add UMB code, patch, and code fixes
|
|
*
|
|
* Revision 1.4 2000/05/26 19:25:19 jimtabor
|
|
* Read History file for Change info
|
|
*
|
|
* Revision 1.3 2000/05/25 20:56:21 jimtabor
|
|
* Fixed project history
|
|
*
|
|
* Revision 1.2 2000/05/08 04:30:00 jimtabor
|
|
* Update CVS to 2020
|
|
*
|
|
* 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.
|
|
*
|
|
* Revision 1.7 2000/03/31 05:40:09 jtabor
|
|
* Added Eric W. Biederman Patches
|
|
*
|
|
* Revision 1.6 2000/03/17 22:59:04 kernel
|
|
* Steffen Kaiser's NLS changes
|
|
*
|
|
* Revision 1.5 2000/03/09 06:07:11 kernel
|
|
* 2017f updates by James Tabor
|
|
*
|
|
* Revision 1.4 1999/09/23 04:40:46 jprice
|
|
* *** empty log message ***
|
|
*
|
|
* Revision 1.2 1999/04/04 18:51:43 jprice
|
|
* no message
|
|
*
|
|
* Revision 1.1.1.1 1999/03/29 15:42:15 jprice
|
|
* New version without IPL.SYS
|
|
*
|
|
* Revision 1.5 1999/02/09 02:54:23 jprice
|
|
* Added Pat's 1937 kernel patches
|
|
*
|
|
* Revision 1.4 1999/02/04 03:18:37 jprice
|
|
* Formating. Added comments.
|
|
*
|
|
* 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 06 Dec 1998 8:44:10 patv
|
|
* Expanded fcb functions for new I/O subsystem.
|
|
*
|
|
* Rev 1.6 04 Jan 1998 23:14:38 patv
|
|
* Changed Log for strip utility
|
|
*
|
|
* Rev 1.5 03 Jan 1998 8:36:02 patv
|
|
* Converted data area to SDA format
|
|
*
|
|
* Rev 1.4 16 Jan 1997 12:46:38 patv
|
|
* pre-Release 0.92 feature additions
|
|
*
|
|
* Rev 1.3 29 May 1996 21:15:14 patv
|
|
* bug fixes for v0.91a
|
|
*
|
|
* Rev 1.2 01 Sep 1995 17:48:44 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:06:06 patv
|
|
* Initial revision.
|
|
*/
|
|
|
|
#define FCB_SUCCESS 0
|
|
#define FCB_ERR_NODATA 1
|
|
#define FCB_ERR_EOF 3
|
|
#define FCB_ERR_WRITE 1
|
|
#define D_ALL D_NORMAL | D_RDONLY | D_HIDDEN | D_SYSTEM | D_DIR | D_ARCHIVE
|
|
|
|
#ifdef PROTO
|
|
fcb FAR *ExtFcbToFcb(xfcb FAR * lpExtFcb);
|
|
fcb FAR *CommonFcbInit(xfcb FAR * lpExtFcb, BYTE * pszBuffer, COUNT * pCurDrive);
|
|
void FcbNameInit(fcb FAR * lpFcb, BYTE * pszBuffer, COUNT * pCurDrive);
|
|
sft FAR *FcbGetSft(COUNT SftIndex);
|
|
VOID FcbNextRecord(fcb FAR * lpFcb);
|
|
/* sft FAR *FcbGetFreeSft(WORD FAR * sft_idx); */
|
|
BOOL FcbCalcRec(xfcb FAR * lpXfcb);
|
|
VOID MoveDirInfo(dmatch FAR * lpDmatch, struct dirent FAR * lpDir);
|
|
#else
|
|
fcb FAR *ExtFcbToFcb();
|
|
fcb FAR *CommonFcbInit();
|
|
void FcbNameInit();
|
|
sft FAR *FcbGetSft();
|
|
VOID FcbNextRecord();
|
|
/* sft FAR *FcbGetFreeSft(); */
|
|
BOOL FcbCalcRec();
|
|
VOID MoveDirInfo();
|
|
#endif
|
|
|
|
static dmatch Dmatch;
|
|
|
|
VOID FatGetDrvData(COUNT drive, COUNT FAR * spc, COUNT FAR * bps,
|
|
COUNT FAR * nc, BYTE FAR ** mdp)
|
|
{
|
|
struct dpb FAR *dpbp;
|
|
|
|
printf("FGDD\n");
|
|
|
|
/* first check for valid drive */
|
|
if ((UCOUNT)drive >= lastdrive)
|
|
{
|
|
*spc = -1;
|
|
return;
|
|
}
|
|
|
|
/* next - "log" in the drive */
|
|
drive = (drive == 0 ? default_drive : drive - 1);
|
|
if (CDSp->cds_table[drive].cdsFlags & CDSNETWDRV) {
|
|
printf("FatGetDrvData not yet supported over network drives\n");
|
|
*spc = -1;
|
|
return;
|
|
}
|
|
dpbp = CDSp->cds_table[drive].cdsDpb;
|
|
dpbp->dpb_flags = -1;
|
|
if ((media_check(dpbp) < 0))
|
|
{
|
|
*spc = -1;
|
|
return;
|
|
}
|
|
|
|
/* get the data vailable from dpb */
|
|
*nc = dpbp->dpb_size;
|
|
*spc = dpbp->dpb_clsmask + 1;
|
|
*bps = dpbp->dpb_secsize;
|
|
|
|
/* Point to the media desctriptor for this drive */
|
|
*mdp = (BYTE FAR*)&(dpbp->dpb_mdb);
|
|
}
|
|
|
|
#define PARSE_SEP_STOP 0x01
|
|
#define PARSE_DFLT_DRIVE 0x02
|
|
#define PARSE_BLNK_FNAME 0x04
|
|
#define PARSE_BLNK_FEXT 0x08
|
|
|
|
#define PARSE_RET_NOWILD 0
|
|
#define PARSE_RET_WILD 1
|
|
#define PARSE_RET_BADDRIVE 0xff
|
|
|
|
#ifndef IPL
|
|
WORD FcbParseFname(int wTestMode, BYTE FAR ** lpFileName, fcb FAR * lpFcb)
|
|
{
|
|
COUNT nIndex;
|
|
WORD wRetCode = PARSE_RET_NOWILD;
|
|
|
|
/* pjv -- ExtFcbToFcb? */
|
|
/* Start out with some simple stuff first. Check if we are */
|
|
/* going to use a default drive specificaton. */
|
|
if (!(wTestMode & PARSE_DFLT_DRIVE))
|
|
lpFcb->fcb_drive = FDFLT_DRIVE;
|
|
if (!(wTestMode & PARSE_BLNK_FNAME))
|
|
{
|
|
for (nIndex = 0; nIndex < FNAME_SIZE; ++nIndex)
|
|
lpFcb->fcb_fname[nIndex] = ' ';
|
|
}
|
|
if (!(wTestMode & PARSE_BLNK_FEXT))
|
|
{
|
|
for (nIndex = 0; nIndex < FEXT_SIZE; ++nIndex)
|
|
lpFcb->fcb_fext[nIndex] = ' ';
|
|
}
|
|
|
|
/* Undocumented behavior, set record number & record size to 0 */
|
|
lpFcb->fcb_cublock = lpFcb->fcb_recsiz = 0;
|
|
|
|
if (!(wTestMode & PARSE_SEP_STOP))
|
|
{
|
|
*lpFileName = ParseSkipWh(*lpFileName);
|
|
if (TestCmnSeps(*lpFileName))
|
|
++ * lpFileName;
|
|
}
|
|
|
|
/* Undocumented "feature," we skip white space anyway */
|
|
*lpFileName = ParseSkipWh(*lpFileName);
|
|
|
|
/* Now check for drive specification */
|
|
if (*(*lpFileName + 1) == ':')
|
|
{
|
|
REG BYTE Drive = DosUpFChar(**lpFileName);
|
|
|
|
/* non-portable construct to be changed */
|
|
if (Drive < 'A' || Drive > 'Z')
|
|
return PARSE_RET_BADDRIVE;
|
|
Drive -= ('A' - 1);
|
|
if (Drive >= lastdrive)
|
|
return PARSE_RET_BADDRIVE;
|
|
else
|
|
lpFcb->fcb_drive = Drive;
|
|
*lpFileName += 2;
|
|
}
|
|
|
|
/* Now to format the file name into the string */
|
|
*lpFileName = GetNameField(*lpFileName, (BYTE FAR *) lpFcb->fcb_fname, FNAME_SIZE, (BOOL *) & wRetCode);
|
|
|
|
/* Do we have an extension? If do, format it else return */
|
|
if (**lpFileName == '.')
|
|
*lpFileName = GetNameField(++*lpFileName, (BYTE FAR *) lpFcb->fcb_fext, FEXT_SIZE, (BOOL *) & wRetCode);
|
|
|
|
return wRetCode ? PARSE_RET_WILD : PARSE_RET_NOWILD;
|
|
}
|
|
|
|
BYTE FAR *ParseSkipWh(BYTE FAR * lpFileName)
|
|
{
|
|
while (*lpFileName == ' ' || *lpFileName == '\t')
|
|
++lpFileName;
|
|
return lpFileName;
|
|
}
|
|
|
|
BOOL TestCmnSeps(BYTE FAR * lpFileName)
|
|
{
|
|
BYTE *pszTest,
|
|
*pszCmnSeps = ":<|>+=,";
|
|
|
|
for (pszTest = pszCmnSeps; *pszTest != '\0'; ++pszTest)
|
|
if (*lpFileName == *pszTest)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL TestFieldSeps(BYTE FAR * lpFileName)
|
|
{
|
|
BYTE *pszTest,
|
|
*pszCmnSeps = "/\"[]<>|.";
|
|
|
|
/* Another non-portable construct */
|
|
if (*lpFileName <= ' ')
|
|
return TRUE;
|
|
|
|
for (pszTest = pszCmnSeps; *pszTest != '\0'; ++pszTest)
|
|
if (*lpFileName == *pszTest)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
BYTE FAR *GetNameField(BYTE FAR * lpFileName, BYTE FAR * lpDestField,
|
|
COUNT nFieldSize, BOOL * pbWildCard)
|
|
{
|
|
COUNT nIndex = 0;
|
|
BYTE cFill = ' ';
|
|
|
|
*pbWildCard = FALSE;
|
|
while (*lpFileName != '\0' && !TestFieldSeps(lpFileName) && nIndex < nFieldSize)
|
|
{
|
|
if (*lpFileName == ' ')
|
|
break;
|
|
if (*lpFileName == '*')
|
|
{
|
|
*pbWildCard = TRUE;
|
|
cFill = '?';
|
|
++lpFileName;
|
|
break;
|
|
}
|
|
if (*lpFileName == '?')
|
|
*pbWildCard = TRUE;
|
|
*lpDestField++ = DosUpFChar(*lpFileName++);
|
|
++nIndex;
|
|
}
|
|
|
|
/* Blank out remainder of field on exit */
|
|
for (; nIndex < nFieldSize; ++nIndex)
|
|
*lpDestField++ = cFill;
|
|
return lpFileName;
|
|
}
|
|
|
|
static sft FAR *FcbGetSft(COUNT SftIndex)
|
|
{
|
|
/* Get the SFT block that contains the SFT */
|
|
for (lpCurSft = sfthead; lpCurSft != (sfttbl FAR *) - 1;
|
|
lpCurSft = lpCurSft->sftt_next)
|
|
{
|
|
if (SftIndex < lpCurSft->sftt_count)
|
|
break;
|
|
else
|
|
SftIndex -= lpCurSft->sftt_count;
|
|
}
|
|
|
|
/* If not found, return an error */
|
|
if (lpCurSft == (sfttbl FAR *) - 1)
|
|
return (sft FAR *) - 1;
|
|
|
|
/* finally, point to the right entry */
|
|
return (sft FAR *) & (lpCurSft->sftt_table[SftIndex]);
|
|
}
|
|
|
|
static VOID FcbNextRecord(fcb FAR * lpFcb)
|
|
{
|
|
if (++lpFcb->fcb_curec > 128)
|
|
{
|
|
lpFcb->fcb_curec = 0;
|
|
++lpFcb->fcb_cublock;
|
|
}
|
|
}
|
|
|
|
static ULONG FcbRec(VOID)
|
|
{
|
|
UWORD tmp = 128;
|
|
|
|
return ((ULONG)lpFcb->fcb_cublock * tmp) + lpFcb->fcb_curec;
|
|
}
|
|
|
|
BOOL FcbRead(xfcb FAR * lpXfcb, COUNT * nErrorCode)
|
|
{
|
|
sft FAR *s;
|
|
LONG lPosit;
|
|
COUNT nRead;
|
|
psp FAR *p = MK_FP(cu_psp, 0);
|
|
|
|
/* Convert to fcb if necessary */
|
|
lpFcb = ExtFcbToFcb(lpXfcb);
|
|
|
|
/* Get the SFT block that contains the SFT */
|
|
if ((s = FcbGetSft(lpFcb->fcb_sftno)) == (sft FAR *) - 1)
|
|
return FALSE;
|
|
|
|
/* If this is not opened another error */
|
|
if (s->sft_count == 0)
|
|
return FALSE;
|
|
|
|
/* Now update the fcb and compute where we need to position */
|
|
/* to. */
|
|
lPosit = FcbRec() * lpFcb->fcb_recsiz;
|
|
if (SftSeek(s, lPosit, 0) != SUCCESS)
|
|
{
|
|
*nErrorCode = FCB_ERR_EOF;
|
|
return FALSE;
|
|
}
|
|
|
|
if (s->sft_flags & SFT_FSHARED)
|
|
{
|
|
nRead = Remote_RW(REM_READ, lpFcb->fcb_recsiz, p->ps_dta, s, nErrorCode);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* Do the read */
|
|
nRead = dos_read(s->sft_status, p->ps_dta, lpFcb->fcb_recsiz);
|
|
}
|
|
|
|
/* Now find out how we will return and do it. */
|
|
if (nRead == lpFcb->fcb_recsiz)
|
|
{
|
|
*nErrorCode = FCB_SUCCESS;
|
|
FcbNextRecord(lpFcb);
|
|
return TRUE;
|
|
}
|
|
else if (nRead < 0)
|
|
{
|
|
*nErrorCode = FCB_ERR_EOF;
|
|
return TRUE;
|
|
}
|
|
else if (nRead == 0)
|
|
{
|
|
*nErrorCode = FCB_ERR_NODATA;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
COUNT nIdx,
|
|
nCount;
|
|
BYTE FAR *lpDta;
|
|
|
|
nCount = lpFcb->fcb_recsiz - nRead;
|
|
lpDta = (BYTE FAR *) & (p->ps_dta[nRead]);
|
|
for (nIdx = 0; nIdx < nCount; nIdx++)
|
|
*lpDta++ = 0;
|
|
*nErrorCode = FCB_ERR_EOF;
|
|
FcbNextRecord(lpFcb);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL FcbWrite(xfcb FAR * lpXfcb, COUNT * nErrorCode)
|
|
{
|
|
sft FAR *s;
|
|
LONG lPosit;
|
|
COUNT nWritten;
|
|
psp FAR *p = MK_FP(cu_psp, 0);
|
|
|
|
/* Convert to fcb if necessary */
|
|
lpFcb = ExtFcbToFcb(lpXfcb);
|
|
|
|
/* Get the SFT block that contains the SFT */
|
|
if ((s = FcbGetSft(lpFcb->fcb_sftno)) == (sft FAR *) - 1)
|
|
return FALSE;
|
|
|
|
/* If this is not opened another error */
|
|
if (s->sft_count == 0)
|
|
return FALSE;
|
|
|
|
/* Now update the fcb and compute where we need to position */
|
|
/* to. */
|
|
lPosit = FcbRec() * lpFcb->fcb_recsiz;
|
|
if (SftSeek(s, lPosit, 0) != SUCCESS)
|
|
{
|
|
*nErrorCode = FCB_ERR_EOF;
|
|
return FALSE;
|
|
}
|
|
|
|
if (s->sft_flags & SFT_FSHARED)
|
|
{
|
|
nWritten = Remote_RW(REM_WRITE, lpFcb->fcb_recsiz, p->ps_dta, s, nErrorCode);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* Do the read */
|
|
nWritten = dos_write(s->sft_status, p->ps_dta, lpFcb->fcb_recsiz);
|
|
s->sft_size = dos_getcufsize(s->sft_status);
|
|
}
|
|
|
|
/* Now find out how we will return and do it. */
|
|
if (nWritten == lpFcb->fcb_recsiz)
|
|
{
|
|
lpFcb->fcb_fsize = s->sft_size;
|
|
FcbNextRecord(lpFcb);
|
|
*nErrorCode = FCB_SUCCESS;
|
|
return TRUE;
|
|
}
|
|
else if (nWritten <= 0)
|
|
{
|
|
*nErrorCode = FCB_ERR_WRITE;
|
|
return TRUE;
|
|
}
|
|
*nErrorCode = FCB_ERR_WRITE;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL FcbGetFileSize(xfcb FAR * lpXfcb)
|
|
{
|
|
COUNT FcbDrive,
|
|
FileNum;
|
|
|
|
/* Build a traditional DOS file name */
|
|
lpFcb = CommonFcbInit(lpXfcb, PriPathName, &FcbDrive);
|
|
|
|
/* check for a device */
|
|
if (IsDevice(PriPathName) || (lpFcb->fcb_recsiz == 0))
|
|
{
|
|
return FALSE;
|
|
}
|
|
FileNum = dos_open(PriPathName, O_RDONLY);
|
|
if (FileNum >= 0)
|
|
{
|
|
LONG fsize;
|
|
|
|
/* Get the size */
|
|
fsize = dos_getfsize(FileNum);
|
|
|
|
/* compute the size and update the fcb */
|
|
lpFcb->fcb_rndm = fsize / lpFcb->fcb_recsiz;
|
|
if ((fsize % lpFcb->fcb_recsiz) != 0)
|
|
++lpFcb->fcb_rndm;
|
|
|
|
/* close the file and leave */
|
|
return dos_close(FileNum) == SUCCESS;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL FcbSetRandom(xfcb FAR * lpXfcb)
|
|
{
|
|
/* Convert to fcb if necessary */
|
|
lpFcb = ExtFcbToFcb(lpXfcb);
|
|
|
|
/* Now update the fcb and compute where we need to position */
|
|
/* to. */
|
|
lpFcb->fcb_rndm = FcbRec();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FcbCalcRec(xfcb FAR * lpXfcb)
|
|
{
|
|
UWORD div=128;
|
|
|
|
/* Convert to fcb if necessary */
|
|
lpFcb = ExtFcbToFcb(lpXfcb);
|
|
|
|
/* Now update the fcb and compute where we need to position */
|
|
/* to. */
|
|
lpFcb->fcb_cublock = lpFcb->fcb_rndm / div;
|
|
lpFcb->fcb_curec = lpFcb->fcb_rndm & 127;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FcbRandomBlockRead(xfcb FAR * lpXfcb, COUNT nRecords, COUNT * nErrorCode)
|
|
{
|
|
FcbCalcRec(lpXfcb);
|
|
|
|
/* Convert to fcb if necessary */
|
|
lpFcb = ExtFcbToFcb(lpXfcb);
|
|
|
|
do
|
|
FcbRead(lpXfcb, nErrorCode);
|
|
while ((--nRecords > 0) && (*nErrorCode == 0));
|
|
|
|
/* Now update the fcb */
|
|
lpFcb->fcb_rndm = FcbRec();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FcbRandomBlockWrite(xfcb FAR * lpXfcb, COUNT nRecords, COUNT * nErrorCode)
|
|
{
|
|
FcbCalcRec(lpXfcb);
|
|
|
|
/* Convert to fcb if necessary */
|
|
lpFcb = ExtFcbToFcb(lpXfcb);
|
|
|
|
do
|
|
FcbWrite(lpXfcb, nErrorCode);
|
|
while ((--nRecords > 0) && (*nErrorCode == 0));
|
|
|
|
/* Now update the fcb */
|
|
lpFcb->fcb_rndm = FcbRec();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FcbRandomIO(xfcb FAR * lpXfcb, COUNT * nErrorCode,
|
|
BOOL (*FcbFunc)(xfcb FAR *, COUNT *))
|
|
{
|
|
UWORD uwCurrentBlock;
|
|
UBYTE ucCurrentRecord;
|
|
|
|
FcbCalcRec(lpXfcb);
|
|
|
|
/* Convert to fcb if necessary */
|
|
lpFcb = ExtFcbToFcb(lpXfcb);
|
|
|
|
uwCurrentBlock = lpFcb->fcb_cublock;
|
|
ucCurrentRecord = lpFcb->fcb_curec;
|
|
|
|
(*FcbFunc)(lpXfcb, nErrorCode);
|
|
|
|
lpFcb->fcb_cublock = uwCurrentBlock;
|
|
lpFcb->fcb_curec = ucCurrentRecord;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
static sft FAR *FcbGetFreeSft(WORD FAR * sft_idx)
|
|
see get_free_sft in dosfns.c
|
|
*/
|
|
|
|
BOOL FcbCreate(xfcb FAR * lpXfcb)
|
|
{
|
|
WORD sft_idx;
|
|
sft FAR *sftp;
|
|
struct dhdr FAR *dhp;
|
|
COUNT FcbDrive;
|
|
|
|
/* get a free system file table entry */
|
|
if ((sftp = get_free_sft((WORD FAR *) & sft_idx)) == (sft FAR *) - 1)
|
|
return DE_TOOMANY;
|
|
|
|
/* Build a traditional DOS file name */
|
|
lpFcb = CommonFcbInit(lpXfcb, PriPathName, &FcbDrive);
|
|
|
|
/* check for a device */
|
|
dhp = IsDevice(PriPathName);
|
|
if (dhp || ((sftp->sft_status = dos_creat(PriPathName, 0)) >= 0))
|
|
{
|
|
sftp->sft_count += 1;
|
|
sftp->sft_mode = O_RDWR;
|
|
sftp->sft_attrib = 0;
|
|
sftp->sft_flags = dhp ?
|
|
((dhp->dh_attr & ~SFT_MASK) & ~SFT_FSHARED) | SFT_FDEVICE | SFT_FEOF : 0;
|
|
sftp->sft_psp = cu_psp;
|
|
fbcopy(lpFcb->fcb_fname, sftp->sft_name, FNAME_SIZE + FEXT_SIZE);
|
|
sftp->sft_dev = dhp;
|
|
lpFcb->fcb_sftno = sft_idx;
|
|
lpFcb->fcb_curec = 0;
|
|
lpFcb->fcb_recsiz = (dhp ? 0 : 128);
|
|
if (!dhp) lpFcb->fcb_drive = FcbDrive;
|
|
lpFcb->fcb_fsize = 0;
|
|
lpFcb->fcb_date = dos_getdate();
|
|
lpFcb->fcb_time = dos_gettime();
|
|
lpFcb->fcb_rndm = 0;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static fcb FAR *ExtFcbToFcb(xfcb FAR * lpExtFcb)
|
|
{
|
|
if (*((UBYTE FAR *) lpExtFcb) == 0xff)
|
|
return &lpExtFcb->xfcb_fcb;
|
|
else
|
|
return (fcb FAR *) lpExtFcb;
|
|
}
|
|
|
|
static fcb FAR *CommonFcbInit(xfcb FAR * lpExtFcb, BYTE * pszBuffer,
|
|
COUNT * pCurDrive)
|
|
{
|
|
fcb FAR *lpFcb;
|
|
|
|
/* convert to fcb if needed first */
|
|
lpFcb = ExtFcbToFcb(lpExtFcb);
|
|
|
|
/* Build a traditional DOS file name */
|
|
FcbNameInit(lpFcb, pszBuffer, pCurDrive);
|
|
|
|
/* and return the fcb pointer */
|
|
return lpFcb;
|
|
}
|
|
|
|
void FcbNameInit(fcb FAR * lpFcb, BYTE * pszBuffer, COUNT * pCurDrive)
|
|
{
|
|
/* Build a traditional DOS file name */
|
|
if (lpFcb->fcb_drive != 0)
|
|
{
|
|
*pCurDrive = lpFcb->fcb_drive;
|
|
pszBuffer[0] = 'A' + lpFcb->fcb_drive - 1;
|
|
pszBuffer[1] = ':';
|
|
pszBuffer += 2;
|
|
}
|
|
else
|
|
{
|
|
*pCurDrive = default_drive + 1;
|
|
}
|
|
|
|
ConvertName83ToNameSZ((BYTE FAR *)pszBuffer, (BYTE FAR *) lpFcb->fcb_fname);
|
|
|
|
/*
|
|
lpszFcbFname = (BYTE FAR *) lpFcb->fcb_fname;
|
|
for (loop = FNAME_SIZE; --loop >= 0; )
|
|
{
|
|
if (*lpszFcbFname != ' ')
|
|
*pszBuffer++ = *lpszFcbFname++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
lpszFcbFext = (BYTE FAR *) lpFcb->fcb_fext;
|
|
if (*lpszFcbFext != ' ')
|
|
{
|
|
*pszBuffer++ = '.';
|
|
for (loop = FEXT_SIZE; --loop >= 0; )
|
|
{
|
|
if (*lpszFcbFext != ' ')
|
|
*pszBuffer++ = *lpszFcbFext++;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
*pszBuffer = '\0';
|
|
*/
|
|
}
|
|
|
|
BOOL FcbOpen(xfcb FAR * lpXfcb)
|
|
{
|
|
WORD sft_idx;
|
|
sft FAR *sftp;
|
|
struct dhdr FAR *dhp;
|
|
COUNT FcbDrive;
|
|
|
|
/* get a free system file table entry */
|
|
if ((sftp = get_free_sft((WORD FAR *) & sft_idx)) == (sft FAR *) - 1)
|
|
return DE_TOOMANY;
|
|
|
|
/* Build a traditional DOS file name */
|
|
lpFcb = CommonFcbInit(lpXfcb, PriPathName, &FcbDrive);
|
|
|
|
/* check for a device */
|
|
dhp = IsDevice(PriPathName);
|
|
if (dhp )
|
|
{
|
|
sftp->sft_count += 1;
|
|
sftp->sft_mode = O_RDWR;
|
|
sftp->sft_attrib = 0;
|
|
sftp->sft_flags =
|
|
((dhp->dh_attr & ~SFT_MASK) & ~SFT_FSHARED) | SFT_FDEVICE | SFT_FEOF;
|
|
sftp->sft_psp = cu_psp;
|
|
fbcopy(lpFcb->fcb_fname, sftp->sft_name, FNAME_SIZE + FEXT_SIZE);
|
|
sftp->sft_dev = dhp;
|
|
lpFcb->fcb_sftno = sft_idx;
|
|
lpFcb->fcb_curec = 0;
|
|
lpFcb->fcb_recsiz = 0;
|
|
lpFcb->fcb_fsize = 0;
|
|
lpFcb->fcb_date = dos_getdate();
|
|
lpFcb->fcb_time = dos_gettime();
|
|
lpFcb->fcb_rndm = 0;
|
|
return TRUE;
|
|
}
|
|
fbcopy((BYTE FAR *) & lpFcb->fcb_fname, (BYTE FAR *) & sftp->sft_name, FNAME_SIZE + FEXT_SIZE);
|
|
if ((UCOUNT)FcbDrive >= lastdrive) {
|
|
return DE_INVLDDRV;
|
|
}
|
|
if (CDSp->cds_table[FcbDrive].cdsFlags & CDSNETWDRV) {
|
|
COUNT result;
|
|
lpCurSft = (sfttbl FAR *)sftp;
|
|
result = int2f_Remote_call(REM_OPEN, 0, 0, 0, (VOID FAR *) sftp, 0, MK_FP(0, O_RDWR));
|
|
result = -result;
|
|
sftp->sft_status = result;
|
|
}
|
|
else {
|
|
sftp->sft_status = dos_open(PriPathName, O_RDWR);
|
|
sftp->sft_size = dos_getfsize(sftp->sft_status);
|
|
dos_getftime(sftp->sft_status,
|
|
(date FAR *) & sftp->sft_date,
|
|
(time FAR *) & sftp->sft_time);
|
|
|
|
}
|
|
if (sftp->sft_status >= 0)
|
|
{
|
|
lpFcb->fcb_drive = FcbDrive;
|
|
lpFcb->fcb_sftno = sft_idx;
|
|
lpFcb->fcb_curec = 0;
|
|
lpFcb->fcb_recsiz = 128;
|
|
lpFcb->fcb_fsize = sftp->sft_size;
|
|
lpFcb->fcb_date = sftp->sft_date;
|
|
lpFcb->fcb_time = sftp->sft_time;
|
|
lpFcb->fcb_rndm = 0;
|
|
sftp->sft_count += 1;
|
|
sftp->sft_mode = O_RDWR;
|
|
sftp->sft_attrib = 0;
|
|
sftp->sft_flags = 0;
|
|
sftp->sft_psp = cu_psp;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL FcbDelete(xfcb FAR * lpXfcb)
|
|
{
|
|
COUNT FcbDrive;
|
|
|
|
/* Build a traditional DOS file name */
|
|
CommonFcbInit(lpXfcb, PriPathName, &FcbDrive);
|
|
|
|
if ((UCOUNT)FcbDrive >= lastdrive) {
|
|
return DE_INVLDDRV;
|
|
}
|
|
current_ldt = &CDSp->cds_table[FcbDrive];
|
|
if (CDSp->cds_table[FcbDrive].cdsFlags & CDSNETWDRV) {
|
|
return -int2f_Remote_call(REM_DELETE, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
/* check for a device */
|
|
if (IsDevice(PriPathName))
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
BYTE FAR *lpOldDta = dta;
|
|
dmatch Dmatch;
|
|
|
|
dta = (BYTE FAR *) & Dmatch;
|
|
if (dos_findfirst(D_ALL, PriPathName[1] == ':' ? &PriPathName[2] : PriPathName) != SUCCESS)
|
|
{
|
|
dta = lpOldDta;
|
|
return FALSE;
|
|
}
|
|
do
|
|
{
|
|
if (dos_delete(Dmatch.dm_name) != SUCCESS)
|
|
{
|
|
dta = lpOldDta;
|
|
return FALSE;
|
|
}
|
|
}
|
|
while (dos_findnext() == SUCCESS);
|
|
dta = lpOldDta;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL FcbRename(xfcb FAR * lpXfcb)
|
|
{
|
|
rfcb FAR *lpRenameFcb;
|
|
COUNT FcbDrive;
|
|
|
|
/* Build a traditional DOS file name */
|
|
lpRenameFcb = (rfcb FAR *) CommonFcbInit(lpXfcb, PriPathName, &FcbDrive);
|
|
|
|
/* check for a device */
|
|
if (IsDevice(PriPathName))
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
BYTE FAR *lpOldDta = dta;
|
|
dmatch Dmatch;
|
|
|
|
dta = (BYTE FAR *) & Dmatch;
|
|
if (dos_findfirst(D_ALL, PriPathName[1] == ':' ? &PriPathName[2] : PriPathName) != SUCCESS)
|
|
{
|
|
dta = lpOldDta;
|
|
return FALSE;
|
|
}
|
|
|
|
do
|
|
{
|
|
fcb LocalFcb;
|
|
BYTE *pToName,
|
|
*pszFrom;
|
|
BYTE FAR *pFromPattern;
|
|
COUNT nIndex;
|
|
|
|
/* First, expand the find match into fcb style */
|
|
/* file name entry */
|
|
/* Fill with blanks first */
|
|
memset(LocalFcb.fcb_fname, ' ', FNAME_SIZE);
|
|
memset(LocalFcb.fcb_fext, ' ', FEXT_SIZE);
|
|
|
|
/* next move in the file name while overwriting */
|
|
/* the filler blanks */
|
|
pszFrom = Dmatch.dm_name;
|
|
pToName = LocalFcb.fcb_fname;
|
|
for (nIndex = 0; nIndex < FNAME_SIZE; nIndex++)
|
|
{
|
|
if (*pszFrom != 0 && *pszFrom != '.')
|
|
*pToName++ = *pszFrom++;
|
|
else if (*pszFrom == '.')
|
|
{
|
|
++pszFrom;
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (*pszFrom != '\0')
|
|
{
|
|
pToName = LocalFcb.fcb_fext;
|
|
for (nIndex = 0; nIndex < FEXT_SIZE; nIndex++)
|
|
{
|
|
if (*pszFrom != '\0')
|
|
*pToName++ = *pszFrom++;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Overlay the pattern, skipping '?' */
|
|
/* I'm cheating because this assumes that the */
|
|
/* struct alignments are on byte boundaries */
|
|
pToName = LocalFcb.fcb_fname;
|
|
for (pFromPattern = lpRenameFcb->renNewName,
|
|
nIndex = 0; nIndex < FNAME_SIZE + FEXT_SIZE; nIndex++)
|
|
{
|
|
if (*pFromPattern != '?')
|
|
*pToName++ = *pFromPattern++;
|
|
else
|
|
++pFromPattern;
|
|
}
|
|
|
|
/* now to build a dos name again */
|
|
LocalFcb.fcb_drive = 0;
|
|
FcbNameInit((fcb FAR *) & LocalFcb, PriPathName, &FcbDrive);
|
|
|
|
if (dos_rename(Dmatch.dm_name,
|
|
PriPathName[1] == ':' ? &PriPathName[2] : PriPathName) != SUCCESS)
|
|
{
|
|
dta = lpOldDta;
|
|
return FALSE;
|
|
}
|
|
}
|
|
while (dos_findnext() == SUCCESS);
|
|
dta = lpOldDta;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
void MoveDirInfo(dmatch FAR * lpDmatch, struct dirent FAR * lpDir)
|
|
{
|
|
BYTE FAR *lpToName,
|
|
FAR * lpszFrom;
|
|
COUNT nIndex;
|
|
|
|
/* First, expand the find match into dir style */
|
|
/* file name entry */
|
|
/* Fill with blanks first */
|
|
|
|
fmemset(lpDir->dir_name, ' ', FNAME_SIZE);
|
|
fmemset(lpDir->dir_ext , ' ', FEXT_SIZE );
|
|
|
|
/* next move in the file name while overwriting */
|
|
/* the filler blanks */
|
|
lpszFrom = lpDmatch->dm_name;
|
|
lpToName = (BYTE FAR *)lpDir->dir_name;
|
|
for (nIndex = 0; nIndex < FNAME_SIZE; nIndex++)
|
|
{
|
|
if (*lpszFrom != 0 && *lpszFrom != '.')
|
|
*lpToName++ = *lpszFrom++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (*lpszFrom != '\0')
|
|
{
|
|
if (*lpszFrom == '.')
|
|
++lpszFrom;
|
|
lpToName = (BYTE FAR *)lpDir->dir_ext;
|
|
for (nIndex = 0; nIndex < FEXT_SIZE; nIndex++)
|
|
{
|
|
if (*lpszFrom != '\0')
|
|
*lpToName++ = *lpszFrom++;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
for (nIndex = 0; nIndex < 10; nIndex++)
|
|
lpDir->dir_reserved[nIndex] = 0;
|
|
lpDir->dir_attrib = lpDmatch->dm_attr_fnd;
|
|
lpDir->dir_time = lpDmatch->dm_time;
|
|
lpDir->dir_date = lpDmatch->dm_date;
|
|
lpDir->dir_start = lpDmatch->dm_cluster;
|
|
lpDir->dir_size = lpDmatch->dm_size;
|
|
}
|
|
|
|
BOOL FcbClose(xfcb FAR * lpXfcb)
|
|
{
|
|
sft FAR *s;
|
|
|
|
/* Convert to fcb if necessary */
|
|
lpFcb = ExtFcbToFcb(lpXfcb);
|
|
|
|
/* Get the SFT block that contains the SFT */
|
|
if ((s = FcbGetSft(lpFcb->fcb_sftno)) == (sft FAR *) - 1)
|
|
return FALSE;
|
|
|
|
/* If this is not opened another error */
|
|
if (s->sft_count == 0)
|
|
return FALSE;
|
|
|
|
if (s->sft_flags & SFT_FSHARED)
|
|
{
|
|
int2f_Remote_call(REM_CLOSE, 0, 0, 0, (VOID FAR *) s, 0, 0);
|
|
}
|
|
|
|
/* now just drop the count if a device, else */
|
|
/* call file system handler */
|
|
if (s->sft_flags & SFT_FDEVICE)
|
|
{
|
|
s->sft_count -= 1;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
s->sft_count -= 1;
|
|
if (s->sft_count > 0)
|
|
return SUCCESS;
|
|
else
|
|
{
|
|
/* change time and set file size */
|
|
dos_setftime(s->sft_status,
|
|
(date FAR *) & lpFcb->fcb_date,
|
|
(time FAR *) & lpFcb->fcb_time);
|
|
dos_setfsize(s->sft_status,
|
|
lpFcb->fcb_fsize);
|
|
return dos_close(s->sft_status) == SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL FcbFindFirst(xfcb FAR * lpXfcb)
|
|
{
|
|
BYTE FAR *lpDir;
|
|
COUNT FcbDrive;
|
|
psp FAR *lpPsp = MK_FP(cu_psp, 0);
|
|
|
|
/* First, move the dta to a local and change it around to match */
|
|
/* our functions. */
|
|
lpDir = (BYTE FAR *) dta;
|
|
dta = (BYTE FAR *) & Dmatch;
|
|
|
|
/* Next initialze local variables by moving them from the fcb */
|
|
lpFcb = CommonFcbInit(lpXfcb, SecPathName, &FcbDrive);
|
|
if (lpXfcb->xfcb_flag == 0xff)
|
|
{
|
|
wAttr = lpXfcb->xfcb_attrib;
|
|
fbcopy(lpXfcb, lpDir, 7);
|
|
lpDir += 7;
|
|
}
|
|
else
|
|
wAttr = D_ALL;
|
|
|
|
*lpDir++ = FcbDrive;
|
|
|
|
|
|
if (dos_findfirst(wAttr, SecPathName) != SUCCESS)
|
|
{
|
|
dta = lpPsp->ps_dta;
|
|
return FALSE;
|
|
}
|
|
|
|
MoveDirInfo((dmatch FAR *) & Dmatch, (struct dirent FAR *)lpDir);
|
|
|
|
lpFcb->fcb_dirclst = Dmatch.dm_cluster;
|
|
lpFcb->fcb_diroff = Dmatch.dm_entry;
|
|
|
|
/*
|
|
This is undocumented and seen using Pcwatch and Ramview.
|
|
The First byte is the current directory count and the second seems
|
|
to be the attribute byte.
|
|
*/
|
|
lpFcb->fcb_sftno = Dmatch.dm_drive; /* MSD seems to save this @ fcb_date.*/
|
|
#if 0
|
|
lpFcb->fcb_cublock = Dmatch.dm_entry;
|
|
lpFcb->fcb_cublock *= 0x100;
|
|
lpFcb->fcb_cublock += wAttr;
|
|
#endif
|
|
|
|
dta = lpPsp->ps_dta;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FcbFindNext(xfcb FAR * lpXfcb)
|
|
{
|
|
BYTE FAR *lpDir;
|
|
COUNT FcbDrive;
|
|
psp FAR *lpPsp = MK_FP(cu_psp, 0);
|
|
|
|
/* First, move the dta to a local and change it around to match */
|
|
/* our functions. */
|
|
lpDir = (BYTE FAR *) dta;
|
|
dta = (BYTE FAR *) & Dmatch;
|
|
|
|
/* Next initialze local variables by moving them from the fcb */
|
|
lpFcb = CommonFcbInit(lpXfcb, SecPathName, &FcbDrive);
|
|
if ((xfcb FAR *) lpFcb != lpXfcb)
|
|
{
|
|
wAttr = lpXfcb->xfcb_attrib;
|
|
fbcopy(lpXfcb, lpDir, 7);
|
|
lpDir += 7;
|
|
}
|
|
else
|
|
wAttr = D_ALL;
|
|
|
|
/* Reconstrct the dirmatch structure from the fcb */
|
|
*lpDir++ = FcbDrive;
|
|
Dmatch.dm_drive = lpFcb->fcb_sftno;
|
|
|
|
fbcopy(lpFcb->fcb_fname, (BYTE FAR *) Dmatch.dm_name_pat, FNAME_SIZE + FEXT_SIZE);
|
|
DosUpFMem((BYTE FAR *) Dmatch.dm_name_pat, FNAME_SIZE + FEXT_SIZE);
|
|
|
|
Dmatch.dm_attr_srch = wAttr;
|
|
Dmatch.dm_entry = lpFcb->fcb_diroff;
|
|
Dmatch.dm_cluster = lpFcb->fcb_dirclst;
|
|
|
|
if (dos_findnext() != SUCCESS)
|
|
{
|
|
dta = lpPsp->ps_dta;
|
|
CritErrCode = 0x12;
|
|
return FALSE;
|
|
}
|
|
|
|
MoveDirInfo((dmatch FAR *) & Dmatch, (struct dirent FAR *)lpDir);
|
|
lpFcb->fcb_dirclst = Dmatch.dm_cluster;
|
|
lpFcb->fcb_diroff = Dmatch.dm_entry;
|
|
|
|
lpFcb->fcb_sftno = Dmatch.dm_drive;
|
|
#if 0
|
|
lpFcb->fcb_cublock = Dmatch.dm_entry;
|
|
lpFcb->fcb_cublock *= 0x100;
|
|
lpFcb->fcb_cublock += wAttr;
|
|
#endif
|
|
|
|
dta = lpPsp->ps_dta;
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|