在linux实现ls的部分功能(系统IO)(1)

 下面的MAIN函数仅用来实现     ls -l 1.txt(用于测试)   ./myls  ./1.txt   (./表示当前目录)

 main函数则实现     ls    ls -l     ls ./     ls -l 1.txt     ls -l ./

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <dirent.h>
#include "errno.h"
#include "string.h"


#define S_ISRU(st_mode) ((S_IRUSR) & (st_mode)) //查看文件权限,与对应掩码做&(与)
#define S_ISWU(st_mode) ((S_IWUSR) & (st_mode)) 
#define S_ISXU(st_mode) ((S_IXUSR) & (st_mode)) 
#define S_ISRG(st_mode) ((S_IRGRP) & (st_mode)) 
#define S_ISWG(st_mode) ((S_IWGRP) & (st_mode)) 
#define S_ISXG(st_mode) ((S_IXGRP) & (st_mode)) 
#define S_ISRO(st_mode) ((S_IROTH) & (st_mode)) 
#define S_ISWO(st_mode) ((S_IWOTH) & (st_mode)) 
#define S_ISXO(st_mode) ((S_IXOTH) & (st_mode)) 


int MAIN(int argc, char* argv[]){
	// ./my_ls ./1.txt
	// 如果命令行参数个数 < 2
	if( argc < 2 ){
		pritnf("Too few argument\n");
		return -1;
	}
	struct stat stu;
	/*
		struct stat {
			dev_t     st_dev;         / ID of device containing file /
			ino_t     st_ino;         / Inode number /
			mode_t    st_mode;        / File type and mode /
			nlink_t   st_nlink;       / Number of hard links /
			uid_t     st_uid;         / User ID of owner /
			gid_t     st_gid;         / Group ID of owner /
			dev_t     st_rdev;        / Device ID (if special file) /
			off_t     st_size;        / Total size, in bytes /
			blksize_t st_blksize;     / Block size for filesystem I/O /
			blkcnt_t  st_blocks;      / Number of 512B blocks allocated /

			struct timespec st_atim;  / Time of last access /
			struct timespec st_mtim;  / Time of last modification /
			struct timespec st_ctim;  / Time of last status change /
            /
                struct timespec { /usr/include/x86_64-linux-gnu/bits/types 
                    time_t tv_sec; // seconds
                    long tv_nsec; // and nanoseconds
                };
            /
			#define st_atime st_atim.tv_sec      / Backward compatibility /
			#define st_mtime st_mtim.tv_sec
			#define st_ctime st_ctim.tv_sec
			};
	*/
	int ret = stat(argv[1], &stu);
    /*
        argv[1]为命令行输入的需要查看属性的文件路径,存入stu
        int stat(const char *pathname, struct stat *statbuf);
            作用:获取一个文件相关的一些信息
            参数:
                - pathname:操作的文件的路径
                - statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
            返回值:
                成功:返回0
                失败:返回-1 设置errno
    */
	if( ret == -1 ){
		perror("stat fail");
		return -1;
	}
	// 1.解析文件类型
	// - d b p s l c
	/*
	st_mode这个变量用来判断文件类型,它的类型为mode_t,其实就是普通的unsigned int,但是只是用了低16位。
	
	#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)  //<sys/stat.h>头文件提供了一些宏来帮助用户执行&操作,是则返回1
    #define S_ISLNK(m)  (((m) & S_IFMT) == S_IFLNK)  
    #define S_ISREG(m)  (((m) & S_IFMT) == S_IFREG)
    #define S_ISBLK(m)  (((m) & S_IFMT) == S_IFBLK)
    #define S_ISDIR(m)  (((m) & S_IFMT) == S_IFDIR)
    #define S_ISCHR(m)  (((m) & S_IFMT) == S_IFCHR)
    #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)

	if ( S_ISREG(stu.st_mode) )
		printf("-");
	else if ( S_ISDIR(stu.st_mode) )	
		printf("d");
	*/	
	switch (stu.st_mode & S_IFMT){//S_IFMT是掩码
    /*
    使用 st_mode & 掩码来得到 st_mode 中特定的部分。比如:

    st_mode & 0170000 : 得到文件类型(S_IFMT)
    st_mode & 0007000 : 得到执行文件时设置信息
    st_mode & 0000777 : 得到权限位
    st_mode & 00100: 判断所有者是否可执行
    (以上数字均为八进制)
    …
    为了方便使用,用 linux 预定义的一些宏来代替这些生硬的数字。这些宏定义在 include                 <sys/stat.h> 头文件中。
    */

	case S_IFBLK:  printf("b");break;
	case S_IFCHR:  printf("c");break;
	case S_IFDIR:  printf("d");break;
	case S_IFIFO:  printf("p");break;
	case S_IFLNK:  printf("l");break;
	case S_IFREG:  printf("-");break;
	case S_IFSOCK: printf("s");break;
	default:	   printf("unknown?\n");break;
	}
	// 2.解析文件权限
	/*
        //bit8 ~ bit0,权限属性区域
    //文件所有者(owner)对应掩码(在<sys/stat.h>)
    #define S_IRWXU 00700	/ mask for file owner permissions /
    #define S_IRUSR 00400	/ owner has read permission /
    #define S_IWUSR 00200	/ owner has write permission /
    #define S_IXUSR 00100	/ owner has execute permission /
     //组用户(group)
    #define S_IRWXG 00070	/ mask for group permissions /
    #define S_IRGRP 00040	/ group has read permission /
    #define S_IWGRP 00020	/ group has write permission /
    #define S_IXGRP 00010	/ group has execute permission /
     //其他用户(other)
    #define S_IRWXO 00007	/ mask for permissions for others (not in group) /
    #define S_IROTH 00004	/ others have read permission /
    #define S_IWOTH 00002	/ others have write permission /
    #define S_IXOTH 00001	/ others have execute permission /


		if ( stu.st_mode & S_IRUSR )
			printf("r");
		else
			printf("-");
	*/
	S_ISRU(stu.st_mode)?printf("r"):printf("-");
	S_ISWU(stu.st_mode)?printf("w"):printf("-");
	S_ISXU(stu.st_mode)?printf("x"):printf("-");
	
	S_ISRG(stu.st_mode)?printf("r"):printf("-");
	S_ISWG(stu.st_mode)?printf("w"):printf("-");
	S_ISXG(stu.st_mode)?printf("x"):printf("-");
	
	S_ISRO(stu.st_mode)?printf("r"):printf("-");
	S_ISWO(stu.st_mode)?printf("w"):printf("-");
	S_ISXO(stu.st_mode)?printf("x"):printf("-");
	
	//3.硬链接数
	printf("%ld", stu.st_nlink);
	//4.属主用户名
	struct passwd* user = NULL;
	user = getpwuid(stu.st_uid);
    /*
        struct passwd *getpwuid(uid_t uid);//返回一个包含分解的password数据库的结构体passwd
        在pwd.h里定义了结构体passwd
        struct passwd
        {
            char *pw_name;		/ Username.  /
            char *pw_passwd;		/ Password.  /
            __uid_t pw_uid;		/ User ID.  /
            __gid_t pw_gid;		/ Group ID.  /
            char *pw_gecos;		/ Real name.  /
            char *pw_dir;			/ Home directory.  /
            char *pw_shell;		/ Shell program.  /
        };
    */
	printf("%s", user->pw_name);
	//5.组用户名
	struct group* grp = NULL;
    /*
        struct group
        {
            char *gr_name;		/ Group name.	/
            char *gr_passwd;		/ Password.	/
            __gid_t gr_gid;		/ Group ID.	/
            char **gr_mem;		/ Member list.	/
        };
    */
	grp = getgrgid(stu.st_gid);
    /*
        struct group *getgrgid(gid_t gid);
    */
	printf("%s", grp->gr_name);
	//6.文件大小
	printf("%ld", stu.st_size);
	//7.修改时间
	struct tm time;
	localtime_r( &stu.st_mtim.tv_sec, &time );
	//struct tm *localtime_r(const time_t *timep, struct tm *result);
	//The localtime_r() function stores  the  data  in  a user-supplied struct
	printf(" %d月 %d %d:%d ", time.tm_mon+1, time.tm_mday, time.tm_hour, time.tm_min);
	/*
		time_t类型在time.h中定义:
		#ifndef __TIME_T
		#define __TIME_T
		typedef  long  time_t;
		#endif

		tm结构在time.h中定义:
		#ifndef _TM_DEFINED
		struct tm{
			int tm_sec; 秒 - 取值区间为[0, 59]
			int tm_min; 分 - 取值区间为[0, 59]
			int tm_hour; 时 - 取值区间为[0, 23]
			int tm_mday; 日 - 取值区间为[1, 31]
			int tm_mon; 月份 - 取值区间为[0, 11]
			int tm_year; 年份 - 其值为1900年至今年数
			int tm_wday; 星期 - 取值区间[0, 6],0代表星期天,1代表星期1,以此类推
			int tm_yday; 从每年的1月1日开始的天数-取值区间为[0, 365],0代表1月1日
			int tm_isdst; 夏令时标识符,使用夏令时,tm_isdst为正,不使用夏令时,tm_isdst为0,不了解情况时,tm_isdst为负
		};
		#define _TM_DEFINED
		#endif
	*/
	//8.文件名
	puts(argv[1]);

	return 0;
}	

