linux c 实现 ls 命令

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <error.h>
#include <time.h>// ctime()函数

#include <dirent.h>//操作目录
#include <sys/stat.h>//操作文件
#include <pwd.h>// 获取文件所有者
#include <grp.h>

//InfoModeAll -a        InfoModeDetail -l
//显示信息模式
typedef enum _InfoMode { InfoModeBothNo,InfoModeAll,InfoModeDetail,InfoModeBoth} InfoMode;
//目录元素种类(文件、目录)
enum ItemCategory { ItemCategoryDir, ItemCategoryFile };

//显示目录中元素列表
void display_dirItemList(char *path, int isAll);
//显示目录中元素信息
void display_dirItemInfo(char *path, int isAll);

//显示目录信息
void display_singleDirInfo(char *path);
//显示文件信息
void display_singleFileInfo(char *path);
//显示文件名,根据文件路径
void display_fileName(char *path);

//显示文件信息
void display_fileInfo(char *path, InfoMode mode);
//显示目录信息
void display_dirInfo(char *path, InfoMode mode);

//解析命令行参数,返回,显示信息模式
InfoMode AnalyticalParm(int argc, char **arg);
//获取完整路径
void getAbsolutePath(char *path);
//检查path是否为绝对路径,0 不是,是相对路径  1 是绝对路径
int checkPathIsAbsolutePath(char *path);
//获取目录下的文件/目录名称,返回char **(这个变量需要动态释放),以及fileNameCount
void getFileNameListFormDir(char *path,int isAll,char fileNameList[][10],int *fileNameCount);
//打印目录元素的属性
void Demonstrate_attribute(struct stat buf);
//判断元素是文件还是目录
int checkPathIsFile(char *path);

int main(int argc, char **arg) {
    /*
    argc = 3;
    arg[0] = "./my_ls";
    arg[1] = "-a";
    arg[1] = "-l";
    arg[2] = "/home/pengjing/文档/10-文件读写/my_ls/bin/Debug/test/";
    //int i;
    //for(i=0; i<argc; i++) {
        //printf("%s\t",arg[i]);
    //}
    //printf("\n");
    */

    InfoMode mode = AnalyticalParm(argc, arg);
    char *path = arg[argc-1];
    //判断是否为文件名,还是目录名,当res_index为0时,是目录名,当res_index为.所在的索引时为文件名
    getAbsolutePath(path);
    //过滤最后一个"/"
    if(path[strlen(path)-1] == '/'){
        path[strlen(path)-1] = '\0';
    }

    int isFile = checkPathIsFile(path);
    if(isFile == 1) {
        display_fileInfo(path,mode);
    } else {
        display_dirInfo(path,mode);
    }

    return 0;
}

void display_dirItemList(char *path, int isAll) {
    int fileNameCount = 0;
    char fileNames[30][10];
    getFileNameListFormDir(path,isAll,fileNames,&fileNameCount);
    int i;
    for(i=0;i<fileNameCount;i++){
        printf("%-s\t",fileNames[i]);
    }
    printf("\n");
}
void display_dirItemInfo(char *path, int isAll) {
    int fileNameCount = 0;
    char fileNameList[30][10];
    char filePathList[30][100];
    int i,j;
    getFileNameListFormDir(path,isAll,fileNameList,&fileNameCount);
    for(i=0; i<fileNameCount; ++i) {
        char filePath[90] = {'\0'};
        strcpy(filePath,path);
        strcat(filePath,"/");
        strcat(filePath,fileNameList[i]);
        strcpy(filePathList[i],filePath);
    }
    struct stat _stat;
    for(i=0; i<fileNameCount; i++) {
        //bzero(_stat,sizeof(struct stat));
        //printf("%s\n",filePathList[i]);
        // /home/pengjing/document/10-文件读写/my_ls/bin/Debug/test/file1
        // char *myPath = "/home/pengjing/document/10-文件读写/my_ls/bin/Debug/test/file1";
        int res_lstat = lstat(filePathList[i],&_stat);
        if(res_lstat == -1) {
            perror("lstat");
            exit(0);
        }
        Demonstrate_attribute(_stat);
    }
}
void getFileNameListFormDir(char *path,int isAll,char fileNameList[][10],int *fileNameCount) {
    struct dirent *diren;
    DIR *dir;
    *fileNameCount = 0;

    //printf("fileNameList size :%ld\n",sizeof(fileNameList));
    if((dir = opendir(path)) == NULL) {
        perror("opendir");
    }
    while((diren = readdir(dir)) != NULL) {
        char *name = diren->d_name;
        if(isAll == 0 && name[0] == '.') {
            continue;
        }
        strcpy(fileNameList[*fileNameCount],name);
        (*fileNameCount)++;
    }
    closedir(dir);
}

