четвер, 28 лютого 2013 р.

DOS FCB

Видалення файла
засобами FCB...
Колись давно-давно, коли я був у десятому класі (але згадати рік не видається можливим, 1995 або 1996, швидше все ж 95), активно цікавився комп'ютерами і дуже хотів розібратися, що ж то за мова така -- асемблер, вдалося мені купити тематичну книжку. Питер Абель, "Ассемблер и программирование для IBM PC", 1992 року російськомовного видання, вона ж, якщо я правильно вгадав, "I. B. M. Personal Computer Assembly Language and Programming" by Peter Abel, 1987.  Що схоже на правду, бо про 4.0 DOS там точно згадується, про новіші -- ні. (1)

Раніше я б назвав цю книжку дуже хорошою. Зараз, маючи можливість порівняти, але не маючи можливості позбутися впливу першого знайомства, стикаюся з певними труднощами у вираженні, що я про неї думаю. Книжка не дуже сильна. Багато що не пояснено або пояснено занадто вузько. Приклади містять багато помилок. Переклад, місцями, жахливий (2). З іншого боку -- вона була першою, дістати аналогічну літературу для мене було практично (3) неможливим, і таки змогла навчити початкам асемблеру, даючи можливість розвиватися далі. Так що я їй вдячний, як би там не було (4).

Здавалося б, до чого тут DOS 1.xx (пост раз, пост два, пост три)? Все просто. Читаючи її, натрапив на розповідь, про те, що ось є такий метод роботи з файлами, за допомогою FCB (File Control Blocks), який крутий, бо є в базовій версії DOS, а значить буде працювати всюди, а є інший, за допомогою "хендлів" (handles, номери файлів), який, відповідно, працюватиме не всюди, лише для DOS 2.0+. Проблема "раз" була в тому, що мені-тодішньому, не особливо досвідченому в асемблері, FCB-метод видався багато складнішим, ніж той другий, з використанням номерів файлів. Тому працював я виключно з останнім, але довго потім мене мучило, що я халявщик -- пішов легкою дорогою. Тут випливає проблема "два" -- не маючи в 15 років особливого досвіду, не маючи доступу до літератури, чи, тим більше, Інтернету (який в Україні вже потроху був, як не дивно, та ще й в моєму теперішньому інституті (5)), навіть не знаючи дати виходу оригінального видання -- 1987, я не зміг усвідомити, що в 1995-96 "базовий" DOS 1.00, як і всі його безпосередні обмеження дааавно неактуальні (6).

Недавно був у мене особливо поганий настрій, вирішив я спробувати ті FCB на смак. Вийшло як завжди -- чотири об'ємних поста...


Структура FCB

FCB ведуть свій родовід від CP/M, та були єдиним засобом роботи з файлами у DOS 1.XX. (Детальніше див. попередні пости). Власне, FCB -- певна структура даних, яку використовує програма для роботи з файлом, передаючи її адресу системним викликам. Існує в двох варіантах, "звичайному" та розширеному. Розмір FCB -- 37 байт, структура наступна:

Зміщення Розмір,
байт
Опис
00h 1 Номер диску. 0 -- поточний, 1 -- A, 2 -- B, і т.д., 0xFF заборонене -- служить маркером розширеного FCB. Встановлюється програмою. Якщо був нуль, після відкриття замінюється на фактичний номер диску.
01h 8 Доповнене пробілами до восьми символів ім'я файлу. Встановлюється програмою, змінювати в процесі роботи, підозрюю, не варто. Може бути CON:, AUX:, PRN:, NUL:, для новіших DOS -- також, COM1:,COM2:, LPT1:, LPT2:.
09h 3 Доповнене пробілами до восьми символів розширення файлу. Встановлюється програмою. 
0Ch 2 Номер поточного блоку. Може встановлюватися програмою, в процесі роботи змінюється DOS. (Наприклад, при послідовному доступу збільшується автоматично. Детальніше див. далі, ).
0Eh 2 Розмір запису. Блок складається із 127 записів. Після відкриття файлу набуває значення 128, може змінюватися програмою.
10h 4 Розмір файлу. Встановлюється DOS при відкритті файлу. При виводі у файл оновлюється DOS. Під час закриття файлу заноситься в каталог FAT. Цікаво, якщо змінити його вручну, той (помилковий!) розмір і пропишеться? Пітер Нортон у своїй книзі пише, що маніпулюючи цим полем, можна прочитати файл-директорію, (виставивши правильний атрибут у розширеному FCB), розмір якого прописано нульовим. Так то FCB-підсистема про директорії не знає нічого.
14h 2 Дата останньої зміни: біти 15-9 -- рік мінус 1980, біти 8-5 -- місяць, 4-0 -- день. Заповнюється DOS, що буде, якщо змінювати -- не знаю.
16h 2 Час останньої зміни (DOS 2+): біти 15-11 -- година (0-23), 10-5 -- хвилини, 4-0 -- к-сть секунд, поділена на два. (Тому квант часу -- 2 секунди). Заповнюється DOS, що буде, якщо змінювати -- не знаю.
18h 8 Зарезервовано для використання DOS. Недокументоване поле, використання, в залежності від версії, див. тут.
20h 1 Номер запису в межах поточного блоку. Записів у блоці -- 127. Встановлюється DOS, може змінюватися програмою.
21h 4 Номер запису для прямого доступу. (Нумерація -- наскрізна, на відміну від послідовного доступу за допомогою блок-номер запису.). Встановлюється тільки програмою (крім функції Int 21/AH=24h, яка генерує номер прямого доступу по блоку і запису). Якщо здійснюється прямий (довільний, на противагу послідовному) доступ, DOS значення полів 0Ch i 20h встановлює автоматично згідно цього поля.
Джерело -- таблиця #01345 списку переривань Ральфа Брауна (взагалі, значна частина посилань буде саме на ті списки, точніше, для простоти, на веб-сервер із ними, офіційна ж сторінка тут: "The x86 Interrupt List").

Вже сам опис натякає на плутаність і неоднозначність такого способу роботи з файлами. Блоки, записи, послідовний і прямий доступ із різною адресацією...

Крім того, видно що FCB, як і DOS 1.XX та CP/M нічого не знають про каталоги. В наступних версіях це обмеження було частково обійдено наступним трюком -- функції роботи з FCB вважали що звернення йде до поточного каталогу. Про дещо кумедні наслідки такого рішення див. підрозділ "PRN, AUX, NUL, CON" Додатку 2 першого поста серії. Для зовсім гурманів додали утиліту ASSIGN. Однак для повноцінного шляху в FCB місця немає, в наступних версіях, щоб не стикатися із такими проблемами в майбутньому, всю інформацію про файл перемістили в область внутрішніх даних DOS, програмі повідомляючи лише номер.

Якщо в першому байті FCB стоїть 0xFF, система вважатиме, що це розширений FCB:

ЗміщенняРозмір,
байт
Опис
00h (-07)10xFF -- сигнатура розширеного FCB.
01h (-06)5Зарезервовано.
06h (-01)1Атрибути файлу. 
07h
(0, початок FCB)
37Власне FCB, як описано вище.

В DOS 1.XX вся інформація про відкритий файл зберігалася безпосередньо в FCB, тому кількість відкритих файлів обмежувалася лише доступною пам'яттю. В DOS 2+ FCB, по великому рахунку, лише посилання на внутрішні структури даних, однак, через особливості (примітивність :) мененджементу пам'яті, місце для них виділяється при запуску, тому максимальна кількість файлів, відкритих через FCB, обмежена. Для керування нею використовується змінна FCBS у файлі CONFIG.SYS.

Функції, що використовують FCB

