/*
Utility for reading long filenames (WIN'95) ;)

I've used the BOOT SECTOR INFORMATION.So if you wanna change it you
can to make it use BIOS services for getting the specific info...

(The problem exists when the BOOT INFO is deleted in the floppy drive)
So Use INT 25h fer getting the BPB & store all values in the variables

If you experience any problems,I'd be glad if you can give me a call.
If you change the code do let me know !

One good thing is you CAN SEARCH FOR DELETED FILES ALSO USING
THIS UTILITY !!!

29/08/96

Send me EMAIL for all comments at:        [email protected]

۲�� Vatsa ����          Srivatsa Srinivasan.
*/

#define _SAFE 100 //safe memory area

#include <conio.h>
#include <math.h>
#include <alloc.h>
#include <dos.h>
#include <dir.h> //Just fer one function current working directory :((
#include <string.h>

typedef unsigned long   ULI_;
typedef unsigned int    UI_;
typedef unsigned char   UC_;


ULI_ SPC;//Sectors per Cluster
ULI_ NOC;//Number of Clusters
ULI_ BPC;//Bytes per cluster
ULI_ BPS;//Bytes per sector
ULI_ NOF;//Number of FAT
ULI_ SPF;//Sectors per FAT
ULI_ SRD;//Sector root directory
ULI_ NRE;//Number of root directory entries
ULI_ RSB;//Reserved sectors at beggining (This is used when you compress the disk!!)

int drive=0;//A=0,B=1,C=2
struct file
       {
       UC_ filename[14];
       UC_ *long_filename;
       UC_ attrib;
       UI_ time;
       UI_ date;
       ULI_ cluster;
       ULI_ sector;
       ULI_ file_size;
       };

struct FileControl
       {
       char path[MAXPATH]; //disk functions file path without long filenames :((
       ULI_ df_file_number;
       ULI_ df_sect_at;
       ULI_ df_current_off;
       ULI_ df_check_FAT;
       struct file FI;
       };
int get_boot_info()
       {
       struct fatinfo diskinfo;
       UC_ *data;
       int flag;

       cprintf("\r\nGetting BOOT SECTOR info... ");
       drive=getdisk();
       getfat(drive+1,&diskinfo);
       SPC=diskinfo.fi_sclus; NOC=diskinfo.fi_nclus; BPC=diskinfo.fi_bysec;
       data = (char *) calloc(BPS+_SAFE, sizeof(char));
       absread(drive,1L,0L,data);
       NOF=data[0x10];
       SPF=data[0x17]*256L+data[0x16];
       RSB=data[0x0F]*256L+data[0x0E];
       BPS=data[0x0C]*256L+data[0x0B];
       NRE=data[0x12]*256L+data[0x11];

       cprintf("DONE :)");
       if(RSB!=1) { cprintf("\r\n Probably has a device driver & is compressed.No Probs."); }
       free(data);
       return 0;
       }



UI_ get_ROOT_sector()
       {
       SRD=(SPF*NOF)+RSB;
       return SRD;
       }

char *get_path_at(char *path,int at)
       {
       int t=0,a=0,b=0;
       char filename[80];
       strcpy(filename,"");
       while(path[a++]!='\\');
       while(t!=at)
               {
               b=0;
               while(path[a]!='\\' && path[a]!='\0') filename[b++]=path[a++];
               while(path[a]=='\\') a++;
               t++;
               if(path[a]=='\0' && at!=t) { b=0; break;}
               }
       filename[b]='\0';
       return filename;
       }

ULI_ clust_to_sect(ULI_ var)
               { return ((var-2)*SPC)+(NRE/16)+(NOF*SPF+RSB); }

ULI_ sect_to_clust(ULI_ var)
               {
//              if(var<(NRE/16)+(NOF*SPF+1)) return var;
               return ((var-(NRE/16)-(NOF*SPF+RSB))/SPC)+2;
               }

