summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/CHKDSK/CHKDSK1.ASM
blob: 6d85d4270457236f50eb09f554c643a5f1c0c3dd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
 TITLE	 CHKDSK - MS-DOS Disk consistancy checker ;
page	,132					;

	.xlist
	include chkseg.inc							;an005;bgb
	INCLUDE CHKCHNG.INC
	INCLUDE DOSSYM.INC
	INCLUDE syscall.inc							;an041;bgb
	INCLUDE ioctl.inc							;an041;bgb;an041;bgb
	INCLUDE CHKEQU.INC
	INCLUDE CHKMACRO.INC
	include chkdata.inc							;an005;bgb
	include pathmac.inc

CODE	SEGMENT PUBLIC PARA 'CODE'
ASSUME	CS:DG,DS:NOTHING,ES:DG,SS:dg
 EXTRN	INT_23:NEAR,   readft:near	    ;an005;bgb
 EXTRN	FATAL:NEAR, PROMPTYN:NEAR, GET_CURRDIR:NEAR
 extrn	calc_fatmap_seg:near, FINDCHAIN:NEAR, CHECKERR:NEAR, DIRPROC:NEAR
 extrn	CHKMAP:NEAR, Main_Init:Near					     ;an049;bgb
 EXTRN	CHKCROSS:NEAR, AMDONE:NEAR, UNPACK:NEAR, GET_THISEL2:NEAR
 EXTRN	PRINTF_CRLF:NEAR, DOCRLF:NEAR, REPORT:NEAR
 extrn	init_fatmap:near, CHKPRMT_END:near					;an005;bgb
 extrn	hook_interrupts:near
 extrn	CHECK_DBCS_CHARACTER:NEAR						;an055;bgb

public SETSTACK, OkDrive, DRVISOK, Root_CD_Ok, NOTVOLID, fat16b, SMALLFAT
public BAD_STACK, RDLOOP, NORETRY1, RDOK, IDOK, ALLDONE, CHECKFILES, GotPath
public IS_ROOT_DIR, NOT_ROOT_DIR, VALID_PATH, ParseName, ScanFile, FRAGCHK
public EACHCLUS, LASTCLUS, NXTCHK, GETNXT, MSGCHK, FILSPOK, CDONE, CDONE1
public PRINTID, FIGREC, Main_Routine, checkit
	.list


	pathlabl chkdsk1
CHKDSK:
; find out if we have enough memory to do the job
    mov     cs:save_drive,al		;save drive validity
;;;;int     12h 			;1k blocks (640k = 280h)		;an054;bgb;an050;bgb
;;;;mov     bx,64			;number of paragraphs			;an054;bgb;an050;bgb
;;;;mul     bx				;640k = a000				;an054;bgb;an050;bgb
;;;;mov     cs:[mem_size],ax		    ;returns number of 1k blocks	;an054;bgb;an050;bgb
    DOS_Call GetCurrentPSP		    ;Get PSP segment address		;Ac034;bgb
    mov     cs:psp_segment,bx							   ;ac034;bgb
    mov     ds,bx			    ;ds points to the psp		;Ac034;bgb
    Assume  DS:Nothing
    MOV     DX,DS:[2]			    ;High break
    mov     cs:[mem_size],dx		    ;move it into data area		;an054;bgb
    MOV     BX,0FFFFH			    ;need at least 64k bytes
    MOV     CX,CS	    ;get segment of where we are
    SUB     DX,CX	    ;top-of-mem  -  pgm  =  # para left in alloc block
    CMP     DX,0FFFH	    ; is the space available > 64K ?
;   $IF     B
    JNB $$IF1
	MOV	CX,4		; Yes, set SP to BX (FFF0)
	SHL	DX,CL		; Convert remaining memory to bytes
	MOV	BX,DX
;   $ENDIF
$$IF1:
SETSTACK:	       ;***Set_Memory*********
    CLI
    PUSH    CS
    POP     SS
ASSUME	SS:DG
    MOV     SP,BX
    STI
    PUSH    AX
    JMP     Main_Init			    ;Go to init routines


;**************************************************************************
; MAIN-ROUTINE
;
; called by - main-init
;
; LOGIC
; *****
;	- get the dpb addr
;	- set the default drive to here
;	- save the directory we are on
;	- set the directory to the root of the drive
;	- print the volume name
;	- get the dpb info
;	- get the addr of the fatmap area
;	- calculate the amount of stack space we have
;**************************************************************************
Main_Routine:
    set_data_segment
