Страница Ивана Рощина > Статьи >

© Иван Рощин, Москва

ZXNet: 500:95/462.53
E-mail: bestview@mtu-net.ru
WWW: http://www.ivr.da.ru

Обрубаем файлам «хвост»

Радиомир. Ваш компьютер» 4/2002)
Дата последнего редактирования: 27.10.2002.

В [1] рассказывалось о проблеме, связанной с использованием текстового редактора Microsoft Word. Напомню: речь шла о том, что в определённых случаях в сохранённом текстовом файле остаются фрагменты текста, удалённые при редактировании, причём автор текста может об этом и не подозревать. А получатель, прочитавший этот файл, может узнать информацию, которая для него вовсе не предназначалась.

Подобная проблема актуальна и для многих текстовых редакторов на ZX Spectrum, хотя причина её возникновения и не такая, как в MS Word. Дело вот в чём: для хранения на диске файла, независимо от его длины, выделяется целое число секторов. Таким образом, остаток последнего сектора («хвост») файла может содержать информацию, к этому файлу не относящуюся. Когда мы сохраняем текст в редакторе, на диск просто записывается целое число секторов с начала текстового буфера. И если длина текста не кратна 256 байтам, в остатке последнего сектора будет то, что находилось в текстовом буфере после фактического конца текста. Загрузив файл в текстовый редактор, мы эту информацию не увидим (потому что в каталоге указывается точная длина файла), но при просмотре содержимого последнего сектора с помощью какого-либо дискового редактора её можно прочесть.

А что находится в буфере после конца текста? Это может быть и остаток предыдущего загруженного в редактор файла (ведь перед загрузкой нового файла буфер не обнуляется — зачем выполнять лишнюю работу?), и фрагменты текста, удалённые при редактировании. А если буфер не очищается при запуске редактора, там может остаться то, что было помещено туда при работе предыдущей программы. Даже если этой программой был обычный «boot», в памяти может остаться каталог диска, с которого был запущен редактор. Понятно, что делать эту информацию общедоступной не хотелось бы.

Однако при операциях копирования файла, пересылки его в форматах hobeta, scl, (и, разумеется, в файлах — образах диска: trd, fdi, td0), а также при упаковке файлов с помощью архиватора HRIP остаток последнего сектора также участвует в операции. Таким образом, нежелательная информация может быть распространена вместе с самим файлом, и доступ к ней может получить множество людей.

Если бы область памяти после конца текста обнулялась перед записью файла, проблема была бы полностью решена. Именно это я и посоветую создателям редакторов. А что делать простым пользователям?

Выход есть — воспользоваться специальной программой, обнуляющей «хвост» указанного файла. Вот её текст:

SECTOR     EQU  #C000  ;#100 байтов
CATALOG    EQU  #C100  ;#800 байтов
FILE_LIST  EQU  #C900  ;#800 байтов

           ORG  #8000

;Инициализация:

           LD   A,(23611) ;системные
           OR   %00001100 ;переменные
           LD   (23611),A ;обработчика
           XOR  A         ;клавиатуры
           LD   (23658),A
           LD   A,(23562)
           PUSH AF
           LD   A,1
           LD   (23562),A

BEGIN      XOR  A         ;CLS
           OUT  (254),A
           LD   HL,#4000
           LD   (HL),L
           LD   DE,#4001
           LD   BC,#17FF
           LDIR
           LD   HL,#5800
           LD   (HL),7
           LD   DE,#5801
           LD   BC,#2FF
           LDIR

;Читаем каталог и определяем его
;контрольную сумму:

           CALL READ_CAT

;Формируем список файлов:

           CALL MAKE_LIST

;Выбор файла:

SELECT     LD   A,(ALL_FILES)
           AND  A             ;если нет
           JR   Z,SELECT_NF   ;файлов...

           XOR  A
           LD   (FIRST),A
           LD   (NUM_F),A
           CALL PRINT_LIST

SELECT_1   CALL CURSOR_ON

WAIT_K     CALL GETSYM
           CP   "q"
           JR   Z,SEL_UP
           CP   11
           JR   Z,SEL_UP
           CP   "a"
           JR   Z,SEL_DN
           CP   10
           JR   Z,SEL_DN
           CP   13
           JR   Z,WORK_FILE
           CP   7
           JP   Z,EXIT
           CP   "r"
           JR   Z,BEGIN
           JR   WAIT_K

