ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

系统调用跟踪——ls功能实现(二)

2021-09-21 13:32:51  阅读:146  来源: 互联网

标签:文件 调用 获取 描述符 ls 目录 dir 跟踪


  在上篇文章中我们跟踪ls命令看到了其所使用的这么几个系统调用:stat、openat、fstat、getdents、close、write等,这里再简单介绍下这几个系统调用的功能:
  stat:为获取文件状态系统调用
  openat:将打开目录/data获取它的文件描述符,返回值3即为文件描述符;
  fstat:获取文件描述符为3的文件状态
  getdents64:获取文件描述符为3的目录项
  close:关闭文件描述符3
  write:在获取到文件目录信息后将参数2中的信息标准输出到控制台

系统调用

  在golang中已经给我们封装好了系统调用的相关函数,只要调用相关函数传入所对应的参数即可,go中的系统调用相关函数都放在syscall包下,如在调用sys_getcwd,获取当前工作目录的绝对路径:

//接收目录字节数组
dir:=make([]byte,100)
//调用sys_getcwd系统调用
n,e:= syscall.Getcwd(dir)
fmt.Println(string(dir))

实现ls

  在Linux中将所有的设备都当做文件来处理,用文件描述符来标识每个文件对象;标准输入、标准输出、标准错误的文件描述符分别为:0、1、2;
ls指令的具体实现流程为:获取目录状态、获取目录项、获取文件状态、获取用户信息;
  在调用getdents64系统调用获取目录项时需要传入该目录的文件描述符,所以需提前获取该目录的文件描述符;

具体的实现流程为:

状态对象stat

st_ino   与该文件关联的inode
st_dev   保存文件的设备
st_uid   文件属主的UID号
st_gid   文件属主的GID号
st_atime 文件上一次被访问的时间
st_ctime 文件的权限、属主、组或内容上一次被修改的时间
st_mtime 文件的内容上一次被修改的时间。(和st_ctime的不同之处显而易见)
st_nlink  该文件上硬连接的个数

dir目录对象

d_ino  int64  //索引节点
off_t  int64  //目录中文件偏移
reclen int16  //长度
d_type int8   //文件类型
d_name []byte //文件名

用户信息: 所属用户、所属组、
权限信息: 目录、文件、符号链接、读写执行

实现伪代码:

//获取目录文件描述符  只读|非阻塞|打开目录|执行系统调用时关闭文件描述符(自动关闭) 
fd,e := syscall.Openat(-0x64,path,syscall.O_RDONLY|syscall.O_NONBLOCK|sysc all.O_DIRECTORY|syscall.O_CLOEXEC, 0666)   
//获取目录状态
e := syscall.Lstat(path, dirStat)
var b = make([]byte, dirStat.Size)
//获得目录项
n, e := syscall.Getdents(fd, b)
buf := bytes.NewBuffer(b)
//目录信息
dir := &dirent{}
var c = 0
//遍历获取目录信息
for ; c < n; {
  _ = binary.Read(buf, binary.LittleEndian, &dir.d_ino)
  binary.Read(buf, binary.LittleEndian, &dir.off_t)
  binary.Read(buf, binary.LittleEndian, &dir.reclen)
  binary.Read(buf, binary.LittleEndian, &dir.d_type)
  //名称长度
  nLen := dir.reclen - 19
  name := buf.Next(int(nLen))
  dir.d_name = name[:len(name)-1]
  //获取目录中文件状态信息
  e := syscall.Stat(filePath, stat)
  if e != nil {
     fmt.Println(e.Error())
  }else {
    mode := stat.Mode
    m := parserAuth(mode)
    //使用uid获取用户名
    u, e := user.LookupId(strconv.Itoa(int(stat.Uid)))
    if e == nil {
      //使用gid获取组名
      g, _ := user.LookupGroupId(u.Gid) //mtim 最后一次修改文件时间,atim 最  后一次访问文件时间 ctim最后一次改变文件状态时间
      opt:=&option{m,u.Username,g.Name,int(stat.Size),time.Unix(stat.Mtim.Unix()).Format(TIME_LAYOUT), string(dir.d_name)}
      list = append(list, opt)
     }
   }
   c = c + int(dir.reclen)
 }

程序执行:

文章首发地址:https://mp.weixin.qq.com/s/Xn_xUHei10sgWkqEhMZo5g

标签:文件,调用,获取,描述符,ls,目录,dir,跟踪
来源: https://www.cnblogs.com/softlin/p/15315376.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有