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

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

stat:功能:读取文件元数据
 
关于stat结构体的结构如下:
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来获得

文件名,这个肯定可以获取。

但是,对于符号链接文件,还需要做一个特珠的处理,如下:
那对于符号链接文件,怎么才能获取它所指向的链接文件呢?可以通过如下函数获取:
所以说,我们完全有能力实现跟ls -l系统命令一样的功能:
注意:
对于符号链接文件,我们查看其文件信息时,应该是lstat函数,而不是stat
对于目前我们实现查看的程序,是用的stat函数,那查看我们新创建的a链接文件的信息是什么呢?
 
这时,我们将state改为lstate,再次查看下:
编译运行:
查看一下lsate函数的说明:
 
好了,今天文件信息的查看学到这,下次下见。

linux系统编程之文件与io(三)的更多相关文章

  1. linux系统编程之文件与io(一)

    经过了漫长的学习,C语言相关的的基础知识算是告一段落了,这也是尝试用写博客的形式来学习c语言,回过头来看,虽说可能写的内容有些比较简单,但是个人感觉是有史起来学习最踏实的一次,因为里面的每个实验都是自 ...

  2. linux系统编程之文件与io(五)

    上一节中已经学习了文件描述符的复制,复制方法有三种,其中最后一种fcntl还并未使用到,关于这个函数,不光只有复制文件描述符的功能,还有其它一些用法,本节就对其进行一一剖析: fcntl常用操作: 这 ...

  3. linux系统编程之文件与io(四)

    今天继续学习文件与io,主要是学习文件共享及文件.复制文件描述符,有点抽象,主要是概念上的理解,但是很重要,下面一一来分解: 文件共享: 回顾一下,在linux系统调用中,是通过文件描述符来访问文件的 ...

  4. linux系统编程之文件与io(二)

    今天继续学习文件与io,话不多说,开始进入正题: 文件的read和write系统调用: 说明:函数中出现在size_t和ssize_t是针对系统定制的数据类型:     下面以一个实现文件简单拷贝的示 ...

  5. linux系统编程之文件与IO(三):利用lseek()创建空洞文件

    一.lseek()系统调用 功能说明: 通过指定相对于开始位置.当前位置或末尾位置的字节数来重定位 curp,这取决于 lseek() 函数中指定的位置 函数原型: #include <sys/ ...

  6. linux系统编程之文件与IO(一):文件描述符、open,close

    什么是IO? 输入/输出是主存和外部设备之间拷贝数据的过程 设备->内存(输入操作) 内存->设备(输出操作) 高级I/O ANSI C提供的标准I/O库称为高级I/O,通常也称为带缓冲的 ...

  7. linux系统编程之文件与IO(七):时间函数小结

    从系统时钟获取时间方式 time函数介绍: 1.函数名称: localtime 2.函数名称: asctime 3.函数名称: ctime 4.函数名称: difftime 5.函数名称: gmtim ...

  8. linux系统编程之文件与IO(四):目录访问相关系统调用

    1. 目录操作相关的系统调用     1.1 mkdir和rmdir系统调用     1.1.1 实例     1.2 chdir, getcwd系统调用     1.2.1 实例     1.3 o ...

  9. linux系统编程之文件与IO(八):文件描述符相关操作-dup,dup2,fcntl

    本节目标: 1,文件共享 打开文件内核数据结构 一个进程两次打开同一个文件 两个进程打开同一个文件 2,复制文件描述符(dup.dup2.fcntl) 一,文件共享 1,一个进程打开两个文件内核数据结 ...

随机推荐

  1. [LeetCode] 346. Moving Average from Data Stream 从数据流中移动平均值

    Given a stream of integers and a window size, calculate the moving average of all integers in the sl ...

  2. (CSDN迁移) 替换字符串中的空格

    题目描述 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. public ...

  3. git stash详解

        应用场景: 1 当正在dev分支上开发某个项目,这时项目中出现一个bug,需要紧急修复,但是正在开发的内容只是完成一半,还不想提交,这时可以用git stash命令将修改的内容保存至堆栈区,然 ...

  4. liunx 定时任务执行java程序配置流程

    java jar包使用build fat jar进行打包 ------------------liunx任务创建--------------------------- 1.查看现有任务计划: cron ...

  5. 题解 Luogu P3959 【宝藏】

    来一篇不那么慢的状压??? 话说这题根本没有紫题难度吧,数据还那么水 我是不会告诉你我被hack了 一看数据规模,n≤12,果断状压. 然后起点要枚举,就设dp状态: f[i][j]=以i为起点到j状 ...

  6. maven 打包错误 Cannot access central in offline mode

    出错的场景是这样的,先是在一台联网的linux机器上下载项目需要的包,linux机器上jdk为1.8 springboot1.5.然后将项目代码和.m2目录拷贝到一台windows机器上,window ...

  7. TiDB基本架构简单总结

    TiDB特点 高可用 水平拓展 事务 SQL支持 TiDB架构 ​ 和MySql不同,TiDB是一个分布式的数据库而不是单个进程,所以整个TiDB是由以下角色组成: TiKV, PD, TiDB, T ...

  8. Pycharm专业版配置远程服务器并自动同步代码

    一.使用场景 如果每次都在本机上面写代码,然后传到服务器上面,在服务器上面运行就太麻烦了.这样的方式十分繁琐,效率很低. 因此,希望可以像下面一样操作: 可以直接在本机上码代码 自动将代码同步到远程服 ...

  9. golang ---网卡信息

    package main import ( "fmt" "log" "net" "strings" ) type Net ...

  10. lucene中Field简析

    http://blog.csdn.net/zhaoxiao2008/article/details/14180019 先看一段lucene3代码 Document doc = new Document ...