linux系统编程之文件与io(三)
上次我们利用文件的read和write来实现了简易的cp命令,其中将源文件拷贝到目标文件时,我们给目标文件的权限是写死的,而非根据源文件的权限生成的,如下:

今天就来解决这个问题,来学习获取文件权限相关的函数,言归正传,正入正题。


struct stat {
dev_t st_dev; /* ID of device containing file文件保存在磁盘上的设备号,包含主设备号和次设备号,它是16位的整数,高八位为主设备号,低八位为次设备号 */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection文件的权限信息 */
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) 如果文件是设备文件,所对应的设备ID*/
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O 系统当中每个块的大小 */
blkcnt_t st_blocks; /* number of 512B blocks allocated 块数目 */
time_t st_atime; /* time of last access 文件总共访问的次数*/
time_t st_mtime; /* time of last modification 最后的修改时间*/
time_t st_ctime; /* time of last status change 最后状态改变的时间,比如说改变了文件权限,并未改变文件的内容*/
};
下面就以程序例子来对其进行说明:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() #define MAJOR(a) (int)((unsigned short)a >> 8)//获取高八位数据,也就是主设备号
#define MINOR(a) (int)((unsigned short)a & 0xFF)//获取低八位数据,也就是次设备号 int main(int argc, char *argv[])
{
if (argc != )
{
fprintf(stderr, "Usage %s file\n", argv[]);
exit(EXIT_FAILURE);
}
struct stat sbuf;
printf("Filename:%s\n", argv[]);//打印文件名
if (stat(argv[], &sbuf) == -)
ERR_EXIT("stat error"); printf("File number:major %d,minor %d inode %d\n", MAJOR(sbuf.st_dev)/**文件主设备号**/, MINOR(sbuf.st_dev)/**文件次设备号**/, sbuf.st_ino/**inode数**/);
return 0;
}
编译:


这时再编译运行:

实际上上面的数据都可由系统命令来进行查看,如下:


总结:主设备号用来区分不同的设备,它决定了用什么样的驱动程序来访问设备;次设备号用来区分同设备中的不同分区。
下面我们继续来查看文件信息,先来打印下文件类型,关于这个数据,它是存放到stat结构体中的mode_t字段中:
先来查看下man帮助:

下面具体代码如下:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() #define MAJOR(a) (int)((unsigned short)a >> 8)
#define MINOR(a) (int)((unsigned short)a & 0xFF) int filetype(struct stat *buf);//获取文件类型函数定义 int main(int argc, char *argv[])
{
if (argc != )
{
fprintf(stderr, "Usage %s file\n", argv[]);
exit(EXIT_FAILURE);
}
struct stat sbuf;
printf("Filename:%s\n", argv[]);
if (lstat(argv[], &sbuf) == -)
ERR_EXIT("stat error"); printf("File number:major %d,minor %d inode %d\n", MAJOR(sbuf.st_dev), MINOR(sbuf.st_dev), (int)sbuf.st_ino); if (filetype(&sbuf))
{
//如果文件类型是设备文件,还可以获取设备更详细的信息:主设备号、次设备号
printf("Device number:major %d,minor %d\n", MAJOR(sbuf.st_rdev), MINOR(sbuf.st_rdev));
} return ;
} int filetype(struct stat *buf)//如果是设备文件,则返回1,否则返回0
{
int flag = 0;
printf("Filetype:");
mode_t mode;
mode = buf->st_mode;
switch (mode & S_IFMT)
{
case S_IFSOCK:
printf("socket\n");
break;
case S_IFLNK:
printf("symbolic link\n");
break;
case S_IFREG:
printf("regular file\n");
break;
case S_IFBLK:
printf("block device\n");
flag = 1;
break;
case S_IFDIR:
printf("directory\n");
break;
case S_IFCHR:
printf("character device\n");
flag = 1;
break;
case S_IFIFO:
printf("FIFO\n");
break;
default:
printf("unknown file type\n");
break;
} return flag;
}
编译运行:

下面来打印文件的权限信息:

下面看具体代码:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() #define MAJOR(a) (int)((unsigned short)a >> 8)
#define MINOR(a) (int)((unsigned short)a & 0xFF) int filetype(struct stat *buf);
void fileperm(struct stat *buf, char *perm);//查看文件权限,以rwx进行格式化 int main(int argc, char *argv[])
{
if (argc != )
{
fprintf(stderr, "Usage %s file\n", argv[]);
exit(EXIT_FAILURE);
} struct stat sbuf;
printf("Filename:%s\n", argv[]);
if (stat(argv[], &sbuf) == -)
ERR_EXIT("stat error"); printf("File number:major %d,minor %d inode %d\n", MAJOR(sbuf.st_dev), MINOR(sbuf.st_dev), (int)sbuf.st_ino);
if (filetype(&sbuf))
{
printf("Device number:major %d,minor %d\n", MAJOR(sbuf.st_rdev), MINOR(sbuf.st_rdev));
}
//打印文件的权限信息
char perm[11] = {0};
fileperm(&sbuf, perm);
printf("File permission bits=%o %s\n", sbuf.st_mode & 07777, perm); return ;
} int filetype(struct stat *buf)
{
int flag = ;
printf("Filetype:");
mode_t mode;
mode = buf->st_mode;
switch (mode & S_IFMT)
{
case S_IFSOCK:
printf("socket\n");
break;
case S_IFLNK:
printf("symbolic link\n");
break;
case S_IFREG:
printf("regular file\n");
break;
case S_IFBLK:
printf("block device\n");
flag = ;
break;
case S_IFDIR:
printf("directory\n");
break;
case S_IFCHR:
printf("character device\n");
flag = ;
break;
case S_IFIFO:
printf("FIFO\n");
break;
default:
printf("unknown file type\n");
break;
} return flag;
} void fileperm(struct stat *buf, char *perm)
{
strcpy(perm, "----------");
perm[0] = '?';
mode_t mode;
mode = buf->st_mode;
switch (mode & S_IFMT)//确定第一位文件类型
{
case S_IFSOCK:
perm[0] = 's';
break;
case S_IFLNK:
perm[0] = 'l';
break;
case S_IFREG:
perm[0] = '-';
break;
case S_IFBLK:
perm[0] = 'b';
break;
case S_IFDIR:
perm[0] = 'd';
break;
case S_IFCHR:
perm[0] = 'c';
break;
case S_IFIFO:
perm[0] = 'p';
break;
} if (mode & S_IRUSR)//与用户读权限进行与操作之后,如果为真,则代表有这个权限
perm[1] = 'r';
if (mode & S_IWUSR)
perm[2] = 'w';
if (mode & S_IXUSR)
perm[3] = 'x';
if (mode & S_IRGRP)
perm[4] = 'r';
if (mode & S_IWGRP)
perm[5] = 'w';
if (mode & S_IXGRP)
perm[6] = 'x';
if (mode & S_IROTH)
perm[7] = 'r';
if (mode & S_IWOTH)
perm[8] = 'w';
if (mode & S_IXOTH)
perm[9] = 'x';
perm[10] = '\0';
}
编译运行:

利用上面所学的东西,我们就可以实现自己的ls -l的功能了,在实现这个功能之时,还有几个知识点需介绍一下:
先看一下ls -l会显示什么信息:

①文件权限,这个上面已经实现过了,所以不成问题
②连接数,对应的是stat->nlink_t,所以不成问题
③用户名,我们知道stat->uid_t,可以根据用户ID获得用户名,通过如下函数:


④组名,我们知道stat->gid_t,可以根据组ID获得组名,通过如下函数:


⑤文件大小,可以通过stat->st_size来获得
⑥文件修改时间,可以通过stat->st_mtime来获得
⑦文件名,这个肯定可以获取。