Як відомо, виклик більшості (але не всіх!) системних функцій DOS здійснюється за допомогою переривання 21h. При тому, код системного виклику, конкретної операції, передається в AH. З FCB працюють наступні:
  • Int 21/AH=0Fh -- відкрити файл за допомогою FCB (на далі цю ремарку не писатиму)
  • Int 21/AH=10h -- закрити файл.
  • Int 21/AH=11h -- "Find First", знайти перший файл по масці.
  • Int 21/AH=12h -- "Find Next", знайти наступний файл по масці.
  • Int 21/AH=13h -- видалити файл.
  • Int 21/AH=14h -- послідовне читання.
  • Int 21/AH=15h -- послідовний запис.
  • Int 21/AH=16h -- створити файл, якщо існує -- обрізається до нуля.
  • Int 21/AH=17h -- перейменувати файл.
  • Int 21/AH=21h -- пряме читання з файлу.
  • Int 21/AH=22h -- прямий запис у файл.
  • Int 21/AH=23h -- отримати розмір файлу в записах.
  • Int 21/AH=24h -- встановити поле прямого запису згідно номера блоку і запису в ньому.
  • Int 21/AH=27h -- блочне пряме читання, з автоматичним оновленням номеру запису.
  • Int 21/AH=28h -- блочний прямий запис, з автоматичним оновленням номеру запису.
  • Int 21/AH=29h -- згенерувати FCB по імені файлу. В імені допускаються wildcard-и (* розширяється до відповідної кількості знаків питань), ім'я диску, але не шлях. 
  • Int 21/AH=1Ah -- встановити область Disk Transfer Area (DTA). Безпосередньо до FCB відношення не має, однак читання-запис здійснюється саме в/з DTA. По замовчуванню під нього виділено поле розміром 127 байт (80h-1) в PSP, за зміщенням 0080h. Але зазвичай цього мало, крім того, там же знаходиться аргументи командної стрічки, переданої при запуску програми.
Повний список функцій DOS по версіях див. тут.

DOS 1.XX підтримував для файлів, відкритих за допомогою FCB, буфер, розміром в один сектор -- якщо записів було менше, ніж 512 байт, вони накопичувалися в ньому, і аж по його заповненню записувалися на диск.

Приклади використання

Детально розписувати не буду, за неактуальністю, просто декілька практичних "етюдів".

Використовуватиметься Flat Assembler. Щоб не писати кожного разу оголошення всіх полів FCB, використано його макроси:

struc fcb_t in_drive,in_name,in_ext,in_record_size
{
         .drive          db      in_drive; Drive specified, Init by User, 0 = default, 1 = A, etc, FFh is not allowed
         .name           db      in_name ; Filename, padded by spaces, 20h, Init by User
     assert $-.name <= 8
     if $-.name < 8
     lbl=$
         .name_padding   db      lbl-.name dup 20h
     end if
         .ext            db      in_ext  ; Extension, padded by spaces, 20h, Init by User
     assert $-.ext <= 3
     if $-.ext < 3
     lbl=$
         .ext_padding    db      lbl-.ext dup 20h
     end if
         .cur_block      db      2 dup 0 ; Current Block, Init by DOS
         .record_size    dw      in_record_size+0 ; (2 dup 0) ; Record size, Init by DOS, def. val=80h=128d
         .file_size      db      4 dup 0 ; File size, Init by DOS
         .date           db      2 dup 0 ; File date, Init by DOS
         .time           db      2 dup 0 ; File time, Init by DOS
         .reserv1        db      8 dup 0 ;
         .cur_record     db      1 dup 0 ; Current record, Init by User
         .random_record  db      4 dup 0 ; Random record, Init by User
}

Цей макрос, fcb_t, приймає аргументи -- диск, ім'я, розширення, розмір запису (хоча останній слід встановлювати після відкриття). Турбується про те, щоб імена та розширення були доповнені до правильної довжини пробілами (оці ігри з $, .name), контролює задовгі імена чи розширення (assert). Використовувати його можна так:
   first_fcb_in_my_life fcb_t  0,"text","txt" 
