uses uni2dos; type TStr3=Array[1..3] of Char; TStr8=Array[1..8] of Char; TStr10=Array[1..10] of Char; type TSector0 = Record Jump : Array[1..3] of Char; { NEAR-переход на код загрузки } OEMName : Array[1..8] of Char; { OEM-имя компании и версия системы } SectSize : Word; { байт на сектор } ClustSize : Byte; { секторов на единицу распределения (кластер) } ResSecs : Word; { резервных секторов (секторов перед первой FAT) } FatCnt : Byte; { число таблиц FAT } RootSiz : Word; { макс.число 32-байтовых элементов корневого оглавления } TotSecs : Word; { общее число секторов на носителе (раздел DOS) } Media : Byte; { дескриптор носителя (то же, что 1-й байт FAT) } FatSize : Word; { число секторов в одной FAT } TrkSecs : Word; { секторов на дорожку (цилиндр) } HeadCnt : Word; { число головок чтения/записи (поверхностей) } HidnSec : Word; { спрятанных секторов (исп. в схемах разделения) } Ostatok : Array[1..486] of Char; { Остаток, что-бы сюда можно было читать сектор } End; type TFile = Record Name : TStr8; { Имя файла } Ext : TStr3; { Расширение } Attr : Byte; { Атрибут файла } Reserv : TStr10; { Резерв } Time : Word; { время создания/модификации в формате filetime } Date : Word; { дата создания/модификации в формате filetime } ClstrNo : Word; { номер начального кластера данных (связь с FAT ) } Size : LongInt; { размер файла в байтах } End; type TLongSearchRec = Record Name : TStr8; { Имя файла } LongName : String; { Длиное имя файла } Ext : TStr3; { Расширение } Attr : Byte; { Атрибут файла } Reserv : TStr10; { Резерв } Time : Word; { время создания/модификации в формате filetime } Date : Word; { дата создания/модификации в формате filetime } ClstrNo : Word; { номер начального кластера данных (связь с FAT ) } Size : LongInt; { размер файла в байтах } FPosInSec : Integer; { Позиция - в секторе } FSecPos : Integer; { Позиция - сектор } FMask : String; { Маска для поиска } FAttr : Byte; { Путь заданный в FindFirst } End; type TDTA = Record Reserved : Array[1..$15] of Byte; { Зарезервированно для FindNext } Attr : Byte; { Атрибут файла } Time : Word; { время создания/модификации в формате filetime } Date : Word; { дата создания/модификации в формате filetime } Size : LongInt; { размер файла в байтах } Name : Array[1..13] of Char; { Имя файла + . +расширение } End; type TDir=Array[0..15] of TFile; var s0 : TSector0; dir : TDir; Root : Word; I : Word; Search : TLongSearchRec; LongDosError : Integer; SecPerCat : Integer; DTA : TDTA; { Текущая DTA } Function ReadSector(A:Pointer;Disk:Byte;Count:Word;Sector:Word):Boolean; var Error :Word; Offs :Word; Begin Offs:=Word(A); Error:=0; asm mov al,[Disk] {Номер диска 0-A} mov cx,[Count] {Счетчик считываемых символов} mov dx,[Sector] {Начальный сектор} mov bx,[Offs] int 25h pop dx je @nError mov ax,1 mov [Error],ax @nError: end; if Error=0 then ReadSector:=True else ReadSector:=False; End; { Получаем длиное имя файла #################################################} function GetUniLFN(I:Word):String; var Str,Str0,Str1:String; Flag:Boolean; Len:Integer; Begin Flag:=true;Str0:=#255+#255;Str:='';Str1:=''; While flag do Begin Str1:=copy(Dir[I-1].Name,2,7)+Dir[I-1].Ext+ copy(Dir[I-1].Reserv,3,8)+char(Dir[I-1].Time)+ char(Dir[I-1].Time shr 8)+char(Dir[I-1].Date)+ char(Dir[I-1].Date shr 8)+char(Dir[I-1].Size)+ char(Dir[I-1].Size shr 8)+char(Dir[I-1].Size shr 16)+ char(Dir[I-1].Size shr 24); Len:=pos(Str0,Str1); If Len<>0 then Begin Flag:=False; Str:=Str+copy(Str1,1,Len); End else Begin dec(i); Str:=Str+Str1; if Dir[I].Attr<>15 then Flag:=False; End; End; GetUniLFN:=Str; End; { Long Find First ###########################################################} Procedure LongFindFirst(Path:String;Attr:Word;var SR:TLongSearchRec); var I,Sec :Integer; Drive :Word; { Номер диска } NameSeg,NameOfs :Word; { Адрес строки для поиска } ParentDir :String; { Родительский каталог } Sector,InSect,Data :LongInt; { Сектор, и позиция каталоговой записи } DTASeg,DTASize,DTAOfs :Word; { Адрес локальгого DTA } Begin LongDOSError:=0; {Drive:=Path[1];} Drive:=0; { Получаем имя диска } ParentDir:=copy(Path,4,Length(Path)-1); { Выделим родительский каталог } If not ReadSector(@s0,Drive,1,0) then Exit; If Pos('\',ParentDir)=0 then Begin { Если ищем в корне #################################################} Path:=Path+#0; NameSeg:=Seg(Path);NameOfs:=Ofs(Path)+1; DTAOfs:=Ofs(DTA);DTASeg:=Seg(DTA);DTASize:=Sizeof(DTA); asm { FindFirst - заполняем } push ds mov ax,[NameSeg] mov ds,ax mov dx,[NameOfs] mov ah,$4E { Функция DOS - найти первый файл } mov cx,Attr { Аттрибуты файла } int 21h jnc @FilesF mov ax,$FF mov [LongDOSError],ax jmp @AsmEnd @FilesF: mov ah,$2f { Получим адрес текущей DTA } int 21h mov ax,es { И скопируем ее в нашу локальную DTA } mov ds,ax mov si,bx mov di,[DTAOfs] mov es,[DTASeg] mov cx,[DTASize] cld rep movsb @AsmEnd: pop ds end; { В DTA.Reserved[14] можно узнать номер найденой записи в каталоге} If LongDOSError<>0 then Exit; Sector:=trunc((DTA.Reserved[14]+256*DTA.Reserved[15])/(s0.SectSize shr 5)); { Номер сектора,где находится каталог с именем } InSect:=(DTA.Reserved[14]+256*DTA.Reserved[15])-Sector*(s0.SectSize shr 5); { Номер записи в секторе } Root:=s0.ResSecs+s0.FatSize*s0.FatCnt; { Вычисляем номер сектора с корнем } If not ReadSector(@dir,0,1,Root+Sector) then Exit; { Читаем сектор } SR.Name:=dir[InSect].Name; { Заполнаяем TLongSearchRec } SR.Ext:=dir[InSect].Ext; SR.Attr:=dir[InSect].Attr; SR.Reserv:=dir[InSect].Reserv; SR.Time:=dir[InSect].Time; SR.Date:=dir[InSect].Date; SR.ClstrNo:=dir[InSect].ClstrNo; SR.Size:=dir[InSect].Size; { Теперь смотрим длиное имя } If (InSect>0) and (dir[InSect-1].attr=15) then SR.LongName:=UniToDos(GetUniLFN(InSect)) else SR.LongName:=dir[InSect].Name+'.'+dir[InSect].Ext; End else Begin { Если ищем не в корне ##############################################} Path:=Path+#0; NameSeg:=Seg(Path);NameOfs:=Ofs(Path)+1; DTAOfs:=Ofs(DTA);DTASeg:=Seg(DTA);DTASize:=Sizeof(DTA); asm { FindFirst - заполняем } push ds mov ax,[NameSeg] mov ds,ax mov dx,[NameOfs] mov ah,$4E { Функция DOS - найти первый файл } mov cx,Attr { Аттрибуты файла } int 21h jnc @FilesF mov ax,$FF mov [LongDOSError],ax jmp @AsmEnd @FilesF: mov ah,$2f { Получим адрес текущей DTA } int 21h mov ax,es { И скопируем ее в нашу локальную DTA } mov ds,ax mov si,bx mov di,[DTAOfs] mov es,[DTASeg] mov cx,[DTASize] cld rep movsb @AsmEnd: pop ds end; { В DTA.Reserved[14] можно узнать номер найденой записи в каталоге} If LongDOSError<>0 then Exit; Sector:=trunc((DTA.Reserved[14]+256*DTA.Reserved[15])/(s0.SectSize shr 5)); InSect:=(DTA.Reserved[14]+256*DTA.Reserved[15])-Sector*(s0.SectSize shr 5); { Номер записи в секторе } Sector:=Sector+DTA.Reserved[16]+256*DTA.Reserved[17]-3; { Номер сектора,где находится каталог с именем } Root:=s0.ResSecs+s0.FatSize*s0.FatCnt; { Вычисляем номер сектора с корнем } Data:=Root+(s0.RootSiz*32) div s0.SectSize; If not ReadSector(@dir,0,1,Data+Sector) then Exit; { Читаем сектор } SR.Name:=dir[InSect].Name; { Заполнаяем TLongSearchRec } SR.Ext:=dir[InSect].Ext; SR.Attr:=dir[InSect].Attr; SR.Reserv:=dir[InSect].Reserv; SR.Time:=dir[InSect].Time; SR.Date:=dir[InSect].Date; SR.ClstrNo:=dir[InSect].ClstrNo; SR.Size:=dir[InSect].Size; { Теперь смотрим длиное имя } If (InSect>0) and (dir[InSect-1].attr=15) then SR.LongName:=UniToDos(GetUniLFN(InSect)) else SR.LongName:=dir[InSect].Name+'.'+dir[InSect].Ext; End; End; { Long Find Next ############################################################} Procedure LongFindNext(var SR:TLongSearchRec); var Drive :Word; { Номер диска } Sector,InSect,Data :LongInt; { Сектор, и позиция каталоговой записи } DTASeg,DTASize,DTAOfs :Word; { Адрес локальгого DTA } Begin Drive:=0; LongDOSError:=0; DTAOfs:=Ofs(DTA);DTASeg:=Seg(DTA);DTASize:=Sizeof(DTA); asm { FindFirst - заполняем } push ds mov ah,$2f { Получим адрес текущей DTA } int 21h mov dx,bx mov ah,$4F { Функция DOS - найти первый файл } int 21h jnc @FilesF mov ax,$FF mov [LongDOSError],ax jmp @AsmEnd @FilesF: mov ah,$2f { Получим адрес текущей DTA } int 21h mov ax,es { И скопируем ее в нашу локальную DTA } mov ds,ax mov si,bx mov di,[DTAOfs] mov es,[DTASeg] mov cx,[DTASize] cld rep movsb @AsmEnd: pop ds end; { В DTA.Reserved[14] можно узнать номер найденой записи в каталоге} If LongDOSError<>0 then Exit; Sector:=trunc((DTA.Reserved[14]+256*DTA.Reserved[15])/(s0.SectSize shr 5)); InSect:=(DTA.Reserved[14]+256*DTA.Reserved[15])-Sector*(s0.SectSize shr 5); { Номер записи в секторе } Sector:=Sector+DTA.Reserved[16]+256*DTA.Reserved[17]-3; { Номер сектора,где находится каталог с именем } Root:=s0.ResSecs+s0.FatSize*s0.FatCnt; { Вычисляем номер сектора с корнем } Data:=Root+(s0.RootSiz*32) div s0.SectSize; If not ReadSector(@dir,0,1,Data) then Exit; { Читаем сектор } SR.Name:=dir[InSect].Name; { Заполнаяем TLongSearchRec } SR.Ext:=dir[InSect].Ext; SR.Attr:=dir[InSect].Attr; SR.Reserv:=dir[InSect].Reserv; SR.Time:=dir[InSect].Time; SR.Date:=dir[InSect].Date; SR.ClstrNo:=dir[InSect].ClstrNo; SR.Size:=dir[InSect].Size; { Теперь смотрим длиное имя } If (InSect>0) and (dir[InSect-1].attr=15) then SR.LongName:=UniToDos(GetUniLFN(InSect)) else SR.LongName:=dir[InSect].Name+'.'+dir[InSect].Ext; End; Begin WriteLn; InitUni; LongFindFirst('A:\1\*.*',$FFFF,Search); While LongDosError=0 do Begin WriteLn(Search.Name+' '+Search.Ext+' ',Search.Size:8,' ', Search.FPosInSec:8,' ',Search.FSecPos:8,' ',Search.LongName); LongFindNext(Search); Search.LongName:=copy(Search.LongName,1,30); End; End.