OkDrive:
;get the dpb addr  from this drive
    mov      dl,AllDrv			     ;Get drive number		     ;AN000;
    DOS_Call Get_DPB		 ;func 32    ;Get DPB pointer		     ;AC000;
    ASSUME  DS:NOTHING,cs:DG
    CMP     AL,-1			   ;is this a good drive?
;   $IF  Z
    JNZ $$IF3
;;;;;;;;JNZ	DRVISOK 		   ;Bad drive (should always be ok)
	LEA	DX,BADDRV_arg		   ;This should never happen		;AC000;
	push	cs
	pop	ds
	call	PRINTf_crlf		       ;			       ;AC000;
	mov	ExitStatus,Bad_Exit	;Get return code			;AC000;
	ret					;Go back to Main_Init		;AC000;
;   $ENDIF
$$IF3:
    MOV     WORD PTR CS:[THISDPB+2],DS	    ;get the dpb segment
    set_data_segment			    ;reset ds to the pgm
    MOV     WORD PTR [THISDPB],BX	    ;get the dpb offset

;**Set_Drive_Info*************************************************************
DRVISOK:
    push    dx
    push    es
    call    hook_interrupts
    pop     es
    pop     dx
; make this drive the default drive
    DEC     DL				    ;A=0 b=1 c=2
    DOS_Call	    Set_Default_Drive	    ;func 0e - no return	       ;AC000;

;get the name of the current directory
    INC     DL				    ;drive number a=1 b=2 c=3
    LEA     SI,USERDIR+1		    ;				    ;AC000;
    DOS_Call	    Current_Dir 	    ;				    ;AC000;
;;;;PUSH    CS
;;;;POP     ES

;change the current directory to the root
    lea     DX,rootstr			;					;an005;bgb
    DOS_Call	    ChDir		    ;				    ;AC000;
;   $IF     C				;will this ever happen?
    JNC $$IF5
;;;;;;;;jnc	Root_CD_Ok			;				;AN000;
	MOV	DX,OFFSET DG:BADCD_arg
	call	display_interface		       ;			       ;AC000;
	mov	ExitStatus,Bad_Exit	;Get return code		       ;AC000;
	ret					;Go back to Main_Init	       ;AC000;
;   $ENDIF
$$IF5:

;get the dpb info
    LDS     BX,[THISDPB]		;ds:bx--> dpb area
    ASSUME  DS:NOTHING
    MOV     AX,[BX.dpb_sector_size]	;Bytes/sector
    MOV     [SSIZE],AX			;Sector size in bytes
    MOV     AL,[BX.dpb_cluster_mask]
    INC     AL
    MOV     [CSIZE],AL			;Sectors per cluster
    MOV     AX,[BX.dpb_max_cluster]	; number of clusters in the disk
    MOV     [MCLUS],AX			;Bound for FAT searching
    DEC     AX			    ;ax= max clusters - 1			;an005;bgb
    MOV     [DSIZE],AX		    ;Total data clusters on disk		;an005;bgb
    CMP     AX,4096-8			;Big or little FAT?
;   $IF     NB
    JB $$IF7
fat16b: INC	es:[BIGFAT]		   ;set 16-bit fat flag to true
	MOV	es:[EOFVAL],0FFF8H	   ;set 16-bit compare fields for fat
	MOV	es:[CHAIN_END],0FFFFh		   ;Marker for end of chain	   ;AC000;
	MOV	es:[BADVAL],0FFF7H	   ;set 16-bit compare fields for fat
;   $ENDIF
$$IF7:
    mov     ax,[bx.dpb_FAT_size]    ;Sectors for one fat (DCR)			;an005;bgb
    mov     fatsiz,ax		    ;Sectors for one fat (DCR)			;an005;bgb
    MOV     CL,[BX.dpb_FAT_count]	   ;Number of FATs			;an005;bgb
    mov     fatcnt,cl								;an005;bgb
    MOV     DX,[BX.dpb_first_FAT]	   ;First sector of FAT 		;an005;bgb
    MOV     firstfat,dx 		   ;First sector of FAT 		;an005;bgb
    MOV     DX,[BX.dpb_first_sector]	   ;First sector of data		;ac048;bgb
    MOV     firstsec,dx 		   ;First sector of data		;ac048;bgb
    MOV     DX,[BX.dpb_dir_sector]	 ;First sector of dir			;ac048;bgb
    MOV     dirsec,dx			 ;First sector of dir			;ac048;bgb
    MOV     DX,[BX.dpb_root_entries]	 ;First sector of dir			;ac048;bgb
    MOV     root_entries,dx			 ;First sector of dir		;ac048;bgb
    set_data_segment			;reset ds to point to data area

