[comp.sys.ibm.pc] Retrieving the value of FILES=???

gday@digigw.digital.co.jp (Gordon Day) (06/13/90)

I am confronted with the problem of finding out length of the global file 
handle table in DOS (>=3.3).  I am aware of the following issues:

- the system default is 8

- the per process default is 20

- int 21 function 67 can be used to increase the per process default to any
  value that will fit into 2 bytes. If global table length < per process length
  then the error is only found when an operation where a new handle is created 
  is attempted.

I am writing a program which MUST be able to find out the number of globally
available file handles. The first observation is that who ever added the 
function 67 to MSDOS really missed the point by providing a function whose 
success or failure was indeterminate at the time of return.  The obvious 
solution would be to provide either the address of the system variable which
identifies the table length (unportable,and it may not exist if the table is
terminated by a marker rather than an offset variable) or a complementary
function which will return the table length through, say, function 68.

The only (ugly) solution that I've come up with is to perform a "consume 
resource until failure" check where I reset the number of available handles by 
my program to some high value and perform a dup (int 21 function 45) on stdin 
until the dup call fails.  At this point, I know that the #successful dups + 
5 (stdin, stdout, etc) = size of the global handle table.

Can you suggest something more elegant?

Gordon W. Day (gday@digital.co.jp)

dixon@sagittarius.crd.ge.com (walt dixon) (06/14/90)

In <605@digigw.digital.co.jp> Gordon Day writes:

>I am confronted with the problem of finding out length of the global file
>handle table in DOS (>=3.3).  I am aware of the following issues:

[text deleted]

The MS-DOS Technical Reference Encylopedia (at least the first edition)
referred to this structure as the System File Table or SFT for short.
DOS maintains the base address of the SFT in a list returned in es:bx
by int 21h ah=52h.  Specifically es:[bx+4] is a dword ptr to the system
file table.  The system file table is organized as a linked list with
the following format:

  +------------------+
  | link to next     |
  | block of entries |
  | (DWORD)          |
  +------------------+
  | entries in this  |
  | block            |
  | (WORD)           |
  +------------------+
  |  1st SFT entry   |
  |  in block        |


  |  last SFT entry  |
  |  in block        |
  +------------------+

You can determine the SFT size by walking the list and adding up the entries
per block.  You can also determine available/used space by looking at the
reference count in the individual SFT entries within each block.  There's
a more complete explaination of the SFT as well as other interesting DOS
data structures in Chapter 10 of "The MS-DOS Papers" (Howard Sams, 1988).
BTW I am the author of this chapter and the following one on device
drivers.  I derrive no revenue from book sales;  I'm just citing a good
reference.

Walt Dixon	{internet:	dixon@crd.ge.com	}
		{us mail:	ge crd			}
		{		po box 8		}
		{		schenectady, ny 12301	}
		{phone		518-387-5798 (W)	}
		{		518-875-6203 (H)	}
Walt Dixon dixon@crd.ge.com

kaleb@mars.jpl.nasa.gov (Kaleb Keithley) (06/14/90)

In article <605@digigw.digital.co.jp> gday@digigw.digital.co.jp (Gordon Day) writes:
>I am confronted with the problem of finding out length of the global file 
>handle table in DOS (>=3.3).  I am aware of the following issues:
>
> [ much deleted ]

How about: (in psuedo-code)

#ifdef DOS
    fopen ("/CONFIG.SYS", "r");

    fscanf (..., "FILES=", ...);

    fscanf (...,  value, ...);

    fclose (...);
#else
    other method appropriate for architecture
#end

Since all DOS machines have to have CONFIG.SYS in the root directory, it
would work for any DOS box.  If the fopen fails, then assume the default.

kaleb@thyme.jpl.nasa.gov            Jet Propeller Labs
Kaleb Keithley

"So that's what an invisible barrier looks like"

dixon@sagittarius.crd.ge.com (walt dixon) (06/15/90)

In article <4057@jato.Jpl.Nasa.Gov> Kaleb Keithley writes:

