#include <stdio.h>
#include <malloc.h>
#include <dos.h>
#include "sysp.h"

void main(void);
void main(void) {

  BOOT _far *boot_rec;
  int i,j, k, status, fat_sectors;
  unsigned total_sectors;
  int ffat, root_begin, root_sectors;
  char drive;
  unsigned _far *fat_buffer;
  FITEM _far *root_buffer, _far *rptr;
  char cbuf[128];
  char _far *clust_buffer;
  int cur_clust;

  union REGS reg;
  struct SREGS segreg;


  printf("\n"
			"\nЧтение каталогов логического диска"
			"\n  (C)Фролов А., 1991"
			"\n");


// Заказываем буфер для чтения BOOT-записи.
// Адрес буфера присваиваем FAR-указателю.

  boot_rec = _fmalloc(sizeof(*boot_rec));

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

  printf("\n"
			"\nВведите обозначение диска (A, B, ...):");

  drive = getche();

// Вычисляем номер дисковода

  drive = toupper(drive) - 'A';

// Читаем загрузочную запись в буфер

  status = getboot((BOOT _far*)boot_rec, drive);

// Если произошла ошибка (например, неправильно указано
// обозначение диска), завершааем работу программы

  if(status) {
		printf("\nОшибка при чтении BOOT-сектора");
		exit(-1);
  }

// Определяем формат таблицы FAT

  total_sectors = boot_rec->bpb.totsecs;

// Если мы работаем с расширенным разделом диска,
// общее количество секторов на диска берем из
// расширенного PBP

  if(total_sectors == 0) total_sectors = boot_rec->bpb.drvsecs;

// Формат FAT определяем исходя из общего
// количества секторов на логическом диске

  if(total_sectors > 20740) {
		printf("\nFAT имеет 16-битовый формат");
		ffat=16;
  }
  else {
		printf("\nFAT имеет 12-битовый формат");
		ffat=12;
  }

// Определяем количество секторов, занимаемых FAT

  fat_sectors = boot_rec->bpb.fatsize;

// Заказываем буфер для FAT

  fat_buffer = _fmalloc(fat_sectors * boot_rec->bpb.sectsize);

// Вычисляем номер первого сектора FAT

  j = boot_rec->bpb.ressecs;

// Читаем FAT в буфер fat_buffer

// Заполняем регистровые структуры для вызова
// прерывания DOS INT 25h

	 reg.x.ax = drive;
	 reg.x.bx = FP_OFF(fat_buffer);
	 segreg.ds = FP_SEG(fat_buffer);
	 reg.x.cx = fat_sectors;
	 reg.x.dx = j;
	 int86x(0x25, &reg, &reg, &segreg);

// Извлекаем из стека оставшееся там после
// вызова прерывания слово

	 _asm pop ax

// Вычисляем номер первого сектора корневого каталога

	root_begin = j + fat_sectors * boot_rec->bpb.fatcnt;

// Вычисляем длину корневого каталога

	root_sectors = (boot_rec->bpb.rootsize * 32) /
						boot_rec->bpb.sectsize;

// Заказываем буфер для корневого каталога

	root_buffer = _fmalloc(root_sectors * boot_rec->bpb.sectsize);

// Читаем корневой каталог в буфер root_buffer

	 reg.x.ax = drive;
	 reg.x.bx = FP_OFF(root_buffer);
	 segreg.ds = FP_SEG(root_buffer);
	 reg.x.cx = root_sectors;
	 reg.x.dx = root_begin;
	 int86x(0x25, &reg, &reg, &segreg);
	 _asm pop ax

// Показываем содержимое корневого каталога

	printf("\n"
			 "\nИмя файла    Аттр. Дата        Время     Кластер Размер"
			 "\n------------ ----- ----------  --------  ------- ------");

	for(rptr = root_buffer;;rptr++) {
		printf("\n");

// Признак конца каталога - нулевой байт в начале
// имени файла

		if(rptr->name[0] == 0) break;

// Выводим содержимое дескриптора файла

		for(i=0; i<8; i++) printf("%c",rptr->name[i]);
		printf(".");
		for(i=0; i<3; i++) printf("%c",rptr->ext[i]);
		printf(" %02X    %02d-%02d-%02d  %02d:%02d:%02d ",
			rptr->attr,
			rptr->date.day,
			rptr->date.month,
			rptr->date.year + 1980,
			rptr->time.hour,
			rptr->time.min,
			rptr->time.sec * 2);
		printf(" %-5d   %lu",
			rptr->cluster_nu,
			rptr->size);

	}

// Получаем буфер для чтения кластеров каталога

	clust_buffer = _fmalloc(boot_rec->bpb.clustsize
						* boot_rec->bpb.sectsize);

	printf("\nНомер первого кластера каталога:");
	gets(cbuf);
	cur_clust = atoi(cbuf);

// Переменная k используется в качестве флага.
// При первом просмотре каталога ее значение равно 0,
// затем эта переменная устанавливается в 1.

	k=0;

	for(;;) {

// Сохраняем номер кластера каталога

		j=cur_clust;

// Вычисляем номер следующего кластера, распределенного
// каталогу

		cur_clust = fat(fat_buffer, ffat, cur_clust);
		printf("%d ",cur_clust);

// Читаем кластер в буфер clust_buffer

		 reg.x.ax = drive;
		 reg.x.bx = FP_OFF(clust_buffer);
		 segreg.ds = FP_SEG(clust_buffer);
		 reg.x.cx = boot_rec->bpb.clustsize;
		 reg.x.dx = root_begin + root_sectors
						+ ((j-2)*boot_rec->bpb.clustsize);
		 int86x(0x25, &reg, &reg, &segreg);
		 _asm pop ax

// Показываем содержимое каталога

		 rptr = (FITEM _far *)clust_buffer;

// Первый дескриптор в каталоге указывает на
// этот же каталог. В поле имени первого дескриптора
// находится строка ".       ". Этот факт можно использовать
// для проверки каталога. Если вы по ошибке указали
// номер кластера, не принадлежащего каталогу,
// программа завершит работу с сообщением об ошибке.

		 if(k == 0) {
			k=1;
			if(strncmp(rptr->name,".       ",8) != 0) {
				printf("\nЭто не каталог !");
				exit(-1);
			}
		 }

		 printf("\n"
			 "\nИмя файла    Аттр. Дата        Время     Кластер Размер"
			 "\n------------ ----- ----------  --------  ------- ------");

		 for(;;rptr++) {
			printf("\n");

// Признак конца каталога - нулевой байт в начале
// имени файла

			if(rptr->name[0] == 0) break;

// Выводим содержимое дескриптора файла

			for(i=0; i<8; i++) printf("%c",rptr->name[i]);
			printf(".");
			for(i=0; i<3; i++) printf("%c",rptr->ext[i]);
			printf(" %02X    %02d-%02d-%02d  %02d:%02d:%02d ",
				rptr->attr,
				rptr->date.day,
				rptr->date.month,
				rptr->date.year + 1980,
				rptr->time.hour,
				rptr->time.min,
				rptr->time.sec * 2);
			printf(" %-5d   %lu",
				rptr->cluster_nu,
				rptr->size);

		}

// Если этот кластер - последний из распределенных каталогу,
// завершаем работу программы

		if((cur_clust == 0xfff) || (cur_clust == 0xffff)) break;

	}

// Освобождаем буфера

  _ffree(root_buffer);
  _ffree(boot_rec);
  _ffree(fat_buffer);
  _ffree(clust_buffer);
}