//显示文件信息
void display_singleFileInfo(char *path) {
    //printf("显示单个文件信息\n");
    struct stat _stat;
    int res_lstat = lstat(path,&_stat);
    if(res_lstat == -1) {
        perror("lstat");
        exit(0);
    }
    Demonstrate_attribute(_stat);
}

void display_fileName(char *path){
    //printf("显示文件名");
    char res[10],*a;
    a = rindex(path,'/');
    strcpy(res,a);
    int i;
    for(i=1;i<strlen(res);i++){
        res[i-1] = res[i];
    }
    res[i-1] = '\0';
    printf("%s\n",res);
}

//显示文件信息
void display_fileInfo(char *path, InfoMode mode) {
    //printf("显示文件的详细信息 mode:%d\n",mode);
    //根据显示模式显示内容
    switch(mode) {
        case InfoModeBothNo: {
            //显示目录中元素的名称
            display_fileName(path);
            break;
        }
        case InfoModeAll: {
            //显示目录中所有元素的名称
            display_fileName(path);
            break;
        }
        case InfoModeDetail: {
            //显示目录下元素的信息
            display_singleFileInfo(path);
            break;
        }
        case InfoModeBoth: {
            //显示目录下所有元素的信息
            display_singleFileInfo(path);
            break;
        }
        default : {
            //mode 错误
            printf("mode 错误");
            exit(0);
            break;
        }
    }
}
//显示目录信息
void display_dirInfo(char *path, InfoMode mode) {
    //printf("显示目录的详细信息 mode:%d\n",mode);
    //根据显示模式显示内容
    switch(mode) {
        case InfoModeBothNo: {
            //显示目录中元素的名称
            display_dirItemList(path,0);
            break;
        }
        case InfoModeAll: {
            //显示目录中所有元素的名称
            display_dirItemList(path,1);
            break;
        }
        case InfoModeDetail: {
            //显示目录下元素的信息
            display_dirItemInfo(path,0);
            break;
        }
        case InfoModeBoth: {
            //显示目录下所有元素的信息
            display_dirItemInfo(path,1);
            break;
        }
        default : {
            //mode 错误
            printf("mode 错误");
            exit(0);
            break;
        }
    }
}

//解析命令行参数,返回parmCount(参数个数),显示信息模式
InfoMode AnalyticalParm(int argc, char **arg) {
    int i;
    InfoMode mode = InfoModeBothNo;
    for(i = 1 ; i < argc; i++) {
        if(arg[i][0] == '-') {
            if(arg[i][1] == 'a') {
                if(mode == InfoModeDetail) {
                    mode = InfoModeBoth;
                    break;
                }
                mode = InfoModeAll;
            } else if(arg[i][1] == 'l') {
                if(mode == InfoModeAll) {
                    mode = InfoModeBoth;
                    break;
                }
                mode = InfoModeDetail;
            }
        }
    }
    return mode;
}

int checkPathIsAbsolutePath(char *path) {
    int res = 0;
    if(path[0] == '/' || path[0] == '~') {
        res = 1;
    }
    return res;
}

