LINUX 完成cp与ls的功能

1:main函数

利用"fgets" 获取文件的命令

调用cmd_handle.c中的cmd_exec(command)主函数

#include "cmd_handle.h"
#include "cmd_cp.h"
#define CMD_SIZE 128

int main(){
        char command[CMD_SIZE];
        do{
                printf("bashshell-->");
                //获取命令
                fgets(command,CMD_SIZE,stdin);
                command[strlen(command)-1]='\0';//将回车符转换\0
                if(strcmp(command,"exit")==0){
                        printf("GoodBye:\n");
                        exit(EXIT_SUCCESS);
                }

                //调用cmd_handle模块方法进行命令解析
                cmd_exec(command);

        }while(1);
        return 0;
}

2:cmd_handle.h

构建command_t的结构体

#ifndef __HEAD_CMD_HANDLE_H__
#define __HEAD_CMD_HANDLE_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>

#define SIZE_NAME 128
#define SIZE_ARGC 10
#define SIZE_PARAM 128



//构建结构体
typedef struct{
        //文件名
        char cmd_name[SIZE_NAME];
        //文件个数
        int cmd_argc;
        //利用二位数组表示文件的个数
        char cmd_param[SIZE_ARGC][SIZE_PARAM];

}command_t;

extern void dispath_command(command_t* );
extern void init_command(command_t*);
extern bool cmd_exec(char*);
extern void parse_command(char*,command_t*);
#endif

3.cmd_handle.c

#include "cmd_handle.h"
#include "cmd_cp.h"
#include "cmd_ls.h"
#define DEBUG

void init_command(command_t* command);
void parse_command(char* command, command_t* cmd);
void show_command(command_t* command){
        printf("\n-----------------command-------------------\n");
        printf("[DEBUG] command name:%s\n",command->cmd_name);
        printf("[DEBUG] command argc:%d\n",command->cmd_argc);
        printf("[DEBuG] command params:\n");
        for(int i=0;i<(command->cmd_argc);i++){
                printf("\tparam <%s>\n",command->cmd_param[i]);
        }
        printf("-------------------------------------------\n");

}

void dispath_command(command_t* command){
        //获取命令

        char *cmd_name=command->cmd_name;
        if(strcmp(cmd_name,"cp")==0){
                operate_cp(command);
        }else if(strcmp(cmd_name,"ls")==0){
                operate_ls(command);
        }

}
//主函数
bool cmd_exec(char* command){
        #ifdef DEBUG
        printf("[DEBUG] command:<%s>",command);
        #endif
        if(NULL== command){
                printf("command is not empty\n");
                return false;
        }
        command_t cmd;
        init_command(&cmd);
        //解释命令
        parse_command(command,&cmd);
        #ifdef DEBUG
         show_command(&cmd);
        #endif
        //获取命令
        dispath_command(&cmd);
}

//初始化
void init_command(command_t* command){
        memset(command->cmd_name,0,SIZE_NAME);
        command->cmd_argc=0;
        for(int i=0;i<SIZE_ARGC;i++){
                memset(command->cmd_param[i],0,SIZE_PARAM);
        }
}

void parse_command(char* command, command_t* cmd){
        /*
        char command[256]="cp /etc/passwd /mnt/hgfs/VMshare/part5_cp";
        char *str=strtok(command," ");
        printf("<str>%s\n",str);
        while((str=strtok(NULL," "))!=NULL){
        printf("str=%s\n",str);
        }
*/
        //利用空格对命令字符串进行分割,获取命令名称(cp)以及每个地址或者文件
        //使用strtok函数
        //替换名称
        char *cmd_name=strtok(command," ");
        strcpy(cmd->cmd_name,cmd_name);
        //获取参数
        int argc =0;
        char *param=NULL;
        //通过循环将命令后面的地址或文件获取
        while((param=strtok(NULL," "))!=NULL){
                strcpy(cmd->cmd_param[argc],param);
                argc++;
        }
        cmd->cmd_argc=argc;
}


~                                                                                                                                                                                                                                                                                                                                                                                                           
~            