void load_structure(UC_ *data,struct file *temp,int aa)
       {
       int t=0,a=0;

       data+=aa*32;
       while(t<0x08 && data[t]!=' ') temp->filename[a++]=data[t++];
       temp->filename[a++]='.';
       t=0x08;
       while(t<0x0B && data[t]!=' ') temp->filename[a++]=data[t++];
       if(temp->filename[a-1]=='.') a--;
       temp->filename[a]='\0';
       a=0; t=0x0B;
       temp->attrib=data[t++]; t=0x16;
       temp->time=data[t+1]*256L+data[t];              t+=2;
       temp->date=data[t+1]*256L+data[t];              t+=2;
       temp->cluster=(data[t+1]*256L);
       temp->cluster+=data[t];
       t+=2;
       temp->sector=clust_to_sect(temp->cluster);
       temp->file_size  = data[t+3] & 0xff;                    temp->file_size<<=8;
       temp->file_size += data[t+2] & 0xff;                    temp->file_size<<=8;
       temp->file_size += data[t+1] & 0xff;    temp->file_size<<=8;
       temp->file_size += data[t]   & 0xff;
       temp->long_filename=0;
       }


ULI_ get_link_cluster(ULI_ clust)
       {
       ULI_ sector=0,os;
       ULI_ next;
       UC_ *data;
       if(NOC>=4087L)
               sector=clust/256L+RSB;
       else
               sector=clust/340L+RSB;

       data = (char *) calloc(BPS+_SAFE, sizeof(char));
       if(data==0) { cprintf("Not enough memory to read FAT"); exit(1); }
       absread(drive,1,sector,data);
       if(NOC>=4087L)
               {
               sector=clust-((sector-RSB)*256L);
               sector*=2;
               next=data[sector+1]*256L+data[sector];
               }
       else //Why does DOS have to be so smart? 12 bits ? That's not FAT ;)
               {
               //This is just an aprox. if u know any other way USE IT!
               sector=clust-((sector-1)*341.333333333L);
               os=sector*1.5;
               next=data[os+1]*256L+data[os];
               if(fmod(sector,2)==0)
                       next&=0x0FFF;
               else
                       next>>=4;
               }
       free(data);
       if(next>0x0FF8 && next<0x0FFF && NOC<4087L)    next=clust; //<EOF>
       if(next>0x0FFF8 && next<0x0FFFF && NOC>=4087L) next=clust; //<EOF>
       if(next==0)
               {
               cprintf("\r\n The file reports that it occupies a certain area");
               cprintf("\r\n but does not show the same in FAT1 ,Run some Disk Scanner FAST");
               cprintf("\r\n :(( ... Taking default values");
               next=clust+1;
               }
       return next;
       }
struct file *get_first(struct FileControl *FC)
       {
       int t=1,max_numb=BPS/32;
       char present_search[80];
       ULI_ cluster;
       UC_ *data;
       data = (UC_ *) calloc(BPS+_SAFE, sizeof(char));
       FC->df_sect_at=get_ROOT_sector();
       FC->df_check_FAT=0; FC->df_current_off=0;
       if(strcmp(FC->path,"\\")==0) return &FC->FI;
       absread(drive,1,FC->df_sect_at,data);
       strcpy(present_search,get_path_at(FC->path,t));
       for(;;)
               {
               if(FC->df_current_off>=max_numb)
                       {
                       FC->df_check_FAT++;
                       if(FC->df_check_FAT>=SPC)
                               {
//                                      cprintf("\r\n Verifying FAT ... ");
                               if(FC->df_sect_at>=NOF*SPF+RSB && FC->df_sect_at<=NOF*SPF+RSB+NRE/16) FC->df_sect_at++; //This means you're in the Root Directory!
                               else
                                       FC->df_sect_at=clust_to_sect(get_link_cluster(sect_to_clust(FC->df_sect_at)));
                               FC->df_check_FAT=0;
//                                      cprintf(" DONE :)");
                               }
                       else
                               FC->df_sect_at++;
                       absread(drive,1,FC->df_sect_at,data);
                       FC->df_current_off=0;
                       }
               load_structure(data,&FC->FI,FC->df_current_off);
               if(FC->FI.filename[0]=='\0') break;
               if(strcmp(present_search,FC->FI.filename)==0)
                       {
                       t++;
                       load_structure(data,&FC->FI,FC->df_current_off);
                       strcpy(present_search,get_path_at(FC->path,t));
                       if(present_search[0]=='\0')
                               {
                               cprintf("\r\n -- Path wildcard found correct :) --",t);
                               cprintf("\r\n PATH : %s",FC->path);
                               FC->df_sect_at=FC->FI.sector; FC->df_current_off=0; FC->df_check_FAT=0;
                               free(data);
                               return &FC->FI;
                               }
                       FC->df_sect_at=FC->FI.sector; FC->df_current_off=-1; FC->df_check_FAT=0;
                       absread(drive,1,FC->df_sect_at,data);
                       }
               FC->df_current_off++;
               }
       cprintf("\r\n -- Unable to trace path :( --");
       free(data);
       return 0;
       }

