APUE读书笔记(4) 文件和目录(上)

第四章 文件和目录(上)

一:主要内容:
  本章主要讲述UNIX系统中文件和目录,与上一章有所区别的是,文件IO主要讨论普通文件;文件和目录主要讲述描述文件系统的其他特征和文件的性质。
  由于该章篇幅较长,所以分为两部分来记录。

二:函数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);  
 
所有4个函数的返回值:若成功;返回0;若出错,返回-1 

  对于buf,它是一个指向文件结构的指针,调用这四个函数不是通过返回值的方式获取对应文件信息,而是通过填充buf来返回结果。值得一提的是,只有函数执行成功的时候才会填充buf。
其中stat和fstat比较类似,只是前者是传入一个路径,后者是传入一个文件描述符fd。lstat的声明形式和stat比较像,lstat用于当想获取符号链接的有关信息而不是对应符号连接指向的文件信息时才使用的。也就是

link 指向 file文件
stat(link, buf) 调用stat 返回file文件信息
lstat(link, buf) 调用lstat 返回link符号连接文件信息

  fstatat函数为一个相对于当前打开目录(由fd参数指向)的路径名返回文件统计信息。flag参数控制着是否跟随着一个符号链接。当AT_SYMLINK_NOFOLLOW标志被设置时,fstatat不会跟随符号链接,而是返回符号链接本身的信息。否则,在默认情况下,返回的是符号链接所指向的实际文件的信息。如果fd参数的值是AT_FDCWD,并且pathname参数是一个相对路径名,fstatat会计算相对于当前目录的pathname参数。如果pathname是一个绝对路径,fd参数就会被忽略。这两种情况下,根据flag的取值,fstatat的作用就跟stat或lstat一样。也就是

link指向file
前两位决定了文件路径,其中如果第二个参数为绝对路径,则忽略第一个参数;第二个参数为相对路径,并且第一个参数为AT_FDCWD,则为相对路径。
fstatat(AT_FDCWD,相对路径,buf, 0)
fstatat(AT_FDCWD,绝对路径,buf, 0)
flag决定了是返回连接符号信息还是连接符号所指向的文件的文件信息
fstatat(,link,buf,AT_SYMLINK_NOFOLLOW ) == lstat(link, buf) 调用lstat 返回link符号连接文件信息
fstatat(,link,buf,0 )					  == stat(link, buf) 调用stat 返回file文件信息

其中,buf的具体结构一般为:

struct stat {    
  mode_t                st_mode;        /* file type & mode (permissions) */    
  ino_t                 st_ino;         /* i-node number (serial number) */    
  dev_t                 st_dev;         /* device number (file system) */    
  dev_t                 st_rdev;        /* device number for special files */    
  nlink_t               st_nlink;       /* number of links */    
  uid_t                 st_uid;         /* user ID of owner */    
  gid_t                 st_gid;         /* group ID of owner */    
  off_t                 st_size;        /* size in bytes, for regular files */    
  struct timespec   st_atime;       /* time of last access */    
  struct timespec   st_mtime;       /* time of last modification */    
  struct timespec   st_ctime;       /* time of last file status change */    
  blksize_t             st_blksize;     /* best I/O block size */    
  blkcnt_t              st_blocks;    /* number of disk blocks allocated */    
}; 

其中timespec结构类型按照秒和纳秒定义了时间,至少包括下面两个字段:
time_t tv_sec;  
long   tv_nsec; 

