UNIX环境高级编程之第4章:文件和目录

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/youngyangyang04/article/details/47624065

</pre><pre>

4.1 引言

上一章主要是为荣的I/O进行的(打开文件,读文件,写文件),本章讲描述文件系统的其他特征和文件的性质。从stat函数开始,诸葛说明stat结构的每一个成员以及了解文件的所有属性。在此过程中讲介绍修改这些属性的各个函数(更改所有者和权限),更加详细的说明UNIX文件系统的结构以及符号链接(symbolic links),本章最后介绍对目录操作的各个函数,并且开发一个以降序遍历目录结构的函数

4.2 函数stat, fstat, fstatat和lstat

#include<sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);
int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);

stat:一旦给出pathname,stat函数将返回与此命名文件有关的信息结构

fstat:通过描述符(descriptor)打开文件的有关信息

lstat:与stat类似,但是当命名文件是一个符号链接(symbolic link)时,lstat返回的是符号链接的信息,而不是符号链接所引用的文件的信息(not the file referenced by the symbolic link)

fstatat:为一个相对于当前打开目录(由fd参数指向)的路径名返回文件的统计信息,flag参数控制这是否跟随这个符号链接。

(1)当flag设置AT_SYMLINK_NOFOLLOW标志是,fstatat不会跟随符号链接,而是返回符号链接本身信息。否则默认情况下,返回的是符号链接所指项的实际文件的信息。

(2)如果fd参数的值是AT_FDCWD,并且pathname参数是一个相对路径名,fstatat会计算相对于当前目录的pathname参数。如果pathname是一个绝对路径,fd参数就会被忽略。这两种情况下,根据flag的值,fstata的作用就和stat和lstat一样

buf的结构体

4.3 文件类型

我们已经介绍了两种不同的文件类型:普通文件和目录

文件类型主要包含一下几种

(1)普通文件(regular file)。可以是普通文本或者二进制

(2)目录文件(directory file)。这种文件包含了其他文件的名字已经指向这些文件有关信息的指针

(3)块特殊文件(block special file)。这种类型的文件对设备提供带缓冲的访问,每次访问以固定长度为单位进行

(4)字符特殊文件(character special file)。对设备不带缓冲的访问,每次访问的长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件

(5)FIFO。这种文件用于进程间通信,特成为命名管道(named pipe)。

(6)套接字(socket)。这种类型的文件用于进程间的网络通信,也可以用在一台宿主机上进程之间的非网络通信。

(7)符号链接(symbolic link)。这种类型的文件指向另一个文件。

文件信息包含在stat结构的st_mode成员中,st_mode成员如下


4.4 设置用户ID和设置组ID

与一个进程相关联的ID有6个或者更多

(1)实际用户ID和实际组ID标志我们究竟是谁。这两个字段再登陆时取 自己的口令文件(password file)中的登陆项
(2)有效用户ID,有效组ID以及附属组ID决定了 文件的访问权限
(3)保存的设置用户ID和保存的设置组ID再执行一个程序是包含了有效用户ID,有效组ID的 副本(copies)
文件所有者由stat结构中的st_uid制定,所有组同理
通常 effective user ID == real user ID     effective group ID == real group ID
可以再文件模式字(st_mode)设置一个特殊标志,其含义就是当执行此文件时将有效用户ID设置为文件所有者的用户ID(st_uid)

4.5 文件访问权限

st_mode包含了对文件的访问权限位,不仅是普通文件, 所有文件都有访问权限(access permission)
每个文件有9个权限位

进程每次打开,创建或删除一个文件,内核就进行文件访问权限测试
内核进行的测试具体如下
(1)若进程的 有效用户是0(超级用户),就允许访问。这就给予超级用户对整个系统的最充分的自由
(2)若进程的有效用ID等于文件的所有者ID(也就是进程拥有此文件),那么如果所有者的适当的访问权限位被设置,泽允许访问
(3)若进程的有效组ID或进程的附属组ID之一等于文件的组ID(注意不要求 进程的有效用ID等于文件的所有者ID),那么如果组适当的访问权限被设置,则允许访问
(4)若其他用户适当的访问权限位(S_IROTH, S_IWOTH, S_IXOTH)被设置,则允许访问