;calc fatmap area
SMALLFAT:	    ;do this for both size fats
    ;old calculation
    ;;;;DEC	AX			;ax= max clusters - 1			    ;an005;bgb
    ;;;;MOV	[DSIZE],AX		;Total data clusters on disk		    ;an005;bgb
    ;;;;MOV	AX,[BX.dpb_FAT_size]	;Sectors for one fat (DCR)		    ;an005;bgb
    ;;;;MOV	CX,AX			;CX = Sectors/Fat			    ;an005;bgb
    ;;;;MUL	[SSIZE] 		;times bytes/sector = bytes per fat	    ;an005;bgb
    ;;;;ADD	fatmap,AX	      ;Allocate FAT space			    ;an005;bgb
    ;;;;MOV	AX,fatmap		 ;  get seg of fatmap			    ;an005;bgb

Root_CD_Ok:					 ;				;AN000;
;set dta area----do i need to do this since we are using int 25?
;set it to fat table
    call    calc_fatmap_seg	    ;find the addr of where to put the fat map	;an005;bgb
;see if we still have enough memory
    mov     ax,mem_size 	     ;get top of memory
    cmp     ax,end_of_fatmap	     ;mem_size must be greater or equal
;   $IF     B			     ; if not, display error msg
    JNB $$IF9
	MOV	DX,OFFSET DG:no_mem_arg
	invoke	printf_crlf
	jmp	alldone 	     ;finished with pgm
;   $ENDIF
$$IF9:
    push    ds				;save ds
    mov     ds,fattbl_seg		;get seg
    xor     dx,dx			;ds:dx--> dta area
;;;;mov     fatmap,dx
    DOS_Call	    Set_DMA		;function 1a			    ;AC000;
    pop     ds				;restore ds

;look for volume entry in dir
    lea     DX,volid			    ;Look for VOL ID			;an005;bgb
    DOS_Call	    Dir_Search_First	    ;function 11		    ;AC000;
    CMP     AL,0			;did we find it?
;   $IF     Z				;yes
    JNZ $$IF11
;;;;;;;;JZ	NOTVOLID
	CALL	PRINTID 		;print volume name, date, time
;   $ENDIF
$$IF11:
NOTVOLID:
    call    get_serial_num		;print volume serial number		;an024;bgb
;;;;call    hook_interrupts
; calculate the place where we run out of ram space				;an005;bgb
;;;;ADD     AX,[MCLUS]	    ;5000    ;fatmap seg + num of clusters?					      ;an005;bgb
;;;;ADD     AX,2	    ;5002   ;Insurance					;an005;bgb
;;;;MOV     [SECBUF],AX 	    ;Allocate fatmap space			;an005;bgb
    mov     ax, offset dg:chkprmt_end ;this label must be the last thing in the code segment
    mov     [secbuf],AX 	    ;location of read/write buffer for dir entries ;an005;bgb
;;;;ADD     AX,[SSIZE]	    ;5202						;an005;bgb
;;;;ADD     AX,20	    ;5216   ;Insurance					;an005;bgb
    mov     ax,0ffffh	    ;get end of segment
    lea     bx,fattbl	    ;get end of program
    sub     ax,bx	    ;this is the amount of stack space we have
    MOV     [STACKLIM],AX	    ;Limit on recursion 			;an005;bgb
; see if we have already overrun the stack
    MOV     DI,SP		     ;where is the stack pointer now?		;an005;bgb
    SUB     DI,100H		    ; Want AT LEAST this much stack from	;an005;bgb
				       ;  our current location			;an005;bgb
    CMP     DI,AX
;   $IF     B
    JNB $$IF13
;;;;;;;;JB	BAD_STACK		; Already in trouble
BAD_STACK:
	MOV	BX,OFFSET DG:STACKMES	;Out of stack
	PUSH	CS
	POP	DS
	JMP	FATAL
;   $ENDIF
$$IF13:

;
;**Read in FAT*****************************************************************
;;;;MOV     DI,fatsiz			;sectors per fat			;an005;bgb
;;;;MOV     CL,[BX.dpb_FAT_count]	   ;Number of FATs
;;;;MOV     DX,[BX.dpb_first_FAT]	   ;First sector of FAT
    mov     cx,fatsiz			;number of sectors to read		;an005;bgb
    mov     dx,firstfat 		;starting sector number 		;an005;bgb
    mov     es,fattbl_seg   ;set up bx for read-disk				;an005;bgb
    xor     bx,bx								;an005;bgb
    MOV     AL,[ALLDRV]     ;set up al with drive letter for read-disk
    DEC     AL		    ;zero based
;;;;MOV     AH,1
RDLOOP:
;;;;XCHG    CX,DI			    ;DI has # of Fats
    call    readft		    ;	readft ();				;AN005;bgb
;   $IF     C			    ; could the fat be read from disk?		;AN005;bgb
    JNC $$IF15
	inc	byte ptr [nul_arg]						;an005;bgb
;;;;;;;;mov	[fatal_arg2],offset dg:baddrvm					;an005;bgb
	mov	[fatmsg2],offset dg:baddrvm				     ;an005;bgb
	lea	BX,badread							;an022;bgb
	JMP	FATAL			;Couldn't read any FAT, BARF            ;an005;bgb
;   $ENDIF			    ;fat could be read from disk		;AN005;bgb
$$IF15:

;   savereg <dx,cx,di,ax>							;an005;bgb
;   mov     Read_Write_Relative.Start_Sector_High,0 ;			    ;AN000;
;   call     Read_Disk		     ;Read in the FAT			     ;AC000;
;   $IF      C
;;;;;;;;JNC	RDOK
;;;;;;;;mov	[badrw_str],offset dg:reading
;	POP	AX			; Get fat# in ah
;	PUSH	AX			; Back on stack
;	xchg	al,ah			; Fat # to AL
;	xor	ah,ah			; Make it a word
;	mov	[badrw_num],ax
;	mov	dx,offset dg:badr_arg
;	invoke	printf_crlf
;	restorereg <ax,cx,di,dx>						;an005;bgb
;	INC	AH
;	ADD	DX,DI
;	LOOP	RDLOOP			;Try next FAT
;;;;;;;;JMP	NORETRY1		;Couldn't read either                   ;AC000;
NORETRY1:
;	inc	byte ptr [nul_arg]
;	mov	[fatal_arg2],offset dg:baddrvm
;	MOV	BX,OFFSET DG:BADRDMES
;	JMP	FATAL			;Couldn't read any FAT, BARF
;   $ENDIF
RDOK:	;**Check_for_FAT_ID**********************************************
;;;;restorereg <ax,ax,ax,ax>	    ;Clean up					;an005;bgb
    mov     es,fattbl_seg	     ;segment of fat-table			;an005;bgb
    xor     si,si		     ;offset of first byte in fat-table 	;an005;bgb
;;;;LODSB			    ;Check FAT ID byte
    mov     al,byte ptr es:[si]     ;get first byte of fat table
    CMP     AL,0F8H		    ;is it the correct id byte?
;   $IF     B,AND
    JNB $$IF17
;;;;;;;;JAE	IDOK
    CMP     AL,0F0H		    ;if not, Is it a "strange" medium?
;   $IF     NZ
    JZ $$IF17
;;;;;;;;jz	IDOK		    ;neither fat nor strange
	MOV	DX,OFFSET DG:BADIDBYT	;FAT ID bad
	CALL	PROMPTYN		;Ask user to stop or not
;	$IF	NZ
	JZ $$IF18
;;;;;;;;;;;;JZ	    IDOK
	    JMP     ALLDONE		    ;User said stop
;	$ENDIF
$$IF18:
;   $ENDIF
$$IF17:

;initialize the fatmap area to all zeros
IDOK:
    call    init_fatmap

;set the dta addr to here for all searches
    MOV     DX,OFFSET DG:DIRBUF     ;FOR ALL SEARCHING
    DOS_Call	    Set_DMA	    ;					    ;AC000;
    XOR     AX,AX		    ;zero out ax
    PUSH    AX			    ;I am root
    PUSH    AX			    ;Parent is root
;
    set_data_segment
checkit:
    CALL    DIRPROC
    CALL    CHKMAP		    ;Look for badsectors, orphans
    CALL    CHKCROSS		    ;Check for second pass
    INVOKE  DOCRLF		     ;display new line
    CALL    REPORT		     ;finished, display data to screen

