Back to home page

DOS ain't dead

Forum index page

Log in | Register

Back to index page
Thread view  Board view
kerravon

E-mail

Ligao, Free World North,
20.10.2025, 08:15
 

recursing subdirectories (Developers)

I would like to (re-implement) a Windows layer on top of an MSDOS layer - noting that I am willing to rewrite application code once I have rules in place. Suitable rules may already exist - maybe I just don't know them.

First the Windows calls:

HANDLE FindFirstFileA(file_pattern, data_returned);

BOOL FindNextFileA(HANDLE h, data_returned);

BOOL FindClose(HANDLE h);

Now thanks to the flexibility of handles - this allows me to open two directories independently. There is no need for them to clash with each other. I can potentially open dir A, then open dir B, and then close dir A, and then close dir B. Instead of recursion.

It so happens that my needs are less than that - it is enough for me to be able to do open A, open B, close B, close A. The greater flexibility would be great, but not necessary.

MSDOS instead has the equivalent of:

int PosFindFirst(char *pat, int attrib); /* func 4e */
int PosFindNext(void); /* func 4f */
void *PosGetDTA(void); /* func 2f */

Now originally I thought that I needed to add a PosFindClose() extension, to provide the same flexibility that Windows has - to let the OS know that I've finished processing this directory.

But at least for my usual needs - at least on the application level - specifically implementing zip - there is the knowledge of a close already - the close happens automatically when FindNext returns non-zero.

So when that happens, it would be in a position to free up any resources (flexible rules for any theoretical MSDOS replacement - regardless of how MSDOS does it currently).

But to work within the current limitations of MSDOS, you could perhaps create a PosFindClose extension, but if it is "unsupported function" then you are required to read to the end of the directory - even if you don't want to - so that a theoretical MSDOS clone with no extensions can free up any resources it is using as the result of the FindFirst that caused it to open in the first place.

Next, what options does a theoretical MSDOS implementation have with the above calls?

As far as I know, current MSDOS only has a single DTA, so if you do a second FindFirst for recursion purposes, the DTA gets clobbered and there is a disaster - unless the application itself takes responsibility for preserving this system structure - the DTA.

That seems like a fundamentally bad design to me - but - with reasonable rules - we may be able to recover.

I can see in my current code that I first get the DTA in preparation for calling FindFirst.

But maybe that order needs to be reversed.

First, here is how the API could work with that order.

And note - I am opening up the possibility of multiple DTAs now, instead of "the" DTA.


METHOD ONE (my NON-preferred way at the moment)

You aren't supposed to just get "the" DTA whenever you feel like it. What you are supposed to do is do a GetDTA call in preparation for some new operation. This gives the OS an opportunity to allocate a NEW DTA and give you a pointer to it. The next operation you do will then operate on that new DTA. If that is a FindFirst/FindNext, then that DTA will be freed when the FindNext hits the end of directory.


METHOD TWO (I think this is better)

FindFirst is allowed to cause the creation of a new DTA. Applications must retrieve the current DTA after doing this operation, instead of assuming it is the same as it was before the operation. "MSDOS-clones" are guaranteed to keep the DTA the same until the last successful FindNext, so you are not required to requery the *current* DTA every time you call FindNext.

You do retain the right to query the current DTA whenever you want, if that serves some purpose.


Next - rules to work within the *current* MSDOS - warts and all. This is a single DTA, and no preservation (as far as I am aware).

So, assuming method two is being used, you've done a findfirst, retrieved the DTA, you're doing findnext calls, everything is working fine, then you decide to recurse - or even open an unrelated directory. The application is required to do the following:

1. Preserve a copy of the DTA up to the filename. Also preserve the address of the DTA.

2. Open the other (sub-)directory with FindFirst.

3. Get the current DTA.

4. If the current DTA is different from the previous DTA, then this is a "sophisticated" MSDOS and you don't make any assumptions about it and you don't touch the DTAs.

5. If some flavor of MSDOS still has the same DTA that was previously being used, then, when you've finished with the new directory, and you wish to go back to the previous directory you were traversing, you need to:

A. (Potentially) Do a fresh GetDTA to see where you stand. This gives MSDOS some opportunity to close a current FindNext sequence, even if it hasn't completed, and switch back to the previous DTA in the stack of DTAs.

B. If you're still at your original old pointer, then you need to first check to see if the contents of the the DTA match what you have already saved. ONLY if they are different, should you copy the saved contents back to the DTA area. Your application could potentially be running in PM16 and you no longer have the ability to write to system memory, so you can't unconditionally copy it.

C. (Potentially) If you're not at your original old pointer, that is an indication that "MSDOS" (future, present, clone) knows what it is doing already, and you shouldn't interfere with the system memory - even if you do have write access.

Note that it may simply be that I have been conceptually wrong for decades, and there are already multiple DTAs, and I have just been using the APIs incorrectly and causing myself problems.

Note that right at the moment I don't see how to make it work with the current APIs, two independent directories being opened, and neither of them having reached the end. Maybe GetDTA could be defined to round-robin the current DTAs in the opposite order to which they were opened, and if you keep track of where you originally were, you can wait until it gets back to that?