//获取文件属性并打印
void Demonstrate_attribute(struct stat buf){
    char buf_time[32]; //存放时间
    struct passwd *psd; //从该结构体中获取文件所有者的用户名
    struct group *grp; //从该结构体中获取文件所有者所属组的组名
/*
    我们使用最多的属性是st_mode.通过着属性我们可以判断给定的文件是一个普通文件还是一个目录,连接等等.可以使用下面几个宏来判断.
    S_ISLNK(st_mode):是否是一个连接
    S_ISREG是否是一个常规文件
    S_ISDIR是否是一个目录
    S_ISCHR是否是一个字符设备
    S_ISBLK是否是一个块设备
    S_ISFIFO是否是一个FIFO文件
    S_ISSOCK是否是一个SOCKET文件

    S_IFMT      0170000     文件类型的位遮罩
    S_IFSOCK    0140000     socket
    S_IFLNK     0120000     符号链接(symbolic link)
    S_IFREG     0100000     一般文件
    S_IFBLK     0060000     区块装置(block device)
    S_IFDIR     0040000     目录
    S_IFCHR     0020000     字符装置(character device)
    S_IFIFO     0010000     先进先出(fifo)
    S_ISUID     0004000     文件的(set user-id on execution)位
    S_ISGID     0002000     文件的(set group-id on execution)位
    S_ISVTX     0001000     文件的sticky位
    S_IRWXU     00700       文件所有者的遮罩值(即所有权限值)
    S_IRUSR     00400       文件所有者具可读取权限
    S_IWUSR     00200       文件所有者具可写入权限
    S_IXUSR     00100       文件所有者具可执行权限
    S_IRWXG     00070       用户组的遮罩值(即所有权限值)
    S_IRGRP     00040       用户组具可读取权限
    S_IWGRP     00020       用户组具可写入权限
    S_IXGRP     00010       用户组具可执行权限
    S_IRWXO     00007       其他用户的遮罩值(即所有权限值)
    S_IROTH     00004       其他用户具可读取权限
    S_IWOTH     00002       其他用户具可写入权限
    S_IXOTH     00001       其他用户具可执行权限
*/
    //获取并打印文件类型
    if (S_ISLNK(buf.st_mode)){ //判断是否为符号链接
        printf("l");
    }else if (S_ISREG(buf.st_mode)){ //判断是否为文件
        printf("-");
    }else if (S_ISDIR(buf.st_mode)){ //判断是否为目录
        printf("d");
    }else if (S_ISCHR(buf.st_mode)){ //判断是否为字符设备文件
        printf("c");
    }else if (S_ISBLK(buf.st_mode)){ //判断是否为块设备文件
        printf("b");
    }else if (S_ISFIFO(buf.st_mode)){ //判断是否为先进先出的FIFO
        printf("f");
    }else if (S_ISSOCK(buf.st_mode)){ //判断是否为socket
        printf("s");
    }
    //获取并打印文件所有者的权限
    //按位与结果作为条件判断,应当判断其与结果为0还是非0数值  当前比较的是buf.st_mode在用户读权限的位与S_IRUSR是否相等
    if (buf.st_mode & S_IRUSR){
        printf("r");
    }else{
        printf("-");
    }
    if (buf.st_mode & S_IWUSR){
        printf("w");
    }else{
        printf("-");
    }
    if (buf.st_mode & S_IXUSR){
        printf("x");
    }else{
        printf("-");
    }
    //获取并打印与文件所有者同组的用户对该文件的操作权限
    if(buf.st_mode & S_IRGRP){
        printf("r");
    }else{
        printf("-");
    }
    if(buf.st_mode & S_IWGRP){
        printf("w");
    }else{
        printf("-");
    }
    if(buf.st_mode & S_IXGRP){
        printf("x");
    }else{
        printf("-");
    }
    //获取并打印其它用户的对该文件的操作权限
    if (buf.st_mode & S_IROTH){
        printf("r");
    }else{
        printf("-");
    }
    if (buf.st_mode & S_IWOTH){
        printf("w");
    }else{
        printf("-");
    }
    if (buf.st_mode & S_IXOTH){
        printf("x");
    }else{
        printf("-");
    }
    printf(" ");
    //根据uid与gid获取文件所有者的用户名与组名
    psd = getpwuid(buf.st_uid);
    grp = getgrgid(buf.st_gid);
    printf("%4d ",buf.st_nlink); //打印文件的链接数(该文件硬链接数目)
    printf("%-9s", psd->pw_name); //打印文件拥有者
    printf("%-8s", grp->gr_name); //打印文件所属用户组
    printf("%6d",(int)buf.st_size); // 打印文件的大小
    char *wo = ctime(&buf.st_mtime);
    strcpy(buf_time, ctime(&buf.st_mtime));
    buf_time[strlen(buf_time) - 1] = '\0'; // 去掉换行符
    printf(" %s\n", buf_time); // 打印文件的时间信息
}

int checkPathIsFile(char *path){
    int res = 0;
    struct stat _stat;
    int res_lstat = lstat(path,&_stat);
    if(res_lstat == -1){
        perror("lstat");
        exit(0);
    }
    if(S_ISREG(_stat.st_mode)){ //判断是否为文件
        res = 1;
    }
    return res;
}

void getAbsolutePath(char *path){
    //组建绝对路径
    char absPath[100];
    int isAbsolutePath = checkPathIsAbsolutePath(path);
    if(isAbsolutePath == 1) {
        //absPath = (char *)malloc(sizeof(char) * strlen(path));
        strcpy(absPath,path);
    } else {
        if(getcwd(absPath,200) == NULL) {
            perror("获取当前工作目录失败");
        }
        strcat(absPath,"/");
        strcat(absPath,path);
        //printf("absPath:%s\n",absPath);
    }
    path = absPath;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值