Инструменты пользователя

Инструменты сайта


msx:floppy_disk_filesystem_structure:020

Первая страницаПредыдущая страницаНазад к обзоруСледующая страницаПоследняя страница

II. Работа с файлами на дискете


Оставьте трудиться напрасно, стараясь извлечь
из одного разума всю мудрость; спрашивайте природу,
она хранит все истины и на вопросы ваши будет
отвечать вам непременно и удовлетворительно.

Р.Бэкон

II.1. Контрольный Буфер Файла

Для работы с файлами Вам, безусловно, пригодится информация о Контрольном Буфере Файла («File Control Block», FCB).

FCB — это такое место в оперативной памяти компьютера (всего 25h=37 байтов), где хранится вся информация, необходимая MSX-DOS для работы с одним файлом, находящимся на диске. В буфере управления файлом (он же — FCB) есть все: от номера дисковода и имени файла до даты и времени его рождения. В некоторых случаях Контрольным Буфером Файла называют и неполную информацию о файле — несколько первых байтов…

Предположим, что Вы программируете на языке MSX BASIC. Тогда Вы можете использовать в своих программах функцию

VARPTR(#n)

,

где:

  • VARPTR ( «VARiable PoinTeR» — «указатель переменной» ) — служебное слово;
  • n — арифметическое выражение, целая часть значения которого определяет номер FCB (от 0 до значения выражения, стоящего в правой части оператора MAXFILES= ).

Эта функция возвращает адрес X байта, начиная с которого расположен в памяти FCBn.

Взгляните на схему расположения информации в FCBn :

Управляющая информация ────╮        Данные
                 ┌───┬───┬─▼─┬───┬───┬───┬───┐
                 │▧▧▧│▧▧▧│∙∙∙│▧▧▧│███│∙∙∙│███│
                 └───┴───┴───┴───┴───┴───┴───┘
     Адреса ——▶   X  X+1     X+8 X+9    X+264
                  ▲
                  │
  Байт, адрес которого возвращает функция VARPTR(#n)

При открытии файла на языке ассемблера Вы должны создать FCB, в котором должна быть записана следующая информация:

           ┌─────┬─────────────────────────────────────────┐
           │Номер│           Содержимое байта              │
           │байта│                                         │
           ├─────┼─────────────────────────────────────────┤
           │ X   │ Тип файла:                              │
           │     │   1 — OPEN FOR INPUT                    │
           │     │   2 — OPEN FOR OUTPUT                   │
           │     │ или OPEN FOR APPEND (для диска)         │
           │     │   4 — файл прямого доступа (для диска)  │
           │     │ или файл последовательного доступа,     │
           │     │ открытый и для чтения, и для записи.    │
           │     │   8 — OPEN FOR APPEND                   │
           │     │     (для устройства MEM:)               │
           ├─────┼─────────────────────────────────────────┤
╭─────────── X+1 │    Ссылка на область памяти, в которой  │
│          │ X+2 │    хранится спецификация файла          │
│          ├─────┼─────────────────────────────────────────┤
│          │ X+3 │                  ?                      │
│          ├─────┼─────────────────────────────────────────┤
│          │ X+4 │ Номер текущего устройства:              │
│          │     │     0 — активное устройство по умолчанию│
│          │     │     1 — дисковод A:                     │
│          │     │     2 — дисковод B: , и т.д.            │
│          │     │   FCh — устройство GRP:                 │
│          │     │   FDh — устройство CRT:                 │
│          │     │   FEh — устройство LPT:                 │
│          │     │   FFh — устройство CAS:                 │
│          │     │ Дополнительные устройства:              │
│          │     │   D4h — устройство COM:                 │
│          │     │       (локальная сеть MSX-1)            │
│          │     │   C0h — устройство MEM:                 │
│          ├─────┼─────────────────────────────────────────┤
│          │ X+5 │                   ?                     │
│          ├─────┼─────────────────────────────────────────┤
│          │ ∙∙∙ │                   ?                     │
│          ├─────┼─────────────────────────────────────────┤
│          │ X+9 │ Содержимое записи файла (256 байт)      │
│          └─────┴─────────────────────────────────────────┘
│
│                 Спецификация файла
│  ┌─────┬────────────────────────────────────────────────────────┐
│  │Номер│                  Содержимое байта                      │
│  │байта│                                                        │
│  ├─────┼────────────────────────────────────────────────────────┤
╰──▶ +00 │ Номер дисковода (0 — по умолчанию, 1 — A:)             │
   │ +01 │ Имя файла                                              │
   │ +09 │ Расширение имени файла                                 │
   ├─────┼────────────────────────────────────────────────────────┤
   │ +12 │ Номер текущего блока (или записи)                      │
   │ +14 │ Текущий размер записи (по умолчанию равен 128)         │
   │ +16 │ Размер файла в байтах                                  │
   │ +20 │ Дата изменения файла                                   │
   │ +22 │ Время изменения файла                                  │
   ├─────┼────────────────────────────────────────────────────────┤
   │ +24 │ Идентификатор устройства ("Device ID", см. табл. ниже) │
   │ +25 │ Размещение директории ("Directory location")           │
   │ +26 │ Первый кластер файла                                   │
   │ +28 │ Последний кластер файла                                │
   │ +30 │ Последний доступный кластер (относительно начала файла)│
   ├─────┼────────────────────────────────────────────────────────┤
   │ +32 │ Номер текущей записи файла последовательного доступа   │
   ├─────┼────────────────────────────────────────────────────────┤
   │ +33 │ Номер случайной записи для файла прямого доступа       │
   │ +34 │ (байты 33,34,35 — если размер записи больше 63         │
   │ +35 │  байты 33,34,35,36 — если размер записи меньше 64)     │
   │ +36 │                                                        │
   └─────┴────────────────────────────────────────────────────────┘

Следует отметить, что в системе MSX BASIC значимыми являются все байты FCB, а в системе MSX-DOS при открытии файла используется только спецификация файла.

Device ID Устройство
040hДиск
0FFhCON (консоль)
0FBhPRN (принтер)
0FChLST (принтер)
0FEhAUX (вспомогательное)
0FDhNUL (нулевое)

II.2. Примеры использования точек BDOS, относящихся к работе с диском


Примеры, немногочисленные, лаконичные, приведенные
к месту, сообщают рассуждению блеск, глубину
и убедительность, но оно становится невразумительным,
если примеров и подробностей чересчур много.

Л.К.Вовенарг. Размышления и максимы

Предложенные ниже примеры позволят Вам подробнее разобраться в использовании входных точек системы BDOS, но для этого вначале необходимо хорошенько ознакомиться со структурой Контрольного Буфера Файла (FCB) и таблицей спецификации файла.

Пример 1. Считывание содержимого сектора.

       LD   C,1Ah         ;Установка нового адреса передачи
       LD   DE,500h       ;В регистре DE - адрес передачи
       CALL 5

       LD   DE,1          ;Чтение H секторов начиная с сектора
       LD   H,3           ;с номером 01, находящимся в регистре DE
       LD   L,0           ;В регистре L - номер дисковода
       LD   C,2Fh         ;Функция чтения
       JP   5

Пример 2. Программа, позволяющая пользователю, находящемуся в операционной системе, удалить файл, находящийся на диске.

BDOS   EQU   5             ;Точка BDOS для MSX-DOS.
       LD    DE,5Ch        ;Адрес FCB
       LD    C,13h         ;Функция BDOS, которая позволяет удалять
       CALL  BDOS          ;файл, определяемый FCB, начальный адрес
       OR    A             ;которого находитя в DE (DE = 005Ch).
       RET   Z             ;Если Файл на диске отсутствует, то выдаем
       LD    DE,MESS       ;сообщение об этом.
       LD    C,9           ;Функция 9 выводит на экран строку символов,
       JP    5             ;пока не встретит символ "$".
MESS:  DEFM  "File not found$"

Пример 3. Программа, позволяющая из операционной системы переименовать файл, находящийся на дискете.

BDOS   EQU   5             ;Точка BDOS для MSX-DOS.
       LD    DE,5Ch
; По этому адресу в операционной системе хранятся:
;   номер устройства (0-текущий дисковод);
;   имя файла и его расширение.
; Всего 12 байтов. Еще через 4 байта хранится то же самое для имени
; второго файла в командной строке. Таким образом, в DE+16 хранится
; первый байт блока FCB второго файла.
       LD    C,17h         ;Функция BDOS для переименования.
       CALL  BDOS          ;
       OR    A             ;Если  функция  выполнилась, то -  выход,
       RET   Z             ;иначе печать сообщения о том, что  файл
       LD    DE,MESS       ;отсутствует.
       LD    C,9           ;
       JP    5
MESS:  DEFM  "File not found$"

Пример 4. Программа, позволяющая создать файл на диске с данными, которые требуется сохранить (OPEN.DBS–имя нового файла).

BDOS   EQU   5             ;Точка BDOS для MSX-DOS.
       LD    DE,File       ;Функция BDOS, которая позволяет открыть
       LD    C,16h         ;новый файл на диске. Старый файл с этим
       CALL  BDOS          ;именем уничтожается.
       LD    HL,6          ;Пусть текущий размер записи будет равен
       LD    (File+14),HL  ; 6 (запишем только 6 байтов).
       LD    HL,0          ;Номер записи для файла  последовательного
       LD    (File+33),HL  ;доступа устанавливаем равным нулю.
       LD    (File+35),HL  ;Тот же номер записи - и для файла прямого
                           ;доступа. Все 4 байта заполняем 00h.
       LD    DE,Data       ;Установка адреса передачи ("откуда").
       LD    C,1Ah
       CALL  BDOS

       LD    DE,File       ;Осуществляем одну запись размером в 6 байт.
       LD    HL,1
       LD    C,26h         ;Функция BDOS для посылки записи в файл.
       CALL  BDOS

       LD    DE,File       ;При закрытии файла на диск дозаписывается
       LD    C,10h         ;все до последнего байта данных, временно
       JP    BDOS          ;расположившихся в оперативной памяти (в
                           ;буфере файла). Эта операция необходима
                           ;всегда при записи на диск.
File:  NOP
       DEFM  "OPEN    DBS" ;Имя нового файла.
       DEFS  25

Data:  DEFB 0Ah,0Bh,0Ch,0Dh,0Eh,0Fh; Данные.

Пример 5. Программа позволяет выводить каталог диска на экран.

       LD    DE,500h       ; Установка адреса передачи
       LD    C,1Ah
       CALL  BDOS
       LD    C,11h         ; Поиск первого появления файлов
       LD    DE,File       ; В имени файла используется специальный
START: CALL  5             ; символ "?"
       OR    A
       RET   NZ
       CALL  Consol        ; Если файл еще есть, то выводим имя.
       LD    C,12h         ; Поиск следующего появления файлов.
       JR    START         ; Когда поиск прекратится,
                           ; подпрограмма завершается
Consol:LD    HL,0A0Dh      ; Перевод строки в конце слова
       LD    (050Ch),HL
       LD    A,24h         ; Символ окончания строки "$"
       LD    (050Eh),A
       LD    DE,0501h      ; Первый байт - номер дисковода: его
       LD    C,9           ; не стоит выводить.
       JP    5
File:  DEFB  0,"???????????"  ; Шаблон поиска

Пример 6. Программа, позволяющая просмотреть содержание текстового файла, находящегося на диске.

BDOS   EQU   5
       LD    HL,5Ch        ;Пересылка номера устройства (драйвера)
       LD    DE,Konec      ;и имени файла в отведенную область для
       LD    BC,0Ch        ;дальнейшей работы с блоком FCB
       LDIR
       LD    DE,Konec      ;Открытие файла
       LD    C,0Fh
       CALL  BDOS
       LD    DE,Adres      ;Установление адреса передачи для загрузки
       LD    C,1Ah         ;файла с диска
       CALL  BDOS
       LD    HL,(Konec+16) ;Устанавливаем размер записи для считывания
       LD    (Konec+14),HL ;равный объему файла.
       LD    HL,0          ;Номер записи для файла прямого и последо﹣
       LD    (Konec+33),HL ;вательного доступа обнуляем, т. е. чита﹣
       LD    (Konec+35),HL ;ем файл с самого начала
       LD    HL,1          ;Производим считывание одной записи =размеру
       LD    DE,Konec      ;файла по адресу передачи
       LD    C,27h
       CALL  BDOS
       LD    HL,Adres      ;┌─────────────────────────────────────┐
LABL_1:LD    A,(HL)        ;│Программа распечатки ASCII кодов.    │
       CP    1Ah           ;│Вывод символов из текстового файла   │
       JP    Z,LABL_2      ;│будет осуществляться до тех пор,пока │
       INC   HL            ;│не встретиться  последний  символ    │
       RST   30h           ;│файла с кодом: 1Аh. Этот код означает│
       DEFB  0             ;│конец любого текстового файла.       │
       DEFW  0A2h          ;│(по стандарту ASCII)                 │
       JP    LABL_1        ;│                                     │
LABL_2:RST   0             ;│Выход в MSX-DOS (рестарт).           │
                           ;└─────────────────────────────────────┘
Konec: DEFS  38            ;Обнуление 38 байтов для блока FCB
Adres: DEFS  25            ;Адрес передачи

Пример 7. Программа, позволяющая копировать файлы.

FILEIN  EQU  5Ch          ;Системные адреса хранения
FILEOUT EQU  6Ch          ;слов командной строки
BDOS    EQU  5            ;Адрес вызова BDOS
                          ;Некоторые макро-определения:
READ    MACRO
        LD   HL,4000h     ;Копирование по 16 Kбайт
        LD   DE,FIN
        LD   C,27h        ;Функция считывания с диска
        CALL BDOS
        LD   (VAL),HL
        RET
        ENDM
WRITE   MACRO
        LD   DE,FOUT
        LD   C,26h        ;Функция записи на диск
        LD   HL,(VAL)
        CALL BDOS
        RET
        ENDM
CLOSE   MACRO
        LD   DE,FOUT
        LD   C,10h        ;Функция закрытия файла
        CALL BDOS
        RET
        ENDM
ADRES   MACRO
        LD   DE,800h
        LD   C,1Ah        ;Установка адреса передачи
        CALL BDOS
        RET
        ENDM
; ——————————————————————— ; Начало программы
START:  LD   A,0C9h       ;Для скоростной работы дисковода
        LD   (38h),A      ;прерывания по таймеру отключили
        DI
        LD   HL,FILEIN
        LD   DE,FIN       ;Первое слово командной строки -
        LD   BC,0Ch       ;и есть первый файл.
        LDIR
        LD   HL,FILEOUT+1
        LD   A,20h
        CP   (HL)
        JR   NZ,OTHER
        EX   DE,HL
        LD   HL,FILEIN+1
        LD   BC,0Bh       ;Если второго слова нет, то
        LDIR              ;имя файла(2) =: имя файла(1)
OTHER:  LD   HL,FILEOUT
        LD   DE,FOUT
        LD   BC,0Ch
        LDIR
        EI
        LD   DE,FIN
        LD   C,0Fh        ;Открытие для считывания файла(1)
        CALL BDOS
        RЕТ  NZ
        LD   DE,FOUT
        LD   C,16h        ;Открытие для записи файла(2)
        CALL BDOS
        LD   HL,0
        LD   (FIN+33),HL
        LD   (FIN+35),HL  ;Считываем и записываем с нулевой
        LD   (FOUT+33),HL ;записи
        LD   (FOUT+35),HL
        INC   HL
        LD   (FIN+14),HL
        LD   (FOUT+14),HL ;Размер записей = 1
SNOWA:  CALL LDIRADRES
        CALL DISKIN
        LD   A,H          ;Пока на выходе при считывании в HL
        OR   L            ;не будет 0, записываем количество
        JR   Z,ENDCOPY    ;считанных записей, иначе закрываем
        CALL LDIRADRES    ;файл (2)
        CALL DISKOUT
        JR   SNOWA
ENDCOPY:CALL DISKCLOSE
        LD   DE,STROKA    ;Сообщение о выполнении
        LD   C,9h
        CALL BDOS
        LD   A,0C3h       ;Воостановление прерываний по таймеру
        LD   (38h),A      ;и выход в систему
        RST  0
;Подпрограммы работы с дисководом, FCB, сообщения, переменные.
DISKIN:      READ
DISKOUT:     WRITE
DISKCLOSE:   CLOSE
LDIRADRES:   ADRES
STROKA:      DEFB 0Dh,0Ah
             DEFM "Copy complete$"
VAL:         DEFS 2
FIN:         DEFS 40
FOUT:        DEFS 40

Пример 8.

;
; ┌───────────────────────────────────────────────────┐
; │  Программа, позволяющая защитить диск от команд:  │
; │            DIR, COPY, DEL и т.д.                  │
; │   Т.е. ото всех команд ОС, кроме команды FORMAT.  │
; └───────────────────────────────────────────────────┘
;
        .z80
;
StrPar  EQU     82h             ;  По этому адресу расположена строка
                                ; параметров
Bdos    MACRO   asx             ; Макрос вызова подпрограмм BDOS
          ld      c,asx
          Call    5
        ENDM
; Устaновка нового адреса передачи для считывания каталога диска
        ld      de,NewDMA
        Bdos    1Ah
; Поиск имени дисковода и обработка результатов поиска
        ld      hl,StrPar
        ld      b,':'
        Call    SearCHR
        cp      255             ; Обработка ошибки
        jr      z,ErrStr
        dec     hl
        ld      a,(hl)          ; Обработка имени дисковода
        and     0DFh
        sub     'A'
; Получаем информацию о диске (заметьте, что в BDOS #1Bh имя драйвера
; "А" эквивалентно 01h)
        push    af
        ld      e,a
        inc     e
        Bdos    1Bh
        cp      255             ; Обработка ошибки
        jr      nz,Next_Step
        ld      de,Mess3
        jr      The_End
; Чтение каталога диска по адресу передачи
Next_Step:
        pop     af
        ld      l,a             ; Имя драйвера
        ld      h,7             ; Максимальная длина каталога
        ld      e,(ix+11h)      ;  Извлекаем номер первого
        ld      d,(ix+12h)      ; кластера каталога
        push    de              ;  Сохраняем de и hl для
        push    hl              ; записи перед выходом
        Bdos    2Fh             ; Читаем каталог в память
        ld      b,(ix+0Bh)      ;  Число файлов,
        ld      hl,NewDMA       ; адрес начала каталога в памяти
                                ; для последующей обработки
; Проверка ключей
        ld      a,(StrPar)
        cp      '-'
        jr      z,Protect
        cp      '+'
        jr      z,ReSet
; Плохие ключи - сообщение и выход
ErrStr:
        ld      de,Mess0
The_End:
        Bdos    9
        rst     0
;
; Засекречивание каталога. Для предотвращения возможной записи на этот
; диск все элементы директории должны быть активными, поэтому свободные
; входные точки заполняются.
Protect:
        ld      a,(hl)
        cp      0               ; Если первый символ элемента каталога
        jr      nz,F_0          ; равен 0, то установить его в "!"
        ld      (hl),'!'
F_0:    cp      0E5h            ; если же первый символ - "Е" русского
        jr      nz,F_1          ; алфавита, то установить его в ":"
        ld      (hl),':'
F_1:    ld      de,11
        add     hl,de
        set     1,(hl)          ; В байте атрибутов установить бит 1 в 1
        ld      de,21
        add     hl,de
        Djnz    Protect
        ld      bc,Mess1
        jr      Finish
; Рассекречивание каталога
ReSet:
        ld      a,(hl)
        cp      '!'             ; Если первый символ элемента каталога
        jr      nz,I_0          ; равен "!", то установить его в 0
        ld      (hl),0
I_0:    cp      ':'             ; Если первый символ элемента каталога
        jr      nz,I_1          ; равен ":", то установить его в "Е"
        ld      (hl),0E5h
I_1:    ld      de,11
        add     hl,de
        res     1,(hl)          ; Рассекретить файл
        ld      de,21
        add     hl,de
        Djnz    ReSet
        ld      bc,Mess2
; Перед выходом в систему - запись измененных секторов на диск
Finish: pop     hl
        pop     de
        push    bc
        Bdos    30h
        pop     de              ; Сообщение,
        jr      The_End         ; конец программы

;    Подпрограмма SearCHR
; Поиск символа в строке параметров, начиная с некоторой позиции
; Вход:  b  - код символа
;        hl - позиция в строке (абсолютный адрес)
; Выход:  если в  a - не 255,
;           то в hl - абсолютный адрес символа;
;        иначе в hl - адрес конца строки (образец не найден).

SearCHR:
        ld      a,(hl)
        cp      13
        jr      z,NoFound
        cp      b
        ret     z
        inc     hl
        jr      SearCHR
NoFound:
        ld      a,255
        ret

Mess0:  db      'Ошибка в строке параметров !',13,10
        db      'Вызов:   A> undir <ключи> <дисковод>',13,10
        db      ' <ключи> :  -  (спрятать)',13,10
        db      '            +  (рассекретить)',13,10,'$'
Mess1:  db      'Каталог засекречен !',13,10,'$'
Mess2:  db      'Каталог рассекречен !',13,10,'$'
Mess3:  db      'Плохое имя дисковода !',13,10,'$'

NewDMA  EQU     $

        END

Небольшое пояснение.
Если Вы заметили, наша программа различает, с чего начинается пустая входная точка каталога — с нуля или с «Е». Это было специально сделано для того, чтобы после засекречивания–рассекречивания директории диска не оставалось никаких следов работы этой программы. Предыдущий вариант этой утилиты не имел такой особенности. После рассекречивания все пустые входные точки начинались с кода Е5h, из–за чего очень сильно увеличивалось время прочтения каталога — система прочитывала все 112 имен файлов. Но стоит системе встретить входную точку, начинающуюся с нуля, она сразу прекращает просмотр каталога. Учитывая эту особенность, при совершенствовании программы мы несколько усложнили ее, заставив разли﹣ чать начало входных точек Справочника.

А теперь — внимание !
Маленький фокус (для тех, кто захочет немного поработать со скрытыми файлами)

Для того, чтобы найти в каталоге скрытый файл (с байтом атрибутов, неравным нулю), установите старший бит (со значением 80h) в номере драйвера в единицу.

Если, например, шаблон поиска расположен по адресу Pattern, то это можно сделать командами ассемблера:

        ld      a,(Pattern)
        or      80h
        ld      (Pattern),a

.

Теперь, пользуясь подпрограммами BDOS Search First и Search Next, Вы легко найдете не только файлы без установленного байта атрибутов, но и скрытые и др. файлы, находящиеся на диске.


Первая страницаПредыдущая страницаНазад к обзоруСледующая страницаПоследняя страница

msx/floppy_disk_filesystem_structure/020.txt · Последние изменения: 2023-06-04 13:44 — GreyWolf