Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to cope with non-terminated actions (like FindFirst/Next)

3 views
Skip to first unread message

R.Wieser

unread,
Dec 9, 2005, 8:01:18 AM12/9/05
to
Hello All,

My subject-line may be a bit fuzzy, but I hope this clears it up : I'm
trying to create a DOS IFS (Installable File System) that connects (using a
packet-driver) to another computer (running Windows). Yep, yet another
remote drive. :-)

The problem I'm having is with the way DOS does a Find-File. It never
terminates the action, so I don't know when to close the connection, and
clean-up (for both the DOS and the Windows ends of the connection).

Is there a (standard) mechanism that I can use for cases like these ? Or
does anyone know of a trick that has allready been used in other
remote-drive IFS programs ?

I would sure like to know :-)

Regards,
Rudy Wieser

Rod Pemberton

unread,
Dec 9, 2005, 6:07:58 PM12/9/05
to
2nd post attempt...

"R.Wieser" <spam...@crayne.org> wrote in message
news:43997ee8$0$11062$e4fe...@news.xs4all.nl...


> Hello All,
>
> My subject-line may be a bit fuzzy, but I hope this clears it up : I'm
> trying to create a DOS IFS (Installable File System) that connects (using
a
> packet-driver) to another computer (running Windows). Yep, yet another
> remote drive. :-)
>
> The problem I'm having is with the way DOS does a Find-File. It never
> terminates the action,

What are you expecting to "terminate the action"? Or, what do you mean by
DOS "never terminates the action"?

> so I don't know when to close the connection, and
> clean-up (for both the DOS and the Windows ends of the connection).
>
> Is there a (standard) mechanism that I can use for cases like these ? Or
> does anyone know of a trick that has allready been used in other
> remote-drive IFS programs ?
>
> I would sure like to know :-)
>
> Regards,
> Rudy Wieser

Well, let's hope someone else can answer your questions: I can't.

When it comes to DOS IFS's, everyone mentions MSCDEX extensions,
INT 2Fh (Multiplex) instead of INT 21h, and
Andrew Schulman's "Undocumented DOS", but
noone ever tells on the Internet how it is done...

My probably less than enlightening hints:
1) findfirst/next don't actually open anything, so what cleanup needs to be
done?
2) In addition to findfirst(), there is _dos_findfirst().
3) The LFN API has an explicit function "FindClose" int 0x21,AX=71a1h.
4) Use Henrik Haftmann's DOSLFN driver for LFN functions. DJGPP has LFN
support,
but Watcom doesn't. You can use "LFN Create or Open File"
int0x21, ax=716Ch followed by "Close file" int 0x21,ax=3eh to force
DOSLFN to update its internal cache when using Watcom.


Rod Pemberton


Rod Pemberton

unread,
Dec 9, 2005, 5:57:40 PM12/9/05
to

"R.Wieser" <spam...@crayne.org> wrote in message
news:43997ee8$0$11062$e4fe...@news.xs4all.nl...
> Hello All,
>
> My subject-line may be a bit fuzzy, but I hope this clears it up : I'm
> trying to create a DOS IFS (Installable File System) that connects (using
a
> packet-driver) to another computer (running Windows). Yep, yet another
> remote drive. :-)
>
> The problem I'm having is with the way DOS does a Find-File. It never
> terminates the action,

What are you expecting to "terminate the action"? Or, what do you mean by


DOS "never terminates the action"?

> so I don't know when to close the connection, and


> clean-up (for both the DOS and the Windows ends of the connection).
>
> Is there a (standard) mechanism that I can use for cases like these ? Or
> does anyone know of a trick that has allready been used in other
> remote-drive IFS programs ?
>
> I would sure like to know :-)
>
> Regards,
> Rudy Wieser

Ted Davis

unread,
Dec 9, 2005, 8:41:59 PM12/9/05
to

What he's referring to is that findfirst leaves DOS structures
populated and in general in a state pending some concluding action.
The proper approach, if memory serves, is to *always* call findnext as
many times as required for it return failure to find - this can be
totally unnecessary from a programmer's point of view when a single
file is sought and findnext is obviously not going to find anything,
but it is necessary from the OS's point of view because in order for
findnext to have meaning, the structures from findfirst must be
retained. findfirst doesn't have a way of knowing that the only file
has been found, but findnext can tell when there are no more to find,
and therefore has to call the findfirst/findnext cleanup function.

The two functions form a pair: findfirst begins the process and
findnext terminates it. Note that there is no findonly function and
"first" implies "next".

--
T.E.D. (tda...@gearbox.maem.umr.edu)

R.Wieser

unread,
Dec 9, 2005, 10:06:54 PM12/9/05
to
Ted Davis <spam...@crayne.org> schreef in berichtnieuws
ntbkp116vq5moe853...@4ax.com...

