FAT12 img tool
阅读原文时间:2023年07月13日阅读:1

NJU/2019/OS

Description:

CODE:

Main.cpp:

/*
@author: Edwin Xu
@Date:2019/11/13
@Note: just ASCII
*/
#include
#include
#include
#include
#include
#include
#include

#define IMG_PATH "a.img"

using namespace std;

//myPrint in NASM
extern "C" {void myPrint(char *c,int len,int color);}
//print func using myPrint()
char chars[];
void print(string s,int color){
const char * c = s.c_str();
strcpy(chars,s.c_str());
myPrint(chars,s.length(),color);
}

//Part1: struct and util functions
struct File
{
string filename;
int size;
int firstCluster;
File(string n, int s, int cluster) {
filename = n;
size = s;
firstCluster = cluster;
}
File(){
size = ;
filename = "";
firstCluster = ;
}
};
struct Directory
{
string dirName ;
//子目录
vector subDirs ;
//当前文件夹的文件
vector subFiles ;
int dirNum=;
int fileNum=;

 void addDir(Directory d) {  
     this->subDirs.push\_back(d);  
     dirNum++;  
 }  
 void addFile(string name,int size,int cluster) {  
     this->subFiles.push\_back(File(name,size,cluster));  
     fileNum++;  
 }

 Directory() {  
     dirName = "";  
 }  
 Directory(string n) {  
     this->dirName = n;  
 }

 //判断有没有son这个儿子  
 int hasSon(string son) {  
     for (int i = ; i < dirNum; i++) {  
         if (son.compare(subDirs\[i\].dirName) == ) {  
             return ;  
         }  
     }  
     return ;  
 }  
 //判断有没有这个file, 并返回cluster  
 int hasFile(string file) {  
     for (int i = ; i < fileNum; i++) {  
         if (file.compare(subFiles\[i\].filename) == ) {  
             return subFiles\[i\].firstCluster; //存在文件,返回cluster  
         }  
     }  
     return -; //不存在文件,返回-1  
 }

};

vector path; //当前已经遍历的目录

string getPath() {
string res = "/";
for (int i = ; i < path.size(); i++) {
res += (path[i] + "/");
}
return res ;
}

void ls_display(Directory d) {
if (d.dirName.length()>) path.push_back(d.dirName); //if not root dir
print(getPath()+":\n",);
if(d.dirName.length()>) print(". .. ",);
for (int i = ; i < d.dirNum; i++) { print(d.subDirs[i].dirName+" ",); } for (int i = ; i < d.fileNum; i++) { print(d.subFiles[i].filename+" ",); } print("\n",); for (int i = ; i < d.dirNum; i++) { ls_display(d.subDirs[i]); } if (d.dirName.length() > )
{
path.pop_back();
}
}

void ls_l_display(Directory d) {
if (d.dirName.length() > ) path.push_back(d.dirName); //if not root dir
print(getPath() +" " + to_string(d.dirNum) + " " + to_string(d.fileNum)+":\n",);
if (d.dirName.length() > ) print( ".\n..\n",);
for (int i = ; i < d.dirNum; i++) { print(d.subDirs[i].dirName,); print(" " + to_string(d.subDirs[i].dirNum) + " " + to_string(d.subDirs[i].fileNum)+"\n",); } for (int i = ; i < d.fileNum; i++) { print(d.subFiles[i].filename +" " + to_string(d.subFiles[i].size)+"\n",); } print("\n",); for (int i = ; i < d.dirNum; i++) { ls_l_display(d.subDirs[i]); } if (d.dirName.length() > ) path.pop_back();
}

/*
get dir node by dir name (note: name is unique)
*/
Directory getDirectory(Directory beginDir,string dirName) {
if (beginDir.dirName.compare(dirName) == ) {
return beginDir; //get it, the current dir is what i want
}
//fond in the subdir:
for (int i = ; i < beginDir.dirNum; i++) {
Directory temp_dir= getDirectory(beginDir.subDirs[i], dirName);
if (temp_dir.dirName.length() != )return temp_dir;
}
return Directory();
}

//Part2: BPB and FAT operations

typedef unsigned char u8; //1B
typedef unsigned short u16; //2B
typedef unsigned int u32; //4B

