home *** CD-ROM | disk | FTP | other *** search
- {Program written by Neil Judell to determine amount of fragmentation on disk.}
- {Edited version by Gary Mathews on June 23, 1988}
- {Recursively searches root directory, subdirectories, and files for frags.}
- {$B-} {Don't buffer the console}
-
- program fats(input,output);
- const
- sub_dir = 16;
- dir_entry_size = 32;
- deleted_entry = 'σ';
- alias_entry = '.';
- dir_entry = 16;
- volable = 8;
-
- type
- str8 = packed array [0..7] of char;
- str3 = packed array [0..2] of char;
-
- {data type defines boot sector data areas}
-
- boot_sector_type = record
- disk_id : packed array[0..2] of byte;
- oem_name : packed array[0..7] of char;
- bytes_per_sector : integer;
- sectors_per_cluster : byte;
- reserved_sect : integer;
- number_fats : byte;
- root_entries : integer;
- total_sectors : integer;
- media_type : byte;
- sectors_per_fat : integer;
- sectors_per_track : integer;
- number_of_heads : integer;
- the_rest : packed array[0..511] of byte;
- end;
-
- {data type defines directory entries}
-
- dir_entry_type = record
- fname : str8;
- fext : str3;
- attr : byte;
- reserved : packed array[0..9] of byte;
- time : integer;
- date : integer;
- first_cluster : integer;
- filesize : packed array [0..1] of integer;
- end;
-
- {data type needed to pass path to recursive routines}
-
- name_type = string[80];
-
- { If we have 12-bit fat entries, we keep 2 sectors of fat in RAM,
- if we have 16-bit fat entries, we keep 1 sector of fat in RAM,
- thus necessitating global definitions of which fat sector we have,
- and global definitions of the fat buffers }
-
- var
- fat_sector : integer;
- fname : string[80];
- boot_sector : boot_sector_type;
- i : integer;
- root_sector : integer;
- first_file_sector : integer;
- fat16 : array[0..256] of integer;
- fat12 : array[0..1024] of byte;
- drivelet : char;
- drivenum : byte;
-
-
- procedure read_sector(sector,segment,offset : integer);
- {use interrupt $25 to read absolute disk sector}
-
- var
- x : byte;
-
- begin
- {First, push bp and ds to preserve them since $25 is a nasty one}
- {then do a popf after the interrupt $25 to preserve the stack}
- {test the carry bit to see if an error, then signal via the x variable}
- {if an error, just croak out}
- Inline(
- $55 {push bp}
- /$1E {push ds}
- /$3E/$A0/>DRIVENUM {ds: mov al,[<drivenum]}
- /$B9/$01/$00 {mov cx,1}
- /$8B/$96/>SECTOR {mov dx,>sector[bp]}
- /$8B/$9E/>SEGMENT {mov bx,>segment[bp]}
- /$8E/$DB {mov ds,bx}
- /$8B/$9E/>OFFSET {mov bx,>offset[bp]}
- /$CD/$25 {int $25}
- /$72/$05 {jc foo}
- /$B0/$00 {mov al,0}
- /$E9/$02/$00 {jmp foo2}
- /$B0/$01 {foo: mov al,1}
- /$9D {foo2: popf}
- /$1F {pop ds}
- /$5D {pop bp}
- /$88/$46/<X {mov <x[bp],al}
- );
- if x=1 then
- begin
- writeln('Cannot read disk error',Chr(7));
- halt(1);
- end;
- end; {procedure read_sector}
-
-
- function cluster_to_sector(cluster : integer): integer;
- {translate cluster number to sector number}
-
- begin
- cluster_to_sector:=((cluster-2)*boot_sector.sectors_per_cluster)+first_file_sector;
- end; {function cluster_to_sector}
-
-
- function next_sector16(sector : integer;var continuous : boolean): integer;
- {given a sector number, find the next sector, if the FAT has 16-bit entries}
- {return next sector=-1 if end of file}
-
- var
- result : integer;
- oldcluster, cluster : integer;
- new_fat_sector : integer;
- rsector : real;
-
- begin
- rsector:=sector;
- if rsector<0 then
- rsector:= rsector+65536.0;
- result:= sector+1;
- continuous:= true;
- if ((result-first_file_sector) mod boot_sector.sectors_per_cluster)=0 then
- begin
- cluster:=trunc((rsector-first_file_sector) / boot_sector.sectors_per_cluster);
- cluster:=cluster+2;
- oldcluster:=cluster;
- new_fat_sector:=(cluster*2) div boot_sector.bytes_per_sector;
- if new_fat_sector<>fat_sector then
- begin
- read_sector(new_fat_sector+boot_sector.reserved_sect,seg(fat16),ofs(fat16));
- fat_sector:=new_fat_sector;
- end;
- cluster:= fat16[cluster mod (boot_sector.bytes_per_sector div 2)];
- result:= cluster_to_sector(cluster);
- if (cluster>=-8) and (cluster<=-1) then Result:= -1;
- Continuous:= (result = -1) or (cluster = oldcluster+1)
- end;
- next_sector16:=result;
- end; {function next_sector16}
-
-
- function next_sector12(sector : integer;var continuous : boolean): integer;
- {given a sector number, find the next sector, if the FAT has 12-bit entries}
- {return next sector=-1 if end of file}
- var
- result : integer;
- oldcluster, cluster : integer;
- new_fat_sector : integer;
- rsector : real;
-
- begin
- rsector:=sector;
- if rsector<0 then
- rsector:=rsector+65536.0;
- result:= sector + 1;
- continuous:=true;
- if ((result-first_file_sector) mod boot_sector.sectors_per_cluster)=0 then
- begin
- cluster:=trunc((rsector-first_file_sector) / boot_sector.sectors_per_cluster);
- cluster:=cluster+2;
- oldcluster:=cluster;
- new_fat_sector:=trunc(cluster*1.5) div boot_sector.bytes_per_sector;
- if new_fat_sector<>fat_sector then
- begin
- read_sector(new_fat_sector+boot_sector.reserved_sect,seg(fat12),ofs(fat12));
- read_sector(new_fat_sector+boot_sector.reserved_sect+1,
- seg(fat12[boot_sector.bytes_per_sector]),ofs(fat12[boot_sector.bytes_per_sector]));
- fat_sector:= new_fat_sector;
- end;
- cluster:=fat12[trunc(oldcluster*1.5) mod boot_sector.bytes_per_sector];
- cluster:=cluster+256*fat12[1+(trunc(oldcluster*1.5) mod boot_sector.bytes_per_sector)];
- if odd(oldcluster)
- then cluster:= (cluster shr 4) and $fff
- else cluster:= cluster and $fff;
- result:= cluster_to_sector(cluster);
- if (cluster >= $FF8) and (cluster >= $FFF) then Result:= -1;
- Continuous:= (result=-1) or (cluster=oldcluster+1)
- end;
- next_sector12:=result;
- end; {function next_sector12}
-
-
- function next_sector(sector : integer;var continuous : boolean) : integer;
- {get next sector number, by first determining if FAT entries are 12 or}
- {16 bits, then calling the appropriate FAT reader}
-
- var
- result : integer;
- rsectors : real;
-
- begin
- rsectors:= boot_sector.total_sectors;
- if rsectors < 0.0
- then rsectors:=rsectors+65536.0;
- if (rsectors / boot_sector.sectors_per_cluster) > 4087.0
- then result:= next_sector16(sector,continuous)
- else result:= next_sector12(sector,continuous);
- next_sector:= result;
- end; {function next_sector}
-
-
- procedure list_file(sector : integer;name : name_type);
- {trace through each files sectors, counting fragments as we go}
-
- var
- i, j, cluster, osector : integer;
- dir_sector : array[0..31] of dir_entry_type;
- continuous : boolean;
- path,oname : name_type;
-
- begin
- i:=0;
- repeat
- sector:= next_sector(sector,continuous);
- if not (continuous) then
- i:= i + 1;
- until (Sector = -1);
- if (i>0) then writeln('file:',name,' fragmented in ',i+1,' pieces');
- end; {procedure list_file}
-
-
- procedure makename(var oname : name_type; fname : str8; fext : str3);
- {convert DOS directory entry name to more readable format}
-
- var
- j : integer;
-
- begin
- if fname[0]=chr(5)
- then oname:=chr(229)
- else oname:=fname[0];
- for j:=1 to 7 do
- oname:=oname+fname[j];
- if pos(' ',oname)<>0 then
- delete(oname,pos(' ',oname),length(oname)+1-pos(' ',oname));
- oname:=oname+'.';
- for j:=0 to 2 do
- oname:=oname+fext[j];
- if pos(' ',oname)<>0 then
- delete(oname,pos(' ',oname),length(oname)+1-pos(' ',oname));
- if pos('.',oname)=length(oname) then
- delete(oname,length(oname),1);
- end; {procedure makename}
-
-
- procedure list_directory(sector : integer;name : name_type);
- {recursively trace out a subdirectory}
-
- var
- pieces, i, j, cluster, osector : integer;
- dir_sector : array[0..31] of dir_entry_type;
- continuous, done : boolean;
- path,oname : name_type;
-
- begin
- {read first sector of directory}
- read_sector(sector,seg(dir_sector),ofs(dir_sector));
- i:=0; {Keep track of which directory entry we are using}
- done:= false;
- pieces:= 0; {count fragments as well}
- repeat
- {if directory entry is a subdirectory or a file, do something}
- if (dir_sector[i].fname[0]<>chr(0)) then
- begin
- if (dir_sector[i].fname[0]<>deleted_entry) and
- (dir_sector[i].fname[0]<>alias_entry) and
- (volable <> (dir_sector[i].attr and volable)) then
- begin {first make the pathname}
- makename(oname,dir_sector[i].fname,dir_sector[i].fext);
- {if subdirectory, go recurse, else just trace file}
- if (dir_entry and dir_sector[i].attr=dir_entry)
- then list_directory(cluster_to_sector(dir_sector[i].first_cluster),name+'\'+oname)
- else list_file(cluster_to_sector(dir_sector[i].first_cluster),name+'\'+oname);
- end;
- i:= i + 1; {try next dir entry}
- {if no more in this sector, read next directory sector}
- if (i >= boot_sector.bytes_per_sector/dir_entry_size) then
- begin
- i:=0;
- sector:= next_sector(sector,continuous);
- if not (continuous) then pieces:=pieces+1;
- if sector<> -1
- then read_sector(sector,seg(dir_sector),ofs(dir_sector))
- else done:=true;
- end;
- end else done:=true;
- until done;
- if (pieces>0) then writeln('directory:',name,' fragmented in ',pieces+1,' pieces');
- end; {procedure list_directory}
-
-
- procedure list_root_directory(sector : integer);
- {Identical to list_directory, but the root directory is special because}
- {it is guaranteed to be continuous, and its sectors are NOT part of the FAT}
-
- var
- i, j, cluster, osector : integer;
- dir_sector : array[0..31] of dir_entry_type;
- done : boolean;
- oname : name_type;
-
- begin
- read_sector(sector,seg(dir_sector),ofs(dir_sector));
- i:=0;
- done:=false;
- repeat
- if (dir_sector[i].fname[0]<>chr(0)) then
- begin
- if (dir_sector[i].fname[0]<>deleted_entry) and
- (dir_sector[i].fname[0]<>alias_entry) and
- (volable <> (dir_sector[i].attr and volable)) then
- begin
- makename(oname,dir_sector[i].fname,dir_sector[i].fext);
- oname:='\'+oname;
- if (dir_entry and dir_sector[i].attr=dir_entry)
- then list_directory(cluster_to_sector(dir_sector[i].first_cluster),oname)
- else list_file(cluster_to_sector(dir_sector[i].first_cluster),oname);
- end;
- i:=i+1;
- if i>=boot_sector.bytes_per_sector/dir_entry_size
- then
- begin
- i:=0;
- sector:=sector+1;
- read_sector(sector,seg(dir_sector),ofs(dir_sector));
- end;
- end else done:= true;
- until Done;
- end; {procedure list_root_directory}
-
-
- begin
- TextBackGround(Blue);
- TextColor(White);
- HiResColor(Blue);
- ClrScr;
- writeln('FRAG V1.1: Search disk for fragmentation');
- writeln;
- write('Drive letter = '); {get drive letter, convert to drive number}
- read(kbd,drivelet);
- DriveLet:= UpCase(DriveLet);
- writeln(drivelet,':');
- drivenum:= ord(drivelet)-ord('A');
- {tell me that I have not read any FAT sector at all yet}
- fat_sector:= -1;
- read_sector(0,seg(boot_sector),ofs(boot_sector)); {read the boot sector}
-
- {print out disk technical information}
-
- writeln;
- writeln('Logical dimensions:');
- write(' Operating environment: ');
- for i:= 0 to 7 do
- write(boot_sector.oem_name[i]);
- writeln;
- writeln(' Number of boot sectors: ',boot_sector.reserved_sect);
- root_sector:= boot_sector.reserved_sect + boot_sector.number_fats *
- boot_sector.sectors_per_fat;
- writeln(' Root directory sectors: ',root_sector);
- writeln(' Sectors/track:',' ':11,boot_sector.sectors_per_track);
- writeln(' Heads:',' ':19,boot_sector.number_of_heads);
- writeln;
-
- {calculate the offset basis for data sectors for cluster<->sector calculations}
-
- first_file_sector:=(boot_sector.root_entries*dir_entry_size) div
- boot_sector.bytes_per_sector;
- first_file_sector:= first_file_sector+boot_sector.reserved_sect;
- first_file_sector:= first_file_sector+boot_sector.sectors_per_fat *
- boot_sector.number_fats;
- list_root_directory(root_sector); {start looking for fragments}
- TextBackGround(Black); {Restore screen color}
- HiResColor(Black)
- end. {main}