Hello Ted,

[snip]

> The proper approach, if memory serves, is to *always* call findnext as
> many times as required for it return failure to find

I'm afraid that even the designers of the OS violate this approach.

A simple "dir <remote drive>" shows at least two non-closed find-first/next
actions (one for the label, and one for a file without an extension. I can
show a logging of the INT 2Fh, AH=11h calls if you like).

And those types of non-closed actions are exactly the ones I need to handle
... :-)

Regards,
Rudy Wieser

Ted Davis

unread,
Dec 10, 2005, 12:48:52 PM12/10/05
to
On Sat, 10 Dec 2005 04:06:54 +0100, "R.Wieser" <spam...@crayne.org>
wrote:

You could try calling INT 2F AX=111C with the registers set up for the
structures.

Nobody ever accused Microsoft of being consistent, and nobody but
Microsoft ever said DOS wasn't buggy.

--
T.E.D. (tda...@gearbox.maem.umr.edu)

Rod Pemberton

unread,
Dec 10, 2005, 8:08:20 PM12/10/05
to
If anyone is interested,
the CPHANTOM file has an IFS written in C based on Schulman's book.

http://www.pcausa.com/resources/ifsqlist.html (bottom of page)
http://mvb.saic.com/freeware/vmslt99a/nt/
http://wwwvms.mppmu.mpg.de/vmssig/archive/C/

The first link has an extra file in the zip called int2f.asm.


Rod Pemberton


Rod Pemberton

unread,
Dec 10, 2005, 9:12:16 PM12/10/05
to
Jim Harper's DDJ SCSI redirector code was online for a while:

1) Google's cache message
2) CDROM.C by Jim Harper
3) ST01.C by Jim Harper

Rod Pemberton

This is Google's cache of http://www.ddj.com/ftp/1993/1993.03/cdrom.txt as
retrieved on Aug 11, 2005 04:35:36 GMT. Google's cache is the snapshot that
we took of the page as we crawled the web. The page may have changed since
that time. Click here for the current page without highlighting. This
cached page may reference images which are no longer available. Click here
for the cached text only. To link to or bookmark this page, use the
following url:
http://www.google.com/search?q=cache:HqpSYfzkDWgJ:www.ddj.com/ftp/
1993/1993.03/cdrom.txt+%22CD-ROM+redirector+for+High+Sierra+and+ISO+9660+dis
ks%22&hl=en

/***************************************************************************
***
* CDROM.C -- by Jim Harper (EXCERPTED LISTING)
* A CD-ROM redirector for High Sierra and ISO 9660 disks.

****************************************************************************
*/

/*...#include directives removed...*/
#define SetC(X) (X) |= 0x01
#define ClrC(X) (X) &= ~0x01

extern unsigned _psp, /* Runtime gives us these variables */
end;
char *IOBuf; /* I/O Buffer ptr */