linux系统编程之文件与io(三)的更多相关文章
- linux系统编程之文件与io(一)
经过了漫长的学习,C语言相关的的基础知识算是告一段落了,这也是尝试用写博客的形式来学习c语言,回过头来看,虽说可能写的内容有些比较简单,但是个人感觉是有史起来学习最踏实的一次,因为里面的每个实验都是自 ...
- linux系统编程之文件与io(五)
上一节中已经学习了文件描述符的复制,复制方法有三种,其中最后一种fcntl还并未使用到,关于这个函数,不光只有复制文件描述符的功能,还有其它一些用法,本节就对其进行一一剖析: fcntl常用操作: 这 ...
- linux系统编程之文件与io(四)
今天继续学习文件与io,主要是学习文件共享及文件.复制文件描述符,有点抽象,主要是概念上的理解,但是很重要,下面一一来分解: 文件共享: 回顾一下,在linux系统调用中,是通过文件描述符来访问文件的 ...
- linux系统编程之文件与io(二)
今天继续学习文件与io,话不多说,开始进入正题: 文件的read和write系统调用: 说明:函数中出现在size_t和ssize_t是针对系统定制的数据类型: 下面以一个实现文件简单拷贝的示 ...
- linux系统编程之文件与IO(三):利用lseek()创建空洞文件
一.lseek()系统调用 功能说明: 通过指定相对于开始位置.当前位置或末尾位置的字节数来重定位 curp,这取决于 lseek() 函数中指定的位置 函数原型: #include <sys/ ...
- linux系统编程之文件与IO(一):文件描述符、open,close
什么是IO? 输入/输出是主存和外部设备之间拷贝数据的过程 设备->内存(输入操作) 内存->设备(输出操作) 高级I/O ANSI C提供的标准I/O库称为高级I/O,通常也称为带缓冲的 ...
- linux系统编程之文件与IO(七):时间函数小结
从系统时钟获取时间方式 time函数介绍: 1.函数名称: localtime 2.函数名称: asctime 3.函数名称: ctime 4.函数名称: difftime 5.函数名称: gmtim ...
- linux系统编程之文件与IO(四):目录访问相关系统调用
1. 目录操作相关的系统调用 1.1 mkdir和rmdir系统调用 1.1.1 实例 1.2 chdir, getcwd系统调用 1.2.1 实例 1.3 o ...
- linux系统编程之文件与IO(八):文件描述符相关操作-dup,dup2,fcntl
本节目标: 1,文件共享 打开文件内核数据结构 一个进程两次打开同一个文件 两个进程打开同一个文件 2,复制文件描述符(dup.dup2.fcntl) 一,文件共享 1,一个进程打开两个文件内核数据结 ...
随机推荐
- ou can mix require and export. You can't mix import and module.exports.
ou can mix require and export. You can't mix import and module.exports.
- MySQL之表关系
MySQL表关系 一对多关系 一对多与多对一是一个概念,指的是一个实体的某个数据与另外一个实体的多个数据有关联关系. 举例,学校中一个学.院可以有很多的学生,而一个学生只属于某一个学院(通常情况下), ...
- php_mvc实现步骤七
shop34-5-登录表单 登录功能分析 功能:登录表单 C控制器-动作 back后台admin控制器loginAction动作完成该功能. Application/back/controller/A ...
- [转帖]DCEP:中国自己的数字货币
DCEP:中国自己的数字货币 https://cloud.tencent.com/developer/news/435883 前面我们讨论了Libra的革命性和局限性,接下来我想跟你聊一件重要的事,那 ...
- 用Python递归做个多层次的文件执行
想用 递归实现多层次的 '.py'执行但是发现好像不能 import os def func(path): if os.path.isdir(path): for name in os.listdir ...
- Magic Line(思维+计算几何问题)(2019牛客暑期多校训练营(第三场))
示例: 输入: 140 1-1 01 00 -1 输出:-1 999000000 1 -999000001 题意:给定平面上一系列的点,求一条以(x1,y1),(x2,y2)两点表示的直线将平面分为包 ...
- [洛谷P5377][THUPC2019]鸽鸽的分割
题目大意:有一个圆,圆上有$n$个点,将这几个点两两连接,问最多分成几部分 题解:发现这相当于一个平面图,由欧拉公式得($F$为平面分割块数,$E$为平面图边数,$V$为平面图点数):$$F=E-V+ ...
- js的for循环中出现异步函数,回调引用的循环值始终是最后的值
一.问题 今天工作中解决bug发现是由“for循环的异步函数,回调引用的循环值始终是最后的值”的现象导致的,如: for (var i = 0; i < files.length; i++) { ...
- Python接口自动化基础---post请求
常见的post传递参数的类型有以下两种: 第一种:application/x-www-form-urlencoded,浏览器原生的form表单,格式如下:input1=xxx&input2=o ...
- 易百教程人工智能python修正-人工智能数据准备-预处理数据
预处理数据 在我们的日常生活中,需要处理大量数据,但这些数据是原始数据. 为了提供数据作为机器学习算法的输入,需要将其转换为有意义的数据. 这就是数据预处理进入图像的地方. 换言之,可以说在将数据提供 ...