struct file *get_next(struct FileControl *FC)
       {
       int max_numb=BPS/32;
       ULI_ cluster;
       UC_ *data;

//              if(FC->FI.long_filename!=NULL) free(FC->FI.long_filename); //deallocate previous allocated memory!
       data = (UC_ *) calloc(BPS+_SAFE, sizeof(char));
       absread(drive,1,FC->df_sect_at,data);
       if(FC->df_current_off>=max_numb)
               {
               FC->df_check_FAT++;
               if(FC->df_check_FAT>=SPC)
                       {
//                              cprintf("\r\n Verifying FAT ... ");
                       if(FC->df_sect_at>=NOF*SPF+RSB && FC->df_sect_at<=NOF*SPF+RSB+NRE/16) FC->df_sect_at++;
                       else
                               {
                               cluster=sect_to_clust(FC->df_sect_at);
                               cluster=get_link_cluster(cluster);
                               FC->df_sect_at=clust_to_sect(cluster);
                               }
                       FC->df_check_FAT=0;
//                              cprintf(" DONE :)");
                       }
                       else
                               FC->df_sect_at++;
//                      cprintf("\r\n Reading.. ");
               absread(drive,1,FC->df_sect_at,data);
               FC->df_current_off=0;
               }
       load_structure(data,&FC->FI,FC->df_current_off);
       if(FC->FI.filename[0]=='\0') {  free(data);return 0;}
       FC->df_current_off++;
       free(data);
       return &FC->FI;
       }


struct file *get_long(struct FileControl *FC)
       {
       int set_1=2,lv=0,lt=0,max_long,k;
       ULI_ cluster;
       UC_ *data,*long_data;
       char *filename;

       data = (UC_ *) calloc(BPS+_SAFE, sizeof(char));
       if(data==0) { cprintf("\r\n NO_MEM 1"); exit(1); }
       while(set_1!=0)
               {
               absread(drive,1,FC->df_sect_at,data);
               if(FC->df_current_off>=BPS/32)
                       {
                       FC->df_check_FAT++;
                       if(FC->df_check_FAT>=SPC)
                               {
//                              cprintf("\r\n Verifying FAT ... ");
                               if(FC->df_sect_at>=NOF*SPF+RSB && FC->df_sect_at<=NOF*SPF+RSB+NRE/16) FC->df_sect_at++;
                                       else
                               {
                               cluster=sect_to_clust(FC->df_sect_at);
                               cluster=get_link_cluster(cluster);
                               FC->df_sect_at=clust_to_sect(cluster);
                               }
                               FC->df_check_FAT=0;
//                              cprintf(" DONE :)");
                               }
                       else
                               FC->df_sect_at++;
//                      cprintf("\r\n Reading.. ");
                       absread(drive,1,FC->df_sect_at,data);
                       FC->df_current_off=0;
                       }
               load_structure(data,&FC->FI,FC->df_current_off);
               if(FC->FI.filename[0]=='\0')
                       {
                       free(data);
                       if(set_1!=2) free(long_data);
                       return 0;
                       }
               FC->df_current_off++;


               if(FC->FI.cluster!=0 && set_1==1)
                       {
                       lt=(max_long+1)*32;
                       lt--;
                       lv=0;
                       while(lt>0)
                               {
                               lt--;
                               for(k=0;k<4;k++) { filename[lv]=long_data[lt]; lt-=2; lv++; }
                               filename[lv]=long_data[lt]; lt-=5; lv++;
                               for(k=0;k<5;k++) { filename[lv]=long_data[lt]; lt-=2; lv++; }
                               filename[lv]=long_data[lt]; lt-=4; lv++;
                               for(k=0;k<2;k++) { filename[lv]=long_data[lt]; lt-=2; lv++; }
                               }
                       FC->FI.long_filename=filename;
//                      free(long_data);
//                      cprintf("<- DONE! ;) ");
                       set_1=0;
                       }
               else
               if(FC->FI.cluster==0 && FC->FI.attrib==0xF && (set_1==0 || set_1==2) && FC->FI.filename[0]!=229)
                       {
//                      cprintf("\r\n                    Recieving LONG ..... ->");
                       set_1=1;
                       lt=(FC->df_current_off-1)*32;

                       max_long=(data[lt]-'A');
                       long_data = (UC_ *) calloc((max_long+1)*32L+_SAFE, sizeof(char));
                       filename = (UC_ *) calloc((max_long+1)*15L+_SAFE, sizeof(char));
                       if(long_data==0) { cprintf("\r\n NO_MEM 2"); exit(1); }
                       if(filename==0) { cprintf("\r\n NO_MEM for longfilename"); exit(1); }
                       }
               if(set_1==1)
                       {
                       lt=(FC->df_current_off-1)*32;
                       lt=FC->df_current_off*32-1;
                       k=0;
                       while(k<32)
                               {
                               long_data[lv]=data[lt];
                               k++;
                               lv++;  lt--;
                               }
//                      cprintf("��");
                       }
               else
               if(set_1==2 && ( FC->FI.attrib & 0x08 )==0) break; //Why care about disk volumes ??
               }
       free(data);
       if(set_1!=2) free(long_data);
       return &FC->FI;
       }