/* Table of saved open SystemFileTable's (SFT's) for DoCloseAll() */
struct SFT _far *CloseTab[MAXCLOSEALL];
unsigned StkSeg, DataSeg,
DriveNo, DriveFlags,
TsrStkSeg, TsrStkPtr,
AppStkSeg, AppStkPtr,
CDType, FIDoff,
Nameoff, Dateoff,
Flagsoff, Blkoff,
Sizeoff, BlkSize,
ChainFlag,
MyStack[STACKSIZE];
unsigned _AX,_BX,_CX,_DX,_DS,_ES,_DI,_FLAGS;
struct IntRegs {
unsigned ES; unsigned DS;
unsigned DI; unsigned SI;
unsigned BP; unsigned SP;
unsigned BX; unsigned DX;
unsigned CX; unsigned AX;
unsigned IP; unsigned CS;
unsigned FLAGS;
};
int Active = 0;
struct isoVolDesc *isoVolDescp;
struct isoDirRec *isoDp;
struct hsVolDesc *hsVolDescp;
struct hsDirRec *hsDp;
struct Cmd Cmd;
struct DirEnt RootEnt,
DirCache[CACHESIZE];
/* Important pointers */
struct SDB _far *SDBp; /* Ptr to Dos Search Data Blk */
struct FDB _far *FDBp; /* Ptr to Dos Found Data Blk */
struct LOL _far *LOLp; /* Ptr to list of lists */
struct CDS _far *CDSp; /* Ptr to cur dir tab entry */
/* These pointers are set according to DOS 3.xx or 4.xx */
char _far *SWAPp, /* Ptr to Dos swap area */
_far *FN1p, /* Ptr to Dos resolved name */
_far * _far *DTApp, /* Ptr to Ptr to Current DTA */
_far * _far *SFTpp, /* Ptr to Ptr to Current SFT */
_far *DosDp, /* Ptr to dir ent for file */
_far *Sattrp, /* Ptr to search attr */
_far *OpenModep; /* Ptr to open mode */
unsigned _far *PSPp; /* Ptr to current PSP */
char *HiSierra = "HISIERRA ",
*Iso9660 = "ISO9660 ";
/*...function prototypes removed...*/
/***********************************************************************/
main(int argc, char *argv[])
{ union REGS regs;
struct SREGS sregs;
unsigned _far *EnvBlkp;
int i, Junk, CdsLen, ProgSize;
DriveNo = 999;
if (argc > 1) {
if (!strcmp(argv[1],"-u") || ! strcmp(argv[1],"-U")) {
regs.h.ah = 0x11;
regs.h.al = DEINSTALL;
int86x(INT2F,&regs,&regs,&sregs);
exit(0);
}
if (argv[1][0] >= 'A' && argv[1][0] <= 'Z' &&
argv[1][1] == ':' && argv[1][2] == '\0') {
DriveNo = argv[1][0] - 'A';
}
if (argv[1][0] >= 'a' && argv[1][0] <= 'z' &&
argv[1][1] == ':' && argv[1][2] == '\0') {
DriveNo = argv[1][0] - 'a';
}
}
if (DriveNo > 26) {
MsgOut("usage: cdrom [A-Z]:\r\n");
exit(1);
}
segread(&sregs); /* Get our stack and data segments */
StkSeg = sregs.ss;
DataSeg = sregs.ds;
regs.h.ah = FUNCID; /* Check if SCSI TSR is present */
regs.h.al = INSTALLCHK;
int86x(INT2F,&regs,&regs,&sregs);
if (regs.h.al != 0xff) {
MsgOut("Scsi tsr not found!\r\n");
exit(1);
}
/* Check if there's a High Sierra or ISO9660 disk in the drive. */
if (ScsiRead(0x10L)) {
MsgOut("IO error.\r\n");
exit(1);
}
hsVolDescp = (struct hsVolDesc *) IOBuf;
isoVolDescp = (struct isoVolDesc *) IOBuf;
CDType = UNKNOWN;
Blkoff = 2;
Sizeoff = 10;
Dateoff = 18;
FIDoff = 32;
Nameoff = 33;
strcpy(RootEnt.FName,"ROOT-CDROM ");
if (strncmp(hsVolDescp->ID,"CDROM",5) == 0) { /* it's High Sierra */
CDType = HIGHSIERRA;
Flagsoff = 24;
hsDp = (struct hsDirRec *)hsVolDescp->DirRec;
RootEnt.Fattr = _A_SUBDIR;
RootEnt.FTime = ToDosTime(hsDp->Date);
RootEnt.FDate = ToDosDate(hsDp->Date);
RootEnt.BlkNo = hsDp->ExtLocLSB;
RootEnt.FSize = hsDp->DataLenLSB;
RootEnt.ParentBlk = hsDp->ExtLocLSB;
BlkSize = hsVolDescp->BlkSizeLSB;
MsgOut("High Sierra disk...\r\n");
}
if (strncmp(isoVolDescp->ID,"CD001",5) == 0) { /* it's ISO 9660 */
CDType = ISO9660;
Flagsoff = 25;
isoDp = (struct isoDirRec *)isoVolDescp->DirRec;
RootEnt.Fattr = _A_SUBDIR;
RootEnt.FTime = ToDosTime(isoDp->Date);
RootEnt.FDate = ToDosDate(isoDp->Date);
RootEnt.BlkNo = isoDp->ExtLocLSB;
RootEnt.FSize = isoDp->DataLenLSB;
RootEnt.ParentBlk = isoDp->ExtLocLSB;
BlkSize = isoVolDescp->BlkSizeLSB;
MsgOut("ISO 9660 disk...\r\n");
}
if (CDType == UNKNOWN) {
MsgOut("Unknown disk type..\r\n");
exit(1);
}
regs.h.ah = 0x52; /* Get Address of List of Lists */
int86x(0x21,&regs,&regs,&sregs);
FP_SEG(LOLp) = sregs.es;
FP_OFF(LOLp) = regs.x.bx;
regs.x.ax = 0x5d06; /* Get address of Dos Swap area */
int86x(0x21,&regs,&regs,&sregs);
FP_SEG(SWAPp) = sregs.ds;
FP_OFF(SWAPp) = regs.x.si;
if (DriveNo > LOLp->LastDrive) {
MsgOut("Drive # to high.\r\n");
exit(1);
}
MsgOut("DOS version "); ToHex(_osmajor); MsgOut("."); ToHex(_osminor);
/* Now set the offsets within Dos according to 3.3x, 4.xx or 5.xx */
if ( _osmajor == 3 && _osminor >= 30) {
CdsLen = 0x51;
PSPp = (unsigned _far *)(SWAPp + 0x10U);
FN1p = SWAPp + 0x0092U;
Sattrp = SWAPp + 0x023aU;
DosDp = SWAPp + 0x01a7U;
SDBp = (struct SDB _far *) (SWAPp + 0x0192U);
DTApp = (char _far * _far *)(SWAPp + 0x000cU);
SFTpp = (char _far * _far *)(SWAPp + 0x0268U);
} else if (_osmajor == 4 || _osmajor == 5) {
CdsLen = 0x58;
PSPp = (unsigned _far *)(SWAPp + 0x10U);
FN1p = SWAPp + 0x009eU;
Sattrp = SWAPp + 0x024dU;
DosDp = SWAPp + 0x01b3U;
SDBp = (struct SDB _far *) (SWAPp + 0x019eU);
DTApp = (char _far * _far *)(SWAPp + 0x000cU);
SFTpp = (char _far * _far *)(SWAPp + 0x027eU);
} else {
MsgOut("Not DOS 3.3x, 4.xx or 5.xx\r\n");
exit(1);
}
/* Cast ptr to table entry pointer */
CDSp = (struct CDS _far *) (LOLp->CDS + DriveNo * CdsLen);
DriveFlags = CDSp->Flags; /* Turn on network & physical bits
*/
CDSp->Flags = 0xC000;
CDSp->RootOff = 2;

CDSp->CurDir[0] = 'A' + DriveNo; /* Set to root */
CDSp->CurDir[1] = ':';
CDSp->CurDir[2] = '\\';
CDSp->CurDir[3] = '\0';

for (i = 0; i < STACKSIZE; i++) /* Initialize our stack */
MyStack[i] = 0x4141;
TsrStkSeg = DataSeg; /* Initialize stack and bottom of program.
*/
TsrStkPtr = (unsigned)&MyStack[STACKSIZE];
if (TsrStkPtr & 0x1U) /* Make sure stack is on a word boundry */
TsrStkPtr--;
/* Program size in paragraphs w/o a heap */
ProgSize = (StkSeg + (((unsigned)&end) >> 4)) - _psp + 1;
for (i = 1; i < CACHESIZE - 1; i++) { /* Initialize cache */
DirCache[i].Forw = &DirCache[i+1];
DirCache[i].Back = &DirCache[i-1];
}
DirCache[0].Forw = &DirCache[1];
DirCache[0].Back = &RootEnt;
DirCache[CACHESIZE-1].Forw = &RootEnt;
DirCache[CACHESIZE-1].Back = &DirCache[CACHESIZE-2];

/* Root dirent provides anchor into the cache */
RootEnt.Forw = &DirCache[0];
RootEnt.Back = &DirCache[CACHESIZE-1];
/* Close files */
_dos_close(0); /* stdin */
_dos_close(1); /* stdout */
_dos_close(2); /* stderr */
Old2F = _dos_getvect(INT2F); /* Grab multiplex interrupt */
_dos_setvect(INT2F,New2F);
FP_SEG(EnvBlkp) = _psp; /* Free the environment */
FP_OFF(EnvBlkp) = 0x2c;
_dos_freemem(*EnvBlkp);
_dos_setblock(ProgSize,_psp,&Junk); /* Shrink our program size */
_dos_keep(0,ProgSize); /* TSR ourself */
}
/***** New2F(struct IntRegs IntRegs) -- our interrupt 2F handler. *****/
void _interrupt _far New2F(struct IntRegs IntRegs)
{
/* See if we handle this function */
if ((IntRegs.AX >> 8U) != 0x11 || Active)
_chain_intr(Old2F);
if ((IntRegs.AX & 0xff) == INSTALLCHK) { /* Install check?? */
IntRegs.AX = 0x00ff;
return;
}
Active++; /* Set flag saying we're active */
ChainFlag = 0; /* Don't chain out by default */
/* Save needed regs from stack */
_AX = IntRegs.AX; _BX = IntRegs.BX;
_CX = IntRegs.CX; _DX = IntRegs.DX;
_DS = IntRegs.DS; _ES = IntRegs.ES;
_DI = IntRegs.DI; _FLAGS = IntRegs.FLAGS;
_asm /* Switch to own stack */
{
cli ; Interrupts off
mov WORD PTR AppStkPtr,sp ; Save app stack
mov WORD PTR AppStkSeg,ss
mov sp,WORD PTR TsrStkPtr ; Load new stack
mov ss,WORD PTR TsrStkSeg
sti ; Interrupts on
}
switch(_AX & 0xff) /* handle the command */
{
case DEINSTALL: DeInstall(); break;
case CHDIR: DoChDir(); break;
case CLOSE: DoClose(); break;
case READ: DoRead(); break;
case GETSPACE: DoGetSpace(); break;
case GETATTR: DoGetAttr(); break;
case OPEN: DoOpen(); break;
case FINDFIRST: DoFindFirst(); break;
case FINDNEXT: DoFindNext(); break;
case SEEK: DoSeek(); break;
case CLOSEALL: DoCloseAll(); break;
case PATHNAME: Spoof(); /* hack */
case 0x25:
default: ChainFlag = 1; break;
}
_asm /* Switch back to app stack */
{
cli ; Interrupts off
mov sp,WORD PTR AppStkPtr ; Load app stack
mov ss,WORD PTR AppStkSeg
sti ; Interrupts on
}
if (ChainFlag) { /* If anyone set the chain flag, chain out */
Active = 0;
_chain_intr(Old2F);
}
/* Restore (possibly modifed) registers */
IntRegs.AX = _AX; IntRegs.BX = _BX;
IntRegs.CX = _CX; IntRegs.DX = _DX;
IntRegs.FLAGS = _FLAGS;
Active = 0; /* Clear Active Flag */
}

