当前位置: 首页 > news >正文

Linux文件属性解析与ls -l命令实现

Linux文件属性解析与ls -l命令实现

1. 项目概述

1.1 系统架构

本项目通过分析Linux系统中ls -l命令的实现原理,深入探讨文件属性信息的获取与解析方法。系统主要分为三个功能模块:

  1. 目录读取模块:负责遍历目录内容
  2. 属性获取模块:通过系统调用获取文件元数据
  3. 信息转换模块:将数字形式的属性转换为可读字符串

1.2 开发环境

  • 操作系统:Ubuntu 18.04 LTS
  • 编译器:gcc 7.5.0
  • 开发语言:C语言

2. 文件属性系统调用

2.1 stat()函数解析

获取文件属性的核心系统调用是stat(),其函数原型如下:

#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(const char *pathname, struct stat *statbuf);

参数说明:

  • pathname:目标文件路径
  • statbuf:用于存储文件属性的结构体指针

返回值:

  • 成功返回0
  • 失败返回-1并设置errno

2.2 stat结构体详解

struct stat包含了文件的完整属性信息:

struct stat { dev_t st_dev; /* 包含文件的设备ID */ ino_t st_ino; /* inode编号 */ mode_t st_mode; /* 文件类型和权限 */ nlink_t st_nlink; /* 硬链接数 */ uid_t st_uid; /* 所有者用户ID */ gid_t st_gid; /* 组ID */ dev_t st_rdev; /* 设备ID(特殊文件) */ off_t st_size; /* 文件大小(字节) */ blksize_t st_blksize; /* 文件系统I/O块大小 */ blkcnt_t st_blocks; /* 分配的512B块数 */ struct timespec st_atim; /* 最后访问时间 */ struct timespec st_mtim; /* 最后修改时间 */ struct timespec st_ctim; /* 最后状态变更时间 */ };

3. 文件类型与权限解析

3.1 文件类型编码

st_mode字段的前4位表示文件类型,常用类型掩码定义如下:

#define S_IFMT 0170000 /* 文件类型掩码 */ #define S_IFSOCK 0140000 /* 套接字 */ #define S_IFLNK 0120000 /* 符号链接 */ #define S_IFREG 0100000 /* 普通文件 */ #define S_IFBLK 0060000 /* 块设备 */ #define S_IFDIR 0040000 /* 目录 */ #define S_IFCHR 0020000 /* 字符设备 */ #define S_IFIFO 0010000 /* 管道/FIFO */

3.2 权限位解析

st_mode的低9位表示文件权限,分为三组:

  1. 所有者权限(位8-6)
  2. 组权限(位5-3)
  3. 其他用户权限(位2-0)

每组包含读(r)、写(w)、执行(x)三种权限,对应的掩码:

#define S_IRWXU 00700 /* 所有者权限掩码 */ #define S_IRUSR 00400 /* 所有者读权限 */ #define S_IWUSR 00200 /* 所有者写权限 */ #define S_IXUSR 00100 /* 所有者执行权限 */ #define S_IRWXG 00070 /* 组权限掩码 */ #define S_IRGRP 00040 /* 组读权限 */ #define S_IWGRP 00020 /* 组写权限 */ #define S_IXGRP 00010 /* 组执行权限 */ #define S_IRWXO 00007 /* 其他用户权限掩码 */ #define S_IROTH 00004 /* 其他用户读权限 */ #define S_IWOTH 00002 /* 其他用户写权限 */ #define S_IXOTH 00001 /* 其他用户执行权限 */

3.3 权限转换实现

st_mode转换为ls -l风格的字符串表示:

void mode_to_letters(int mode, char str[]) { strcpy(str, "----------"); /* 文件类型 */ if (S_ISDIR(mode)) str[0] = 'd'; if (S_ISCHR(mode)) str[0] = 'c'; if (S_ISBLK(mode)) str[0] = 'b'; if (S_ISLNK(mode)) str[0] = 'l'; /* 所有者权限 */ if (mode & S_IRUSR) str[1] = 'r'; if (mode & S_IWUSR) str[2] = 'w'; if (mode & S_IXUSR) str[3] = 'x'; /* 组权限 */ if (mode & S_IRGRP) str[4] = 'r'; if (mode & S_IWGRP) str[5] = 'w'; if (mode & S_IXGRP) str[6] = 'x'; /* 其他用户权限 */ if (mode & S_IROTH) str[7] = 'r'; if (mode & S_IWOTH) str[8] = 'w'; if (mode & S_IXOTH) str[9] = 'x'; }

4. 用户与组信息获取

4.1 用户信息查询

通过getpwuid()获取用户信息:

#include <pwd.h> struct passwd *getpwuid(uid_t uid); struct passwd { char *pw_name; /* 用户名 */ char *pw_passwd; /* 用户密码 */ uid_t pw_uid; /* 用户ID */ gid_t pw_gid; /* 组ID */ char *pw_gecos; /* 用户信息 */ char *pw_dir; /* 主目录 */ char *pw_shell; /* shell程序 */ };

4.2 组信息查询

通过getgrgid()获取组信息:

#include <grp.h> struct group *getgrgid(gid_t gid); struct group { char *gr_name; /* 组名 */ char *gr_passwd; /* 组密码 */ gid_t gr_gid; /* 组ID */ char **gr_mem; /* 组成员列表 */ };

4.3 ID到名称转换实现

将用户ID和组ID转换为名称字符串:

char *uid_to_name(uid_t uid) { struct passwd *pw_ptr; static char numstr[10]; if ((pw_ptr = getpwuid(uid)) == NULL) { sprintf(numstr, "%d", uid); return numstr; } else { return pw_ptr->pw_name; } } char *gid_to_name(gid_t gid) { struct group *grp_ptr; static char numstr[10]; if ((grp_ptr = getgrgid(gid)) == NULL) { sprintf(numstr, "%d", gid); return numstr; } else { return grp_ptr->gr_name; } }

