ls命令的实现

本文详细介绍了一个自制ls命令的实现过程,包括如何利用C语言及系统调用来列出指定目录下的文件和子目录,并显示每个文件的详细信息如权限、所有者等。

转自:http://blog.chinaunix.net/space.php?uid=25909722&do=blog&id=2856481

http://blog.chinaunix.net/uid-25909722-id-2876133.html


ls - list directory contents (man ls)

ls的功能是列出目录中的内容。那目录中都有写什么内容呢?我们知道磁盘上的文件系统由文件和目录组成,文件的内容可以是任意的数据,而目录的内容只能是文件名的列表和子目录名的列表。
也就是说:目录中的内容 是该目录下的文件和子目录它们的 名字的列表

我们先来看一看关于 目录的结构体:(/usr/include/bits/dirent.h)
  1. struct dirent {
  2.        ino_t          d_ino        /* inode number */
  3.        off_t          d_off        /* offset to the next dirent */
  4.        unsigned short d_reclen     /* length of this record */
  5.        unsigned char  d_type       /* type of filenot supportedby all file system types */
  6.        char           d_name[256]  /* filename */
  7. };
d_ino是目录中的文件的i-node节点号,通过d_ino可以找到该文件的i-node节点,而i-node节点中保存了文件的属性等信息。通过i-node节点就可以访问到文件的内容。

关于目录访问的一些函数:(/usr/include/dirent.h)
  1. #include <sys/types.h>
  2. #include <dirent.h>

  3. DIR *opendir(const char *name);
  4. DIR *fdopendir(int fd);
  5. struct dirent *readdir(DIR *dirp);
  6. int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
  7. int closedir(DIR *dirp);
  8. void rewinddir(DIR *dirp);
关于目录中文件的属性等信息使用 struct stat 结构体来描述的,其结构的定义如下: (/usr/include/bits/stat.h)
  1. struct stat
  2. {
  3.     __dev_t st_dev;                 /* Device. */

  4.     unsigned short int __pad1;      /用于填充对齐 */

  5.     __ino_t   st_ino;               /* 32bit file serial number. */
  6.     __mode_t  st_mode;              /* File mode. */
  7.     __nlink_t st_nlink;             /* Link count. */

  8.     __uid_t   st_uid;               /* User ID of the file's owner. */
  9.     __gid_t   st_gid;               /* Group ID of the file's group.*/
  10.     __dev_t   st_rdev;              /* Device number, if device. */

  11.     unsigned short int __pad2;      /用于填充对齐 */

  12.     __off_t     st_size;            /* Size of file, in bytes. */
  13.     __blksize_t st_blksize;         /* Optimal block size for I/O. */
  14.     __blkcnt_t  st_blocks;          /* Number 512-byte blocks allocated. */

  15.     struct timespec st_atim;        /* Time of last access. */
  16.     struct timespec st_mtim;        /* Time of last modification. */
  17.     struct timespec st_ctim;        /* Time of last status change. */

  18. # define st_atime st_atim.tv_sec    /* Backward compatibility. */
  19. # define st_mtime st_mtim.tv_sec
  20. # define st_ctime st_ctim.tv_sec

  21.     __ino64_t st_ino;               /* File serial number. */
  22. };
该结构体提供了关于文件(或者设备)的如下重要信息:
st_mode      文件类型和许可权限
st_nlink      文件链接数
st_uid         文件属主id
st_gid         文件属主所在组的id
st_size        文件的字节数
st_blocks    文件所占的块数

ACM”三个时间:
st_atime     文件最后访问时间 ( access time)
st_mtime    文件最后修改时间 ( modification time)
st_ctime     文件属性/状态最后改变的时间 ( change status time)