/***************************************************************************
***
* ST01.C -- by Jim Harper. (EXCERPTED LISTING) -- A simple SCSI transport
TSR
* that communicates with CDROM.C module via INT2F. The DoScsi() routine
below
* handles the actual work of of transferring data to/from the SCSI device.

****************************************************************************
*/
void DoScsi(void)
{
struct Cmd _far *Cmdp;
unsigned Phase,
NumBytes,
Byte = 0,
i;
FP_SEG(Cmdp) = _DS;
FP_OFF(Cmdp) = _DX;

FP_SEG(Datap) = Cmdp->DSeg;
FP_OFF(Datap) = Cmdp->DOff;

NumBytes = 512;

Endp = Datap;
Cmdp->Count = 0L;

/* Clear control reg */
*RegPort = 0x00;

/* Bus has gotta be free */
if ((*RegPort & BUSYBIT) != 0x00) {
Cmdp->Stat = 0x80;
return;
}
/* Clear control reg */
*RegPort = 0x00;
/* Assert HBA's address */
*DataPort = 0x80;
/* Set the arbitration bit */
*RegPort = (ARBITSTART | PENABLE);
/* Wait for arbitration to complete */
for (Timer1 = HZ * 3; (*RegPort & ARBITDONE) == 0x00;)
if (!Timer1) {
Cmdp->Stat = 0x81;
return;
}
/* OR the target & our ID bits into the data reg */
*DataPort = 0x80 | (0x01 << (unsigned)Cmdp->ID);

/* Assert SELect, bus enable, deassert arbitration */
*RegPort = (SEL | PENABLE | BUSENABLE);
for (Timer1 = 2; Timer1;)
;
/* Wait for BUSY */
for (Timer1 = HZ * 3; (*RegPort & BUSYBIT) == 0x00;)
if (!Timer1) {
*RegPort = 0x00;
Cmdp->Stat = 0x82;
return;
}
/* Drop Select */
*RegPort = (PENABLE | BUSENABLE);

/* Wait for command phase */
for (Timer1 = HZ * 3; ((Phase = (*RegPort & PHASEMASK)) != COMMAND);)
if (!Timer1) {
*RegPort = 0x00;
Cmdp->Stat = 0x83;
return;
}
Cmdp->Stat = 0x00;
for (Timer1 = HZ * 10;;) { /* Cmd must complete in 10s */
if (!Timer1) {
Cmdp->Stat = 0x84;
return;
}
Phase = *RegPort & PHASEMASK;
switch(Phase) {
case COMMAND:
while ((*RegPort & PHASEMASK) == COMMAND)
*DataPort = Cmdp->CDB[Byte++];
break;
case DATAIN:
_asm
{
push es
push ds
mov cx,NumBytes
les di,Datap
lds si,DataPort
cld
repeat1:
movsb
dec si
loop repeat1
pop ds
pop es
}
Datap += NumBytes;
break;
case DATAOUT:
_asm
{
push es
push ds
mov cx,NumBytes
les di,DataPort
lds si,Datap
cld
repeat2:
movsb
dec di
loop repeat2
pop ds
pop es
}
break;
case STATUS: Cmdp->Stat = *DataPort; break;
case MSGIN: Cmdp->Sense = *DataPort; break;
case BUSFREE: *RegPort = 0x00;
Cmdp->Count += Datap - Endp;
return;
}
/* Delay long enough */
for (i = 0; (*RegPort & REQ) && i < 5; i++)
;
}
}