;*****************************************************************************
ALLDONE:
    CALL    AMDONE
;;;;;MOV     AH,EXIT
;;;;;;;;XOR	AL,AL
;;;;;; ;mov	ExitStatus,Bad_Exit	;Get return code			;AC000;
;;;;;;;;INT	21H
	ret				;Ret to Main_Init for common exit	;AN000;

ASSUME	DS:DG
;**Extent_Check***************************************************************
Break	<Check for extents in specified files>
;
; Search the directory for the files specified on the command line and report
; the number of fragmented allocation units found in each one.	We examine the
; given path name for a directory.  If it is found, we CHDIR to it.  In any
; event, we move to the file name part and do a parseFCB call to convert it
; into an FCB for a dir_search_first.  If the parse did NOT advance the
; pointer to the null byte terminating the string, then we have a bogus anme
; and we should report it.
;

CHECKFILES:
	set_data_segment
; see if there is a '\' in the path name
	MOV	DI,OFFSET DG:PATH_NAME
	MOV	SI,DI
	MOV	CX, FNAME_LEN		;					;an011;bgb
	ADD	DI,CX			; ES:DI points to char AFTER last char
	DEC	DI			; Point to last char
doagain: MOV	 AL,[DIRCHAR]		 ;try to find '\' in path name
	STD
	REPNE	SCASB
	CLD
;	$IF	Z			;a '\' was found in path		;an055;bgb
	JNZ $$IF21
	    mov     al,[di]		;get byte preceding '\' 		;an055;bgb
	    call    check_dbcs_character ;see if dbcs leading char		;an055;bgb
;	    $IF     C			;carry means dbcs leading char		;an055;bgb
	    JNC $$IF22
		jmp	doagain 	;so ignore				;an055;bgb
;	    $ELSE								;an055;bgb
	    JMP SHORT $$EN22
$$IF22:
		jmp	GotPath 	;found a '\' and not dbcs		;an055;bgb
;	    $ENDIF								;an055;bgb
$$EN22:
;	$ENDIF									;an055;bgb
$$IF21:
;;;;;;;;;;;;;;;;;;;;;JZ      GotPath		     ; found path char. 	;an055;bgb
; No '\' was found.  set up pointers for parse FCB call.
	MOV	DI,OFFSET DG:PATH_NAME
	CMP	BYTE PTR [DI+1],':'  ;was a drive letter entered?
	JNZ	ParseName
	ADD	DI,2
	JMP	SHORT ParseName

;*****************************************************************************
; found a '\' in the path name
;Change directories and set up the appropriate FCB
GotPath:
	INC	DI			; DI points AT the path sep
	PUSH	WORD PTR [DI]		; Save two chars here
	PUSH	DI			; Save location
	SUB	SI,DI
	JZ	IS_ROOT_DIR		; SI=DI=First char which is a dirchar
	NEG	SI
	CMP	SI,2
	JNZ	NOT_ROOT_DIR
	CMP	BYTE PTR [DI-1],':'	; d:\ root spec?
	JNZ	NOT_ROOT_DIR		; Nope
IS_ROOT_DIR:
	INC	DI			; Don't zap the path sep, zap NEXT char
NOT_ROOT_DIR:
	MOV	BYTE PTR [DI],0
	MOV	DX,OFFSET DG:PATH_NAME
	DOS_Call	Chdir		;					;AC000;
	POP	DI			; Recall loc
	POP	WORD PTR [DI]		; recall chars
	JNC	VALID_PATH
	INVOKE	DOCRLF
	MOV	DX,OFFSET DG:INVPATH_arg
	invoke	printf_crlf
	JMP	CDONE1

;*****************************************************************************
VALID_PATH:
	INC	[DIR_FIX]
	INC	DI		; Point past path sep to first char of name
ParseName:
; parse the filename and get back a formatted fcb for it in es:di
	MOV	SI,DI		      ; DS:SI points to name
	MOV	DI,offset dg:FCB_copy ; ES:DI points to FCB
	MOV	AL,ALLDRV	      ; drive number
	STOSB			      ; put it into fcb
	DEC	DI		      ; Back to start of FCB
	MOV	pFileName,SI	      ; save end of file name
	MOV	AL,00000010B	      ; tell parse to change drive letter if needed
	DOS_Call	Parse_File_Descriptor	;				;AC000;
	CMP	BYTE PTR [SI],0       ;ds:si should point past filename
	JZ	ScanFile
