// Shawn Nematbakhsh // lab wed. 6-9 // 12/5/02 // file system - this program manipluates a MSDOS floppy disk // #include "floppy.h" // the fid table static struct file_t table[10]; // // the fid of the actual image static int fd_fid; // // current directory static struct dir_t cd; // function that opens the image for reading int fd_load(char driveLetter) { int i; // clear out fd table for(i=0;i<10;++i) table[i].name=NULL; // start at root secotr cd.sector=ROOT_SECTOR; cd.cluster=-12; // make sure we're opening the 'A' drive if(toupper(driveLetter) != 'A') return 0; // use tmp.img if((fd_fid=open("tmp.img", O_RDWR))==-1) return 0; return 1; } // this function does a ls in teh current directory int fd_ls() { unsigned char buf[32]; int i; int cluster=cd.cluster; // seek to cd lseek(fd_fid,cd.sector,SEEK_SET); repeat: if(cluster==0) return 1; // print file names in current sector for(i=0;i<16;++i) { read(fd_fid, buf, 32); if(!is_empty(buf) && buf[0]!=0xe5) { printf("%s\n",get_file_name(buf)); } } // see if we have to go to the next sector for additional files if(cluster < 0) cluster++; else cluster=fat_lookup(cluster); if(!(cluster >= 0xff8 && cluster <= 0xfff)) { lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto repeat; } return 1; } // this function takes a 32 byte file entry and returns the file name char* get_file_name(unsigned char buf[32]) { char *file=(char*)malloc(13*sizeof(char)); int j; int on=0; for(j=0;j<8;++j) if(buf[j]!=' ') file[on++]=buf[j]; if(buf[8]!=' ') file[on++]='.'; for(j=8;j<11;++j) if(buf[j]!=' ') file[on++]=buf[j]; file[on]='\0'; return file; } // this function indicates if a file on the disk is a file or dir int f_or_d(char *file,unsigned char buf[32],int type) { if(strcmp(file,get_file_name(buf))==0) { if(type==FILE_TYPE) return !(buf[11] & 0x10); if(type==DIRECTORY_TYPE) return (buf[11] & 0x10); } return 0; } // changes the current directory int fd_cd(char *directory) { unsigned char buf[32]; int i; int cluster=cd.cluster; // seek to cd lseek(fd_fid,cd.sector,SEEK_SET); repeat: if(cluster==0) return 0; for(i=0;i<16;++i) { // look for the specified dir read(fd_fid, buf, 32); if(is_empty(buf) || buf[0]==0xe5) continue; if(f_or_d(directory,buf,DIRECTORY_TYPE)) { // change current cd if it exists cd.cluster=(buf[27]<<8)+buf[26]; cd.sector=(cd.cluster+31)*BPS; return 1; } } // see if we have to continue on to next cluster if(cluster < 0) cluster++; else cluster=fat_lookup(cluster); if(!(cluster >= 0xff8 && cluster <= 0xfff)) { lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto repeat; } return 0; } // this function takes a 32 byte file entry and returns one if the entry is "empty", that // is, if no active file is taking up the space int is_empty(unsigned char buf[32]) { int i; if(buf[0]==0xe5) return 1; for(i=0;i<11;++i) if(buf[i]==0x00) return 1; return 0; } // function to create a directory int fd_mkdir(char *name) { char buf[32]; int i; int cluster=cd.cluster; lseek(fd_fid,cd.sector,SEEK_SET); again: if(cluster==0) return 0; for(i=0;i<16;++i) { // search for empty entry to write new dir to read(fd_fid,buf,32); if(is_empty(buf)) { // once we find one, create and set the location lseek(fd_fid,-32,SEEK_CUR); for(i=0;i<8;++i) { if(i > 8) & 0xff; buf[2]=buf[3]=buf[4]=buf[5]='J'; write(fd_fid,buf,6); sector_clear((i+31)*BPS); fat_set(i,0xff8); return 1; } } // see if we can continue to another cluster to find a free spot if(fat_lookup(cluster)>= 0xff8 && fat_lookup(cluster) <= 0xfff) { sector_clear((next_empty_cluster()+31)*BPS); fat_set(cluster,next_empty_cluster()); cluster=next_empty_cluster(); fat_set(cluster,0xff8); lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto again; } else { if(cluster < 0) cluster++; else cluster=fat_lookup(cluster); lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto again; } return 0; } // this function takes a cluster number and returns the value in teh // fat assigned to the cluster int fat_lookup(int cluster) { int result=0x00; char byte; int old=lseek(fd_fid,0,SEEK_CUR); lseek(fd_fid,10*BPS+cluster*12/8,SEEK_SET); // read 12 bits if(cluster%2==0) { read(fd_fid,&byte,1); result+=byte&0xff; read(fd_fid,&byte,1); result+=(byte & 0x0f) << 8; } else { read(fd_fid,&byte,1); result += (byte & 0xf0) >> 4; read(fd_fid,&byte,1); result+=(byte & 0xff)<< 4; } lseek(fd_fid,old,SEEK_SET); return result; } // this function takes a cluster number and sets the fat entry of that cluster to the // value passed void fat_set(int cluster,int value) { char byte; int old=lseek(fd_fid,0,SEEK_CUR); lseek(fd_fid,10*BPS+cluster*12/8,SEEK_SET); // set 12 bits if(cluster%2==0) { byte=value & 0xff; write(fd_fid,&byte,1); read(fd_fid,&byte,1); lseek(fd_fid,-1,SEEK_CUR); byte &= 0xf0; byte += (value >> 8) & 0x0f; write(fd_fid,&byte,1); } else { read(fd_fid,&byte,1); lseek(fd_fid,-1,SEEK_CUR); byte &= 0x0f; byte += (value & 0x0f) << 4; write(fd_fid,&byte,1); byte = (value >> 4) & 0xff; write(fd_fid,&byte,1); } lseek(fd_fid,old,SEEK_SET); } // this function returns the next available empty cluster in the fat int next_empty_cluster() { int i=2; while(fat_lookup(i++) != 0); return i-1; } // this function clears out a sector, filling it with null chars void sector_clear(int sector) { int i; int old=lseek(fd_fid,0,SEEK_CUR); char byte=0x00; lseek(fd_fid,sector,SEEK_SET); for(i=0;i<512;++i) write(fd_fid,&byte,1); lseek(fd_fid,old,SEEK_SET); } // this function deletes a file int fd_rm(char *name) { unsigned char buf[32]; int i; int cluster=cd.cluster; int target,newTarget; lseek(fd_fid,cd.sector,SEEK_SET); repeat: if(cluster==0) return 0; for(i=0;i<16;++i) { // search for the file in the current cluster read(fd_fid, buf, 32); if(is_empty(buf) || buf[0]==0xe5) continue; if(f_or_d(name,buf,FILE_TYPE)) { // if we find it then delete it, and free up its fat entry lseek(fd_fid,-32,SEEK_CUR); buf[0]=0xe5; write(fd_fid,buf,1); target=(buf[27]<<8)+buf[26]; while(fat_lookup(target)>= 0xff8 && fat_lookup(target) <= 0xfff) { newTarget=fat_lookup(target); fat_set(target,0xfff); target=newTarget; } return 1; } } // see if we should search in another cluster for the file if(fat_lookup(cluster)==0) cluster++; else cluster=fat_lookup(cluster); if(!(cluster >= 0xff8 && cluster <= 0xfff)) { lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto repeat; } return 0; } // this fucntion moves a file, basically a rename int fd_mv(char *source,char *destination) { unsigned char buf[32]; int i; int cluster=cd.cluster; lseek(fd_fid,cd.sector,SEEK_SET); repeat: if(cluster==0) return 0; for(i=0;i<16;++i) { // search for file in current cluster read(fd_fid, buf, 32); if(is_empty(buf) || buf[0]==0xe5) continue; if(f_or_d(source,buf,DIRECTORY_TYPE) || f_or_d(source,buf,FILE_TYPE)) { // if found then change the name to the one passed buf[8]=buf[9]=buf[10]=' '; for(i=0;i<8;++i) { if(strlen(destination) < i || destination[i]=='.') while(i<8) buf[i++]=' '; else buf[i]=destination[i]; } for(i=0;i= 0xff8 && cluster <= 0xfff)) { lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto repeat; } return 0; } // this function opens a file on the floppy and returns the file descriptor FD_Handle fd_open(char *filename, int mode) { int i; unsigned char buf[32]; int index; int cluster=cd.cluster; int target; // see if the table is full or if the file is already open for(i=0;i<10;++i) if(table[i].name && strcmp(table[i].name,filename)==0) return -1; for(index=0;index<10;++index) if(!table[index].name) break; if(index==10) return -1; lseek(fd_fid,cd.sector,SEEK_SET); repeat: // search for the file name if(cluster==0) goto more; for(i=0;i<16;++i) { read(fd_fid, buf, 32); if(is_empty(buf) || buf[0]==0xe5) continue; // if found them open if(f_or_d(filename,buf,FILE_TYPE)) { lseek(fd_fid,-32,SEEK_CUR); target=(buf[27]<<8)+buf[26]; table[index].name=malloc(strlen(filename)+1 * sizeof(char)); strcpy(table[index].name,filename); table[index].cluster=target; table[index].base=lseek(fd_fid,0,SEEK_CUR); table[index].offset=0; table[index].size=0; table[index].mode=mode; return index; } } if(cluster < 0) cluster++; else cluster=fat_lookup(cluster); if(!(cluster >= 0xff8 && cluster <= 0xfff)) { lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto repeat; } // consider the case where we write to an empty file...it must be created more: if(mode!=WRITE) return -1; lseek(fd_fid,cd.sector,SEEK_SET); cluster=cd.cluster; again2: // create the file if(cluster==0) return 0; for(i=0;i<16;++i) { // find empty location to write to read(fd_fid,buf,32); if(is_empty(buf)) { // write file info to disk lseek(fd_fid,-32,SEEK_CUR); buf[8]=buf[9]=buf[10]=' '; for(i=0;i<8;++i) { if(strlen(filename) < i || filename[i]=='.') while(i<8) buf[i++]=' '; else buf[i]=filename[i]; } for(i=0;i> 8) & 0xff; buf[2]=buf[3]=buf[4]=buf[5]=0x00; buf[3]=0x20; write(fd_fid,buf,6); sector_clear((i+31)*BPS); fat_set(i,0xff8); table[index].name=malloc(strlen(filename)+1 * sizeof(char)); strcpy(table[index].name,filename); table[index].cluster=i; table[index].base=lseek(fd_fid,0,SEEK_CUR)-32; table[index].size=0; table[index].offset=0; table[index].mode=mode; return index; } } // see if we should search some more for an empty spot if(fat_lookup(cluster)>= 0xff8 && fat_lookup(cluster) <= 0xfff) { sector_clear((next_empty_cluster()+31)*BPS); fat_set(cluster,next_empty_cluster()); cluster=next_empty_cluster(); fat_set(cluster,0xff8); lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto again2; } else { if(cluster < 0) ++cluster; else cluster=fat_lookup(cluster); lseek(fd_fid,(cluster+31)*BPS,SEEK_SET); goto again2; } return -1; } // this function closes an open file handle void fd_close(FD_Handle fdHandle) { char buf[32]; if(fdHandle>=0 && fdHandle < 10 && table[fdHandle].name) { free(table[fdHandle].name); table[fdHandle].name=NULL; // write size data lseek(fd_fid,table[fdHandle].base,SEEK_SET); read(fd_fid,buf,32); lseek(fd_fid,table[fdHandle].base,SEEK_SET); buf[31]=(table[fdHandle].size >> 24) & 0xff; buf[30]=(table[fdHandle].size >> 16) & 0xff; buf[29]=(table[fdHandle].size >> 8) & 0xff; buf[28]=table[fdHandle].size & 0xff; } } // this function reads bytes from a file, and buts them in the passed buffer int fd_read(FD_Handle fdHandle,char *buffer,int length) { int on=0; char byte; int cluster; // make sure file is open and ok for read if(fdHandle < 0 || fdHandle > 9) return -1; if(!table[fdHandle].name) return -1; if(table[fdHandle].mode != READ) return -1; lseek(fd_fid,(table[fdHandle].cluster+31)*BPS + table[fdHandle].offset,SEEK_SET); // read data while(on < length && table[fdHandle].offset < 512) { read(fd_fid,&byte,1); table[fdHandle].offset++; buffer[on++]=byte; // wrap around to next cluster if necessary if(table[fdHandle].offset==512) { cluster=fat_lookup(table[fdHandle].cluster); if(cluster >= 0xff8 && cluster <= 0xfff) return on; table[fdHandle].cluster=cluster; table[fdHandle].offset=0; lseek(fd_fid,(table[fdHandle].cluster+31)*BPS + table[fdHandle].offset,SEEK_SET); } } return on; } // this function writes to the file, very similar to read... int fd_write(FD_Handle fdHandle,char *buffer,int length) { int on=0; int cluster; if(fdHandle < 0 || fdHandle > 9) return -1; if(!table[fdHandle].name) return -1; if(table[fdHandle].mode != WRITE) return -1; lseek(fd_fid,(table[fdHandle].cluster+31)*BPS + table[fdHandle].offset,SEEK_SET); while(on < length && table[fdHandle].offset < 512) { // write data instead of reading write(fd_fid,buffer+on,1); on++; table[fdHandle].size++; table[fdHandle].offset++; if(table[fdHandle].offset==512) { cluster=fat_lookup(table[fdHandle].cluster); if(cluster >= 0xff8 && cluster <= 0xfff) { cluster=next_empty_cluster(); fat_set(table[fdHandle].cluster,cluster); fat_set(cluster,0xff8); } table[fdHandle].cluster=cluster; table[fdHandle].offset=0; lseek(fd_fid,(table[fdHandle].cluster+31)*BPS + table[fdHandle].offset,SEEK_SET); } } return on; } // this function leeks the location pointer for a file descriptor int fd_lseek(FD_Handle fdHandle,int offset) { int cluster; // make sure file is open if(fdHandle < 0 || fdHandle > 9) return -1; if(!table[fdHandle].name) return -1; lseek(fd_fid,(table[fdHandle].cluster+31)*BPS + table[fdHandle].offset,SEEK_SET); while(offset > 0) { // lseek up to the end of the cluster if(offset <= 511 - table[fdHandle].offset) { table[fdHandle].offset+=offset; return 1; } // if we go over the cluster then go on to the next offset= offset -511 + table[fdHandle].offset; cluster=fat_lookup(table[fdHandle].cluster); // if we've reached the end of the file... if(cluster >= 0xff8 && cluster <= 0xfff) { table[fdHandle].offset=512; return 0; } table[fdHandle].cluster=cluster; table[fdHandle].offset=0; offset--; } return 1; }