-- оголошується FCB для файлу text.txt на поточному диску.

Аналогічно оголошено і макрос для розширених FCB. Обидва макроси задані у файлі fcb_def.inc, див. архів у кінці поста.

Ввід-вивід на екран в програмі теж здійснюватиметься засобами DOS 1, щоб програму можна було запускати і з-під нього (інакше й сенсу немає возитися). Зокрема, використано славну функцію Int 21/AH=09h -- вивід стрічки, що закінчується символом '$', на екран (7).

Попередження: на асемблері я програмував ну дуже давно, та й тоді особливим профі не був, код достатньо "брудний", в піаніста не стріляти, грає як може.

fcb1.asm/fcb1.com


Файл fcb1.asm демонструє запис та читання файлів засобами FCB. В ньому реалізовано доволі розгорнуту обробку помилок, але без використання розширеного коду помилки, який з'явився в DOS 3.0.

Створюємо, (або обрізаємо, якщо вже існував),  файл:

        mov             ah,16h  ; Створити файл, використовуючи FCB
        mov             dx,first_fcb_in_my_life ; DS:DX <--- FCB
        int             21h
        cmp             al,00   ; 0 -- OK, 0xFF -- error
        jz              @F
        jmp             err_creating
@@:
Відмінне від 0 значення регістру AL свідчить про помилку. @F означає найближчу анонімну локальну мітку попереду, @@ якраз оголошує її. first_fcb_in_my_life оголошено так:

first_fcb_in_my_life fcb_t  0,"text","txt",1

Вивід програми виглядає так:

Disk field in closed FCB:0
Record size before opening:1
File successfully created
Disk field in opened FCB:5
Record size after opening:128


Видно, що DOS при відкритті файлу сам встановлює розмір запису.

Записуємо у нього 8-байтові записи, для вибору наступного засобу просто переставляємо DTA (незручно, жах!)

our_w_record_size      equ     8       ; Щоб і не 1, але і не 128   

mov             dx, record0

next_record:
        push            dx       ; Зберігаємо для подальших ітерацій

    ** Вивід інформації користувачу **
   
        pop             dx
        push            dx      ; "Оновлюємо" адресу - мало хто її зіпсував
                                ; під час попередніх викликів
                                ; Неохота щось хитьріше придумувати.
        mov             ah,1Ah   ; Встановити DTA
        int             21h

    ** Робота з записом **

        pop             dx
        add             dx,our_w_record_size

;--SKIPPED-------------------------------------------------------------
record0         db      our_w_record_size   dup '0'
record1         db      our_w_record_size   dup '1'
...........
recordY         db      our_w_record_size   dup 'Y'
recordZ         db      our_w_record_size   dup 'Z'

cur_record_num  dw      0
max_records_num dw      10+'Z'-'A'

Всього таких записів 10+26=36.

Після встановлення DTA запис здійснюється просто:

        mov             dx,first_fcb_in_my_life
        mov             ah,15h   ; Записуємо запис із поточного DTA
        int             21h
        cmp             al,00   ; 0 -- OK, other -- error
        jz              @F
        jmp             err_writing
@@:


Виводить програма щось таке:

Writing to file. Record size: 8

Current block: 0    Current record field: 0
DTA changed to our record.
Writing our record number: 0
Record written.
Current block: 0    Current record field: 1
DTA changed to our record.
Writing our record number: 1
** skipped **
Current block: 0    Current record field: 35
DTA changed to our record.
Writing our record number: 35
Record written.
File written. Proceeding to reading.

Видно, що DOS автоматично оновлює поле запису.

Записавши файл, прочитаємо його чотирма різними способами. Спочатку послідовно, із розміром запису 2. 2 є дільником 8, (а значить і розміру файлу), тому у файлі буде ціла кількість записів:

Each readed record is printed with preamble in form: block:record:data.
Record size: 2

0:1:00;
0:2:00;
0:3:00;
0:4:00;
0:5:11;
0:6:11;
0:7:11;
0:8:11;
0:9:22;

....skipped......
1:10:YY;
1:11:YY;
1:12:YY;
1:13:ZZ;
1:14:ZZ;
1:15:ZZ;
1:16:ZZ;

End of file.

 
Потім прочитаємо послідовно, записами по 7 байт, (остача від ділення розміру файлу, 36*8=288, дорівнює 1):


0:1:0000000;
0:2:0111111;
0:3:1122222;
0:4:2223333;
0:5:3333444;
0:6:4444455;
0:7:5555556;
0:8:6666666;
0:9:7777777;
0:10:7888888;



....skipped......
0:41:ZZZZZZZ;
Partial record readed: 0:42:Z      ;
End of file.
 
Видно, що останній запис неповний, містить лише один символ.

Реалізовано це так:

cont_reading_1:
        clear_mem       DTA1,2*our_r_record_size2,'$'
                                          ; Щоб можна було безпечно виводити,
                                          ; не заморочуючись особливо

        mov             dx,first_fcb_in_my_life
        mov             ah,14h
        int             21h
        cmp             al,0
        jz              print_readed_1
        cmp             al,1    ;end of file (no data)
        jnz             @F
        print_txt       none_read_msg
        jmp             finished_read_1
@@:
        cmp             al,3    ; partial record
        jnz             @F
        print_txt       partial_read_msg
        jmp             print_readed_1

@@:
        jmp             err_reading


print_readed_1:
        
        ....Друкуємо прочитане...

        jmp             cont_reading_1
finished_read_1:

print_txt -- це такий макрос, якщо що, див. fcb1.asm. Для простоти, область DTA, перед читанням заповнюється символами долара, щоб можна було безпосередньо виводити його вміст за допомогою функції AH=09h.

За допомогою читання прямого доступу прочитаємо 8-й 8-байтовий запис:

mov             word [first_fcb_in_my_life.random_record], 8
        mov             word [first_fcb_in_my_life.random_record+2], 0

...виводимо інформацію про те, як проходить виконання програми...

        mov             dx, first_fcb_in_my_life
        mov             ah, 21h
        int             21h
        cmp             al,0
        jz              print_readed_random_1
        cmp             al,1    ;end of file (no data)
        jnz             @F
        print_txt       none_read_msg
        jmp             finished_random_read_1
@@:
        cmp             al,3
        jnz             @F
        print_txt       partial_read_msg
        jmp             print_readed_random_1

@@:
        jmp             err_reading

print_readed_random_1:

Програма виведе:

Demonstration of random read.

Record size: 8
Current block: 0    Current record field: 0
Reading relative (absolute) record number: 08
Readed record: 88888888
Current block: 0    Current record field: 8


Зауваження: Ralf Brown's Interrupt List стверджує, що пряме читання не змінює позиції у файлі, але вивід програми (як під DosBox, так і під DOS 1.XX та DOS 2.00) однозначно свідчить -- обманює. Ну, або я щось не так зрозумів чи проінтерпретував.

Нарешті, блочним доступом прочитаємо весь файл за раз:

        mov             word [first_fcb_in_my_life.cur_block],0
        mov             [first_fcb_in_my_life.cur_record], 0
        mov             [first_fcb_in_my_life.record_size],our_w_record_size
        ; Початкова позиція береться з random_record!
        mov             word [first_fcb_in_my_life.random_record], 0
        mov             word [first_fcb_in_my_life.random_record+2], 0