;
; Twiddle the file name to be truly bogus.  Zorch the drive letter
;
	MOV	BYTE PTR es:[DI],-1
ScanFile:
	INVOKE	DOCRLF
;set dma pointer to here
	MOV	DX,OFFSET DG:DIRBUF	;FOR ALL SEARCHING
	MOV	BP,DX
	ADD	BP,27			;bp points to clus in the dir entry
	DOS_Call	Set_DMA 	;set dma ptr here for dir search	 ;AC000;
;try to find the file specified
	MOV	AH,DIR_SEARCH_FIRST		 ;Look for the first file
FRAGCHK:
	MOV	DX,offset dg:FCB_copy
	INT	21H
	OR	AL,AL			;Did we find it?
	JNZ	MSGCHK			;No -- we're done
; we found the file
; look for fragmentation
	XOR	AX,AX			;Initialize the fragment counter
	MOV	SI,[BP] 		;Get the first cluster		     ;an005;bgb
	CALL	UNPACK			;see what that cluster points to
	CMP	DI,[EOFVAL]		;End-of-file?
	JAE	NXTCHK			;Yes -- go report the results
	INC	SI
	CMP	SI,DI
	JZ	EACHCLUS
	INC	AX
EACHCLUS:
	MOV	[OLDCLUS],DI		;Save the last cluster found
	MOV	SI,DI			;Get the next cluster
	CALL	UNPACK
	INC	[OLDCLUS]		;Bump the old cluster
	CMP	DI,[OLDCLUS]		;Are they the same?
	JNZ	LASTCLUS		;No -- check for end-of-file
	JMP	SHORT EACHCLUS		;Continue processing
LASTCLUS:
	CMP	DI,[EOFVAL]		;End-of-file?
	JAE	NXTCHK			;Yes -- go report the results
	INC	AX			;No -- found a fragement
	JMP	SHORT EACHCLUS		;Continue processing
NXTCHK: 	      ;reached the end of a file
	OR	AX,AX			;did we find any fragmentation?
	JZ	GETNXT
;we found fragmentation
	MOV	[FRAGMENT],2		;Signal that we output at least one file
	inc	ax			;bump by one for ends
	mov	[block_num],ax
	mov	word ptr rarg1,ax		 ;					 ;an011;bgb
	mov	word ptr rarg1+2,0
	mov	si,offset dg:dirbuf	;point to filename			;an011;bgb
	INC	SI			;move pointer past drive letter
; get the full path name for this file
	CALL	get_THISEL2
; print it out
	mov	dx,offset dg:extent_arg
	invoke	printf_crlf
GETNXT:
	MOV	AH,DIR_SEARCH_NEXT	    ;Look for the next file
	JMP	FRAGCHK
MSGCHK:
	CMP	AH,DIR_SEARCH_FIRST	;was this the first file searched for?
	JNZ	FILSPOK
;	MOV	SI,offset dg:FCB_copy + 1   ;File not found error
;	CALL	get_THISEL2
	MOV	SI,pFileName
	CALL	get_currdir
	mov	dx,offset dg:OPNERR_arg
	invoke	printf_crlf		    ;bad file spec
	jmp	short cdone
FILSPOK:
	CMP	BYTE PTR [FRAGMENT],2
	JZ	CDONE
; all files were ok
	mov	dx,offset dg:NOEXT_arg
	invoke	printf_crlf
CDONE:
	CMP	BYTE PTR [DIR_FIX],0
	JZ	CDONE1
	MOV	DX,OFFSET DG:USERDIR
	DOS_Call	ChDir			;				;AC000;
CDONE1:
	RET