另外在/usr/include/sys/stat.h中提供了下列关于文件信息的宏定义:
  1. typedef __dev_t     dev_t;
  2. typedef __gid_t     gid_t;
  3. typedef __ino_t     ino_t;
  4. typedef __mode_t    mode_t;
  5. typedef __nlink_t   nlink_t;
  6. typedef __off_t     off_t;
  7. typedef __uid_t     uid_t;
  8. typedef __blkcnt_t  blkcnt_t;
  9. typedef __blksize_t blksize_t;

  10. /* Test macros for file types. */

  11. #define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))

  12. #define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)   /directory 目录文件类型
  13. #define S_ISCHR(mode) __S_ISTYPE((mode), __S_IFCHR)   /char 字文件类型
  14. #define S_ISBLK(mode) __S_ISTYPE((mode), __S_IFBLK)   /block 块文件类型
  15. #define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)   /regular 普通文件类型
  16. #define S_ISFIFO(mode) __S_ISTYPE((mode), __S_IFIFO)  /FIFO 管道文件类型
  17. #define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)   /link 链接文件类型
  18. #define S_ISSOCK(mode) __S_ISTYPE((mode), __S_IFSOCK/sock 网络套接字文件类型

  19. /* Protection bits. */

  20. #define S_ISUID __S_ISUID     /* Set user ID on execution. */
  21. #define S_ISGID __S_ISGID     /* Set group ID on execution. */

  22. #define S_IRUSR __S_IREAD     /* Read by owner. */
  23. #define S_IWUSR __S_IWRITE    /* Write by owner. */
  24. #define S_IXUSR __S_IEXEC     /* Execute by owner. */
  25. /* Read, write, and execute by owner. */
  26. #define S_IRWXU (__S_IREAD|__S_IWRITE|__S_IEXEC)

  27. #define S_IRGRP (S_IRUSR >> 3) /* Read by group. */
  28. #define S_IWGRP (S_IWUSR >> 3) /* Write by group. */
  29. #define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */
  30. /* Read, write, and execute by group. */
  31. #define S_IRWXG (S_IRWXU >> 3)

  32. #define S_IROTH (S_IRGRP >> 3) /* Read by others. */
  33. #define S_IWOTH (S_IWGRP >> 3) /* Write by others. */
  34. #define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */
  35. /* Read, write, and execute by others. */
  36. #define S_IRWXO (S_IRWXG >> 3)

  37. # define S_BLKSIZE 512         /* Block size for `st_blocks'. */