int BytsPerSec; //Bytes of every sector
int SecPerClus; //sectors of a cluster
int RsvdSecCnt; //Boot记录占用的扇区数
int NumFATs; //FAT tables Num
int RootEntCnt; //max files Num of root directory
int FATSz; //num of FAT sectors

#pragma pack (1) /*指定按1字节对齐*/

//offset is 11 bytes
struct BPB {
u16 BPB_BytsPerSec; //每扇区字节数
u8 BPB_SecPerClus; //每簇扇区数
u16 BPB_RsvdSecCnt; //Boot记录占用的扇区数
u8 BPB_NumFATs; //FAT表个数
u16 BPB_RootEntCnt; //根目录最大文件数
u16 BPB_TotSec16;
u8 BPB_Media;
u16 BPB_FATSz16; //FAT扇区数
u16 BPB_SecPerTrk;
u16 BPB_NumHeads;
u32 BPB_HiddSec;
u32 BPB_TotSec32; //如果BPB_FATSz16为0,该值为FAT扇区数
};
//BPB over,length is 25 bytes

//root directory entry
struct RootEntry {
char DIR_Name[];
u8 DIR_Attr; //file attr
char reserved[];
u16 DIR_WrtTime;
u16 DIR_WrtDate;
u16 DIR_FstClus; //start cluster No
u32 DIR_FileSize;
};
//根目录条目结束,32字节
#pragma pack () /*取消指定对齐,恢复缺省对齐*/

struct subEntry {
char DIR_Name[];
u8 DIR_Attr;
char reserved[];
u16 DIR_WrTime;
u16 DIR_WrDate;
u16 DIR_FstClus;
u32 DIR_FileSize;
};

#pragma pack () /*取消指定对齐,恢复缺省对齐*/

void fillBPB(struct BPB* bpb_ptr); //载入BPB
void printFiles(struct RootEntry* rootEntry_ptr, Directory* rootnode); //打印文件名,这个函数在打印目录时会调用下面的printChildren
void printChildren(char * directory, int startClus,Directory * d); //打印目录及目录下子文件名
int getFATValue(int num); //读取num号FAT项所在的两个字节,并从这两个连续字节中取出FAT项的值,
void printFileContent(int startClus);
int getFATValue(int num);

Directory root;
FILE* fat12; //global variable

void init() {
struct BPB bpb;
struct BPB* bpb_ptr = &bpb;

 //载入BPB  
 fillBPB(bpb\_ptr);

 //init all global variables  
 BytsPerSec = bpb\_ptr->BPB\_BytsPerSec;  
 SecPerClus = bpb\_ptr->BPB\_SecPerClus;  
 RsvdSecCnt = bpb\_ptr->BPB\_RsvdSecCnt;  
 NumFATs = bpb\_ptr->BPB\_NumFATs;  
 RootEntCnt = bpb\_ptr->BPB\_RootEntCnt;  
 if (bpb\_ptr->BPB\_FATSz16 != ) {  
     FATSz = bpb\_ptr->BPB\_FATSz16;  
 }  
 else {  
     FATSz = bpb\_ptr->BPB\_TotSec32;  
 }

 struct RootEntry rootEntry;  
 struct RootEntry\* rootEntry\_ptr = &rootEntry;

 //print in cursion  
 printFiles(rootEntry\_ptr,&root);  

}
//erase the spaces in the biginning and end
string& trim(std::string &s)
{
if (s.empty()) return s;
s.erase(, s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ") + );
return s;
}

string ls_l_resolve(string command) {
const char * cmd1 = command.c_str();
int len = command.length();

 //处理 -lll这种多个l的情况  
 int \_l\_beginIndex = ;  
 for (int i = ; i < len-; i++) {  
     if (cmd1\[i\] == '-'&&cmd1\[i + \] == 'l') {  
         \_l\_beginIndex = i + ;  
         break;  
     }  
 }  
 int l\_endIndex = \_l\_beginIndex;  
 for (int i = \_l\_beginIndex + ; i < len; i++) {  
     if (cmd1\[i\] != 'l') {  
         l\_endIndex = i;  
         break;  
     }  
 }  
 if (\_l\_beginIndex != l\_endIndex) {  
     command = command.substr(, \_l\_beginIndex+) + command.substr(l\_endIndex,len-l\_endIndex);  
 }  
 //cout << "comm:" << command << endl;  
 const char \* cmd = command.c\_str();  
 len = command.length();

 int beginIndex = , endIndex = ;  
 int hasBegun = ; //是否已经进入目录的 beginIndex

 //form1:ls path -l  
 if (cmd\[len - \] == 'l'&&cmd\[len - \] == '-') {  
     for (int i = ; i < len; i++) {  
         if (cmd\[i\] != ' '&&!hasBegun) {  
             beginIndex = i;  
             hasBegun = ;  
             //break;  
         }  
         if (hasBegun && (cmd\[i\] == ' ' || cmd\[i\] == '-')) {  
             endIndex = i;  
             break;  
         }  
     }  
 }  
 else {  
     //form2:ls -l path  
     for (int i = ; i < len; i++) {  
         if (cmd\[i\] == '-'&&cmd\[i + \] == 'l') {  
             beginIndex = i + ;  
             break;  
         }  
     }  
     for (int i = beginIndex+; i < len; i++) {  
         if (cmd\[i\] != ' ') {  
             beginIndex = i;  
             break;  
         }  
     }  
     endIndex = len;  
 }  
 string res = command.substr(beginIndex, endIndex - beginIndex);  
 return res;  

}
//to upper
string upper(string s) {
string res;
const char* c = s.c_str();
for (int i = ; i < s.length(); i++) { if (c[i] > &&c[i]<)res += (c[i] - ); else res += c[i]; } return res; } //tranform path like '/a/b/c', return a vector vector getPathVector(string path) {
vector pathVec;
const char* pathChars = path.c_str();
int len = path.length();
int beginIndex = ;
if (pathChars[] == '/')beginIndex++;
char temp[];//temp char arr
for (int i = beginIndex; i < len; i++) {
if (pathChars[i] == '/'||i==len-) {
pathVec.push_back(path.substr(beginIndex,(i==len-)?len:i-beginIndex));
beginIndex = i + ;
}
}
return pathVec;
}