/*
	./a.out 123 234
	argv[0] ==> ./a.out
	argv[1] ==> 123
	argv[2] ==> 234
	argc 参数个数
*/
// ls    ls -l     ls ./     ls -l 1.txt     ls -l ./

typedef enum{
    listDefault,
    listStatus,
    listDir,
    listStatusFile,
    listStatusDir,
    Default,
} LsState;

typedef enum{
    Success,        //0   errno = 0,表示没有错误因为系统的errno是从1开始
    False,          //1
} readDirState;

//输出该目录下的文件名
int IsDirFile( const char* dirPath ){
    char dirpath[256] = {0};
    // ls
    if( dirPath == NULL )
        getcwd(dirpath, sizeof(dirpath)-1);
    /*
        char *getcwd(char *buf, size_t size);
        copies an absolute pathname of the current work‐
        ing directory to the array pointed to by buf, which is of length size
    */   
    else
        strcpy(dirpath, dirPath);
    DIR* dirp = opendir(dirpath);
    /*
        struct __dirstream   
       {   
            void *__fd;    
            char *__data;    
            int __entry_data;    
            char *__ptr;    
            int __entry_ptr;    
            size_t __allocation;    
            size_t __size;    
            __libc_lock_define (, __lock)    
       };   
  
       typedef struct __dirstream DIR;
    */
    if(dirp == NULL){
        perror("opendir fail");
        return -1;
    }
    
    //读取目录项
    struct dirent* dirent = NULL;
    /*
        struct dirent {
               ino_t          d_ino;       / Inode number /
               off_t          d_off;       / Not an offset; see below /
               unsigned short d_reclen;    / Length of this record /
               unsigned char  d_type;      / Type of file; not supported
                                              by all filesystem types /
               char           d_name[256]; / Null-terminated filename /
           };
    */
    while(1){
        errno = Success;       //即errno = 0,表示没有错误因为系统的errno是从1开始
        // readdir每次只返回一个目录项
        dirent = readdir(dirp);
        if(dirent == NULL && errno == Success){
            printf("read dirent finish\n");
            break;
        }
        else if( dirent == NULL && errno != Success ){
            perror("read dir err");
            continue;
        }
        
        //解析目录项
        puts(dirent->d_name);
    }
    closedir(drip);
    return 0;
}