Any thoughts?

Thanks. Paul.

ecm

Homepage E-mail

Düsseldorf, Germany,
20.10.2025, 08:54

@ kerravon
 

recursing subdirectories

You're supposed to set the DTA to a different buffer ("different DTA") whenever (before) you open a new concurrent search. The find data in the first DTA should be sufficient to resume the first search, when you reset the DTA to point to that find data, regardless of how many other searches you started. Alternatively you could copy the find data from a single DTA and stash it elsewhere, then restore it later. In any case, the populated find data if preserved is supposed to be able to resume concurrent searches regardless of what order you call the DOS.

Redirectors should try to emulate this, although the find data may not be large enough to reference their file system internals. So the find data can contain a handle, pointing to a redirector-internal find data block, which is cleaned up either when the search call returns "no more files", LFN find close is called, or eg the process terminates.

---
l

kerravon

E-mail

Ligao, Free World North,
20.10.2025, 18:02
(edited by kerravon, 22.10.2025, 03:43)

@ ecm
 

recursing subdirectories

> You're supposed to set the DTA to a different buffer ("different
> DTA") whenever (before) you open a new concurrent search. The find data in
> the first DTA should be sufficient to resume the first search, when you
> reset the DTA to point to that find data, regardless of how many other
> searches you started.

Thanks for that!

I looked that up:

https://www.ctyme.com/intr/rb-2589.htm

So it is set to point to my PSP initially, which means it will wipe out my
command line.

That's fine - and it also means that there is a known size limit to the
size of the DTA - 0x80.

Although closer inspection:
https://www.ctyme.com/intr/rb-2977.htm#Table1626

suggests that this is a fixed size that won't be expanded with new DOS versions.

And that size is decimal 43 bytes.

> Alternatively you could copy the find data from a
> single DTA and stash it elsewhere, then restore it later. In any case, the
> populated find data if preserved is supposed to be able to resume
> concurrent searches regardless of what order you call the DOS.

Ok, great.

> Redirectors should try to emulate this, although the find data may not be
> large enough to reference their file system internals. So the find data can

What's a redirector?

> contain a handle, pointing to a redirector-internal find data block, which
> is cleaned up either when the search call returns "no more files", LFN find
> close is called, or eg the process terminates.

Ok, I looked those up.

LFN FindFirst: AX = 714Eh
https://www.ctyme.com/intr/rb-3203.htm
LFN FindNext: AX=714Fh
https://www.ctyme.com/intr/rb-3204.htm
LFN FindClose: AX=71A1h
https://www.ctyme.com/intr/rb-3211.htm
And the structure that includes the LFN:
https://www.ctyme.com/intr/rb-3203.htm#Table1779

And that looks like a fixed decimal 318 byte table too.

And I see that the FindFirst explicitly mentions the carry flag issue:

For compatibility with DOS versions prior to v7.00, the carry flag should be set on call to ensure that it is set on exit


EDIT: corrected LFN FindClose AX (thanks ecm)

ecm

Homepage E-mail

Düsseldorf, Germany,
20.10.2025, 20:30

@ kerravon
 

recursing subdirectories - redirector

> I looked that up:
>
> https://www.ctyme.com/intr/rb-2589.htm
>
> So it is set to point to my PSP initially, which means it will wipe out my
> command line.
>
> That's fine - and it also means that there is a known size limit to the
> size of the DTA - 0x80.
>
> Although closer inspection:
> https://www.ctyme.com/intr/rb-2977.htm#Table1626
>
> suggests that this is a fixed size that won't be expanded with new DOS
> versions.
>
> And that size is decimal 43 bytes.

That tracks, yes.

> > Alternatively you could copy the find data from a
> > single DTA and stash it elsewhere, then restore it later. In any case,
> the
> > populated find data if preserved is supposed to be able to resume
> > concurrent searches regardless of what order you call the DOS.
>
> Ok, great.
>
> > Redirectors should try to emulate this, although the find data may not
> be
> > large enough to reference their file system internals. So the find data
> can
>
> What's a redirector?

As of circa MS-DOS v3.10 and higher, there are two different kinds of file systems: local (FAT12, FAT16, or in v7.10 FAT32) and redirector. Every "DOS drive" is one or the other.