//得到路径中的目录
Directory locateDirectory(string path) {
path = upper(path);
vector pathVector = getPathVector(path);
vector dirArr;

 for (int i = ; i < pathVector.size(); i++) {  
     dirArr.push\_back(getDirectory(root, pathVector\[i\]));  
 }

 Directory res = dirArr\[dirArr.size() - \];  
 int isOK = ;  
 if(dirArr.size()==){  
     if(dirArr\[\].dirName.length()==)isOK=;  
 }  
 else{  
     for (int i = ; i < pathVector.size() - ; i++) {  
         if (!dirArr\[i\].hasSon(dirArr\[i + \].dirName)) {  
             isOK = ;  
             break;  
         }  
     }  
 }  
 if (!isOK) res.dirNum = -; //如果路径不正确,将返回目录节点的dirName置-1  
 return res;  

}

void Main() {
string inp;
while ()
{
print(">",);
getline(cin, inp);
inp = trim(inp);

     const char\* c\_inp = inp.c\_str();

     int has\_ = ;  
     for(int i =;i<inp.length();i++){  
         if(c\_inp\[i\]=='-'){  
             has\_ = ;  
             break;  
         }  
     }

     if (inp.compare("exit") == ) {  
         print( "Bye!\\n",);  
         break;  
     }  
     if (inp.length() >=  && c\_inp\[\] == 'l'&&c\_inp\[\] == 's') {  
         if (!inp.compare("ls")) {  
             ls\_display(root);  
         }  
         else if(!inp.substr(,).compare("ls")&&!has\_){  
             string path = inp.substr(,inp.length()-);  
             path = trim(path);  
             Directory dir = locateDirectory(path);  
             ls\_display(dir);  
         }  
         else if(!inp.compare("ls -l")) {  
             ls\_l\_display(root);  
         }  
         else if(!inp.substr(,).compare("ls -L")) {  
             print("your command is invalid!\\n",);  
         }  
         else {  
             string path = ls\_l\_resolve(inp);  
             //cout << "path: " << path << endl;

             if (path.length() == ) {  
                 print("The path is invalid! Try again!\\n",);  
             }  
             else {  
                 Directory dir = locateDirectory(path);  
                 if (dir.dirNum==-) {  
                     print("The path is invalid! Try again!\\n",);  
                 }  
                 else {  
                     ls\_l\_display(dir);  
                 }  
             }  
         }  
     }  
     else if (!inp.substr(,).compare("cat")) {  
         int i;  
         for (i = ; i < inp.length(); i++) {  
             if (c\_inp\[i\] != ' ')break;  //取出cat后面的space  
         }  
         //取出文件和目录:  
         int endIndex = inp.length() - ;  
         for (int i = endIndex; i >= ; i--) {  
             if (c\_inp\[i\] == '/') {  
                 endIndex = i;  
                 break;  
             }  
         }

         string path = inp.substr(i, endIndex - i);  
         string fileName = inp.substr(endIndex + , inp.length() - endIndex - );

         if (endIndex == inp.length() - ) {  
             path = "";  
             fileName = inp.substr(i, inp.length()-i);  
         }  
         //cout << "path: " << path << " file: " << fileName << endl;  
         Directory dir;  
         if (path.length() == ) { //path is empty, so it's root entry  
             dir = root;  
         }  
         else {  
             dir = locateDirectory(path);  
         }  
         if (dir.dirNum == -) {  
             print("The path is invalid!\\n",);  
         }  
         else {  
             int cluster = dir.hasFile(upper(fileName));  
             if (cluster==-) {  
                 print("The file is not exist!\\n",);  
             }  
             else {  
                 if (cluster >= )  
                     printFileContent(cluster);  
             }

         }  
     }  
     else if(inp.length()>){  
         string s = "Wrong Command! Try Again!\\n";  
         print(s,);  
     }  
 }  

}