cp部分

1.cmd_cp.h

利用枚举函数分别对不同的文件类型枚举

结构体

src_file_name[SIZE_SRC_FILE_NAME]文件名

#ifndef __HEAD_CMD_CP_H__
#define __HEAD_CMD_CP_H__

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include "cmd_handle.h"
#define SIZE_SRC_FILE_NAME 128


//枚举
enum FILE_TYPE{
        FT_FILE=1,
        FT_DIR,
        FT_OTHER,
        FT_ERROR=1000
};



typedef struct{
        enum FILE_TYPE ft;
        char src_file_name[SIZE_SRC_FILE_NAME];

}fileInfo_t;


extern bool file_isExist(char* srcpath);
extern void cmd_cp_parse_srcpath(command_t* command,fileInfo_t* fileInfo);
extern int cmd_cp_dir(fileInfo_t fileInfo,char* dest);
extern enum FILE_TYPE cmd_cp_parse_filetype(fileInfo_t* fileInfo);
extern int cmd_cp_file(fileInfo_t sr,char* dest);
extern void cmd_cp_exec(fileInfo_t fileInfo,command_t* command);
extern int operate_cp(command_t* command);
#endif

2.cmd_cp.c

#include"cmd_cp.h"
#include "cmd_handle.h"
#define DEBUG


int operate_cp(command_t* command){
        if(NULL==command){
                perror("[DEBUG]command is NULL:");
                return -1;
        }
        //判断参数是否足够(复制需要两个参数)
        if((command->cmd_argc)!=2){
                perror("[DEBUG]Not enough parameters:");
                return -1;
        }

        fileInfo_t file;
        //提取源文件的名称
        cmd_cp_parse_srcpath(command,&file);
        //判断文件是否存在
        if(!file_isExist(file.src_file_name)){
                printf("Exist is null");
                return -1;
        }


        //提取文件类型
        enum FILE_TYPE ft = cmd_cp_parse_filetype(&file);
        if(ft == FT_ERROR){
                return -1;
        }
        file.ft=ft;

        #ifdef DEBUG
        printf("-----------------file------------------\n");
        printf("[DEBUG] filetype:%d\t",file.ft);
        printf("[DEBUG] src_file_name %s\n",file.src_file_name);
        printf("---------------------------------------\n");
        #endif
        cmd_cp_exec(file,command);
        return 0;
}



//判断文件是否存在
bool file_isExist(char* srcpath){
        if(NULL == srcpath){
                perror("[DEBUG]srcpath is empty\n");
                return false;
        }
        return((access(srcpath,F_OK))==0)?true:false;

}


//提取源文件的名称
void cmd_cp_parse_srcpath(command_t* command,fileInfo_t* fileInfo){
        //拿到文件名
        strcpy(fileInfo->src_file_name,command->cmd_param[0]);
        //打印文件名
        #ifdef DEBUG
        printf("[DEBUG] src path:%s\n",fileInfo->src_file_name);
        #endif
}

//提取文件类型
enum FILE_TYPE cmd_cp_parse_filetype(fileInfo_t* fileInfo){
        struct stat statbuf;
        int ret =stat(fileInfo->src_file_name,&statbuf);
        if(ret != 0){
                perror("statbuf");
                return FT_ERROR;
        }
        mode_t mode =statbuf.st_mode;
        if(S_ISREG(mode)){
                return FT_FILE;
        }else if(S_ISDIR(mode)){
                return FT_DIR;
        }else{
                return FT_OTHER;
        }

}

void cmd_cp_exec(fileInfo_t fileInfo,command_t* command){
        enum FILE_TYPE ft =fileInfo.ft;
        switch(ft){
                case FT_FILE :
                        cmd_cp_file(fileInfo,command->cmd_param[1]);
                        break;
                case FT_DIR :
                        cmd_cp_dir(fileInfo,command->cmd_param[1]);
                        break;
        }
}



