From: Jon Freivald <jaf@jaflrn.UUCP>
Newsgroups: alt.msdos.programmer
Subject: Re: Local vs Net drive. How Tell ?
Date: Fri, 22 Jan 93 13:28:11 EST
Organization: The Wizzard's Cave, East Meadow, NY

jones@hal.uvm.edu (Mike Jones) writes:

> I am building a network login program to work under StarLan (lanman
> 2.0).  Currently I look for a mounted network drive (by attempting to
> get drive params/diskspace) to figure out if "net logon" worked (it
> doesn't return any values via status or doserror).
> 
> Problem, Drive D: is a network drive for most people, and on almost
> all of our computers, there is no local drive D:.  However, there are
> some prof's around who have a local drive D:.  Some other drive gets
> mounted for them.  So the logical check is, does drive H: exist, if
> not, does drive D: ?  For the Prof's, drive D: will always exist.
> 
> The quick fix is to do a findfirst() and look for a specific file
> (network.dat).  But I have seen programs that know how many disks are
> installed in the system, and which ones are local, and which are
> network drives.  How do they do this ?
> 
> Is there one "get params" call that returns the information that I
> want.  Versions of DOS are 3.1 upto 5.0, so it has to work everywhere,
> and for everybody.
> 
> Thanks,
>   Mike
> 
> (sorry, can't move net drive D: to E:.  It was thought of, but not
> done because of the large number of machines that we have.  Maybe next
> year.  I want a full time fix.)

Mike,

     Attached are 3 files - drives.c, ceh.asm & numflopy.asm - if you
put them together, you end up with drives.exe which will go out and find
all your drives and tell you what type they are.  It ought to be quite
easy for you to modify this code to suit your needs...

Jon

P.S. - this was put together using Borland TurboC++ 1.0 & TASM 2.0 (I
think).  If you use MSC, you've got some work to do, but all the pieces
of how to make it work are here...

-------- drives.c -----------------------------------------------------

//===========================================================================
//
//	drives.c
//
//	test prog for critical error handler & disk determination routine
//
//	also requires ceh.asm and numflopy.asm
//
//	TurboC  - use:
//		tasm /mx ceh.asm
//		tasm /mx numflopy.asm
//		tcc -mt drives.c ceh.obj numflopy.obj
//
//===========================================================================

#pragma inline			// start compilation via assembly to eliminate
				// the error message generated
#include <stdio.h>
#include <dos.h>

//===========================================================================
//
//	function declarations
//
//===========================================================================

int	main ( void );
int	check_disk_type ( int disk_number );
int	test_cd_driver ( void );
extern	void setCEH ( void );
extern	void unsetCEH ( void );
extern	unsigned short	number_floppy ( void );

//===========================================================================
//
//	character arrays
//
//===========================================================================

char	*drive_type	[] = { "", "160K diskette", "180K diskette",\
	"320K diskette", "360K diskette", "1.2M diskette", "720K diskette",\
	"1.44M diskette", "unknown floppy disk type", "fixed disk",\
	"network file service", "CD-ROM", 0 };

//===========================================================================
//
//	miscellany
//
//===========================================================================

#define	SMALL	0
char	memory_model = SMALL;	// needed for C-Express functions ( numflopy.asm )
int	cd_driver = 0;		// status for presence/version of CD-ROM driver

//===========================================================================
//
//	main()
//
//		arguments:	currently none
//
//		returns:	0
//
//===========================================================================

int main ( void )

{
	int i, disk_type_found;

	setCEH();

	cd_driver = test_cd_driver();

	if ( cd_driver == 1 )
		{
		printf("\n\n\a\tA CD-ROM device driver (MSCDEX compatible) has been detected,");
		printf("\n\thowever, it is not version 2.0 or higer.  This program will be unable");
		printf("\n\tto differentiate between the CD-ROM drive(s) and any network drive(s)");
		printf("\n\n");
		}

	for ( i=1; i <= number_floppy(); i++ )
		{
		disk_type_found = check_disk_type ( i );
		if ( disk_type_found != 0 )
			{
			printf("\nDrive %c:, type - %s", (i + 'a' - 1), drive_type[disk_type_found]);
			}
		}

	if ( i == 2 )
		i++;
	
	for ( ; i < 27; i++ )
		{
		disk_type_found = check_disk_type ( i );
		if ( disk_type_found != 0 )
			{
			printf("\nDrive %c:, type - %s", (i + 'a' - 1), drive_type[disk_type_found]);
			}
		}

	printf("\n");

	unsetCEH();

	return ( 0 );
}

//===========================================================================
//
//	check_disk_type()
//
//		determines whether disk is local, remote, or CD-ROM
//
//		arguments:	int	disk_number	number of disk as
//							from getdisk()
//
//		returns:	int	disk type;
//							0 = no disk
//							1 = 160K floppy
//							2 = 180K floppy
//							3 = 320K floppy
//							4 = 360K floppy
//							5 = 1.2M floppy
//							6 = 720K floppy
//							7 = 1.44M floppy
//							8 = unknown floppy
//							9 = local
//							10 = network
//							11 = CD-ROM
//
//		uses global:	cd_driver	(0 if no driver or < 2.0, 1 if >= 2.0)
//
//===========================================================================

int check_disk_type ( int disk_number )

{
	union	REGS	regs;
	struct	SREGS	sregs;
	unsigned char far *des_byte;		// media descriptor byte
	int	rc = 1;

	regs.h.dl = disk_number;		// drive number to test (a: == 1)
	regs.h.ah = 0x1C;			// "get drive data" function
	int86x ( 0x21, &regs, &regs, &sregs );

	if ( regs.h.al == 0xFF )		// Did an error occur?
		{
		return ( 0 );			// Assume no disk present
		}
	des_byte = MK_FP ( sregs.ds, regs.x.bx );	// Make the far pointer to the descriptor byte

	if ( ( des_byte[0] != 0xF8 ) && ( des_byte[0] != 0x00 ) )	// Is it a fixed disk?

	/*  This is where the code varies from the documentation I can find
on the subject -- it *SEEMS* that CD's return a descriptor byte of 0x00,
however, I cannot find that documented anywhere... (0xF8 is fixed disk).
I've had to include the test for 0x00 here so that we progress to the tests
further down the line... */

		{
		regs.h.ah = 0x36;		// If not, get the number of sectors on it
		regs.h.dl = disk_number;	//   to determine the type of floppy it is
		int86 ( 0x21, &regs, &regs );	//   (the descriptor byte is not specific enough...)
		switch ( regs.x.dx * regs.x.ax )
			{
			case 313:		// 160K
				return ( 1 );
			case 351:		// 180K
				return ( 2 );
			case 630:		// 320K
				return ( 3 );
			case 708:		// 360K
				return ( 4 );
			case 2371:		// 1.2M
				return ( 5 );
			case 1426:		// 720K
				return ( 6 );
			case 2847:		// 1.44M
				return ( 7 );
			default:		// Unknown type
				return ( 9 );
			}
		}

	// If we get this far, it's a hard, net or CD-ROM disk

	rc = 9;					// Set rc to 9 if we get this far because
						//   it's at least a local hard disk
	regs.h.ah = 0x44;			// Int 21, func 44, sub 9 is IOCTL, we
	regs.h.al = 0x9;			//   use it to diff local & net/cd (remote)
						//   This requires DOS 3.1 or higher
	regs.h.bl = (unsigned char) disk_number;
	int86 ( 0x21, &regs, &regs );

	if ( ( regs.x.dx & 0x1000 ) == 0x1000 )	// if bit 12 of DX is 1, disk is remote
		{
		rc = 10;			// if we're here, we're either net or cd
		if ( cd_driver == 2 )		// test for cd requires MSCDEX >= 2.0, variable
			{			//   cd_driver is set by test_cd_driver()
			regs.h.ah = 0x15;
			regs.h.al = 0x0b;
			regs.x.bx = 0;
			regs.x.cx = disk_number - 1;	// less 1 due to a: == 0
			int86 ( 0x2f, &regs, &regs );

			if ( regs.x.ax != 0 && regs.x.bx == 0xadad )	// check on BX not really necessary since we
				{		//   check for the presence of MSCDEX elsewhere, however, let's leave it
						//   in for reusabilitiy's sake
				rc = 11;	// disk is CD-ROM
				}
			}
		}
	return ( rc );
}

//===========================================================================
//
//	test_cd_driver()
//
//		tests for presence of and version of MSCDEX driver
//			(version >= 2.0 required for "is this a CD" test)
//
//		arguments:	none
//
//		returns:	0 = no driver loaded or no CD-ROMs
//				1 = driver loaded, >= 1 CD, < version 2.0
//				2 = driver loaded, >= 1 CD, >= version 2.0
//
//===========================================================================

int test_cd_driver ( void )

{
	union REGS regs;

	asm	mov	ax,1500h				// check if CD-ROM available
	asm	xor	bx,bx
	asm	int	2fh					// invoke MSCDEX
	asm	or	bx,bx					// one or more CD-ROMs?
	asm	jnz	present					// yes, CD-ROMs are present

	return ( 0 );						// no MSCDEX or 0 CD-ROM units

	present:						// One or more CD-ROMs

	regs.h.ah = 0x15;
	regs.h.al = 0x0c;					// get version number
	regs.x.bx = 0;
	int86 ( 0x2f, &regs, &regs );
	if ( regs.h.bh < 2 )
		return ( 1 );					// version < 2.0
	return ( 2 );						// version >= 2.0
}

//===========================================================================
//
//	End of file, drives.c
//
//===========================================================================

------------- ceh.asm --------------------------------------------------
;       setCEH()        Install replacement Critical Error Handler to cause
;			automatic "Fail" on drive-not-ready when testing
;			empty floppy drives.  All other conditions are passed
;			to the original handler
;
;	unsetCEH()	Use to deinstall our replacement CEH
;
;	use:	tasm /mx ceh.asm
;
;	written by Jesse Chisholm, 91.12.31
;	released to the Public Domain: 91.12.31
;	modified to use from C code by Jon Freivald, 92.01.12

;_STACK	segment	para stack 'STACK'
;	dw	100h dup (0)
;_STACK	ends

_TEXT	segment word public 'CODE'

	assume	cs:_TEXT

	PUBLIC _setCEH, _unsetCEH

Oldint24	dd	0		; store the original address

Newint24	dd	int24		; address of new CEH

;
; This code is executed during program's initialization
; to install the new critical error handler.
;

_setCEH		proc	near

		push	bx		; save some registers
		push	dx
		push	ds
		push	es

		mov	ax,3524h	; get the original vector
		int	21h
		mov	word ptr Oldint24,bx
		mov	bx,es
		mov	word ptr Oldint24+2, bx

		lds	dx,Newint24	; DS:DX == handler address
		mov	ax,2524h	; set new vector
		int	21h		; transfer to MS-DOS

		pop	es		; restore registers
		pop	ds
		pop	dx
		pop	bx

		ret
_setCEH		endp

;
; This code is executed in the program's termination and cleanup code
;
_unsetCEH	proc	near

		push	dx			; save some registers
		push	ds

		mov	dx,word ptr Oldint24	; check if vector ever set
		or	dx,word ptr Oldint24+2
		cmp	dx,0
		je	unsetCEHx		; no, don't reset

		mov	ax,2524h		; restore old address
		lds	dx,Oldint24
		int	21h

		xor	dx,dx			; zap address for next time
		mov	word ptr Oldint24,dx
		mov	word ptr Oldint24+2,dx

unsetCEHx:	pop	ds			; restore registers
		pop	dx

		ret
_unsetCEH	endp

;
; This is the replacement critical error handler.
; If the drive was not ready, it causes the MS-DOS function
; to "FAIL".  All other conditions are passed to the original
; int 24 handler.
;

int24		proc	far

		mov	ax,di		; get error code
		cmp	al,02h		; 02 == DRIVE NOT READY
		 je	FloppyNotReady
		jmp	far ptr [Oldint24]	; go to original handler

FloppyNotReady:
		mov	al,03h		; 03 == Fail function call in progress

		iret				; exit critical error handler
int24		endp

_TEXT	ends

	end

-------- numflopy.asm ------------------------------------------------

;unsigned short  number_floppy();

	EXTRN  _memory_model:byte

_TEXT	SEGMENT BYTE PUBLIC 'CODE'
	ASSUME CS:_TEXT
	PUBLIC _number_floppy
_number_floppy proc near
	sub  ax,ax		;clear AX in case none
	int  11h		;make BIOS equipment chk
	test ax,1		;any drives at all?
	jz   L1			;jump ahead if not
	and  ax,11000000B	;clear bits 0-5
	mov  cl,6		;ready for shift
	shr  ax,cl		;bits to bottom of AX
	inc  ax			;count from 1, not 0
L1:	cmp  _memory_model,0	;quit
	jle  Quit		;
	db   0CBh		;RET far
Quit:	ret			;RET near
_number_floppy endp
_TEXT	ENDS
	END


=============================================================================
                   Jon Freivald ( jaf%jaflrn@uunet.UU.NET )
	 Nothing is impossible for the man who doesn't have to do it.
		    PGP V2 public key available on request
=============================================================================