void fillBPB( struct BPB* bpb_ptr) {
int check;
//BPB从偏移11个字节处开始
check = fseek(fat12, , SEEK_SET);
if (check == -)
print("fseek in fillBPB failed!\n",);

 //BPB长度为25字节  
 check = fread(bpb\_ptr, , , fat12);  
 if (check != )  
     print("fread in fillBPB failed!\\n",);  

}

void printFiles(struct RootEntry* rootEntry_ptr, Directory* root) {
int base = (RsvdSecCnt + NumFATs * FATSz) * BytsPerSec; //根目录首字节的偏移数
int check;
char realName[]; //暂存将空格替换成点后的文件名

 //依次处理根目录中的各个条目  
 int i;  
 for (i = ; i < RootEntCnt; i++) {

     check = fseek(fat12, base, SEEK\_SET);  
     if (check == -)  
         print("fseek in printFiles failed!\\n",);

     check = fread(rootEntry\_ptr, , , fat12);  
     if (check != )  
         print("fread in printFiles failed!\\n",);  
     base += ;  
     if (rootEntry\_ptr->DIR\_Name\[\] == '\\0') continue;    //empty entry

     //filliter ilvalid  
     int j;  
     int boolean = ;  
     for (j = ; j < ; j++) {  
         if (!(((rootEntry\_ptr->DIR\_Name\[j\] >= ) && (rootEntry\_ptr->DIR\_Name\[j\] <= )) ||  
             ((rootEntry\_ptr->DIR\_Name\[j\] >= ) && (rootEntry\_ptr->DIR\_Name\[j\] <= )) ||  
             ((rootEntry\_ptr->DIR\_Name\[j\] >= ) && (rootEntry\_ptr->DIR\_Name\[j\] <= )) ||  
             (rootEntry\_ptr->DIR\_Name\[j\] == ' '))) {  
             boolean = ;    //invalid char  
             break;  
         }  
     }  
     if (boolean == ) continue;    //not object

     int k;  
     if ((rootEntry\_ptr->DIR\_Attr & 0x10) == ) {  
         //it's a file  
         int tempLong = -;  
         for (k = ; k < ; k++) {  
             if (rootEntry\_ptr->DIR\_Name\[k\] != ' ') {  
                 tempLong++;  
                 realName\[tempLong\] = rootEntry\_ptr->DIR\_Name\[k\];  
             }  
             else {  
                 tempLong++;  
                 realName\[tempLong\] = '.';  
                 while (rootEntry\_ptr->DIR\_Name\[k\] == ' ') k++;  
                 k--;  
             }  
         }  
         tempLong++;  
         realName\[tempLong\] = '\\0';    //filename is realName

         root->addFile(realName,rootEntry\_ptr->DIR\_FileSize,rootEntry\_ptr->DIR\_FstClus);  
         //output fileName:  
         //printf("FileName: %s\\n", realName);  
     }  
     else {  
         //it's a dir  
         int tempLong = -;  
         for (k = ; k < ; k++) {  
             if (rootEntry\_ptr->DIR\_Name\[k\] != ' ') {  
                 tempLong++;  
                 realName\[tempLong\] = rootEntry\_ptr->DIR\_Name\[k\];  
             }  
             else {  
                 tempLong++;  
                 realName\[tempLong\] = '\\0';  
                 break;  
             }  
         }    //dir name is realName

         Directory d = Directory(realName);  
         root->addDir(d);

         //priint recurisively  
         printChildren(realName, rootEntry\_ptr->DIR\_FstClus, &root->subDirs\[root->dirNum-\]);  
     }  
 }  

}