; This is the old parameter passing scheme					;ac048;bgb
; inputs: AH - the sector number within the cluster				;ac048;bgb
;	  BX - cluster number							;ac048;bgb
; output: DX - absolute sector number						;ac048;bgb
;*****************************************************************************	;ac048;bgb
; FIGREC - This procedure calculates the absolute sector number of a logical	;ac048;bgb
;	   drive, given any cluster number and the sector within that cluster.	;ac048;bgb
;	   You can use this to find the sector number for a file.		;ac048;bgb
;										;ac048;bgb
;	   This procedure was entirely re-written for dos 4.0, since the	;ac048;bgb
;	   sector number can now be a DOUBLE word value.			;ac048;bgb
;										;ac048;bgb
; called by: getent in chkproc							;ac048;bgb
;										;ac048;bgb
; inputs: BX - cluster number							;ac048;bgb
;	  AH - sector number within cluster					;ac048;bgb
;	  csize - sectors per cluster (from dpb)				;ac048;bgb
;	  firstsec - starting sector number of the data area (from dpb) 	;ac048;bgb
;										;ac048;bgb
;outputs: DX - absolute sector number (low order)				;ac048;bgb
;	  INT26.start_sector_high     (hi  order)				;ac048;bgb
;										;ac048;bgb
;regs changed: DX only								;ac048;bgb
;										;ac048;bgb
;formula: cluster (3-fff7) * secs/cluster (1-8) = (3-7ffb8)			;ac048;bgb
;	  + sector-offset (0-8) + first-sector (1-ffff) = (7ffb9-8ffbf) 	;ac048;bgb
;										;ac048;bgb
; logic: 1. adjust the cluster number, since the 1st two clusters in the fat	;ac048;bgb
;	    are not used. cluster number can be from 3-fff7.			;ac048;bgb
;	 2. get the sectors-per-cluster, and multiply it times cluster number	;ac048;bgb
;	    in AX.  since this is a word multiply, the high order number goes	;ac048;bgb
;	    into DX.								;ac048;bgb
;	 3. add in the sector-number-within-the-cluster.  Each cluster		;ac048;bgb
;	    (usually) contains several sectors within a cluster.  This sector	;ac048;bgb
;	    number is that number.  It may be from zero to the max number of	;ac048;bgb
;	    sectors/cluster (which can be up to 8 so far on IBM systems).	;ac048;bgb
;	    Do an ADC in case there is a overflow of the word register. 	;ac048;bgb
;	 4. add in the starting cluster number of the data area.  This now	;ac048;bgb
;	    gives you the logical sector number within that drive.		;ac048;bgb
;*****************************************************************************	;ac048;bgb
procedure figrec,NEAR								;ac048;bgb
	push	ax		   ;save registers				;ac048;bgb
	push	bx		   ;save registers				;ac048;bgb
	push	cx		   ;save registers				;ac048;bgb
										;ac048;bgb
	xor	ch,ch		 ;clear out hi byte of sector-offset		;ac048;bgb
	mov	cl,ah		 ;move sector-offset into cx			;ac048;bgb
	mov	ax,bx		   ;move cluster number into ax for mult	;ac048;bgb
										;ac048;bgb
	xor	bh,bh		   ;zero out bh 				;ac048;bgb
	mov	bl,csize	   ;get sectors per cluster			;ac048;bgb
	dec	ax		   ; sub 2 for the 1st 2 unused clus in the fat ;ac048;bgb
	dec	ax			;					;ac048;bgb
	mul	bx		   ;ax=low word, dx=hi word			;ac048;bgb
										;ac048;bgb
	add	ax,cx		   ;add sector offset				;ac048;bgb
	adc	dx,0		   ;inc hi word if overflow			;ac048;bgb
	add	ax,[firstsec]	   ;add first data sector			;ac048;bgb
	adc	dx,0		   ;inc hi word if overflow			;ac048;bgb
										;ac048;bgb
	mov	Read_Write_Relative.Start_Sector_High,dx ;save hi value 	;ac048;bgb
	mov	dx,ax		 ;convert to old format- dx=low 		;ac048;bgb
										;ac048;bgb
	pop	cx								;ac048;bgb
	pop	bx								;ac048;bgb
	pop	ax								;ac048;bgb
	RET									;ac048;bgb
endproc figrec									;ac048;bgb


;*****************************************************************************
SUBTTL	PRINTID - Print Volume ID info
PAGE
PRINTID:
ASSUME	DS:DG
	call	docrlf				;				;AN000;
;get volume name								;an012;bgb
	xor	si,si			;Point at DTA where find first just done;;an005;bgb
	lea	DI,arg_buf		;Where to put vol name for message	;AC000;
	add	si,DirNam		;Point at the vol label name		;AN000;
;;;;;;;;lea	DI,arg_buf		;Point at vol label location in arg_Buf ;AC000;
	MOV	CX,11			; Pack the name
	push	ds								;an005;bgb
	mov	ds,fattbl_seg							;an005;bgb
	REP	MOVSB			; Move all of it