这四部是按顺序执行。注意:如果进程拥有此文件(也就是有效ID等于用户ID),用户访问权限批准或者拒绝访问,则不查看组访问权限
同样如果进程的有效用ID不等于文件的所有者ID,若进程属于某个适当的组,则按照组访问权限批准或拒绝,不查看其他用户(other)的权限

4.6 新文件和目录的所有权(Ownership of New Files and Directories)

底单张讲述的open或creat创建新文件时,并没有说明赋予新文件的用户ID和组ID是什么
新文件的用户ID设置为 进程的有效用户ID
新文件的组ID
(1) 新文件的组ID可以是进程的有效组ID.
(2) 新文件的组ID可以是它所在目录的组ID

4.7 函数access和faccessat

access和faccessat函数是按 实际用户ID实际组ID进行权限测试的
#include <unistd.h>
int access(const char * pathname, int mode);
int faccessat(int fd, const char * pathname, int mode, int flag);
mode为F_OK测试文件是否存在,还可以用

faccessat函数与access函数再下面两种情况下是相同的:
(1)pathname参数为绝对路径
(2)fd参数取值为AT_FDCWD而pathname参数为相对路径。否则faccessat计算相对与打开的目录(由fd参数指向)的pathname
flag参数可以改变faccesssat的行为,如果flag设置为AT_EACCESS,则检查用的是 调用进程的有效用户ID和有效组ID,还是实际用户ID和实际组ID

4.8 函数unask

<span style="font-weight: normal;">为每个与进程相关联的文件模式创建屏蔽字umask函数为进程设置文件模式,也就是使用umask之后,该进程所创建的文件的相关权限都会被关闭掉的umask值为0,可以保证任何用户都能读文件用户可以设置umask值控制他们所创建的文件的默认权限</span>

4.9 函数chmod, fchmod和fchmodat 

这三个文件可以更改现有文件的访问权限
#include<sys/stat.h>
int chmod(const char *pathname, mode_mode);
int fchmod(int fd, mode_t mode);
int fchmodat(int fd, const char *pathname, mode_t mode, int flag);

flag参数用于改变fchodat的行为,当设置了AT_SYMLINK_NOFOLLOW标志时,fchmodat并不会跟随符号链接(symbolic links)

4.10 粘着位(Sticky Bit)

粘着位主要应用再文件夹上,为了避免一个用户删除另一个用户的文件。用户只能删除自己创建的文件,或者被root用户删除

4.11 函数chown, fchown, fchownat, and lchown

下面的函数可用来更改文件的用户ID和组ID
#include <unistd.h>
int chown(const char *pathname, uid_t owner, git_t group);
int fchown(int fd, uid_t owner, git_t group);
int fchownat(int fd, const char *pathname, uid_t owner, git_t group, int flag);
int lchown(const char *pathname, uid_t owner, git_t group);
如果flag参数中设置了AT_SYMLINK_NOFOLLOW标志,则fchown和lchown效果相同
当_POSIX_CHOWN_RESTRICTED有效时,不能更改其他用户文件的用户ID。可以所用有的文件的组ID,单只能更改你所属的组

4.12 文件长度

stat结构成员st_size表示以 字节为单位的文件长度。此字段只对 普通文件目录文件符号链接有意义
文件中的空洞(holes in a File):设置的偏移量超过文件尾,并且写入一些数据造成的

4.13 文件截断(File Truncation)

#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int fd, off_t length);

这两个函数将一个现有的文件长度截断为length。如果文件长度小于length,则文件长度变成length

4.14 文件系统

有点没看懂

4.15 函数link, linkat, unlink, unlinkat和remove

 任何一个文件可以有多个目录项指向其i节点。使用下列函数link, linkat可以创建一个指向现有文件的链接