Local drives have a CDS entry, DPB, usually an msbio UPB (unless they're backed by another block device driver), and an on-disk BPB in the boot sector.

Redirector drives only have a CDS entry, which has the "net" bit set (also documented in the interrupt list). The redirector may have internal tables relating to what it provides as a DOS drive, but these are specific to the redirector and not in a generally known format.

The original redirector was the IBM/MS network client, which could allow to add DOS drives for networked file systems. Later, mscdex/shsucdx type resident CDFS extensions re-used the redirector interface to provide CD-ROM file systems as DOS drives. Other extensions such as iHPFS are also redirectors. The same is true of the "mfs" (Mach FS) part of dosemu2, which provides (optionally r/w) access to Linux host directories as DOS drives.

(shsucdx and dosemu2 mfs have some support for LFNs, which requires either cooperation by the LFN server (doslfn) in the case of shsucdx, or for the redirector extension to also hook the int 21h function 71h subfunctions in the case of mfs.)

> > contain a handle, pointing to a redirector-internal find data block,
> which
> > is cleaned up either when the search call returns "no more files", LFN
> find
> > close is called, or eg the process terminates.
>
> Ok, I looked those up.
>
> LFN FindFirst: AX = 714Eh
> https://www.ctyme.com/intr/rb-3203.htm
> LFN FindNext: AX=714Fh
> https://www.ctyme.com/intr/rb-3204.htm
> LFN FindClose: AX=714Eh
> https://www.ctyme.com/intr/rb-3211.htm

Find close is 71A1h, not 714Eh.

> And the structure that includes the LFN:
> https://www.ctyme.com/intr/rb-3203.htm#Table1779
>
> And that looks like a fixed decimal 318 byte table too.
>
> And I see that the FindFirst explicitly mentions the carry flag issue:
>
> For compatibility with DOS versions prior to v7.00, the carry flag should
> be set on call to ensure that it is set on exit

Yes, indeed, as discussed previously. But the mentions like this aren't always present.

---
l

ecm

Homepage E-mail

Düsseldorf, Germany,
20.10.2025, 20:33

@ ecm
 

recursing subdirectories - redirector

Addendum: The redirector interface is useful because many common housekeeping tasks on pathnames and handles are relegated to the DOS, and the redirector provides a special interface on int 2Fh function 11h that's used by the DOS. This is partially undone by redirectors like mfs that want to support LFNs because the int 21h function 71h subfunctions do not correspond to any traditional redirector interfaces. (dosemu2 adds a few redirector extensions, but not that many.)

---
l

kerravon

E-mail

Ligao, Free World North,
25.10.2025, 16:56

@ ecm
 

recursing subdirectories - redirector

> > Although closer inspection:
> > https://www.ctyme.com/intr/rb-2977.htm#Table1626
> >
> > suggests that this is a fixed size that won't be expanded with new DOS
> > versions.
> >
> > And that size is decimal 43 bytes.
>
> That tracks, yes.

Did Microsoft document this somewhere?

ie before calling FindFirst, you should SET the DTA to point to
a 43-byte buffer?

If not, how are you supposed to know something like this?
ie that Microsoft guarantees that you only need 43 bytes
for eternity. And that it doesn't need to be aligned on any
particular boundary (2/4/8/16/32 bytes).

Thanks. Paul.

usotsuki

25.10.2025, 18:15

@ kerravon
 

recursing subdirectories - redirector

> > > Although closer inspection:
> > > https://www.ctyme.com/intr/rb-2977.htm#Table1626
> > >
> > > suggests that this is a fixed size that won't be expanded with new DOS
> > > versions.
> > >
> > > And that size is decimal 43 bytes.
> >
> > That tracks, yes.
>
> Did Microsoft document this somewhere?
>
> ie before calling FindFirst, you should SET the DTA to point to
> a 43-byte buffer?
>
> If not, how are you supposed to know something like this?
> ie that Microsoft guarantees that you only need 43 bytes
> for eternity. And that it doesn't need to be aligned on any
> particular boundary (2/4/8/16/32 bytes).
>
> Thanks. Paul.

Programmers' manuals from Microsoft for multiple versions of MS-DOS (I checked 2.0, 3.2 and 4.0) describe a 43-byte struct. The 3.2 and 4.0 manuals have example code that reserves exactly 43 bytes for a findfirst buffer.

kerravon

E-mail

Ligao, Free World North,
26.10.2025, 03:22

@ usotsuki
 

recursing subdirectories - redirector

> Programmers' manuals from Microsoft for multiple versions of MS-DOS (I
> checked 2.0, 3.2 and 4.0) describe a 43-byte struct. The 3.2 and 4.0
> manuals have example code that reserves exactly 43 bytes for a findfirst
> buffer.

Thanks. I found that here, by searching for find_first (with an underscore):

https://www.pcjs.org/documents/books/mspl13/msdos/dosref40/

I'd like to make sure I have a legal copy of this.

Apparently this was on a "Microsoft Programmer’s Library 1.3 CD-ROM":

https://www.pcjs.org/documents/books/mspl13/

I don't want to join the MSDN or anything like that. But I'm happy to
purchase something from ebay.

I already have purchased things like DOS 6.22 (I think) from ebay, and
a lot of other stuff. I may already have the manual (at another location)
now that I know what to look for.

Any idea what my options are? How did Microsoft make this available?

I already checked their github for MSDOS 4.0 and they didn't provide
the manuals.

Rugxulo

Homepage

Usono,
26.10.2025, 03:34

@ kerravon
 

recursing subdirectories - redirector

> Any idea what my options are? How did Microsoft make this available?

Dunno, but HelpPC says this.

Back to index page
Thread view  Board view
22747 Postings in 2119 Threads, 402 registered users, 21 users online (0 registered, 21 guests)
DOS ain't dead | Admin contact
RSS Feed
powered by my little forum