;"Вверх":

SEL_UP     LD   A,(NUM_F)
           AND  A
           JR   Z,WAIT_K

           CALL CURSOR_OFF

           LD   HL,NUM_F
           DEC  (HL)
           LD   A,(FIRST)
           SUB  (HL)
           JR   C,SELECT_1
           JR   Z,SELECT_1

           LD   HL,FIRST
           DEC  (HL)
           CALL PRINT_LIST
           JR   SELECT_1

;"Вниз":

SEL_DN     LD   A,(NUM_F)
           INC  A
           LD   HL,ALL_FILES
           CP   (HL)
           JR   Z,WAIT_K

           CALL CURSOR_OFF

           LD   HL,NUM_F
           INC  (HL)

           LD   A,(FIRST)
           ADD  A,17
           SUB  (HL)
           JR   NC,SELECT_1

           LD   HL,FIRST
           INC  (HL)
           CALL PRINT_LIST
           JR   SELECT_1

;Если на диске нет файлов, ждем нажатия
;"R" или "EDIT":

SELECT_NF  CALL GETSYM
           CP   7
           JP   Z,EXIT
           CP   "r"
           JP   Z,BEGIN
           JR   SELECT_NF

;Обработка файла.

WORK_FILE  LD   A,(NUM_F)
           LD   H,0
           LD   L,A
           ADD  HL,HL
           ADD  HL,HL
           ADD  HL,HL
           ADD  HL,HL  ;*16
           LD   DE,FILE_LIST
           ADD  HL,DE
           PUSH HL
           POP  IX

;Проверка, можно ли обрабатывать файл:

           LD   A,(IX+8)  ;это Бейсик?
           CP   "B"
           JP   Z,WAIT_K

           LD   A,(IX+11) ;младший байт
           AND  A         ;длины = 0?
           LD   (USED),A
           JP   Z,WAIT_K

           LD   A,(IX+12) ;длина в сект.
           INC  A         ;соответствует
           CP   (IX+13)   ;длине
           JP   NZ,WAIT_K ;в байтах?

;Определяем трек-секторный адрес
;последнего сектора файла:

           LD   D,0
           DEC  A
           LD   B,A
           AND  15
           ADD  A,(IX+14)
           BIT  4,A
           RES  4,A
           LD   E,A         ;сектор
           JR   Z,WORK_1
           INC  D

WORK_1     LD   A,B
           RRCA
           RRCA
           RRCA
           RRCA
           AND  15
           ADD  A,(IX+15)
           ADD  A,D
           LD   D,A         ;трек

           LD   (DISK_ADR),DE

;Проверяем по контрольной сумме
;каталога: вдруг в дисководе уже другой
;диск? Если так, перечитываем каталог.

           LD   HL,(SUM)
           PUSH HL
           CALL READ_CAT
           LD   HL,(SUM)
           POP  DE
           AND  A
           SBC  HL,DE
           JP   NZ,BEGIN

;Обнуляем неиспользуемое пространство
;в последнем секторе файла:

           LD   DE,0
DISK_ADR   EQU  $-2
           LD   HL,SECTOR
           LD   B,1
           LD   C,5
           PUSH DE
           PUSH HL
           CALL #3D13

           LD   H,SECTOR/256
           LD   L,0
USED       EQU  $-1

WORK_2     LD   (HL),0
           INC  L
           JR   NZ,WORK_2

           POP  HL
           POP  DE
           LD   B,1
           LD   C,6
           CALL #3D13

;После обработки - снова на выбор файла:

           JP   WAIT_K

;Выход из программы:

EXIT       LD   HL,#2758
           EXX
           POP  AF        ;восст. период
           LD   (23562),A ;автоповтора
           RET

;---------------------------------------
;Переменные:

SUM        DS   2 ;контрольная сумма
ALL_FILES  DS   1 ;кол-во файлов
FIRST      DS   1 ;N верхнего файла
NUM_F      DS   1 ;N выбранного файла