在上一篇博文http://blog.chinaunix.net/space.php?uid=25909722&do=blog&id=2856481中,我们学习了实现ls命令要涉及到的相关的结构体和函数。有了前面的基础,本文我们实实在在的实现ls命令:


  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <dirent.h>
  4. #include <sys/stat.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include <pwd.h>
  8. #include <grp.h>

  9. void do_ls(char[]);
  10. void do_stat(char*);
  11. void show_file_info(char*, struct stat*);
  12. void mode_str(int, char[]);
  13. char *uid_str(uid_t);
  14. char *gid_str(gid_t);

  15. int main(int argc, char *argv[])
  16. {
  17.         if(argc == 1)
  18.                 do_ls(".");
  19.         else
  20.                 while(--argc){
  21.                         printf("%s:\n", *++argv);
  22.                         do_ls(*argv);
  23.                 } 

  24.         return 0;
  25. }

  26. void do_ls(char dirname[])
  27. {
  28.         DIR *dir_ptr;           /* the directory */
  29.         struct dirent *direntp; /* each entry */
  30.         char full_path[256];

  31.         if((dir_ptr = opendir(dirname)) == NULL){
  32.                 fprintf(stderr, "ls2: cannot open %s\n", dirname);
  33.         }else{
  34.                 while((direntp = readdir(dir_ptr)) != NULL){
  35.                         strcpy(full_path, dirname);
  36.                         int dir_len = strlen(dirname);
  37.                         if(dirname[dir_len - 1] != '/'){  /* 处理目录字符串最后没有‘/’的情况 */
  38.                                 full_path[dir_len] = '/';
  39.                                 strcpy(full_path + dir_len + 1, direntp->d_name);
  40.                         }else
  41.                                 strcpy(full_path + dir_len, direntp->d_name);

  42.                         do_stat(full_path);
  43.                 } 
  44.                 closedir(dir_ptr);
  45.         } 
  46. } 
  47. void do_stat(char *filename/* 获得目录中文件的相关信息 */
  48. {
  49.         struct stat info;
  50.         
  51.         /* 如果filename最后没有‘/’的话,stat调用失败 */
  52.         if(stat(filename, &info) == -1){ /* cannot stat */
  53.                 perror("stat"); /* say why */
  54.                 printf("filename:%s\n", filename);
  55.         }else{
  56.                 char *pname = strrchr(filename, '/');
  57.                 show_file_info(pname + 1, &info);
  58.         }
  59. }

  60. void show_file_info(char *filename, struct stat *info_p/* 打印文件的相关信息 */
  61. {
  62.         char modestr[11];

  63.         mode_str(info_p->st_mode, modestr);

  64.         printf("%s", modestr);
  65.         printf("%3d ", (int)info_p->st_nlink);
  66.         printf("%-8s", uid_str(info_p->st_uid));
  67.         printf("%-8s", gid_str(info_p->st_gid));
  68.         printf("%4ld ", (long)info_p->st_size);
  69.         printf("%.12s ", 4 + ctime(&info_p->st_mtime));
  70.         printf("%s\n", filename);
  71. }

  72. void mode_str(int mode, char str[]/* 将文件的相关信息转化成 “crw-rw---"的形式 */
  73. {
  74.         strcpy(str, "----------"); /* default = no perms */
  75.         if(S_ISDIR(mode)) str[0] = 'd'; /* directory */
  76.         if(S_ISCHR(mode)) str[0] = 'c'; /* char device */
  77.         if(S_ISBLK(mode)) str[0] = 'b'; /* block device */
  78.         if(S_ISLNK(mode)) str[0] = 'l';

  79.         if(mode & S_IRUSR) str[1] = 'r'; /* 3 bits for user */
  80.         if(mode & S_IWUSR) str[2] = 'w';
  81.         if(mode & S_IXUSR) str[3] = 'x';

  82.         if(mode & S_IRGRP) str[4] = 'r'; /* 3 bits for group */
  83.         if(mode & S_IWGRP) str[5] = 'w';
  84.         if(mode & S_IXGRP) str[6] = 'x';

  85.         if(mode & S_IROTH) str[7] = 'r'; /* 3 bits for other */
  86.         if(mode & S_IWOTH) str[8] = 'w';
  87.         if(mode & S_IXOTH) str[9] = 'x';
  88. }

  89. char *uid_str(uid_t uid/* 将uid转化成username */
  90. {
  91.         static char numstr[10];
  92.         struct passwd *pw_ptr;

  93.         if((pw_ptr = getpwuid(uid)) == NULL){
  94.                 sprintf(numstr, "%d", uid);
  95.                 return numstr;
  96.         }else
  97.                 return pw_ptr->pw_name;
  98. }

  99. char *gid_str(gid_t gid/* 将gid转化成groupname */
  100. {
  101.         static char numstr[10];
  102.         struct group *grp_ptr;

  103.         if((grp_ptr = getgrgid(gid)) == NULL){
  104.                 sprintf(numstr, "% d", gid);
  105.                 return numstr;
  106.         }else
  107.                 return grp_ptr->gr_name;
  108. }
编译和运行结果:
digdeep@ubuntu:~/uulp$ gcc -Wall -o ls1 ls1.c
digdeep@ubuntu:~/uulp$ ./ls1  /etc/network/
/etc/network/:
drwxr-x---  2 root    root     4096 Apr 26 07:03 if-down.d
drwxr-x---  2 root    root     4096 Jul 14 10:47 if-up.d
drwxr-x---  2 root    root     4096 Apr 26 07:05 if-pre-up.d
drwxr-x---  6 root    root     4096 Jun 14 05:34 .
drwxr-x---  2 root    root     4096 Apr 26 07:05 if-post-down.d
-rwrr-----   1 root    root      196 Jun 14 05:33 interfaces
drwxr-x---147 root    root    12288 Sep 19 20:33 ..


评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值