>In article <605@digigw.digital.co.jp> gday@digigw.digital.co.jp
> (Gordon Day) wr:
>>I am confronted with the problem of finding out length of the global file
>>handle table in DOS (>=3.3).  I am aware of the following issues:
>>
>> [ much deleted ]

>How about: (in psuedo-code)

>#ifdef DOS
>    fopen ("/CONFIG.SYS", "r");
>    fscanf (..., "FILES=", ...);
>    fscanf (...,  value, ...);
>    fclose (...);
>#else
>    other method appropriate for architecture
>#end

>Since all DOS machines have to have CONFIG.SYS in the root directory, it
>would work for any DOS box.  If the fopen fails, then assume the default.

This technique should work in almost all cases.  The parsing logic should
be a little smarter because it is possible to "comment" out lines in
CONFIG.SYS.  Its also possible to grow the System File table after boot
by linking a memory block to the existing chain.  Finally as Kaleb notes
there is the posibility that the open will fail.  I still prefer traversing
the SFT blocks.

Walt Dixon	{internet:	dixon@crd.ge.com	}
		{us mail:	ge crd			}
		{		po box 8		}
		{		schenectady, ny 12301	}
		{phone:		518-387-5798 (W)	}
		{		518-875-6203 (H)	}
Walt Dixon dixon@crd.ge.com

malloy@nprdc.arpa (Sean Malloy) (06/15/90)

In article <4057@jato.Jpl.Nasa.Gov> kaleb@mars.UUCP (Kaleb Keithley) writes:
>How about: (in psuedo-code)
>#ifdef DOS
>    fopen ("/CONFIG.SYS", "r");
>    fscanf (..., "FILES=", ...);
>    fscanf (...,  value, ...);
>    fclose (...);
>#else
>    other method appropriate for architecture
>#end
>
>Since all DOS machines have to have CONFIG.SYS in the root directory, it
>would work for any DOS box.  If the fopen fails, then assume the default.

Only if you are running a reasonably vanilla DOS system. My system
has the following startup parameters:

===============CONFIG.SYS:
	BUFFERS=1
	FILES=10
	DEVICE=C:\QEMM\QEMM.SYS RAM EXCLUDE=C600-C7FF
	<remainder of file deleted for brevity>

===============AUTOEXEC.BAT:
	C:\QEMM\LOADHI BUFFERS+39
	C:\QEMM\LOADHI FILES+30
	<remainder of file deleted for brevity>

Your example will not, then, work for _my_ DOS box, returning '10'
when there are really 40 file handles. Additionally, opening
"/CONFIG.SYS" only works if you are running the program from your
boot drive. My system has A-H as valid drives; if I try to open
"/CONFIG.SYS" on G:, I'm going to get a null file pointer back from
fopen().


                                               | "The three most dangerous
 Sean Malloy                                   | things in the world are a
 Navy Personnel Research & Development Center  | programmer with a soldering
 San Diego, CA 92152-6800                      | iron, a hardware type with a
 malloy@nprdc.navy.mil                         | program patch, and a user
                                               | with an idea."

darcy@druid.uucp (D'Arcy J.M. Cain) (06/15/90)

In article <4057@jato.Jpl.Nasa.Gov> kaleb@mars.UUCP (Kaleb Keithley) writes:
> [Discussion about finding the files/process in DOS]
>How about: (in psuedo-code)
>    fopen ("/CONFIG.SYS", "r");
>    fscanf (..., "FILES=", ...);
>    fscanf (...,  value, ...);
>    fclose (...);
>
And if the table has been changed using int 67h it doesn't tell you the
correct value.  What you need is a TSR that you run at startup which
does the following at initialisation.

Determines the value for max files using following:
    From command line if given
    From FILES= in config.sys if available
    Normal default otherwise.

Use int 67h to set up this value - this makes sure value is known.

It then sets up a hook to int 67h to check for special value in BX (say
-1) and returns current value if it is that special value.  Otherwise
it calls the original int 67h and keeps track of the new value.  Then
your programs can call int 67h with -1 to get the current value.

No wonder they call it Messy-DOS.  :-)


-- 
D'Arcy J.M. Cain (darcy@druid)     |   Government:
D'Arcy Cain Consulting             |   Organized crime with an attitude
West Hill, Ontario, Canada         |
(416) 281-6094                     |