5. 完整实现代码

5.1 主程序框架

#include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <sys/stat.h> #include <pwd.h> #include <grp.h> #include <time.h> #include <string.h> void do_ls(char dirname[]); void do_stat(char *dirname, char *filename); void show_file_info(char *filename, struct stat *info_p); void mode_to_letters(int mode, char str[]); char *uid_to_name(uid_t uid); char *gid_to_name(gid_t gid); int main(int argc, char *argv[]) { if (argc == 1) { do_ls("."); } else { while (--argc) { printf("%s:\n", *++argv); do_ls(*argv); } } return 0; }

5.2 目录遍历实现

void do_ls(char dirname[]) { DIR *dir_ptr = NULL; struct dirent *direntp = NULL; if ((dir_ptr = opendir(dirname)) == NULL) { fprintf(stderr, "ls2: cannot open %s\n", dirname); } else { while ((direntp = readdir(dir_ptr)) != NULL) { do_stat(dirname, direntp->d_name); } closedir(dir_ptr); } }

5.3 文件属性处理

void do_stat(char *dirname, char *filename) { struct stat info; char pathname[256]; sprintf(pathname, "%s/%s", dirname, filename); if (stat(pathname, &info) == -1) { perror(filename); } else { show_file_info(filename, &info); } } void show_file_info(char *filename, struct stat *info_p) { char modestr[11]; mode_to_letters(info_p->st_mode, modestr); printf("%-12s", modestr); printf("%-8d", (int)info_p->st_nlink); printf("%-8s", uid_to_name(info_p->st_uid)); printf("%-8s", gid_to_name(info_p->st_gid)); printf("%-16ld", (long)info_p->st_size); printf("%-16.12s", 4 + ctime(&info_p->st_mtime)); printf("%s\n", filename); }

6. 编译与测试

6.1 编译命令

gcc ls2.c -o ls2

6.2 测试输出示例

$ ./ls2 / drwxrwxr-x 2 root root 4096 Apr 18 15:05 cdrom/ drwxr-xr-x 18 root root 4180 Nov 19 08:58 dev/ drwxr-xr-x 2 root root 12288 Nov 19 08:59 sbin/ drwxr-xr-x 25 root root 4096 Nov 9 10:21 ./ drwxrwxrwx 13 root root 4096 Nov 19 13:56 tmp/ dr-xr-xr-x 13 root root 0 Nov 19 08:57 sys/ dr-xr-xr-x 242 root root 0 Nov 19 08:57 proc/ drwxr-xr-x 22 root root 4096 Apr 18 23:24 lib/ -rw------- 1 root root 8453792 Oct 18 18:37 vmlinuz/
http://www.jsqmd.com/news/541764/

相关文章:

  • 3个核心功能:从效率瓶颈到资源整合的高效管理与智能处理指南
  • 从STM32到RK3588:嵌入式系统升级机制对比全解析
  • OpenClaw技能扩展指南:给nanobot添加QQ机器人通道
  • 做 GBase 8c 迁移适配时,我更先盯兼容模式、对象改造和 SQL 行为差异,而不是急着把数据先搬过去
  • OpenClaw文件处理:用GLM-4.7-Flash自动整理杂乱文档
  • Unity游戏开发:用Curvy Spline插件5分钟搞定物体曲线运动(附避坑指南)
  • hadoop+spark+Hive物流预测系统 物流数据分析可视化 Echarts可视化 Django框架 大数据
  • 把 cursor 的工具活动栏改成垂直形式
  • Mac M1芯片适配:OpenClaw运行百川2-13B-4bits量化版性能实测
  • Bypass Paywalls Clean技术全解析:突破付费内容限制的完整指南
  • 键值的两种写法对比(显式键值对与ES6简写),两种写法对 VS Code 代码转跳的细微差别
  • Win11Debloat:3步搞定Windows系统瘦身,让你的电脑重获新生!
  • 2026年知名的16号工字钢精选厂家 - 品牌宣传支持者
  • hadoop+spark+hive游戏推荐系统 游戏可视化数据分析 可视化
  • Lycopersicon Esculentum (Tomato) Lectin (LEL, TL), Fluorescein;特异性荧光探针
  • OpenClaw技能扩展实战:GLM-4.7-Flash驱动公众号自动发布
  • 如何高效使用开源工具:3个实战技巧快速上手WebPlotDigitizer图表数据提取
  • AutoDL环境下conda与pip混合安装PyTorch和DGL的避坑指南
  • 【2026最新】AI产品经理学习路径全解析:顺序错了,努力全白费!
  • 24小时稳定运行:OpenClaw+nanobot镜像的进程守护方案
  • 小型团队知识库:OpenClaw驱动Qwen3-32B-Chat实现文档智能检索
  • 基于PSO算法的海陆空多栖无人机路径规划探索
  • 从实验室到产品:脑机接口(BCI)开发中,EEG实时预处理流程设计与避坑指南
  • 营收3.48亿!五一视界交出上市后首份成绩单
  • 从零掌握ComfyUI-WanVideoWrapper:AI视频制作工具实战指南
  • OpenClaw+Qwen3.5-4B-Claude镜像:30分钟搭建逻辑分析机器人
  • uStepper S开源库深度解析:闭环步进控制与TMC2130驱动实战
  • 当我谈 Rax 按端拆分代码的时候我谈些什么:代码规范相关
  • 5个提升3D打印成功率的Cura实战技巧:面向创客的开源切片解决方案
  • Vue/React项目实战:集成docx-preview实现动态报表预览与下载功能