Linux应用开发:文件属性与目录(上)
Posted JeckXu666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux应用开发:文件属性与目录(上)相关的知识,希望对你有一定的参考价值。
目录
Linux应用开发:文件属性与目录(上)
一、文件类型
Linux 系统下一共分为 7 种文件类型:普通文件、目录、字符设备文件、块设备文件、符号链接文件、管道文件以及套接字文件,这7个文件主要有以下区别:
- 普通文件:最常见的文件类型
- 目录文件:目录也是一种文件类型
- 设备文件:对应于硬件设备
- 符号链接文件:类似于 Windows 的快捷方式
- 管道文件:用于进程间通信的文件
- 套接字文件:用于网络通信的文件
下面详细介绍一下各个文件:
1.1 普通文件
Linux 系统下是最常见的,如文本文件、二进制文件、源代码文件都是普通文件,也就是 一般意义上的文件;普通文件中的 数据存在系统磁盘中,文件中的内容可以以 字节为单位 进行存储于访问
普通文件可以分为两大类:文本文件和二进制文件:
-
文本文件:文件中的内容是由文本构成的,文本指的是 ASCII 码字符
-
二进制文件:二进制文件中存储的本质上也是数字,只不过对于二进制文件来说,这些数字并不是文本字符编码,而是真正的 二进制数字
通过 stat 命令可以查询文件类型,如下:
ls 指令也可以查看文件类型:
用 ls 展开后,每个文件的第一个是一个 ‘-’,其含义如下:
- ’ - ':普通文件
- ’ d ':目录文件(dir)
- ’ c ':字符设备文件(char)
- ’ b ':块设备文件(block)
- ’ l ':符号链接文件(link)
- ’ s ':套接字文件(socket)
- ’ p ':管道文件(pipeline)
1.2 目录文件
目录文件就是文件夹,是一种特殊文件,可以使用 vim 打开:
文件夹中记录了该文件夹本省的路径以及该文件夹下所存放的文件
1.3 字符设备文件和块设备文件
Linux 系统下,一切皆文件,也包括各种硬件设备,设备文件(字符设备文件、块设备文件)对应的是硬件设备,在 Linux 系统中,硬件设备会对应到一个设备文件,应用程序通过对设备文件的读写来操控、使用硬件设备
虽然有设备文件,但是设备文件并不对应磁盘上的一个文件,而是由文件系统虚拟出来的,一般是由内存来维护,当系统关机时,设备文件都会消失
字符设备文件一般存放在 Linux 系统/dev/目录下,所以/dev 也称为虚拟文件系统 devfs
列出 Ubuntu 下的文件, agpgart、autofs、btrfs-control、console 等这些都是字符设备文件,而 loop0、loop1 这些便是块设备文件,我们可以根据第一个字符来判断
1.4 符号链接文件
符号链接文件(link)类似于 Windows 系统中的快捷方式文件,是一种特殊文件,它的内容指向的是另一个文件路径,当对符号链接文件进行操作时,系统根据情况会对这个操作转移到它指向的文件上去
理解为 Windows 下的快捷方式
1.5 管道文件
管道文件是建立在内存之上可以同时被两个进程访问的文件,主要用于进程间通信
1.6 套接字文件
套接字文件(socket)也是一种进程间通信的方式,与管道文件不同的是,它们可以在不同主机上的进程间通信,实际上就是网络通信
二、stat 函数
2.1 stat() 函数
使用 stat 命令查看文件的属性,本质上是通过调用 stat() 函数来获取文件属性,stat 函数是 Linux 中的系统调用,用于获取文件相关的信息,函数原型如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
pathname:用于指定一个需要查看的文件路径
buf:struct stat 类型指针,用于指向一个 struct stat 结构体变量。调用 stat 函数的时候需要传入一个 struct
stat 变量的指针,获取到的文件属性信息就记录在 struct stat 结构体中
返回值:成功返回 0;失败返回-1,并设置 error
2.2 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;
/* 设备号(指针对设备文件) */
off_t st_size;
/* 文件大小(以字节为单位) */
blksize_t st_blksize;
/* 文件内容存储的块大小 */
blkcnt_t st_blocks;
/* 文件内容所占块数 */
struct timespec st_atim;
/* 文件最后被访问的时间 */
struct timespec st_mtim;
/* 文件内容最后被修改的时间 */
struct timespec st_ctim;
/* 文件状态最后被改变的时间 */
;
st_mode 是 struct stat 结构体中的一个成员变量,是一个 32 位无符号整形数据,该变量记录了文件的类型、文件的权限这些信息,该整形各位如下:
- O 对应的 3 个 bit 位用于描述其它用户的权限
- G 对应的 3 个 bit 位用于描述同组用户的权限
- U 对应的 3 个 bit 位用于描述文件所有者的权限
- S 对应的 3 个 bit 位用于描述文件的特殊权限
文件类型这 4 个 bit 位用于描述该文件的类型:
S_IFSOCK 0140000 socket(套接字文件)
S_IFLNK 0120000 symbolic link(链接文件)
S_IFREG 0100000 regular file(普通文件)
S_IFBLK 0060000 block device(块设备文件)
S_IFDIR 0040000 directory(目录)
S_IFCHR 0020000 character device(字符设备文件)
S_IFIFO 0010000 FIFO(管道文件)
成员变量中的 struct timespec 结构体是 Linux 系统中时间相关的结构体,用于存储时间信息,原型如下:
struct timespec
time_t tv_sec;
/* 秒 */
syscall_slong_t tv_nsec;
/* 纳秒 */
;
三、fstat 和 lstat
除了 stat 函数之外,还可以使用 fstat 和 lstat 两个系统调用来获取文件属性信息,fstat、lstat 与 stat 的作用一样,但是参数、细节方面有些不同
3.1 fstat 函数
stat 是从文件名出发得到文件属性信息,不需要先打开文件;而 fstat 函数则是从文件描述符出发得到文件属性信息,函数原型
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int fstat(int fd, struct stat *buf);
如果不想通过打开文件来得到文件属性信息,那么就使用 stat,如果文件已经打开了,那么就使用 fstat
3.2 lstat 函数
对于符号链接文件,stat、fstat 查阅的是符号链接文件所指向的文件对应的文件属性信息,而 lstat 查阅的是符号链接文件本身的属性信息,函数原型如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int lstat(const char *pathname, struct stat *buf);
四、文件归属
Linux 是一个多用户操作系统,系统中一般存在着好几个不同的用户,而 Linux 系统中的每一个文件都有一个与之相关联的用户和用户组,通过这个信息可以 判断文件的所有者和所属组
Linux 系统会为每一个用户或用户组分配一个 ID,将用户名或用户组名与对应的 ID 关联起来,所以 系统通过用户 ID(UID)或组 ID(GID)就可以识别出不同的用户和用户组
如下,我们查看一个文件的信息,可以看到他的 UID 和 GID:
文件的用户 ID 和组 ID 分别由 struct stat 结构体中的 st_uid 和 st_gid 所指定
而对于一个进程来说也有所属组,与一个进程相关联的 ID 一般有 5 个或更多,具体可以分为以下部分:
- 实际用户 ID 和实际组 ID 就是 执行该进程的用户是谁、以及该用户对应的所属组;实际用户 ID 和实际组 ID 确定了进程所属的用户和组
- 有效用户 ID、有效组 ID 以及附属组 ID 用于文件访问权限检查
"进程对文件是否拥有 xx 权限" 其实质是当前执行该进程的用户是否拥有对文件的 xx 权限
chown 是一个系统调用,该系统调用可用于改变文件的所有者(用户 ID)和所属组(组 ID),函数原型如下:
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
- pathname:用于指定一个需要修改所有者和所属组的文件路径
- owner:将 文件的所有者 修改为该参数指定的用户(以用户 ID 的形式描述)
- group:将 文件的所属组 修改为该参数指定的用户组(以用户组 ID 的形式描述)
- 返回值:成功返回 0;失败将返回-1,兵并且会设置 errno
函数使用注意:
- 只有超级用户进程能更改文件的用户 ID
- 普通用户进程只能将文件的组 ID 修改为其所从属的任意附属组 ID,前提条件是该进程的有效用户 ID 等于文件的用户 ID;而 超级用户进程可以将文件的组 ID 修改为任意值
以上是关于Linux应用开发:文件属性与目录(上)的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向Linux 文件权限 ( Linux 权限简介 | 系统权限 | 用户权限 | 匿名用户权限 | 读 | 写 | 执行 | 更改组 | 更改用户 | 粘滞 )(代码片段