... Вивід інформації про роботу...

        mov             dx,first_fcb_in_my_life
        mov             cx,[max_records_num]
        mov             ah,27h
        int             21h
        push            cx      ; save for latter usage
                        ; Таке враження, що його значення все ж некоректне...

        cmp             al,0
        jz              print_readed_block_1
        cmp             al,1    ;end of file (no data)
        jnz             @F
        print_txt       none_read_msg
        jmp             print_readed_block_1
@@:
        cmp             al,3
        jnz             @F
        print_txt       partial_read_msg
        jmp             print_readed_block_1

@@:
        jmp             err_reading

print_readed_block_1:

Тут варто зробити кілька зауважень:
  1. Позиція, з якої читати, береться із поля для прямого доступу, вміст полів поточного блоку та запису ігнорується.
  2. Систематичних досліджень я не проводив, але здається, обіцяне значення CX після виклику -- кількість прочитаних записів, в нього не потрапляє...
 В результаті побачимо щось таке:

Reading entire file by random block read.
Record size: 8
Current block: 0    Current record field: 0
Requested records: 35
Readed records: 35
Readed:
00000000111111112222222233333333444444445555555566666666777777778888888899999999AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFFGGGGGGGGHHHHHHHHIIIIIIIIJJJJJJJJKKKKKKKKLLLLLLLLMMMMMMMMNNNNNNNNOOOOOOOOPPPPPPPPQQQQQQQQRRRRRRRRSSSSSSSSTTTTTTTTUUUUUUUUVVVVVVVVWWWWWWWWXXXXXXXXYYYYYYYY
Current block: 0    Current record field: 35


На завершення закриваємо файл:

mov             dx,first_fcb_in_my_life
        mov             ah, 10h  ; Закриваємо файл
        int             21h
        cmp             al,00   ; 0 -- OK, 0xFF -- error
        jz              @F
        jmp             err_closing
@@:

fcb2.asm/fcb2.com


Файл fcb2.asm показує, як можна маніпулювати файлами за допомогою FCB. Реалізовуючи його, мені було вже зовсім лінь возитися із обробкою помилок, тому вона зовсім-зовсім базова.

Спочатку він, за допомогою функцій Find First/Find Next, виводить список файлів у поточному каталозі разом із розмірами:

Listing of all files in current dir:

DEBUG   COM    014364b
DOSBOX  LNK    0826b
FCB1    ASM    015222b
FCB1    COM    03725b
FCB2    ASM    06551b
FCB2    COM    01940b
FCB_DEF BIN    00b
FCB_DEF INC    02490b
OUTPUT2 LOG    00b
OUTT           07625b
TEXT    TXT    0288b


Потім, використовуючи розширений FCB, виводить всі файли та директорії:

Listing of all files and directories in current dir:
               00b
        .      00b
FASM           00b
DEBUG   COM    014364b
DOSBOX  LNK    0826b
FCB1    ASM    015222b
FCB1    COM    03725b
FCB2    ASM    06551b
FCB2    COM    01940b
FCB_DEF BIN    00b
FCB_DEF INC    02490b
OUTPUT2 LOG    00b
OUTT           07625b
TEXT    TXT    0288b
 

Видно, що присутні два службових каталоги, "." і ".." (перший -- фактично взагалі без назви, бо в полі імені та полі розширення лише пробіли, другий має одну додаткову крапку в полі розширення), та FASM -- в ньому живе асемблер, яким я програми компілював.

Далі програма перейменовує файл TEXT.TXT, який залишився від FCB1.COM, стирає перейменований, та створює порожній TEXT.TXT, щоб для повторного запуску FCB2.COM не потрібно було спершу запускати FCB1.COM:

Renaming file TEXT.TXT to NEWNAME.EXT
File renamed.

Erasing renamed file
File erased.
Recreating file for next run