void printChildren(char * directory, int startClus,Directory* d) {
//offset of No.2 cluster(the first cluster)
int dataBase = BytsPerSec * (RsvdSecCnt + FATSz * NumFATs + (RootEntCnt * + BytsPerSec - ) / BytsPerSec);
char fullName[]; //file /dir fullname
int strLength = strlen(directory);
strcpy(fullName, directory);
fullName[strLength] = '/';
strLength++;
fullName[strLength] = '\0';
char* fileName = &fullName[strLength];

 int currentClus = startClus;  
 int value = ;  
 int ifOnlyDirectory = ;

 while (value < 0xFF8) { //value <FF8H  
     value = getFATValue(currentClus);  
     if (value < ) {  
         break;  
     }  
     if (value == 0xFF7) {  
         print("Bad cluster,failed!\\n",);  
         break;  
     }

     char\* str = (char\*)malloc(SecPerClus\*BytsPerSec);    //暂存从簇中读出的数据  
     char\* content = str;

     int startByte = dataBase + (currentClus - )\*SecPerClus\*BytsPerSec;  
     int check;  
     check = fseek(fat12, startByte, SEEK\_SET);  
     if (check == -)  
         print("fseek in printChildren failed!\\n",);

     check = fread(content, , SecPerClus\*BytsPerSec, fat12);  
     if (check != SecPerClus \* BytsPerSec)  
         print("fread in printChildren failed!\\n",);

     //solve date of content,the regular entry structure is as same as root dir entry.  
     int count = SecPerClus \* BytsPerSec;    //bytes of a cluster  
     int loop = ;  
     while (loop < count) {  
         int i;  
         char tempName\[\];    //暂存替换空格为点后的文件名  
         if (content\[loop\] == '\\0') {  
             loop += ;  
             continue;  
         }    //empty entry

             //filiter the invaild things  
         int j;  
         int boolean = ;  
         for (j = loop; j < loop + ; j++) {  
             if (!(((content\[j\] >= ) && (content\[j\] <= )) ||  
                 ((content\[j\] >= ) && (content\[j\] <= )) ||  
                 ((content\[j\] >= ) && (content\[j\] <= )) ||  
                 (content\[j\] == ' '))) {  
                 boolean = ;    //invaild char  
                 break;  
             }  
         }  
         if (boolean == ) {  
             loop += ;  
             continue;  
         }    //not object file

         if ((content\[loop + \] & 0x10) == ) {  
             //File :  
             int k;  
             int tempLong = -;  
             for (k = ; k < ; k++) {  
                 if (content\[loop + k\] != ' ') {  
                     tempLong++;  
                     tempName\[tempLong\] = content\[loop + k\];  
                 }  
                 else {  
                     tempLong++;  
                     tempName\[tempLong\] = '.';  
                     while (content\[loop + k\] == ' ') k++;  
                     k--;  
                 }  
             }  
             tempLong++;  
             tempName\[tempLong\] = '\\0';    

             int a = content\[loop+\],  
                 b = content\[loop + \],  
                 c = content\[loop + \],  
                 d1 = content\[loop + \];  
             a = a >=  ? a :  + a;//处理负数  
             b = b >=  ? b:  + b;  
             c = c >=  ? c :  + c;  
             d1 = d1 >=  ? d1 :  + d1;

             int size = a + \*b + \*\*c + \*\*\*d1;

             int x = content\[loop + \];  
             int y = content\[loop + \];  
             //cout << "cluster of : " << fullName<<"/"<<tempName<<" :" <<y \* 256 + x << endl;  
             d->addFile(tempName,size, y \*  + x);  
             strcpy(fileName, tempName);  
             //printf("%s\\n", fullName);  
             ifOnlyDirectory = ;  
         }  
         else {  
             //dir  
             int k;  
             int tempLong = -;

             for (k = ; k < ; k++) {  
                 if (content\[loop + k\] != ' ') {  
                     tempLong++;  
                     tempName\[tempLong\] = content\[loop + k\];  
                 }  
                 else {  
                     while (content\[loop + k\] == ' ') k++;  
                     k--;  
                 }  
             }  
             tempLong++;  
             tempName\[tempLong\] = '\\0';  
             strcpy(fileName, tempName);  
             ifOnlyDirectory == ;

             Directory dir = Directory(tempName);  
             d->addDir(dir);

             int a = content\[loop + \];  
             int b = content\[loop + \];  
             printChildren(fullName, b\*+a, &d->subDirs\[d->dirNum-\]);  
         }  
         loop += ;  
     }  
     free(str);  
     currentClus = value;  
 };  
 //if (ifOnlyDirectory == 0)  
 //    printf("%s\\n", fullName);    //空目录的情况下,输出目录  

}