;---------------------------------------
;Процедура READ_CAT читает каталог диска
;и вычисляет его контрольную сумму.

READ_CAT   LD   C,0    ;сброс
           CALL #3D13  ;контроллера

           LD   C,#18  ;настройка
           CALL #3D13  ;на диск

           LD   B,8        ;чтение
           LD   DE,0       ;восьми
           LD   HL,CATALOG ;секторов
           LD   C,5        ;каталога
           CALL #3D13

;Вычисление контрольной суммы:

           LD   IX,CATALOG ;адр. начала
           LD   BC,#800    ;счетчик
           LD   HL,0       ;нач. сумма
           LD   D,0

CALC_SUM   LD   E,(IX)   ;прибавляем
           ADD  HL,DE    ;очередной байт
           INC  IX
           DEC  BC
           LD   A,B
           OR   C
           JR   NZ,CALC_SUM

           LD   (SUM),HL
           RET

;---------------------------------------
;Процедура MAKE_LIST формирует список
;файлов и подсчитывает их количество.

MAKE_LIST  LD   HL,CATALOG
           LD   DE,FILE_LIST
           LD   IX,#8000

;XH - счетчик элементов каталога (128),
;XL - счетчик файлов.

MAKE_M1    LD   A,(HL)     ;файлы
           AND  A          ;закончились?
           JR   Z,MAKE_M4

           DEC  A          ;удаленный
           JR   Z,MAKE_M2  ;файл?

           LD   BC,16      ;переносим
           LDIR            ;описатель
           INC  XL         ;увел. кол-во
           JR   MAKE_M3

MAKE_M2    LD   BC,16
           ADD  HL,BC

MAKE_M3    DEC  XH         ;счетчик
           JR   NZ,MAKE_M1

MAKE_M4    LD   A,XL
           LD   (ALL_FILES),A
           RET

;---------------------------------------
;Процедуры для изображения курсора:
;CURSOR_ON - нарисовать,
;CURSOR_OFF - стереть.

CURSOR_ON  LD   B,%00111000
           JR   CURSOR_1

CURSOR_OFF LD   B,%00000111

CURSOR_1   LD   A,(NUM_F)
           LD   HL,FIRST
           SUB  (HL)
           ADD  A,4
           LD   E,A
           LD   D,1
           CALL GET_A_A
           LD   (HL),B
           LD   D,H
           LD   E,L
           INC  DE
           LD   BC,11
           LDIR
           RET

;---------------------------------------
;Процедура PRINT_LIST выводит на экран
;имена файлов, начиная с FIRST, пока не
;будет выведено 18 имен или пока не
;кончатся файлы.

PRINT_LIST LD   XH,0      ;счетчик

           LD   DE,FILE_LIST
           LD   H,0
           LD   A,(FIRST)
           LD   L,A
           ADD  HL,HL
           ADD  HL,HL
           ADD  HL,HL
           ADD  HL,HL ;*16
           ADD  HL,DE

;HL указывает на имя файла.

NEXT_OT    LD   B,8
           LD   D,2
           LD   A,XH
           ADD  A,4
           LD   E,A

           PUSH HL
LOOP_P2    LD   A,(HL)
           INC  HL
           CALL PRINT_SYM
           INC  D
           DJNZ LOOP_P2
           LD   A,(HL)
           INC  D
           CALL PRINT_SYM
           POP  HL

           LD   A,(FIRST)
           ADD  A,XH
           LD   B,A
           LD   A,(ALL_FILES)
           DEC  A
           CP   B
           RET  Z

           INC  XH
           LD   A,XH
           CP   18
           RET  Z

           LD   DE,16
           ADD  HL,DE
           JR   NEXT_OT

;---------------------------------------
;Процедура PRINT_SYM печатает на экране
;один символ (без атрибутов).
;
;Вход: A - код символа,
;      D - координата X,
;      E - координата Y.
;
;Выход: регистры не изменены.

PRINT_SYM  PUSH BC
           PUSH DE
           PUSH HL
           PUSH AF

           LD   L,A
           LD   H,0
           ADD  HL,HL
           ADD  HL,HL
           ADD  HL,HL   ;*8
           LD   BC,#3C00
           ADD  HL,BC

           PUSH HL
           CALL GET_A_S
           POP  DE

           LD   B,8