Rod Pemberton

unread,
Dec 11, 2005, 5:02:28 AM12/11/05
to

"R.Wieser" <spam...@crayne.org> wrote in message
news:43997ee8$0$11062$e4fe...@news.xs4all.nl...
> Hello All,
>
> Is there a (standard) mechanism that I can use for cases like these ? Or
> does anyone know of a trick that has allready been used in other
> remote-drive IFS programs ?

I think I found the answer to your question of findfirst/next may have been
solved in CMU's Mach DOS emulator. The
network redirector code in CMU's Mach DOS emulator is in dos.h and dos_fs.c.
These files made it into DOSEMU and PCEMU as mfs.c, mfs.h, emufs.S.

David Hedley's PCEMU http://pcemu.sourceforge.net/
Robert Sanders' DOSEMU http://dosemu.sourceforge.net/

CMU's Mach DOS emulator i386.mdos.src.tar.Z from here:
http://www.cs.cmu.edu/afs/cs.cmu.edu/project/mach/public/src/


Rod Pemberton


R.Wieser

unread,
Dec 11, 2005, 9:04:11 AM12/11/05
to
Rod Pemberton <dont...@bitbucket.cmm> schreef in berichtnieuws
dngteh$8sr$1...@domitilla.aioe.org...

Hello Rod,

