下面的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