#include<unistd.h>
int link(const char *existingpath, const char *newpath);
int linkat(int efd, const char *existingpath, int nfd, const chat *newpath, int flag);

这两个函数创建一个新的目录项newpath, 它引用现有的文件existingpath。如果newpath已经存在则返回出错
对于linkat函数,现有文件是通过efd和existingpath参数制定的,新的文件也是通过nfd和newpath制定的
当现有的文件是符号链接时,由flag参数来控制linkat函数是创建指向现有的符号链接的链接还是创建指向符号链接所指项的文件的链接

为了删除现有的目录项,可以调用unlink函数
#include <unistd.h>
int unlink(const char *pathname);
int unlinkat(int fd, const char *pathname, int flag);
关闭一个文件是,内核会检查打开该文件的进程数,如果个数为0再检查链接计数,如果计数也为0则删除该文件
#include<unistd.h>
int symlink(const char *actualpath, const char *sympath);
int symlinkat(const char *actualpath,int fd, const char *sympath);

unlink的这个特性经常被程序用来确保即使再程序崩溃的时候,它做创建的临时文件也不会一留下来。进程用open或者creat 创建一个文件,然后调用unlink,当进程终止时候,该文件被删除
我们也可以用remove函数解除对一个文件或者目录的链接。对于文件remove和unlink相同,对于目录remove和rmdir功能相同

除了oldname或newname指向相对路径名时,其他情况这两个函数都是一样的

4.16 函数rename和renameat

文件或者目录可以用rename或renameat函数重命名
除了当oldname或newname指向相对路径名时,其他情况下renameat函数与rename函数功能相同

4.17 符号链接(Symbolic Links)

符号链接是对一个文件的间接指针。引入符号链接是为了避开硬链接的一些限制
(1)硬链接通常要求链接和文件位于一个文件系统中
(2)只有超级用户才能创建指向目录的硬链接
符号链接以及它指向的何种对象 没有任何文件系统限制
符号链接一般用于将一个文件或者整个目录的结构移到系统中的另一个位置

4.18 创建和读取符号链接

可以使用symlink或symlinkat函数创建一个符号链接
#include<stdio.h>
int rename(constt chat *oldname, const char *newname);
int renameat(int oldfd, const char *oldname, int newfd, const char *newname);

4.19 文件的时间

4.20 函数futimens, utimensat, utimes

futimens和utimensat函数可以更改一个文件的访问和修改的时间
futimens和utimensat函数包含再POSIX.1中,第三个函数utimes包含在Single UNIXSpecification的XSI扩展中

4.21 函数mkdir, mkdirat和rmdir

用mkdir和mkdirat函数创建目录,用rmdir函数删除目录
#include <sys/stst.h>
int mkdir(const chat *pathname, mode_t mode);
int mkdirat(int fd, const char *pathname, mode_t mode);
rmdir删除目录,但要求一定是空的

4.22 读目录


4.23 函数chdir, fchdir, getcwd 

每个进程都有一个当前工作目录,此目录是搜索所有相对路径名的起点
进程调用chdir或者fchdir函数可以更改当前工作目录
#include<unistd.h>
int chdir(const char *pathname);
int fchdir(int fd);

fchdir函数提供一个便捷的方法,再更换当前工作目录前,先用open打开,保存返回的文件描述符,然后希望回到原目录,是要简单的讲file descriptor传给fchdir
这两个函数分别用pathname和打开的文件描述符来制定新的当前工作目录
因为当前工作目录是进程的一个属性,所以它只影响调用chdir的进程本身,而不影响其他进程

getcwd函数提供保存当前工作路径的功能
char *getcwd (char *buf, size_t size);

4.24 设备特殊文件

4.25 文件访问权限位小结

4.26 小结

本章主要围绕着stat函数,详细介绍了stat结构中的每一个成员

对文件和目录的所有属性已经对文件和目录进行操作的所有函数全面了解,这对UNIX编程很重要

猜你喜欢

转载自blog.csdn.net/youngyangyang04/article/details/47624065
今日推荐