//Cut this if you dont need this.....
//--------------------------------------------------------------------
///*
       int to_day(ULI_ date)     { date&=0x001F; return date; }
       int to_month(ULI_  date)  { date&=0x01E0; date>>=5; return date; }
       int to_year(ULI_  date)   { date&=0xFE00; date>>=9; return date+1980; }
       int to_seconds(ULI_ date) { date&=0x001F; return date*2; }//seconds can NEVER be odd!
       int to_min(ULI_  date)    { date&=0x07E0; date>>=5; return date; }
       int to_hour(ULI_  date)   { date&=0xF800; date>>=0xB; return date; }

void main ( argc, argv ) // Just an example..
int argc ;
char *argv[] ;
       {
       struct FileControl FC; //Main structure like ffblk in <dir.h>
       ULI_ t=0;
       char page=0,scroll=0,*temp;
//      cprintf("\r\n Enter Path : ");
//      scanf("%s",FC.path);
       if(argc==2 || argc==1 )
               {
               getcwd(FC.path,MAXPATH); temp=FC.path; temp+=2; //Best way to shift text ? Huh ? Power of C !
               strcpy(FC.path,temp);
               if(argc==2 && (strcmp(argv[1],"/p")==0 || strcmp(argv[1],"/P")==0)) scroll=1;
               }
       else
               {
               strcpy(FC.path,argv[1]);
               if(argc>2 && (strcmp(argv[2],"\\p")==0 || strcmp(argv[2],"\\P")==0)) scroll=1;
               t=0;
               while(FC.path[t]!='\0') { FC.path[t]=toupper(FC.path[t]); t++; }
               }
       t=0;
       get_boot_info(); // :(( This you'll have to do at the beg of your prog :((
       if(get_first(&FC)!=0)//something like findfirst()
               {
               while(get_long(&FC)!=0)//something like findnext()
                       {
                       if(FC.FI.filename[0]!=229) // Deleted file (Have programmed to get the deleted file too so dont display it)
                               {
                               if((FC.FI.attrib&0x10)!=0)
                                       {
                                       textcolor(15);
                                       cprintf("\r\n%ld> %7ld %02d-%02d-%4d %02d:%02d:%02d � %15s  ",t
                                               ,FC.FI.file_size,to_day(FC.FI.date),to_month(FC.FI.date),to_year(FC.FI.date)
                                                       ,to_hour(FC.FI.time),to_min(FC.FI.time),to_seconds(FC.FI.time),FC.FI.filename);
                                       }
                               else
                                       {
                                       textcolor(7);
                                       cprintf("\r\n%ld> %7ld %02d-%02d-%4d %02d:%02d:%02d   %15s  ",t
                                               ,FC.FI.file_size,to_day(FC.FI.date),to_month(FC.FI.date),to_year(FC.FI.date)
                                                       ,to_hour(FC.FI.time),to_min(FC.FI.time),to_seconds(FC.FI.time),FC.FI.filename);
                                       }
                               if(FC.FI.long_filename!=0)
                                       cprintf(" � %s",FC.FI.long_filename);
                               t++;
                               if(scroll==1) { page++; if(page>20) { getch(); page=0; } }
                               }
                       if(FC.FI.long_filename!=NULL)
                               free(FC.FI.long_filename); //deallocate previous allocated memory for long filenames!

                       }
               textcolor(7);
               cprintf("\r\n\n Total Enteries = %ld \r\n",t);
               }
       }
//*/