//进行文件复制
int cmd_cp_file(fileInfo_t sr,char* dest){
        //读文件
        FILE* srcfile=fopen(sr.src_file_name,"r");
        //写文件
        FILE* destfile=fopen(dest,"w+");
        if(NULL == srcfile || NULL == destfile){
                perror("[DEBUG] stcfile and destfile:");
                return -1;
        }

        //开始循环
        char buf[512]={0};
        ssize_t num;
        while((num =fread(buf,1,sizeof(buf),srcfile))!=0){
                fwrite(buf,1,num,destfile);
        }

        fclose(srcfile);
        fclose(destfile);
        return 0;

}



int cmd_cp_dir(fileInfo_t fileInfo,char* dest){
        //递归终止条件
        //意思是如果目标是文件 那就进行文件复制(也是终止条件)
        if(fileInfo.ft ==FT_FILE){
                return cmd_cp_file(fileInfo,dest);
        }

        //进行递归操作
        //1.打开目录opendir
        // DIR *opendir(cint cmd_cp_dir(fileInfo_t fileInfo,char* dest)onst char *name);
        DIR* dir = opendir(fileInfo.src_file_name);
        if(NULL == dir){
                perror("opendir");
                return -1;
        }
        //2.生成子目录
        char* newSrcPath = strcat(fileInfo.src_file_name,"/");
        char* newDestPath = strcat(dest,"/");

        //3.判断目标目录是否存在
        if(access(newDestPath,F_OK) == -1){
                //目录不存在 尝试创建
                if(mkdir(newDestPath,0777) == -1){
                        perror("mkdir failed");
                        return -1;
                }
        }

        //4.读取目录的内容
        struct dirent* dirent;
        while((dirent=readdir(dir))!=NULL){
                if(strcmp(dirent->d_name,".")==0 || strcmp(dirent->d_name,"..")==0){
                        continue;
                }
                char curSrcPath[512]={0};
                strcpy(curSrcPath,newSrcPath);

                char curDestPath[512]={0};
                strcpy(curDestPath,newDestPath);

                //进行拼接
                strcat(curSrcPath,dirent->d_name);
                strcat(curDestPath,dirent->d_name);

                fileInfo_t fi;
                strcpy(fi.src_file_name,curSrcPath);
                fi.ft =cmd_cp_parse_filetype(&fi);

                cmd_cp_dir(fi,curDestPath);
        }
        return 0;

}
                                            

ls部分

1.cmd_ls.h

#ifndef __HEAD_CMD_LS_H__
#define __HEAD_CMD_LS_H__

#pragma once
#include "cmd_handle.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
//getgrgid 函数 头文件
#include <grp.h>
//getpwuid 函数 头文件
#include <pwd.h>



#define SZ_NAME 64
#define SZ_PERMISSION 10
#define SZ_TIME 64
#define SZ_LINK_CONTENT 128
#define SZ_PATH 64


//文件属性的结构体
typedef struct{
        struct stat f_attr_stat; //系统原有的info
        char f_attr_type;//文件类型
        char f_attr_uname[SZ_NAME];//文件的所属者
        char f_attr_gname[SZ_NAME];//文件所属组
        char f_attr_mtime[SZ_TIME];//最后修改时间
        char f_attr_permission[SZ_PERMISSION];//文件权限
        char f_attr_name[SZ_NAME]; // 文件名
        char f_atter_link_content[SZ_LINK_CONTENT];//软链接文件名

}file_attribute_t;


extern int operate_ls(command_t* command);
//ls命令的总入口
extern int cmd_ls_execute(command_t*);
//遍历目录
extern int cmd_list_directory(char*);
extern int get_file_attr(file_attribute_t* fileAttr,char* path,const char* filename,int isSymbolicLink);
extern void make_path(char* path, const char* dest);
extern void show_file_attribute(file_attribute_t* fileAttr);
extern int getchar_file_type(file_attribute_t* fileAttr);
extern void get_file_uname(file_attribute_t* fileAttr);
extern void get_file_gname(file_attribute_t* fileAttr);
extern void show_file_attribute(file_attribute_t* fileAttr);
extern void get_file_last_modify_time(file_attribute_t* fileAttr);
extern void get_file_symbolic_link_name(char* path,file_attribute_t* fileAttr);
extern int get_file_permission(file_attribute_t* fileAttr);
#endif