david@csource.OZ.AU (david nugent) (06/15/90)

In <605@digigw.digital.co.jp> gday@digigw.digital.co.jp (Gordon Day) writes:

>The only (ugly) solution that I've come up with is to perform a "consume 
>resource until failure" check where I reset the number of available 
>handles by my program to some high value and perform a dup (int 21 
>function 45) on stdin until the dup call fails.  At this point, I know 
>that the #successful dups + 5 (stdin, stdout, etc) = size of the global 
>handle table.

>Can you suggest something more elegant?


Nope.  I am aware that there is a way of doing what you want, but
I don't know it, unfortunately.

But I can certainly suggest very strongly that you don't attack
it this way.  I've known many a program to get into trouble doing this,
particularly if there's no upper limit placed on the number of files.

There do exist DOS-like environments which probably do run your software
if you didn't do the above 'trick'.  PC-MOS/386 for example; since there
IS no upper limit to the number of files it can handle (save the memory
available in the SMP, which is similar to a Unix kernel's workspace), so
a program might go "forever" opening files only to have the system crash
when the kernel runs out of SMP and isn't able to recover.

This IS a workaround in MOS - by setting the maximum number of open handles
on a task-by-task basis - but the problem which arise from that is that
it's no longer possible to increase the number of available handles.

It guess it's a trade-off, but if you at least place some ceiling on
how many files you attempt to open, that's something.  If MOS's kernel
runs out of memory as a result, you're still in trouble though.

david

-- 
         * Unique Computing Pty Ltd, Melbourne, Australia. *
       david@csource.oz.au  3:632/348@fidonet  28:4100/1@signet

bressler@iftccu.ca.boeing.com (Rick Bressler) (06/16/90)

Also, I wouldn't count on config.sys being there.  Turns out that during boot,
the system doesn't look at the permissions on the file, so I keep mine set to 
system, hidden and read only.  Keeps people from messing around with it, and 
gives me a cleaner root.  In fact, autoexec.bat runs fine with the hidden 
and read only attributes.  All you can see when you list the roor are 
directories.

-rick-

dixon@ra.crd.ge.com (walt dixon) (06/16/90)

In article <1990Jun15.133128.17259@druid.uucp> D'Arcy J.M. Cain writes:

>In article <4057@jato.Jpl.Nasa.Gov> kaleb@mars.UUCP (Kaleb Keithley) writes:
>> [Discussion about finding the files/process in DOS]
>>How about: (in psuedo-code)
>>    fopen ("/CONFIG.SYS", "r");
>>    fscanf (..., "FILES=", ...);
>>    fscanf (...,  value, ...);
>>    fclose (...);
>>
>And if the table has been changed using int 67h it doesn't tell you the
>correct value.  What you need is a TSR that you run at startup which
>does the following at initialisation.

>Determines the value for max files using following:
>    From command line if given
>    From FILES= in config.sys if available
>    Normal default otherwise.

>Use int 67h to set up this value - this makes sure value is known.

>It then sets up a hook to int 67h to check for special value in BX (say
>-1) and returns current value if it is that special value.  Otherwise
>it calls the original int 67h and keeps track of the new value.  Then
>your programs can call int 67h with -1 to get the current value.

>No wonder they call it Messy-DOS.  :-)

There seems to be some confusion here.  DOS maintains two separate tables.
Each program contains the address and size of a Job File Table (JFT) within
its PSP.  The default size of the JFT is 20 files,  and its default location
is within the PSP.  As far as I can tell from a real quick disassembly,
int 21h ah=67h just replaces the JFT pointer and size in the PSP.  (Of course
it copies the existing JFT contents and initializes any new entries properly).

DOS uses the file handle returned by open/create requests as an index into
the job file table.  Unused JFT entries contain a 0xff;  active entries
contain an integer in the 0 to 0xfe range.  This entry is an index into
the System File Table.  The System File Table is a global table containing
specific information about all open files and devices.  Among the information
in the SFT is the name of the file/device,  a reference count,  an owner
PSP,  a pointer to the device header for character devices or a pointer
to the Device Control Block for block devices, various flags,  and other
miscellaneous information.