Для створення списку файлів використовується маска "*.*", яка перетворюється у поля імені та розширення FCB (вони в пам'яті йдуть послідовно і для маски "*.*" мають виглядати так: "???????????") за допомогою відповідної функції:

        mov             ah,29h ; PARSE FILENAME INTO FCB
        mov             al,11b ; Parsing options, see http://www.ctyme.com/intr/rb-2685.htm
        mov             si,filemask
        mov             di,second_fcb_in_my_life
        int             21h

Важлива ремарка щодо неї -- вона (принаймні під DosBox -- полінувався перевірити під DOX 1.XX ) не розпізнає розширені FCB, тому для них їй слід передавати вказівник на початок основної частини FCB:

        mov             di,third_fcb_in_my_life+07h

Функції FindFirst -- AH=11h, слід передавати не відкритий FCB, а FCB знайденого файлу вона зберігатиме в DTA. Перед викликами FindNext -- AH=12h, змінювати вихідний FCB не можна. Свої результати FindNext кладе туди ж, в DTA. Розпізнають розширений FCB, створюючи в DTA теж розширений.

Працює воно якось так (приклад для розширеного FCB див. безпосередньо в fcb2.asm):

        mov             dx, DTA1
        mov             ah, 1Ah   ; Встановити DTA
        int             21h

        mov             ah,29h ; PARSE FILENAME INTO FCB
        mov             al,11b ; Parsing options, see http://www.ctyme.com/intr/rb-2685.htm
        mov             si,filemask
        mov             di,second_fcb_in_my_life
        int             21h

        mov             ah,11h ; FindFirst by FCB
        mov             dx,second_fcb_in_my_life
        int             21h
        cmp             al,0
        jz              @F
        print_txt       error_msg
        jmp             exit          

cont_listing_1:
        ;       DTA -- Finded file FCB
        mov             dx, DTA1
        ;mov             [found_FCB.record_size],1 ; FCB record size
        mov             [DTA1+0Eh],1 ; FCB record size
        mov             ah,23h       ; Get file size in records
        int             21h

    ... Вивести знайдене ім'я файлу та його розмір на екран...
       
        mov             ah,12h ; FindNext
        mov             dx,second_fcb_in_my_life
        int             21h
        cmp             al,0
        jnz             @F ;// Файли кінчилися
        jmp             cont_listing_1
@@:

FlatAssembler щось закапризував, тому, для простоти і враховуючи обмеженість в часі, зміщення в FCB, який знаходиться в DTA, задав вручну, типу DTA1+0Eh. Для отримання розміру файлу використано ще одну функцію, AH=23h. Вона повертає розмір файлу в записах, тому, щоб отримати його в байтах, встановлюю розмір запису рівним 1.

Перейменування просте -- береться FCB, в ньому, починаючи з зміщення 11h, поміщається нове ім'я, в тому ж форматі, що й звичайне ім'я+розширення (8+3, із доповненням пробілами), викликається функція AH=17h:

        mov             si,newname
        mov             di,one_more_fcb_in_my_life+11h ; offset for new name
        mov             cx,11
        rep movsb

        mov             dx,one_more_fcb_in_my_life
        mov             ah,17h
        int             21h     ;Rename file
        cmp             al,0
        jz             @F
        print_txt       error_msg
        print_txt       eol
        jmp             exit
@@:

Стирати файл ще простіше:

        mov             dx,second_fcb_in_my_life
        mov             ah,13h  ;DELETE FILE USING FCB
        int             21h

Архів з прикладами

Скачуємо тут: FCB_SMPL.ZIP.

Містить тексти програм та їх скомпільовані варіанти: FCB1.ASM/.COM, FCB2.ASM/.COM, файл із оголошеними структурами FCB, FCB_DEF.INC та результати їх роботи:
  • OUTPUT1.LOG і OUTPUT2.LOG відповідно для FCB1 i FCB2 під DosBox,
  • OUTPUT1.D20 і OUTPUT2.D20  -- вивід DOS 2.00
  • OUTPUT1.D10 і OUTPUT2.D10  -- останній екран виводу PC-DOS 1.00. На жаль, простого  способу отримати весь вивід я не знайшов -- перенаправлення немає. Однак і цей шматок дає можливість підтвердити, що й DOS 1.00 переставляв положення у файлі при прямому звертанні.
  • OUTPUT1.D11 і OUTPUT2.D11  -- останній екран виводу PC-DOS 1.10. 

Актуальність


Як вже писалося, перші DOS були, на рівні програмного коду, сумісні із популярною тоді ОС мікрокомп'ютерів, CP/M. Завдяки цьому багато програм перенести під DOS було просто. З виходом DOS 2.00 цей метод роботи з файлами застарів. Підтримувався у пізніших версіях DOS, а потім і Windows, для сумісності із старими програмами. Детально не перевіряв, ходять чутки, що їх підтримка у серії Windows NT (включаючи 2000 і XP) не дуже коректна. До середини 1990-х вони стали остаточно неактуальними, зокрема, Windows не дозволяв з їх допомогою працювати із FAT32 дисками (крім як читати мітку тому).

Десь в цей же період був невеликий спалах актуальності -- виявилося, що більшість антивірусів не слідкують за цим способом доступу до файлів. В даний момент, правда, не скажу точно, чи були в дикій природі віруси, які намагалися користатися цією нагодою.

Зараз, із приходом 64-бітних ОС, "проходом" 32-х років з часу виходу DOS 1.00 (а що, кругла дата ;-), та іншими очевидними причинами, актуальність виключно історична. Хоча, популярна любительська OS, KolibriOS, використовує (поверхнево) схожу структуру для роботи з файлами.


ОСЬ І ВСЕ. 
Ще одна епопея, тривалістю, в певному сенсі, в 17+ років, завершилася (сподіваюся, як мінімум, що завершилася, навіть останній FCB в FCB2.ASM так і назвав: "last_fcb_in_my_life_i_hope"). 
Як є питання - пишіть. А поки:
Дякую за увагу!

____________

Виноски

(1) Хто хоче на неї подивитися, див: djvu, текст. Для гурманів можна навіть купити. Крім того, історичного, видання існує також відносно нове, 2001, (2003 російською), 5-те видання. Чесно кажучи, на той час воно виглядало вже зовсім жалюгідно... Відмінність від видання 1987, по великому рахунку, несуттєва.

(2) В юності я того зрозуміти не міг -- бракувало знань, як предметної області, так і англійської, як не смішно. Перше спонукало думати, що це я чогось не розумію, друге -- заважало розпізнати характерні патерни недоперекладу.

(3) Себто -- на практиці. Так то вона, безперечно, існувала і у Львові.

(4) Купив я її у ліцеїста-хіміка, старшого, здається, на рік (може -- на два...), який забив на дану тему. Будучи студентом позичив, разом із іншими, викладачу. Викладач, мало того, що не віддав її, так ще й образився, що я її йому не позичив. :-)

(5) Цитуючи вікіпедію: "Саме з Інституту [фізики конденсованих систем] в лютому 1993 року було здійснено перше в Україні некомутоване підключення до глобального Інтернету."

(6) До речі, щодо заплутаності. Вже не вперше зауважував, що коли нова технологія з'являється, вона мало того що нова і толком не розвинута, так її ще й реалізовують і використовують якимось неприродно складним чином. Арифметику згадуючи. (Може колись і про це напишу...)

Хоча FCB не були першим засобом роботи з файлами -- давно вже існували всілякі Unix-и, з їх хендлами (номерами файлів), але все ж, вони були введені в CP/M, першій ОС персональних комп'ютерів. Напевне Кілдал мав якісь міркування зробити саме так...

(7) Зацитую Кілдала: "Ask Bill [Gates] why the string in [MS-DOS] function 9 is terminated by a dollar sign. Ask him, because he can't answer. Only I know that.". Чи розповів він комусь -- не знаю. Як хто знає -- пишіть!

Немає коментарів:

Дописати коментар