[Snip]


> I think I found the answer to your question of findfirst/next may have
been
> solved in CMU's Mach DOS emulator. The
> network redirector code in CMU's Mach DOS emulator is in dos.h and
dos_fs.c.
> These files made it into DOSEMU and PCEMU as mfs.c, mfs.h, emufs.S.

Thanks for the links. I'll take a look :-)

Regards,
Rudy Wieser

R.Wieser

unread,
Dec 11, 2005, 8:39:36 AM12/11/05
to
Ted Davis <spam...@crayne.org> schreef in berichtnieuws
g45mp151kpvsckm7b...@4ax.com...

Hello Ted,

[Snip]

> You could try calling INT 2F AX=111C with the registers set up
> for the structures.

Yes, I could. I could allso just send a "terminate find action" to the
tremote computer. But when ? How can/do I decide that that
find-first/next has got enough ?

> Nobody ever accused Microsoft of being consistent, and nobody but
> Microsoft ever said DOS wasn't buggy.

It has got a better track-record than Windows has :-)

Regards,
Rudy Wieser

R.Wieser

unread,
Dec 11, 2005, 8:34:49 AM12/11/05
to

Guys, guys. For some reason I do not seem to get thru : I *CANNOT* add the
OS or user-program. The only thing I can do is to recieve IFS requests, and
act upon them.

To illustrate what I mean, some user could decide to loop recursivily thru
all directories on the remote drive. It means that I could have about 64
find-first/find-next calls open. All of which are not closed.

I don't know if you guys are aware, but when you type "dir drive:\*.*" the
OS (including W95 & W98, not checked on above versions) uses simple
dos-calls (find-first, find next), and not the LFN variants. And there is
*nothing* I can change about it ....

Hope that clarifies it a bit.

Regards,
Rudy Wieser


Skarmander

unread,
Dec 11, 2005, 2:54:03 PM12/11/05
to
Then set aside a circular buffer for FindFirst requests, and discard them on
a FIFO basis as you run out. You seem to be asking for a way to implement
miracles. You cannot both have a limited number of pending requests and the
demand that all outstanding requests must remain valid even if none are
closed explicitly.

Of course this does mean you'll need synchronization if calls are to be
reentrant (I don't know if this is required). If you can't do *that* either,
you'll need a clever lock-free data structure.

If you want to be really good you can use a dynamically growing structure
and expire FindFirst requests based on time only (it's extremely unlikely a
FindFirst handle will be needed for more than a few seconds), or a hybrid
approach where you have a dynamically growing structure with an upper bound
where you do some trade-off between memory used and maximum time a request
remains valid. You could even measure "time" in the number of FindFirst
calls made overall if it's too complicated to use real time.

I'd imagine FindFirst requests do not take up much memory, if properly
implemented. You can probably afford a lot of open requests and get away
with a statically sized queue/hash table. No well-behaved application can
open a large number of FindFirsts, close none of them, and still expect for
every single one to remain valid.

S.

R.Wieser

unread,
Dec 11, 2005, 4:37:56 PM12/11/05
to
Skarmander <spam...@crayne.org> schreef in berichtnieuws
439c83f3$0$24373$e4fe...@news.xs4all.nl...

Hello Skarmander,

[Snip]
> ....and discard them on a FIFO basis as you run out.

That could be a working solution. Especially when I make the number of
connectoids (handshaking UDP packets) variable (when a "cannot do anymore"
pops up the user can just re-start with a larger number of connectoids
available).

> You seem to be asking for a way to implement miracles.

This miracle MUST have been solved before. I have TCP/IP software for DOS
here (closed-source MS stuff, much memory-hungry) that should have the same
problem.

> You cannot both have a limited number of pending requests and the
> demand that all outstanding requests must remain valid even if none are
> closed explicitly.

Yep, that was my sentiment exactly. But I'm working with a
memory-constraint (just like any other method would do, even dynamically
growing of the connections), and I can't do anything about the second. :-)

> ... and maximum time a request remains valid. You could even


> measure "time" in the number of FindFirst calls made overall

Well, timing-out is what I'm currently doing. Not the best solution. :-)

> No well-behaved application can open a large number of FindFirsts,
> close none of them, and still expect for every single one to remain valid.

I'm sorry for you, but that is *exactly* what an app. may expect : as long
as it does not overwrite the first 21 bytes of the DTA, it can, as far as
DOS is concerned, do another find-next whenever it wants (even hours or days
later).

And yes, I'm trying to find the "best" solution, not one that will work for
a limited number of apps most of the time. :-)