int putFileStatus(const char* filePath){
    struct stat stu;
    int ret = stat(filePath, &stu);
    if( ret == -1 ){
        perror("stat fail");
        return -1;
    }
    //1.解析文件类型 - d b p s l c
    switch( stu.st_mode & S_IFMT ){
              case S_IFBLK:  printf("b");break;
			  case S_IFCHR:  printf("c");break;
			  case S_IFDIR:  printf("d");break;
			  case S_IFIFO:  printf("p");break;
			  case S_IFLNK:  printf("l");break;
			  case S_IFREG:  printf("-");break;
			  case S_IFSOCK: printf("s");break;
			  default:		 printf("unknown?\n");	break;
	}
    //2.解析文件权限
    S_ISRU(stu.st_mode)?printf("r"):printf("-");
	S_ISWU(stu.st_mode)?printf("w"):printf("-");
	S_ISXU(stu.st_mode)?printf("x"):printf("-");
	
	S_ISRG(stu.st_mode)?printf("r"):printf("-");
	S_ISWG(stu.st_mode)?printf("w"):printf("-");
	S_ISXG(stu.st_mode)?printf("x"):printf("-");
	
	S_ISRO(stu.st_mode)?printf("r"):printf("-");
	S_ISWO(stu.st_mode)?printf("w"):printf("-");
	S_ISXO(stu.st_mode)?printf("x"):printf("-");
    //3.硬链接数
    printf(" %ld", stu.st_nlink);
    //4.属主用户名
    struct passwd* user = NULL;
    user = getpwuid(stu.st_uid);//(类似游戏个人名片的uid,根据uid能查到账户信息)
    printf("%s", user->pw_name );
    
    // 5.组用户名
	struct group * grp = NULL;
	grp = getgrgid(stu.st_gid);
	printf(" %s", grp->gr_name);

	// 6.文件大小	
	printf(" %ld", stu.st_size);
    
    //7.修改时间
    struct tm time;
	localtime_r(&stu.st_mtim.tv_sec, &time);
	printf(" %d月 %d %d:%d ", time.tm_mon+1, time.tm_mday, time.tm_hour, time.tm_min);
    // 8.文件名
	puts(filePath);

int lsDirFileStatus(const char *dirPath){
	char dirpath[256] = {0};
	// ls -l
	if ( dirPath == NULL )        
		getcwd(dirpath, sizeof(dirpath)-1);
	else
		strcpy(dirpath, dirPath);
    
    DIR *dirp = opendir(dirpath);
	if ( dirp == NULL )
	{
		perror("opendir fail");
		return -1;
	}

	// 读取目录项
	struct dirent *dirent = NULL;
	while (1)
	{
		errno = Success;
		// readdir 每次只返回一个目录项
		dirent = readdir(dirp);
		if ( dirent == NULL && errno == Success )
		{
			printf("read dirent finsh\n");
			break;
		}
		else if ( dirent == NULL && errno != Success )
		{
			perror("read dir err");
			continue;
		}

        
		// 获取文件属性
		struct stat stu;
        char tempPath[256] = {0};
        strcpy(tempPath, dirpath);
        //dirPath /home/china d_name 1.txt  /home/china/1.txt
        strcat(tempPath, "/");
        strcat(tempPath, dirent->d_name); 
        // 读这个文件的属性
        
        putFileStatus( tempPath );        
	}

	closedir(dirp);

	return 0;
}
    
int main(int argc, char *argv[]){
    LsState state = Default;
    struct stat stu;
    // ls
    if ( argc == 1 )
    	state = listDefault;
    // ls -l  ls ./    
    else if ( argc == 2 )
    	state = ( strcmp(argv[1], "-l") == 0 )?listStatus:listDir;
    else if ( argc == 3 )
    {
        stat(argv[2], &stu);
        state = ( S_ISDIR(stu.st_mode) ) ? listStatusDir : listStatusFile;
    }    
    
    switch( state )
    {
        case listDefault : lsDirFile(NULL); break;    
        case listStatus  : lsDirFileStatus(NULL); break;
        case listDir     : lsDirFile(argv[1]); break;
        case listStatusFile : putFileStatus(argv[2]); break;   
        case listStatusDir  : lsDirFileStatus(argv[2]); break;    
        default : printf("cmd Err\n");     
    }
        
    return 0;
}
参考链接:https://blog.csdn.net/Edward_LF/article/details/124398321
参考链接:https://blog.csdn.net/djw931017/article/details/86746449

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值