上次我们利用文件的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] 228. Summary Ranges 总结区间

    Given a sorted integer array without duplicates, return the summary of its ranges. Example 1: Input: ...

  2. golang高级用法总结

    sync.WaitGroup add()  done()  wait() 相当于计数器,done会减一,wait会等待所有线程都执行完才执行下面代码 sync.pool 用来封装连接池

  3. dubbo源码分析01:SPI机制

    一.什么是SPI SPI全称为Service Provider Interface,是一种服务发现机制,其本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件.这样可以在运行时,动态为 ...

  4. Hystrix学习笔记

     服务降级: DashBoard: 例中的8001为要监控的地址:

  5. C++Primer 5th Chap2 Variables and basic Types

    wchar_t,char16_t,char32_t用于拓展字符集 char和signed char并不一样,由编译器决定类型char表现上述两种中的哪一种 一般long的大小和int无二,如果超过in ...

  6. 18 IO流(十五)——RandomAccessFile随机访问文件及使用它进行大文件切割的方法

    本文部分内容转自:https://blog.csdn.net/nightcurtis/article/details/51384126 1.RandomAccessFile特点 RandomAcces ...

  7. github上热门深度学习项目

    github上热门深度学习项目 项目名 Stars 描述 TensorFlow 29622 使用数据流图进行可扩展机器学习的计算. Caffe 11799 Caffe:深度学习的快速开放框架. [Ne ...

  8. 使用PHP开发HR系统(4)

    本节我们讲述如何引入页面框架来建立漂亮的主页. ============================================================================ ...

  9. Build step 'Send files or execute commands over SSH' changed build result to UNSTABLE

    删除logs文件夹日志即可

  10. gitlab 安装、备份与还原及常见设置

    gitlab 安装.备份与还原及常见设置 安装 安装过程比较简单,跑在 docker 上,执行命令即可 -v参数后面的值为卷的名称,自动创建数据卷(如果数据卷不存在) https://docs.git ...