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
//当前文件夹的文件
vector
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
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
vector
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
vector
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
手机扫一扫
移动阅读更方便
你可能感兴趣的文章