;       SCCSID = @(#)d_qfsinf.asm	6.1 91/02/15
;	SCCSID = @(#)d_qfsinf.asm	1.4 90/01/22
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
;***  D_QFSINF.ASM - API stub routine DosQFsInfo
;
;	Member of API library
;	David Silverstein
;	Copyright MicroSoft Corporation, 1986
;	27-May-1986
;
;	library routine for API simulator
;
;	Called from dos 2.x,3.x compatible dos 5.x applications
;
;	Special Information
;		none
;
;	Modification History
;
;	06-Jan-87 (billme): Replace initial pushes and final pops
;	with calls to __api_begin and __api_end resp.  This will
;	reduce the size of FAPI and allow support for signals.
;
;	15-Jan-87 (billme): Change as many statics as possible to locals
;	to save space (both from not consuming static space and from
;	not have to use segment override - cs - for access)
;
;	27-Feb-87 (robertc): Added pop and push of bp in qfsi14 to
;	avoid use of corrupted register.
;
;	11-Jun-87 (robertc): moved buffer size check in level 2 to
;	before any other work is done.
;
;	1-Jul-87 (robertc): added check for critical error on disk
;	access int21 function exits.
;
;	22-Jul-87 (Tarng): Make DTA saved/restored correspondently.
;
;	18-Aug-87 (robertc): add cs override to acces of crit_err_flag
;
;	12-Apr-88 (robertc): fix exiting to avoid critical errors
;			     on retried errors.
include basemaca.inc
include realmac.inc
include dos2equ.inc
include error.inc
include api.inc

	EXTRN	__api_begin_lsf:near
	EXTRN	_api_getvrsn:near
	EXTRN	__api_end:near
	EXTRN	api_get_extended:far	;@@ added support for DOSErrorClass
	EXTRN	crit_err_flag:word	 ;@@need to check for critical error
;/********************** START OF SPECIFICATIONS *********************/
;/*								     */
;/* SUBROUTINE NAME: DosQFSInfo					     */
;/*								     */
;/* DESCRIPTIVE NAME: Dos Query File System Information		     */
;/*								     */
;/* FUNCTION: Gets information for a file system device		     */
;/*								     */
;/*								     */
;/*								     */
;/* NOTES:    Real Mode Only					     */
;/*	      Simulates OS/2 call from DOS 2.x,3.x environment	     */
;/*								     */
;/* ENTRY POINT: DosQFSInfo					     */
;/*								     */
;/*    LINKAGE: Call Far					     */
;/*								     */
;/* INPUT: Stack Frame in form of:				     */
;/*								     */
;/*	PUSH   WORD  DriveNumber - logical drive number		     */
;/*	PUSH   WORD  FSInfoLevel - level of file system		     */
;/*				   information required		     */
;/*	PUSH@  OTHER FSInfoBuf - storage area to return		     */
;/*				 file system info		     */
;/*	PUSH   WORD  FSInfoBufSize - length of FSInfoBuf	     */
;/*								     */
;/*								     */
;/* EXIT-NORMAL:   AX = 0					     */
;/*								     */
;/* EXIT-ERROR:	   AX = Errorcode				     */
;/*	  may return error code from Dos 2.x, 3.x, OS/2		     */
;/*								     */
;/* EFFECTS:  AX, all other registers preserved			     */
;/*								     */
;/* INTERNAL REFERENCES: none					     */
;/*								     */
;/*    ROUTINES: none						     */
;/*								     */
;/* EXTERNAL REFERENCES: crit_err_flag				     */
;/*								     */
;/*    ROUTINES: __api_begin_lsf				     */
;/*		 __api_end					     */
;/*		 api_get_extended				     */
;/*		 _api_get_version				     */
;/*		 Int 21h - Get Disk Free Space			     */
;/*		 Int 21h - Get DTA				     */
;/*		 Int 21h - Set DTA				     */
;/*		 Int 21h - Find First				     */
;/*		 Int 21h - Get/Set Media ID			     */
;/*								     */
;/*********************** END OF SPECIFICATIONS **********************/

;***	DOSQFSINFO
;
;	simulates DOS 5.0 call from DOS 2.x,3.x environment
;
;	errorcode = unsigned far pascal
;	DosQFsInfo(DriveNumber, FSInfoLevel, FSInfoBuf, FSInfoBufSize)
;
;	ENTRY:
;		DriveNumber - logical drive number
;		FSInfoLevel - level of file system information required
;		FSInfoBuf -  storage area to return file system info
;		FSInfoBufSize - length of FSInfoBuf
;
;	RETURN:
;		AX = 0 if no error, else error code (see DOS 5 spec)
;
;	Pseudo Code:
;		save registers
;		use BP as pointer to stack parameters
;		if level1
;			call get disk free space
;			load returned data into FSInfoBuf
;		if level2
;			save disk transfer address
;			set disk transfer address to local memory
;			search for volume label using find first
;			if found, copy label data into FSInfoBuf
;		restore registers
;		return
;
;	WARNING:
;		may return error code from Dos 2.x, 3.x (see dos manuals)
;

	title	DOSQFSINFO
;
;	EXTRN	DOSQFSINFO:FAR
;
;	PUSH	WORD DriveNumber
;	PUSH	WORD FSInfoLevel
;	PUSH	@ DWORD FSInfoBuf
;	PUSH	WORD FSInfoBufSize
;	CALL	DOSQFSINFO
;


; The purpose of this segment is to share a reusable data area between api
; library routines. This is a win since it decreases the total api library
; overhead in the application's executable.

APIBUF	segment byte common 'CODE'

__api_buffer	db	DTAFINDSTRUCSIZE dup(?)

APIBUF	ends


_TEXT	segment byte public 'CODE'

	assume	CS:_TEXT, DS:nothing

	public	DOSQFSINFO

DriveNumber	equ	[BP+14]
FSInfoLevel	equ	[BP+12]
FSInfoBuf	equ	[BP+8]
FSInfoBufSize	equ	[BP+6]

mediainfo	struc
level		dw	0
serial		dd	?
volume		db	11 dup(' ')
fstype		db	8  dup(' ')
mediainfo	ends
pcdosBuf	mediainfo	<>

LEVEL1			equ	1	; passed value for level 1 info
LEVEL2			equ	2	; passed value for level 2 info
LEVEL1_INFO_SIZE	equ	18	; bytes needed in FSInfoBuf for info
LEVEL2_INFO_SIZE	equ	17	; bytes needed for level 2 info
VOL_LABEL		equ	08h	; volume label file attribute
FNAME_PREFIX_SIZE	equ	8	; maximum filename size less extension
FNAME_EXT_SIZE		equ	3	; filename extension size


drivepath	db	'A:'
defltpath	db	'\*.*',0
					; local
oldDTA		equ	[bp-4]		; old DTA pointer (dd)
DTA_flag	db	0		; set DTA flag


DOSQFSINFO	proc	far

	mov	ax,4
	call	__api_begin_lsf ; init bp and save bp,ds,bx,cx,dx,si,di,es
				; also create local stack frame (size of ax)
				; required to save: bp,bx,cx,dx,ds,si,di

	push	bp		; save bp for __api_end

	cmp	word ptr [FSInfoLevel], LEVEL1	; do we have a valid info level?
	je	qfsi1
	cmp	word ptr [FSInfoLevel], LEVEL2	; do we have a valid info level?
	je	qfsi4
	mov	ax, error_invalid_level		; load error code
	jmp	qfsi18				;@@ go to exit point

qfsi1:
	;LEVEL 1
	; is the size of FSInfoBuf big enough?

	cmp	word ptr [FSInfoBufSize], LEVEL1_INFO_SIZE
	jae	qfsi2
	mov	ax, error_buffer_overflow	; load error code
	jmp	qfsi16				;@@ go to exit point

qfsi2:
	mov	dx, [DriveNumber]		; get drive number parameter
	mov	ah, D2_GetDskFreeSpc
	int	21h				; get disk free space function
	cmp	ax, 0ffffh			; was the drive invalid?
	jne	qfsi3				; drive ok

	mov	ax, error_invalid_drive		; load error code
	jmp	qfsi15				; go exit

qfsi3:
	les	di, [FSInfoBuf]			; get address of FSInfoBuf

	mov	es:[di + 4], ax			; sectors per allocation unit
	xor	ax, ax
	mov	es:[di + 6], ax

	mov	es:[di], ax			; File System ID
	mov	es:[di + 2], ax

	mov	es:[di + 8], dx			; number of allocation units
	mov	es:[di + 10], ax

	mov	es:[di + 12], bx		; available allocation units
	mov	es:[di + 14], ax

	mov	es:[di + 16], cx		; bytes per sector

	; ax is already cleared to zero (error return)

	jmp	qfsi18

qfsi4:
	;LEVEL 2
	call	_api_getvrsn
	cmp	ax,0A14h		; Is this OS/2 version 10.2
	jb	ChkPCDOS
; OS/2 10.2 method
	mov	cx,word ptr [FSInfoBufSize]
	mov	ax,6900h
	mov	bx,[DriveNumber]
	mov	bh,2
	lds	dx,[FSInfoBuf]
	int	21h
	ljc	ExtendedExit
	xor	ax,ax
	jmp	NormalExit

ChkPCDOS:
	cmp	ax,0400h		; Is is PCDOS 4.0 or greater
	jb	PCDOS3X			; No use old method

; PCDOS 4.0 and Above Method
	mov	ax,6900h
	mov	bx,[DriveNumber]
	mov	bh,0
	mov	dx, OFFSET pcdosBuf
	push	cs
	pop	ds
	int	21h
	ljc	ExtendedExit
;Move the serial Number into Users Buffer
	mov	si, OFFSET pcdosBuf + 2 ; DS:SI = Serial #
	les	di,[FSInfoBuf]
	mov	cx,2			;
	repnz	movsw			; Move Serial # to user Buffer
					; ds:si = volume label

;Move the Volume Label
	mov	cx,11
	inc	di			; point past the count
	repnz	movsb			; move the label

;Move the count into the Buffer
	mov	cx,11
	dec	di			; point back at last label char
CountLoop:
	cmp	byte ptr es:[di],' '	; is character a blank
	jne	GotCount		; non-blank exits loop
	dec	cx			; decrement count
	dec	di			; decrement character pointer
	loop	CountLoop		; look again.
GotCount:
	 mov	[FSInfoBuf]+5,cx
	jmp	NormalExit

PCDOS3X:

	; is the size of FSInfoBuf big enough? @@Moved before other work(P5470)

	mov	ax, error_buffer_overflow	; load error code
	cmp	word ptr [FSInfoBufSize], LEVEL2_INFO_SIZE
	jge	qfsi45
	jmp	qfsi18
qfsi45:
	cmp	word ptr [DriveNumber], 'Z'-'A'+1 ; valid drive number?
	jbe	qfsi5
	mov	ax, error_invalid_drive		; load error code
	jmp	qfsi18				; go exit with error
qfsi5:
	mov	ah, D2_GetDTA			; Get current disk transfer
	int	21h				; address and save it.
	mov	[oldDTA], bx
	mov	[oldDTA + 2], es

	mov	ah, D2_SetDTA			; Set a new disk transfer
	mov	dx, SEG APIBUF			; address for the find first
	mov	ds, dx				; call.
	mov	dx, offset APIBUF:__api_buffer
	int	21h
	mov	DTA_flag,1			; set up DTA flag

; Build pathname with the given drive number for the Find First call

	mov	dx, SEG _TEXT			; set up segment for path
	mov	ds, dx
	mov	ax, [DriveNumber]		; get drive number
	or	ax, ax				; default drive? @@performance
	jne	qfsi6				; go calc drive letter
	mov	dx, offset _TEXT:defltpath	; driveless path
	jmp	short qfsi7
qfsi6:
	add	al, 'A' - 1			; calc drive letter
	mov	bx, offset _TEXT:drivepath	; Load the drive letter into
	mov	byte ptr _TEXT:[bx], al		; the pathname.
	mov	dx, bx				; pathname pointer
qfsi7:
	mov	cx, VOL_LABEL			; search for volume label
	mov	ah, D2_FindFirst
	int	21h
	jnc	qfsi8				; found volume label
	mov	ax, error_no_volume_label	; error code for no volume label
	jmp	short qfsi15			; go exit with error code in ax

qfsi8:

	cld					; clear direction flag
	mov	ax, SEG APIBUF
	mov	ds, ax
	les	di, [FSInfoBuf]			; get address of FSInfoBuf
	lea	si, APIBUF:[__api_buffer].find_FileDate
	movsw					; copy label date into FSinfoBuf
	lea	si, APIBUF:[__api_buffer].find_FileTime
	movsw					; copy label time into FSinfoBuf
	lea	si, APIBUF:[__api_buffer].find_FileName

	mov	bx, di			; save label size pointer for later
	inc	di			; inc past label size

	mov	cx, FNAME_PREFIX_SIZE
	xor	bp, bp			; clear label size counter
qfsi9:
	lodsb				; get label char
	or	al, al			; is this the end? @@performance
	je	qfsi13			; go add null terminator
	cmp	al, '.'
	je	qfsi10			; go pad with spaces for rest of prefix
	inc	bp			; inc label size counter
	stosb				; store label char in FSinfoBuf
	loop	qfsi9			; loop for entire prefix
	jmp	short qfsi11
qfsi10:
	mov	al, ' '			; pad remainer of prefix with spaces
	add	bp, cx			; add space count to label size counter
	rep	stosb
qfsi11:
	mov	cx, FNAME_EXT_SIZE
qfsi12:
	lodsb				; get next volume label char
	or	al, al			; is this the end? @@performance
	je	qfsi13			; go add null terminator
	cmp	al, '.'			; is this is '.'?
	je	qfsi12			; ignore it
	inc	bp			; inc label size counter
	stosb				; store label char in FSinfoBuf
	loop	qfsi12			; loop for file extension size
qfsi13:
	xor	ax, ax
	stosb				; store null terminator
	mov	cx, bp			; get volume label length
	mov	es:[bx], cl		; save in FSinfoBuf
	jmp	qfsi16			;@ No error path

qfsi15:
	cmp	cs:crit_err_flag,0ffh	;@@ did a critical error occur
	jne	qfsi16			;@@
	call	api_get_extended	;@@ added support for DOSErrorClass

qfsi16:					;@@
	cmp	DTA_flag,0		;@@ Is DTA changed?
	je	qfsi18
	xchg	ax, bx				; save error code
	mov	ah, D2_SetDTA			; restore old disk transfer area
	pop	bp			; we might have destroyed original
	lds	dx, dword ptr [oldDTA]
	push	bp			; do not need it till exit time
	int	21h
	xchg	bx, ax				; restore error code
	mov	DTA_flag,0			; turn off DTA flag

qfsi18:
	jmp	short NormalExit
ExtendedExit:
	call	api_get_extended

NormalExit:
	pop	bp		; restore bp for __api_end
	mov	cs:crit_err_flag,0h   ;@@ reset possible critical error flag

	call	__api_end	; check sigs & restore es,di,si,dx,cx,bx,ds,bp

	ret	10	; clear stack of entry parameters (bytes)

DOSQFSINFO	endp

_TEXT	ends

	end