2.cmd_ls.c

#include "cmd_ls.h"
#include "cmd_handle.h"
#define DEBUG



int operate_ls(command_t* command)

{
        //判断是否为空
        if(NULL == command){
                perror("[DEBUG] command is NULL");
                return -1;
        }
        //调用cmd_ls模块
        if(cmd_ls_execute(command)==-1)
        {
                printf("ls failed.\n");
                return -1;
        }

}


int cmd_ls_execute(command_t* command)
{
        if(NULL==command){
                printf("command is NULL.\n");
                return -1;
        }
        //判断参数的个数(ls -l)
        if((command->cmd_argc)==1)
        {
                strcpy(command->cmd_param[1],".");
        }else if(command->cmd_argc!=2){
                printf("Command parameter error.\n");
                return -1;
        }
        //遍历目录函数cmd_list_directory
        return cmd_list_directory(command->cmd_param[1]);
}



//遍历目录
int cmd_list_directory(char* dirpath)
{
        //打开目录 
        DIR* dir = opendir(dirpath);
        if(NULL == dir){
                perror("open dir");
                return -1;
        }

        //遍历目录
        file_attribute_t fileAttr;
        char path[SZ_PATH]={0};
        struct dirent* pdirent = NULL;
        while ((pdirent =readdir(dir))!=NULL)
        {
        //剔除(./)与(../)两个目录
        if((strcmp(pdirent->d_name,".")==0) || (strcmp(pdirent->d_name,"..")==0)){
                        continue;
                }
/*              #ifdef DEBUG    
                printf("[DEBUG] filename: <%s>.\n",pdirent->d_name);
                #endif
*/      //创建空间
                memset(&fileAttr,0,sizeof(fileAttr));
                make_path(path,dirpath);
                get_file_attr(&fileAttr,path,pdirent->d_name,pdirent->d_type==DT_LNK);

        }
        closedir(dir);
 
        return 0;
}



//拼接路径
void make_path(char* path, const char* dest){
        //复制
        strcpy(path,dest);
        //拼接
        strcat(path,"/");
}



//获取文件属性
int get_file_attr(file_attribute_t* fileAttr,  char* path, const char* filename, int isSymbolicLink)
{
                int ret=-1;
                if(isSymbolicLink)
                {
                ret = lstat(strcat(path,filename),&fileAttr->f_attr_stat);
                }
                else
                {
                ret = stat(strcat(path,filename),&fileAttr->f_attr_stat);
                }
                if(ret == -1)
                {
                        perror("stat");
                        return -1;
                }
                // 获取文件类型
                if(getchar_file_type(fileAttr)==-1)
                {
                        printf("get file type failed.\n");
                        return -1;
                }
                show_file_attribute(fileAttr);

                //获取文件权限
                if(get_file_permission(fileAttr)==-1)
                {
                        printf("get file permission failed\n");
                        return -1;

                }

                get_file_uname(fileAttr);
                get_file_gname(fileAttr);


                get_file_last_modify_time(fileAttr);

                //复制文件名称
                strcpy(fileAttr->f_attr_name,filename);
                get_file_symbolic_link_name(path,fileAttr);
                show_file_attribute(fileAttr);
                get_file_last_modify_time(fileAttr);


        return 0;

}
//显示文件属性信息
void show_file_attribute(file_attribute_t* fileAttr){

        printf("%c",fileAttr->f_attr_type);
        printf("%s ",fileAttr->f_attr_permission);
        printf("%ld ",fileAttr->f_attr_stat.st_nlink);
        printf("%s ",fileAttr->f_attr_uname);
        printf("%s ",fileAttr->f_attr_gname);
        printf("%ld ",fileAttr->f_attr_stat.st_size);
        printf("%s ",fileAttr->f_attr_mtime);
        if(fileAttr->f_attr_type=='l')
        {
        printf("%s-->%s",fileAttr->f_attr_name,fileAttr->f_atter_link_content);

        }else
        {
        printf("%s",fileAttr->f_attr_name);

        }

        putchar('\n');

}