Thanks for your response, you gave me something to think about.

Regards,
Rudy Wieser

Skarmander

unread,
Dec 11, 2005, 7:26:18 PM12/11/05
to
R.Wieser wrote:
> Skarmander <spam...@crayne.org> schreef in berichtnieuws
> 439c83f3$0$24373$e4fe...@news.xs4all.nl...
<snip>

>> You seem to be asking for a way to implement miracles.
>
> This miracle MUST have been solved before. I have TCP/IP software for DOS
> here (closed-source MS stuff, much memory-hungry) that should have the same
> problem.
>
It probably does. It probably hasn't "solved" the problem in any definitive
way, though. Just in a way that happens to work. There should be a way of
bringing it to its knees; I'm betting it's not necessarily all that hard either.

<snip>


>> No well-behaved application can open a large number of FindFirsts,
>> close none of them, and still expect for every single one to remain valid.
>
> I'm sorry for you, but that is *exactly* what an app. may expect : as long
> as it does not overwrite the first 21 bytes of the DTA, it can, as far as
> DOS is concerned, do another find-next whenever it wants (even hours or days
> later).
>

No, that is not exactly what an application may expect. Not calling FindNext
until it returns "no more files" is a violation of the interface. You cannot
possibly *know* what an application may expect at this point. Anything goes.
Your specification has been rendered worthless, and you're down to trying to
guess what the other side wants from you. Not a happy position to be in, but
there you go.

You can try to be as accommodating to broken code as you like, but somewhere
the buck has to stop. You have to make *some* sort of tradeoff. If you want
closure on this, then simply *measure* what applications are doing. Do they
really do a new FindNext "hours or days later"? How many simultaneous open
requests are we talking about? 10? 100? 32,767? How many per second? What
happens if you write your own application that deliberately tries to break
the driver and set it loose on existing drivers? When does it fail? Does it
even fail, or is some unknown mechanism at work that will accommodate some
pathological cases?

To profile is to know. You could waste hours or days on a solution that is
"maximally fair" which still won't work in the particular case you're using
it for. Conversely, a "stupid" solution you hack up in a few minutes could
happen to do exactly what applications expect.

> And yes, I'm trying to find the "best" solution, not one that will work for
> a limited number of apps most of the time. :-)
>

Then, again, your only recourse is to try and find out how applications
expect FindFirst/Next to behave, and give them what they want. The "best"
solution does not exist in this case, since the constraints you're given
make the general problem unsolvable.

> Thanks for your response, you gave me something to think about.
>

Don't think, just do it. If it doesn't work, rewrite it. Unless your code
will operate a nuclear power plant, you won't make headway here by trying to
design the ultimate unfallible driver first. It probably can't be done. Feel
your way around.

S.

David J. Craig

unread,
Dec 12, 2005, 12:53:57 AM12/12/05
to
Int 21h, Function 11h maintains all the necessary data for findnext at the
DTA in the FCB. Only the later protected OS versions have the OS maintain
that data.

"R.Wieser" <spam...@crayne.org> wrote in message

news:439c309f$0$11062$e4fe...@news.xs4all.nl...

R.Wieser

unread,
Dec 12, 2005, 6:08:19 AM12/12/05
to
David J. Craig <spam...@crayne.org> schreef in berichtnieuws
oYydnXGltJ3kjQDe...@comcast.com...

Hello David,

> Int 21h, Function 11h maintains all the necessary data for findnext at the
> DTA in the FCB.

So does INT 21h, AH=4Eh/4Fh

And "all the necessary data" ? For local files, yes. For remote files, no.
1) what does "cluster number" mean for a remote file ?
2) How can I recover the (local) path to the (remote) file from it :-)

Regards,
Rudy Wieser

R.Wieser

unread,
Dec 12, 2005, 5:55:01 AM12/12/05
to
Skarmander <spam...@crayne.org> schreef in berichtnieuws
439cc3c1$0$11080$e4fe...@news.xs4all.nl...

Hello Skarmander,

[Snip]

> It probably does. It probably hasn't "solved" the problem in any
> definitive way, though. Just in a way that happens to work.