三:文件类型
  UNIX系统的文件类型大多数是普通文件和目录,但是还有其他类型,算上普通文件和目录一共有七种
  1. 普通文件,可以是文本文件也可以是二进制文件,对于UNIX内核而言这两者并没有什么区别,但是要注意的事二进制可执行文件需要遵循一种标准化的格式好让内核能够确定程序文本和数据的加载位置
  2. 目录文件,这种文件包含了其他文件的名字以及指向这些文件的有关信息的指针。只有对目录文件有读权限才可以读该目录下的文件内容。但只有内核可以直接写目录文件。
  3. 块特殊文件,这种类型的文件提供对设备(如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。
  4. 字符特殊文件,,这种类型的文件提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。
  5. FIFO,这个文件是管道文件,用于进程间的通信,有时也称为命名管道。
  6. 套接字, 这种类型的文件用于进程间的网络通信,套接字也可用于在一台宿主机上进程之间的非网络访问。
  7. 符号链接,这种类型的文件可以指向另一个文件。
  文件的类型信息包含在stat结构中的st_mode中,可以用宏来确定文件类型。
四:设置用户ID和组ID
  与一个进程相关联的ID由六个甚至更多,如下:

实际用户ID
实际组ID

有效用户ID
有效组ID
附属组ID

保存的设置用户ID
保存的设置组ID

  前两个标识了我们究竟是谁,这两个字段在登陆时取自口令文件中的登陆项。通常,在一个登录会话期间这些值并不会改变,但是超级用户有办法改变他们
  中间三个决定了我们对文件的访问权限
  最后两个标识了在执行一个程序时,包含了有效用户ID和有效组ID的副本
  一般情况下,有效用户ID等于实际用户ID,有效组ID等于实际组ID
  每一个文件都有其所有者和所有组,这也就是我们常说的uid和gid。
  当执行一个程序文件的时候,进程的有效用户ID通常就是实际用户ID,有效组ID通常是实际组ID
五:文件访问权限
  st_mode中也包括了对文件的访问权限位。每个文件都有九个访问权限位,可以把他们分为三类:

用户读、写、执行
组读、写、执行
其他读、写、执行

  chmod命令可以修改这九个权限位。u表示用户,g表示组,o表示其他,a表示这三者。
  这三类访问权限以各种方式由不同的函数使用,在这里我们说几条规则。
  1. 当我们打开任意类型的文件时,我们肯定对路径上的每一个目录都具有执行权限,这也就是为什么目录的执行权限位通常被称为搜索位的原因。比如我们打开/usr/myz/1.txt,那我们对于/,/usr,/usr/myz都具有执行权限。
  2. 为了在一个目录创建一个新文件,必须对该目录具有写权限和执行权限
  3. 为了删除一个现有文件,必须对包含该文件的目录具有写权限和执行权限。对该文件本身不需要有读写权限
  4. 如果使用exec函数中的任意一个函数执行一个文件,则必须保证两点:该文件为普通文件;具有对该文件的执行权限
六:新文件和目录的所有权
  新文件的用户ID会等于进程的有效用户ID,对于组ID,则会复杂一些:新文件的组ID可以是进程的有效组ID;也可以是他所在目录的组ID。
七:函数access和faccessat
  对于有些情况下,我们希望通过按照进程的实际用户ID和实际组ID来测试其访问能力。下面两个函数就是按照实际用户ID和实际组ID来进行访问测试的。

#include <unistd.h>
int access(const char * pathname, int mode);
int faccessat(int fd, const char * pathname, int mode, int flag);
两个函数的返回值:若成功,返回0;若出错,返回-1.

其中,如果测试文件是否已经存在,mode就为F_OK;否则mode是图4-7中所列常量的按位或。

mode说明
R_OK测试读权限
W_OK测试写权限
X_OK测试执行权限

  faccessat函数与access函数在下面两种情况下是相同的:一种是pathname参数为绝对路径,另一种是fd参数取值为AT_FDCWD而pathname参数为相对路径。否则,faccessat计算相对于打开目录(由fd参数指向)的pathname。
  flag参数可以用于改变faccessat的行为,如果flag设置为AT_EACCESS,访问检查用的是调用进程的有效用户ID和有效组ID,而不是实际用户ID和实际组ID。
八:函数umask
  函数umask为进程设置文件模式创建屏蔽字,并返回之前的值。函数原型如下:

#include <sys/stat.h>

mode_t umask(mode_t cmask);
返回值:之前的文件模式创建屏蔽字

  其中cmask时我们之前说的九个访问控制位他们所对应的九个常量(S_IRUSR,S-IWUSR等)中的若干个按位或构成的。可以说umask函数在进程创建一个新文件或者是新目录的时候就一定会使用文件模式创建屏蔽字。这里顺带一提,我们经常会看见有人可以使用一些命令加数字对文件进行权限位设置,也是因为使用了umask的原因。对于三类访问权限中的任何一类,都是使用4、2、1来标识读、写、执行的比如如果一个文件的umask值是777(这和我七酱无关),说明这个文件的用户、组、和其他人都可以对这个文件进行读写执行

九:函数chmod、fchmod、fchmodat
  这三个函数可以使我们更改现有的文件的访问权限。函数原型如下:

#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
int fchmodat(int fd, const char *pathname, mode_t mode, int flag);

  chmod函数在指定的文件上进行操作,而fchmod函数则对已打开的文件进行操作。fchmodat函数与chmod函数在下面两种情况下是相同的:一种是pathname参数为绝对路径,另一种是fd参数取值为AT_FDCWD而pathname参数为相对路径。否则,fchmodat计算相对于打开目录(由fd参数指向)的pathname。flag参数可以用于改变fchmodat的行为,当设置了AT_SYMLINK_NOFOLLOW标志时,fchmodat并不会跟随符号链接。
十:粘着位
  首先我们需要明确一点,粘着位仅仅对目录生效
  如果一个目录被设置了粘着位,那么只有对该目录具有写权限并且满足一下条件之一的用户才可以删除或者重命名该目录下的文件:拥有此文件、拥有此目录、超级用户。
  典型的使用粘着位的目录是:/tmp和/var/tmp,在这两个目录下用户仅仅能对自己的文件进行操作,而不能删除或者重命名属于其他人的文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值