// 获取文件类型
int getchar_file_type(file_attribute_t* fileAttr)
{
        if(NULL == fileAttr)
        {
                return -1;
        }
        mode_t mode = fileAttr->f_attr_stat.st_mode;
        switch(mode & S_IFMT)
        {
                case S_IFDIR:
                        fileAttr->f_attr_type='d';
                break;
                case S_IFREG:
                        fileAttr->f_attr_type='-';
                break;
                case S_IFBLK:
                        fileAttr->f_attr_type='b';
                break;
                case S_IFSOCK:
                        fileAttr->f_attr_type='s';
                break;
                case S_IFLNK:
                        fileAttr->f_attr_type='l';
                break;
                case S_IFIFO:
                        fileAttr->f_attr_type='p';
                break;
                case S_IFCHR:
                fileAttr->f_attr_type='c';
                break;
                default:
        mode_t mode = fileAttr->f_attr_stat.st_mode;
                break;
}
return 0;
}



//获取文件权限
int get_file_permission(file_attribute_t* fileAttr)
{
        if(NULL == fileAttr)
        {
                return -1;
        }
        //在per数组中放入三个权限
        char perm[]={'r','w','x'};
        int index= 0;//索引从0开始,为文件类型
        //st_mode 是 struct stat 结构体中的一个成员,它表示文件的类型和权限
        mode_t mode =fileAttr->f_attr_stat.st_mode;
        //8种类型
        for(int i=8;i>=0;i--){
                if((mode>>i) & 1)
                {
                        fileAttr->f_attr_permission[index]=perm[index%3];//每三次一循环,分别给予权限
                }else{
                        fileAttr->f_attr_permission[index]='-';//普通文件               
                }
        index++;
        }
        fileAttr->f_attr_permission[index]='\0';//循环结束 给结构体文件权限是\0结束
        return 0;
}


//获取所属用户名的方法get_file_uname
void get_file_uname(file_attribute_t* fileAttr)
{
        struct passwd* pwd = getpwuid(fileAttr->f_attr_stat.st_uid);
        strcpy(fileAttr->f_attr_uname,pwd->pw_name);
}


//获取所属组名的方法get_file_gname
void get_file_gname(file_attribute_t* fileAttr)
{
        struct group* group = getgrgid(fileAttr->f_attr_stat.st_gid);
        strcpy(fileAttr->f_attr_gname,group->gr_name);
}



//显示最后文件修改时间
void get_file_last_modify_time(file_attribute_t* fileAttr)
{
        char* mtimestr=ctime(&fileAttr->f_attr_stat.st_mtim.tv_sec);
        //将回车符换为\0
        mtimestr[strlen(mtimestr)-1]='\0';
        strcpy(fileAttr->f_attr_mtime,mtimestr);

}


//获取软连接名称
void get_file_symbolic_link_name(char* path,file_attribute_t* fileAttr)
{
        if(fileAttr->f_attr_type=='l')
        {
                readlink(path,fileAttr->f_atter_link_content,SZ_LINK_CONTENT);
        }
}



Makefile部分

.PHONY: cleanall

TAR = bashshell
RMRF = rm -rf
GCC = gcc

# 查找当前目录下所有的.c文件
SRC = $(wildcard *.c)
# 将.c文件替换为.o文件,生成对象文件列表
OBJS = $(patsubst %.c,%.o,$(SRC))

# 链接所有对象文件生成可执行文件
$(TAR) : $(OBJS)
        $(GCC) $^ -o $@
        @echo "Compilation successful. Executable: $(TAR)"

# 编译单个.c文件生成.o文件
%.o : %.c
        $(GCC) -c $< -o $@

# 清理目标,删除所有.o文件和可执行文件
cleanall:
        $(RMRF) *.o $(TAR)
        @echo "Cleanup completed."
    

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值