Предпоследняя статья из цикла про структуры MS DOS. В этой статье разберём таблицу файлов DOS.
DOS создает таблицу открытых файлов и записывает её адрес в векторную таблицу связи (CVT) в поле file_tab (смотреть тему: viewtopic.php?t=97). В этой таблице для каждого открытого в системе файла хранится такая информация, как число(handle, дескриптор), режим открытия файла (чтение, запись, чтение и запись), два байта информации об устройстве (диске), указатель на заголовок драйвера, обслуживающего устройство, номер последнего прочитанного кластера, информация о файле (дата, время, имя, расширение, номер первого кластера и т.д.).
Размер таблицы файлов определяется строкой FILES=XX в файле config.sys. Каждая таблица DFT (DOS File Table) содержит адрес следующей таблицы и количество управляющих блоков файлов DFCB (DOS File Control Block) в этой таблице, каждому файлу соответствует свой DFCB.
Формат этой таблицы в разных версиях DOS отличается, приведу формат таблицы для версии DOS 3.x:
(0) dd next указатель на следующую таблицу файлов
(+4) dw file_count количество файлов в этой таблице
--- Дальше идут блоки DFCB в количестве file_count штук ----
(0) dw handl_num количество файловых чисел, связанных с данным файлом (file handle)
(+2) db access_mode режим доступа к файлу, заданный при открытии файла
(+3) dw reserv1 зарезервировано
(+5) dw dev_info информация IOCTL, полученная для устройства, на котором расположен этот файл
(+7) dd driver указатель на драйвер, обслуживающий устройство, содержащее файл
(+11)dw first_clu номер первого кластера, распределенного файлу
(+13)dw time время последнего изменения файла в упакованном формате
(+15)dw date дата последнего изменения файла в упакованном формате
(+17)dd fl_size размер файла в байтах
(+21)dd offset текущее смещение внутри файла в байтах
(+25)dw reserv2 зарезервировано
(+27)dw last_clu номер только что прочитанного кластера
(+29)3 reserv3 зарезервировано
(+32)11 filename имя файла в формате FCB (имя выровнено на левую границу поля, дополнено пробелами до 8 символов, справа к нему прилегает 3 символа расширения без точки)
(+43)dw reserv4 зарезервировано
(+45)dw ownr_psp PSP программы, открывшей файл
(+47)dw reserv5 зарезервировано
Формат таблицы для DOS 4.x:
(0) dd next указатель на следующую таблицу файлов
(+4) dw file_count количество файлов в этой таблице
--- Дальше идут блоки DFCB в количестве file_count штук ----
(0) dw handl_num количество файловых чисел, связанных с данным файлом (file handle)
(+2) db access_mode режим доступа к файлу, заданный при открытии файла
(+3) dw reserv1 зарезервировано
(+5) dw dev_info информация IOCTL, полученная для устройства, на котором расположен этот файл
(+7) dd driver указатель на драйвер, обслуживающий устройство, содержащее файл
(+11)dw first_clu номер первого кластера, распределенного файлу
(+13)dw time время последнего изменения файла в упакованном формате
(+15)dw date дата последнего изменения файла в упакованном формате
(+17)dd fl_size размер файла в байтах
(+21)dd offset текущее смещение внутри файла в байтах
(+25)dw reserv2 зарезервировано
(+27)dw reserv7 зарезервировано
(+29)3 reserv3 зарезервировано
(+32)db reserv4 зарезервировано
(+33)11 filename имя файла в формате FCB (имя выравнено на левую границу поля, дополнено пробелами до 8 символов, справа к нему прилегает 3 символа расширения без точки)
(+44)dw reserv5 зарезервировано
(+46)dw ownr_psp PSP программы, открывшей файл
(+48)dw reserv6 зарезервировано
(+50)dw last_clu номер только что прочитанного кластера
(+52)dd reserv8 зарезервировано
Теперь, когда мы знаем структуру этой области памяти, можно с ней поработать, как всегда, напишу программу, которая выводит нам список всех открытых файлов на экран:
Код: Выделить всё
.model tiny
.286
code segment
org 100h
start:
mov ah, 52h
int 21h
mov si, offset dft_addr
mov ax, word ptr es:[bx+4] ;
mov word ptr[si], ax ;
;write in variable address of DFT
mov ax, word ptr es:[bx+6] ;
mov word ptr[si+2], ax ;
read_dft:
;Write DFT in DS:[SI]
mov si, offset dft_addr
push word ptr[si]
push word ptr[si+2]
pop ds
pop si
push ss
pop es
mov di, offset dft.next
mov cx, 55d
rep movsb
push es
pop ds
work_with_dft:
mov si, offset dft_addr
push word ptr[si]
push offset display.num+8
call hex_ascii
push word ptr[si+2]
push offset display.num+3
call hex_ascii
;Read address of next DFT
mov si, offset dft.next
push word ptr[si]
push offset display.num0+8
call hex_ascii
push word ptr[si+2]
push offset display.num0+3
call hex_ascii
;Read count of files
push dft.file_count
push offset display.num1+3
call hex_dec
mov ah, 9d
mov dx, offset display.ths_dft_
int 21h
mov cx, dft.file_count
read_dfcb:
call read_file
mov ah, 9d
mov dx, offset display.filename_
int 21h
pusha
read_next_dfcb:
mov si, offset dft_addr
mov di, word ptr[si]
push word ptr[si+2]
pop ds
add off_in_dft, 59d
add di, off_in_dft
mov si, di
mov di, offset dft.handle_num
mov cx, 49d
rep movsb
push es
pop ds
;Clear fields of display structure
mov di, offset display.time_
mov cx, 3d
clr_time:
mov word ptr[di], 3030h
add di, 3d
loop clr_time
mov di, offset display.date_
mov word ptr[di], 3030h
add di, 3d
mov word ptr[di], 3030h
add di, 3d
mov word ptr[di], 3030h
add di, 2d
mov word ptr[di], 3030h
mov di, offset display.filesize_
mov cx, 9d
null_size:
mov byte ptr[di], 0
inc di
loop null_size
mov byte ptr[di], 30h
mov display.mode_, 30h
popa
loop read_dfcb
push si
push ax
push bx
mov si, offset dft.next
mov ax, word ptr[si]
mov bx, word ptr[si+2]
mov si, offset dft_addr
mov word ptr[si], ax
mov word ptr[si+2], bx
pop bx
pop ax
pop si
mov off_in_dft, 6d
cmp word ptr dft_addr, 0FFFFh
jz exit
jmp read_dft
exit:
mov ax, 4c00h
int 21h
dft_addr dd ?
off_in_dft dw 6d
display_ struc
ths_dft_ db 0Ah, 'THIS DFT TABLE;', 9d
num db 4d dup(0), ':', 4d dup(0), 0Ah, 0Dh
next_ db 'NEXT DFT TABLE:', 9d
num0 db 4d dup(0), ':', 4d dup(0), 0Ah, 0Dh
file_count_ db 'COUNT OF FILES:', 9d
num1 db 5d dup(0), 0Ah, 0Ah, 0Dh, 24h
filename_ db 8d dup(20), '.', 3d dup(20), 9d
time_ db '00:00:00', 9d
date_ db '00.00.0000', 9d
filesize_ db 9d dup(0), 30h, ' bytes', 9d
mode_ db 30h, 0Ah, 0Dh, 24h
display_ ends
display display_ <>
dft_ struc
next dd ?
file_count dw ?
handle_num dw ?
access_mode db ?
reserv1 dw ?
dev_info dw ?
driver dd ?
first_clu dw ?
time dw ?
date dw ?
fl_size dd ?
off_set dd ?
reserv2 dw ?
last_clu dw ?
reserv3 db 3d dup(?)
filename db 11d dup(?)
reserv4 dw ?
ownr_psp dw ?
reserv5 dw ?
dft_ ends
dft dft_ <>
;---------------------------------------
;Read and write in structure file info
read_file proc uses ax cx dx bx di
;Read file size
mov si, offset dft.fl_size
push word ptr[si+2]
push offset display.filesize_+4
call hex_dec
push word ptr[si]
push offset display.filesize_+9
call hex_dec
;Read filename and extension
mov si, offset dft.filename
mov di, offset display.filename_
mov cl, 8d
rep movsb
mov di, offset display.filename_+9
mov cl, 3d
rep movsb
;Read access mode of file
xor ax, ax
mov al, dft.access_mode
push ax
push offset display.mode_
call hex_dec
;Read date and unpacking
mov ax, dft.date
mov bx, ax
mov cx, ax
and ax, 0000000000011111b ;day
and bx, 0000000111100000b ;
shr bx, 5d ;month
and cx, 1111111000000000b ;
shr cx, 9d ;
add cx, 1980d ;year
push ax
push offset display.date_+1
call hex_dec
push bx
push offset display.date_+4
call hex_dec
push cx
push offset display.date_+9
call hex_dec
;Read time and unpacking
mov ax, dft.time
mov bx, ax
mov cx, ax
and ax, 0000000000011111b ;
shl al, 1d ;seconds
and bx, 0000011111100000b ;
shr bx, 5d ;minutes
and cx, 1111100000000000b ;
shr cx, 11d ;hours
push ax
push offset display.time_+7
call hex_dec
push bx
push offset display.time_+4
call hex_dec
push cx
push offset display.time_+1
call hex_dec
ret
read_file endp
;------------------------------------------
;HEX IN DECIMAL ASCII PROCEDURE.
;PARAMETERS(STACK):
;- NUMBER
;- LAST BYTE IN MEMORY FOR DISPLAY
hex_dec proc uses ax bx di dx bp
mov bp, sp
mov ax, word ptr ss:[bp+14]
mov di, word ptr ss:[bp+12]
mov bx, 0Ah
xor dx, dx
in_decimal:
cmp ax, 0
jz stop_decimal
div bx
add dl, 30h
mov byte ptr[di], dl
xor dx, dx
dec di
jmp in_decimal
stop_decimal:
ret 4
hex_dec endp
;---------------------------------------
;HEX NUMBER IN ASCII CODE PROCEDURE.
;PARAMETERS(STACK):
;- NUMBER
;- LAST BYTE IN ARRAY FOR DISPLAY
hex_ascii proc uses ax bx di cx bp
mov bp, sp
mov bx, word ptr ss:[bp+14]
mov di, word ptr ss:[bp+12]
mov cx, 4d
translate:
mov ax, bx
and ax, 0Fh
cmp al, 9d
ja letter
add al, 30h
mov byte ptr[di], al
ror bx, 4d
dec di
loop translate
jmp end_of_trans
letter:
add al, 37h
mov byte ptr[di], al
ror bx, 4d
dec di
loop translate
end_of_trans:
ret 4
hex_ascii endp
code ends
end start
Как можно заметить, наша программа это тоже открытый файл в ОС, так как она хранится на жёстком диске, то системе сначала надо открыть файл, затем прочитать его с диска и загрузить в оперативную память для выполнения.
Использовалась версия компилятора MASM 6.11 в контексте операционной системы MS DOS 6.22!
В своих статьях стараюсь максимально кратко и ёмко описать структуры MS DOS и зачем они используются, надеюсь, что у меня всё получается
Спасибо за внимание!
С уважением, push0ret!