//输出文件内容:
void printFileContent(int startClus) {
int dataBase = BytsPerSec * (RsvdSecCnt + FATSz * NumFATs + (RootEntCnt * + BytsPerSec - ) / BytsPerSec);
int check;
int curclus = startClus;
int value = ;
while (value < 0xFF8) {//
value = getFATValue(curclus);
if (value < ) {
break;
}
if (value == 0xFF7) {
print( "bad cluster\n",);
}
char temp[];
int startByte = dataBase + * (curclus - );
check = fseek(fat12, startByte, SEEK_SET);
if (check == -)print( "Failed!\n",);
check = fread(temp, , , fat12);
temp[] = '\0';
print(temp,);
print("\n",);
curclus = value;
}
}

int getFATValue(int num) {
int fatBase = RsvdSecCnt * BytsPerSec;
int fatPos = fatBase + num * / ;
int type = ;
if (num % == ) {
type = ; //even
}
else {
type = ; //odd
}
u16 bytes;
u16* bytes_ptr = &bytes;
int check;
check = fseek(fat12, fatPos, SEEK_SET);
if (check == -) {
print("fseek in getFATValue failed!\n",);
return -;
}
check = fread(bytes_ptr, , , fat12);
if (check != ) {
print("fread in getFATValue failed!\n",);
return -;
}
//u16为short,结合存储的小端顺序和FAT项结构可以得到
//type为0的话,取byte2的低4位和byte1构成的值,type为1的话,取byte2和byte1的高4位构成的值
if (type == ) {
bytes = bytes << ; bytes = bytes >> ;
}
else {
bytes = bytes >> ;
}
return bytes;
}

// Main, entrance of this program
int main() {
fat12 = fopen(IMG_PATH, "rb"); //open the fat12 image
init(); //init, build the file tree
Main(); //command solve and execute
fclose(fat12); //clost the file stream in the last。
return ;
}

NASM CODE:

my_print.asm

global myPrint
;void myPrint(char *,int len,int color);
;color: -default, -red
;EdwinXu
section .data
color_default: db 1Bh, '[37;0m',
.length equ $ - color_default
color_red: db 1Bh, '[31;1m',
.length equ $ - color_red

section .text

myPrint:
mov eax, [esp+]
cmp eax,
je default_color

;set red
mov eax,
mov ebx,
mov ecx, color_red
mov edx, color_red.length
int 80h
jmp color_end
;set default color:
default_color:
mov eax,
mov ebx,
mov ecx, color_default
mov edx, color_default.length
int 80h

;print the str
color_end:
mov eax,
mov ebx,
mov ecx, [esp+] ;str
mov edx, [esp+] ;len
int 80h
;recover the color
mov eax,
mov ebx,
mov ecx, color_default
mov edx, color_default.length
int 80h

 ret

Makefile:

all:

ALL:
nasm -f elf32 my_print.asm
g++ -m32 my_print.o Main.cpp -o main
./main