Well, I would love to know which "just happens to work" method MS used. :-)

> There should be a way of bringing it to its knees; I'm betting it's
> not necessarily all that hard either.

Harder than you might think. Currently quite a few people have read this
conversation, and none of them responded with "what are you mumbling about,
the solution is .....".

[snip]


> No, that is not exactly what an application may expect. Not calling
FindNext
> until it returns "no more files" is a violation of the interface.

Than complain to MS. As I mentioned before, it's own OS does not honor it.
I allso cannot remember ever having read about that constraint, although you
are one of a few people that has mentioned it. Can you give me a
reference/URL to it ?

> You cannot possibly *know* what an application may expect at this point.

Let's first try to solve the first problem, and than the next please. (FYI :
the problem you are sketching is *not* a problem for me. Trying to read
beyond the last file generates a #18 error - "no more files")

> You can try to be as accommodating to broken code as you like, but
somewhere
> the buck has to stop.

[snip]

Yes, it's a trade-off. But please allso acknowledge that my IFS-driver
should *at least* be able to accomodate THE OS. Currently it cannot even
do that, because of non-closed find-first's BY THE OS.

[snip]


> Don't think, just do it. If it doesn't work, rewrite it.

"just rewrite it" :-) Gladly, my dear Sir. But should I not need to have
an idea to what to rewrite the code to ? Or am I expected to just press
buttons & see if it will compile later ?

> Feel your way around.

...

Regards,
Rudy Wieser

Waldek Hebisch

unread,
Dec 13, 2005, 5:22:09 PM12/13/05
to
In comp.lang.asm.x86 R.Wieser <spam...@crayne.org> wrote:
> > You seem to be asking for a way to implement miracles.
>
> This miracle MUST have been solved before. I have TCP/IP software for DOS
> here (closed-source MS stuff, much memory-hungry) that should have the same
> problem.
>
> > You cannot both have a limited number of pending requests and the
> > demand that all outstanding requests must remain valid even if none are
> > closed explicitly.
>
> Yep, that was my sentiment exactly. But I'm working with a
> memory-constraint (just like any other method would do, even dynamically
> growing of the connections), and I can't do anything about the second. :-)
>

Looking at Ralf Brown description it seems that DOS uses 10 bytes of FCB
to retain state between searches. If needed you can probably use a few
more bytes.

So, you probably can store in the FCB enough info to identify remote
directory. It is not enough to store full pathname, but you can get the
patchname searching directory tree for a given directory (as long as you
can identify it). Of course searching is slow but if you cache locally
mappings from id-s to pathnames remote you will need to search only in
cases which would otherwise fail.

--
Waldek Hebisch
heb...@math.uni.wroc.pl

R.Wieser

unread,
Dec 14, 2005, 4:43:47 AM12/14/05
to
Waldek Hebisch <spam...@crayne.org> schreef in berichtnieuws
dnnhih$q12$1...@panorama.wcss.wroc.pl...

Hello Waldek,
[Snip]

> Looking at Ralf Brown description it seems that DOS uses 10 bytes
> of FCB to retain state between searches. If needed you can probably
> use a few more bytes.

I'm aware of that area, but I'm not sure if I can "just use" it : it isn't
specifically mentioned as being "free" for when the target-drive is
non-local ... Nor does Ralf have a description of the last 4 bytes, or what
the cluster & index do for non-local drives.

Wait a minute : 10 bytes ? You don't mean 8 starting at offset 13 (just
behind the search-for attribute), but the 10 starting at offset 33 (just
behind the found attribute) ? If that's so, that would be no good. A
program could erase the returned search-results (everything beyond the 21
byte, and still be able to find the next file.

Some programmers have been known to do a recursive directory-tree traversal,
only saving & restoring the DTA's first 21 bytes on the stack.

I'm currently allready utilizing that 8-byte area, as I store the ID of the
connectoid to the server in there. That should make sure that even if the
(contents of the) DTA is(are) moved I do still know wich search-service
thread on the remote computer I have to send it to. :-)

> So, you probably can store in the FCB enough info to identify remote
> directory. It is not enough to store full pathname, but you can get the
> patchname searching directory tree for a given directory (as long as you
> can identify it). Of course searching is slow but if you cache locally
> mappings from id-s to pathnames remote you will need to search only in
> cases which would otherwise fail.

That's not a bad idea. I was thinking about much the same, but was thought
I should be able to locally resolve the DTA-contents to a directory-path
(drive & search-mask are allready available in the DTA itself). You gave
my brain a nudge, and made me aware that I only need to have an ID of the pa
th. And for some reason I think that the clusternumber could be used for
just such a purpose (if DOS will allow it) :-)

Thanks for the suggestion.

Regards,
Rudy Wieser

0 new messages