The FILES statement in CONFIG.SYS sets the size of the System File Table
NOT the size of the Job File Table.  Int 21h AH=67h sets the size of the
Job File Table.  As I noted in a previous posting,  the correct way
to determine the size of the system file table is to find its base
through int 21h ah=52h and walk the linked list of table blocks adding
up block sizes.  One could also count used/free table entries in this
process.  To determine the size of the JFT,  one only has to look inside
the PSP.  Scanning the table pointed to by the appropriate PSP address,
allows one to determine its free/used entries.

This information is more fully described in Chapter 10 of "The MS-DOS
Papers" (Howard Sams, 1988).  I am the author of this chapter and the
following one on device drivers.  (BTW I derive no revenue from book
sales).  The material presented in Chapter 10 came from disassembling
DOS 3.10 and may be a little dated.  As I initially noted,  I have not
fully disassembled DOS 3.30 which actually supports int 21h AH=67h.


Walt Dixon		{internet:	dixon@crd.ge.com	}
			{us mail:	ge crd			}
			{		po box 8		}
			{		schenectady, ny 12301	}
			{phone:		518-387-5798 (W)	}
			{		518-875-6203 (H)	}
Walt Dixon dixon@crd.ge.com

david@csource.OZ.AU (david nugent) (06/17/90)

In <4057@jato.Jpl.Nasa.Gov> kaleb@mars.jpl.nasa.gov (Kaleb Keithley) writes:

>How about: (in psuedo-code)

>#ifdef DOS
>    fopen ("/CONFIG.SYS", "r");
>    fscanf (..., "FILES=", ...);
>    fscanf (...,  value, ...);
>    fclose (...);
>#else
>    other method appropriate for architecture
>#end

>Since all DOS machines have to have CONFIG.SYS in the root directory, it
>would work for any DOS box.  If the fopen fails, then assume the default.


Several pitfalls;

	How do you determine what drive the system booted from? (and
	don't say looking at COMSPEC - even my own system boots DOS
	from a floppy and I have "SHELL=C:\COMMAND.COM ..." on it,
	which makes that assumption completely invalid),

	How can you guarantee that CONFIG.SYS hasn't been edited since
	boot,

	Some application may have adjusted the number of allowed
	handles using DOS Fn 67H,

	What if there's no FILES= statement (use the MS-DOS default -
	but since DOS Fn 67H exists, that's also a problem),

	How do you handle workstations on a network using an auto-
	boot PROM where CONFIG.SYS is no longer available since the
	system boots from what is essentially a temporary memory image,

	What about a dual boot OS/2 system which might use something
	like CONFIG.DOS instead of CONFIG.SYS,

	How do you handle "DOS-like" environments such as PC-MOS/386
	where a FILES= statement is invalid, yet there IS no practical
	limit to the number of handles; certainly the DOS default does
	NOT apply

Reading CONFIG.SYS is a kludge, at best.  If you need this information,
it's for a reason - and relying on extremely unreliable sources can get
you into trouble very quickly.

david

-- 
         * Unique Computing Pty Ltd, Melbourne, Australia. *
       david@csource.oz.au  3:632/348@fidonet  28:4100/1@signet

david@csource.OZ.AU (david nugent) (06/18/90)

In <1990Jun15.133128.17259@druid.uucp> darcy@druid.uucp (D'Arcy J.M. Cain) writes:

>Use int 67h to set up this value - this makes sure value is known.

>It then sets up a hook to int 67h to check for special value in BX (say
>-1) and returns current value if it is that special value.  Otherwise
>it calls the original int 67h and keeps track of the new value.  Then
>your programs can call int 67h with -1 to get the current value.

Just a slight correction.  That's not INT 67H; it's INT 21H function 67H.

And -1 in BX is actually a valid value for this call.  It will actually
work provided there's enough memory available.


>No wonder they call it Messy-DOS.  :-)

Yup. ;-)
-- 
         * Unique Computing Pty Ltd, Melbourne, Australia. *
       david@csource.oz.au  3:632/348@fidonet  28:4100/1@signet