;get the year									;an012;bgb
	xor	si,si			;Get back pointer to FCB		;an009;bgb
	mov	ax,ds:[si].DirDat	   ;yyyyyyym mmmddddd Put in SysDisp form  ;AN009;bgb
	and	ax,Year_Mask		;yyyyyyy0 00000000			;AN000;
	shr	ax,1			;0yyyyyyy 00000000			;AN000;
	xchg	al,ah			;00000000 0yyyyyyy			;AN000;
	add	ax,1980 		;					;AN000;
	mov	es:Sublist_msg_Idmes.Sublist_Offset+(size Sublist_Struc),ax ;	   ;AN009;bgb
;get the month									;an012;bgb
	mov	ax,ds:[si].DirDat	   ;yyyyyyym mmmddddd			   ;AN009;bgb
	and	ax,Month_Mask		;0000000m mmm00000			;AN000;
	mov	cl,5			;					;AN000;
	shr	ax,cl			;00000000 0000mmmm			;AN000;
	mov	cl,al			;0000mmmm				;AN000;
;get the day									;an012;bgb
	mov	ax,ds:[si].DirDat	   ;yyyyyyym mmmddddd			   ;AN009;bgb
	and	ax,Day_Mask		;00000000 000ddddd			;AN000;
	mov	ah,cl			;0000mmmm 000ddddd			;AN000;
	xchg	ah,al			;make it display correctly		;an012;bgb
	mov	es:Sublist_msg_Idmes.Sublist_Segment+(size Sublist_Struc),ax ;	   ;AN009;bgb
;get the time									;an012;bgb
	mov	ax,ds:[si].DirTim	   ;hhhhhmmm mmmsssss			   ;AN009;bgb
	and	ax,Hour_Mask		;hhhhh000 00000000			;AN000;
	mov	cl,11			;					;AN000;
	shr	ax,cl			;00000000 000hhhhh			;AN000;
	mov	ch,al			;000hhhhh				;AN000;
	mov	ax,ds:[si].DirTim	   ;hhhhhmmm mmmsssss			   ;AN009;bgb
	and	ax,Minute_Mask		;00000mmm mmm00000			;AN000;
	mov	cl,3			;					;AN000;
	shl	ax,cl			;00mmmmmm 00000000		       ;AN000;
	mov	al,ch			;00mmmmmm 000hhhhh			;AN000;
	mov	es:Sublist_msg_Idmes.Sublist_Offset+(size Sublist_Struc)+(size Sublist_Struc),ax ;AN009;bgb
	mov	es:Sublist_msg_Idmes.Sublist_Segment+(size Sublist_Struc)+(size Sublist_Struc),0 ;AN009;bgb
	pop	ds								;an009;bgb
	Message Idmes_Arg		; the parts out as needed		;AC000'
;;;;;;;;call	doCRLF
	ret				;




;*****************************************************************************	;an024;bgb
; Get the volume serial number							;an024;bgb
;*****************************************************************************	;an024;bgb
; Input:  FCB_Drive								;an024;bgb
; Output: SerNum if no carry							;an024;bgb
; Notes:  Only DOS Version 3.4 and above will contain serial numbers		;an024;bgb
;*****************************************************************************	;an024;bgb
   PUBLIC GET_SERIAL_NUM							;an024;bgb
procedure Get_Serial_Num,NEAR		;AN000;S				     ;an024;bgb
   mov	al,GENERIC_IOCTL	   ;AN000;S					;an041;bgb;an024;bgb
   xor	bx,bx			   ;zero out bx 				;an041;bgb;an024;bgb
   mov	bl,alldrv		   ;AN000;S Which drive to check		;an024;bgb
   mov	ch,rawio		   ;8 = disk io 				;an041;bgb;an024;bgb
   mov	cl,Get_Media_Id 	   ;66h = get media id				;an041;bgb;an024;bgb
   LEA	dx,SerNumBuf		   ;AN000;S Pt to the buffer			;an024;bgb
   Dos_call ioctl		   ;AN000;S Make the call			;an041;bgb;an024;bgb
;  $IF	NC
   JC $$IF26
       message	msgserialnumber 						    ;an024;bgb
;  $ENDIF
$$IF26:
   ret				   ;AN000;S					;an024;bgb
endproc Get_Serial_Num			   ;AN000;S					;an024;bgb
	pathlabl chkdsk1							;an024;bgb
CODE	ENDS
	END	CHKDSK