Linux文件系统的逻辑结构体是一个普通的树。假设文件系统只有目录DIR和普通文件FILE。DIR可拥有可变数量子节点。同一父亲节点称为兄弟节点。路径以/开头为绝对路径。否则是以当前目录(CWD)的相对路径。
可以用二叉树来实现普通的树
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libgen.h>
typedef struct Node{
char name[64];
char type;
struct Node *childPtr, *siblingPtr, *parentPtr;
}Node;
static Node *root, *cwd;
bool ap = false;
int deep = 0;
int num = 0;
static char line[128];
char command[16], pathname[64];
char dname[64], bname[64];
int mkdir_(),rmdir_(),cd(), ls(),pwd(),creat_(),rm(),save(),reload(),menu(),quit();
char *commad_list[] = {"mkdir", "rmdir", "cd", "ls", "pwd", "creat", "rm", "save", "reload", "menu", "quit", NULL};
int (*f_ptr[])() = { (int (*)())mkdir_, rmdir_, cd, ls, pwd, creat_, rm, save, reload, menu, quit };
void get_dir_base(){
char temp[128];
ap = false;
if(pathname[0] == '/') ap = true;
strcpy(temp, pathname);
strcpy(dname, dirname(temp));
strcpy(temp, pathname);
strcpy(bname, basename(temp));
}
void initialie(){
root = (Node*)malloc(sizeof(Node));
root->siblingPtr = root;
root->parentPtr = root;
root->childPtr = NULL;
root->name[0] = '/';
root->name[1] = '\0';
root->type = 'D';
cwd = root;
}
int findCommand(){
int i = 0;
while(commad_list[i]){
if(!strcmp(command, commad_list[i])) return i;
i++;
}
return -1;
}
void getCommand(){
bzero(line, 128);
read(STDIN_FILENO, line, 128);
bzero(command, 128);
line[strlen(line) - 1] = '\0';//kill \n
sscanf(line, "%s %s", command, pathname);
int idx = findCommand();
if(idx == -1) return;
f_ptr[idx]();
}
Node* mk_Node(char type){
Node *p = (Node*)malloc(sizeof(Node));
strcpy(p->name, bname);
p->type = type;
p->childPtr = NULL;
p->siblingPtr = NULL;
return p;
}
Node* find_d(){
get_dir_base();
char *s;
Node* per ;
per = cwd;
if(ap) per = root;
Node* cur = per->childPtr;
if(strcmp(dname, ".")){
s = strtok(dname, "/");
while(s){
while(cur){
if(!strcmp(s, cur->name) && cur->type == 'D'){
per = cur;
break;
};
cur = cur->siblingPtr;
}
if(cur == NULL) return NULL;
cur = per->childPtr;
s = strtok(NULL, "/");
}
}
return per;
}
int _pwd(Node* p, int fd){
char *s[deep];
char tmp[1024];
bzero(tmp, 1024);
Node* cur = p;
int i = 0;
int off = 0;
for(;i < deep && cur != root; i++){
s[i] = cur->name;
cur = cur->parentPtr;
}
tmp[off++] = '/';
while(i--){
int size = strlen(s[i]);
memcpy(tmp + off, s[i], size);
off += size;
if(i) tmp[off++] = '/';
}
tmp[off++] = '\n';
tmp[off] = '\0';
write(fd, tmp, strlen(tmp));
return 0;
}
int pwd(){
return _pwd(cwd, STDOUT_FILENO);
}
int save(){
int fd = open(pathname, O_RDWR|O_CREAT|O_TRUNC, 0666);
Node *stack[num];
Node* cur = root->childPtr;
if(cur == NULL) return -1;
int i = 0;
stack[i++] = cur;
while(i > 0){
cur = stack[--i];
write(fd, &cur->type, 1);
write(fd, " ", 2);
_pwd(cur, fd);
if(cur->siblingPtr) stack[i++] = cur->siblingPtr;
if(cur->childPtr) stack[i++] = cur->childPtr;
}
close(fd);
return 0;
}
int cd(){
Node* per = find_d();
Node* cur = per->childPtr;
while(cur){
if(!strcmp(bname, cur->name) && cur->type == 'D') break;
cur = cur->siblingPtr;
}
if(cur == NULL) return -1;
cwd = cur;
return 0;
}
int _rmdf(char type){
Node* per = find_d();
Node* cur = per->childPtr;
while(cur){
if(!strcmp(bname, cur->name) && cur->type == type) break;
per = cur;
cur = cur->siblingPtr;
}
if(cur == NULL) return -1;
if(type == 'D' && cur->childPtr != NULL) return -1;
if(per->childPtr == cur){
free(cur);
per->childPtr = NULL;
}else{
per->siblingPtr = cur->siblingPtr;
free(cur);
}
return 0;
}
int ls(){
Node* per = find_d();
if(per == NULL) return -1;
Node* cur = per->childPtr;
while(cur){
printf("type : %c name : %s \n", cur->type, cur->name);
cur = cur->siblingPtr;
}
return 0;
}
int rmdir_(){
if(!_rmdf('D')){
deep--;
return 0;
}
return -1;
}
int rm(){
return _rmdf('F');
}
int _mkdf(char type){
Node* per = find_d();
if(per == NULL) return -1;
Node* cur = per->childPtr;
if(cur == NULL){
per->childPtr = mk_Node(type);
per->childPtr->parentPtr = per;
num++;
return 0;
}
while(cur){
if(!strcmp(bname, cur->name) && cur->type == 'D') return -1;
per = cur;
cur = cur->siblingPtr;
}
per->siblingPtr = mk_Node(type);
per->siblingPtr->parentPtr = per->parentPtr;
num++;
return 0;
}
int reload(){
struct stat st;
if(stat(pathname, &st) == -1) return -1;
int fd = open(pathname, O_RDONLY);
char buf[st.st_size];
char tmp[128];
char type;
int i = 0;
int off = 0;
while((i = read(fd, buf + off, st.st_size - off)) > 0){
off += i;
}
close(fd);
i = 0;
int j = 0;
while(i < off){
if(buf[i] != '\n') i++;
else{
bzero(tmp, 128);
memcpy(tmp, buf + j, i - j);
sscanf(tmp, "%c %s",&type , pathname);
if(type == 'D') mkdir_();
else if(type == 'F') creat_();
else return -1;
j = ++i;
}
}
return 0;
}
int menu(){
printf("mkdir dirpath\n");
printf("rmdir dirpath\n");
printf("cd dirpath\n");
printf("ls dirname\n");
printf("pwd \n");
printf("cteat filepath\n");
printf("rm filepath\n");
printf("save filepath\n");
printf("reload filepath\n");
printf("quit\n");
return 0;
}
int creat_(){
return _mkdf('F');
}
int mkdir_(){
if(!_mkdf('D')){
deep++;
return 0;
}
return -1;
}
int quit(){
sprintf(pathname, "text.txt");
save();
exit(0);
return 0;
}
void show(){
printf("welcom to !\n");
printf("command menu show commands\n");
}
int main()
{
//scanf("%*[^\n]%*c");
initialie();
show();
while(1){
//fflush(stdin);
getCommand();
}
return 0;
}