LOOP_PR_S  LD   A,(DE)
           LD   (HL),A
           INC  DE
           INC  H
           DJNZ LOOP_PR_S

           POP  AF
           POP  HL
           POP  DE
           POP  BC

           RET

;---------------------------------------
;Процедура GET_A_S рассчитывает адрес
;на экране.
;
;Вход:  D - X, E - Y.
;Выход: HL - адрес.

GET_A_S    LD   A,E
           AND  #18
           OR   #40
           LD   H,A
           LD   A,E
           AND  7
           RRA
           RRA
           RRA
           RRA
           ADD  A,D
           LD   L,A
           RET

;---------------------------------------
;Процедура GET_A_A рассчитывает адрес
;в области атрибутов.
;
;Вход:  D - X, E - Y.
;Выход: HL - адрес.

GET_A_A    LD   A,E
           RRA
           RRA
           RRA
           AND  3
           OR   #58
           LD   H,A
           LD   A,E
           AND  7
           RRA
           RRA
           RRA
           RRA
           ADD  A,D
           LD   L,A
           RET

;---------------------------------------
;Процедура GETSYM ждет нажатия клавиши.

GETSYM     XOR  A
           LD   (23560),A
GET_1      LD   A,(23560)
           AND  A
           JR   Z,GET_1
           RET

После компиляции сохраните объектный код, например, под именем «del_tail <C>» и напишите простейший Бейсик-загрузчик:

    10 CLEAR 32767: RANDOMIZE USR 15619: REM: LOAD "del_tail"
       CODE
    20 RANDOMIZE USR 32768
    30 RANDOMIZE USR 15616

Скачать программу в формате hobeta (1 КБ ZIP)


Пользоваться программой очень просто. После запуска выводится каталог диска, выбрать нужный файл можно с помощью клавиш «Q», «A» и курсорных; «Enter» — начать обработку файла, «R» — перечитать каталог, «Edit» — выйти в TR-DOS.

Перед тем, как начать обработку выбранного файла, программа проверяет: не был ли заменён диск с момента чтения каталога? Если да, то просто перечитывается каталог.

Есть и ещё одна проверка: в случае, если выбран Бейсик-файл, или длина файла в байтах не соответствует длине в секторах, или длина в байтах равна целому числу секторов, обработка файла не производится.

Программу можно использовать не только для обработки текстовых файлов. Но хочу предупредить, чтобы вы были уверены в формате обрабатываемых файлов: бывает, что «хвост» файла содержит какие-либо нужные данные.

Программу можно усовершенствовать: добавить выбор дисковода, возможность обработки сразу нескольких помеченных файлов, обнуление неиспользуемых секторов диска и информации о стёртых файлах в каталоге диска…

Литература

  1. «Слово — не воробей». «Радиомир. Ваш компьютер» 10/2001, стр. 36.

Другие мои статьи о TR-DOS:

1. 

«Доступ к порту #1F в TR-DOS 5.03». «ZX-Ревю» 1—2/1997.

2. 

«О сокращении времени форматирования». «ZX-Ревю» 1—2/1997.

3. 

«TR-DOS: как не допустить ошибки?». «ZX-Ревю» 5—6/1997.

4. 

«Работа с диском при включённых прерываниях». Adventurer #9, «Чёрная ворона» #3, «Радиолюбитель. Ваш компьютер» 6/2000 (дополненная версия).

5. 

«Вывод трёхсимвольных расширений файлов в операционной системе TR-DOS». «Радиолюбитель. Ваш компьютер» 7/2000.

6. 

«Усовершенствованный алгоритм определения смены диска». «Радиолюбитель. Ваш компьютер» 9/2000.

7. 

«Расширения файлов TR-DOS». «Радиолюбитель. Ваш компьютер» 12/2000, «Радиомир. Ваш компьютер» 9/2001 (под псевдонимом BV_Creator).

8. 

«Использование избыточной информации для защиты файлов от повреждений». «Радиомир. Ваш компьютер» 11/2002.

9. 

«Проверка корректности файловой структуры дисков TR-DOS». «Радиомир. Ваш компьютер» 6/2004.

Страница Ивана Рощина > Статьи >