APUE 2 文件和目录

来源:互联网 发布:org.apache.log4j.mdc 编辑:程序博客网 时间:2024/05/22 12:33

本文代码实现采用golang的syscall包,其通常会包装一层系统调用不过大体相似


1.文件属性结构 Stat_t

文件的类型

文件类型 描述 普通文件 可能是文本或二进制 目录文件 包含该目录内的文件名,和有关这些文件信息的指针 块特殊文件 提供对设备带缓冲的访问 字特殊文件 提供对设备不带缓冲的访问,每次访问长度可变 FIFO 命名管道,用于进程间通信 套接字 用于进程间的网络通信,也可用于同一台宿主机进程间非网络通信 符号链接 指向另一个文件

描述文件属性的结构体Stat_t

type Stat_t struct {        Dev       uint64  //设备号,文件(以及i节点)在此文件系统中        Ino       uint64 //inode号        Nlink     uint64 //链接数        Mode      uint32 //文件类型&访问权限        Uid       uint32 //属主ID        Gid       uint32 //属组ID        X__pad0   int32        Rdev      uint64 //实际设备号,只有块字特殊文件才有此值        Size      int64 //文件大小,byte单位        Blksize   int64 //最佳I/O块大小        Blocks    int64 //已分配块数(512字节块或其他,根据不同系统可能不同)        Atim      Timespec //访问时间        Mtim      Timespec //修改内容时间        Ctim      Timespec //修改文件属性时间        X__unused [3]int64}type Timespec struct {        Sec  int64 //秒        Nsec int64 //纳秒}

2.查看文件属性信息stat、fstat、lstat

func Stat(path string, stat *Stat_t) (err error)func Fstat(fd int, stat *Stat_t) (err error)func Lstat(path string, stat *Stat_t) (err error)

Stat函数根据传入的path,读取文件属性写至stat,注意Stat函数会追踪符号链接至真实文件
Fstat函数根据当前已打开的文件描述符,读取属性至stat
Lstat函数同Stat,但不会追踪链接文件,直接返回符号链接的属性

3.进程相关的ID

4.4

  • 实际ID:通常为登录会话时取自口令文件中的登陆项,超级用户进程有方法改变。表示当前的会话(如SHELL)属于哪个ID
  • 有效ID:用于文件访问权限的检测
  • 保存的设置ID:有效ID的副本 exec函数使用
  • 文件所有ID:文件Stat_t中的Uid Gid

通常情况下,启动一个进程时会将有效ID设置为实际ID
但是在文件Mode属性中存在特殊的位设置用户设置组,如若设置了该位置,启动一个进程时有效ID会被设置为文件所有ID

4.文件访问权限

所有类型的文件均具有访问权限设置,其值在Stat_t中的Mode
4.5
对于不同类型的文件,再此处做2类区分,文件和目录:

  • 文件
    • 对于文件进行有关的open write read操作时,根据具体的操作类型判断对应的访问权限(读 写)是否有效
    • 当文件为可执行文件时,若需要执行则执行位要有效
  • 目录
    • 目录的读权限,允许读某目录中的所有文件名列表
    • 目录的写权限,允许对某目录项的内容进行修改,如增减文件
    • 目录的执行权限,决定是否可以对该目录进行搜索操作,如想打开、执行。增加删除某一文件,则其所有父层级的目录均需要拥有执行权限。执行权限确定了是否允许找到这个文件(如CD到某一目录,需要拥有该目录的执行权限)

5.创建新文件和目录的所有权

新文件的用户ID设置为当前进程有效用户ID
组ID取决于其所属的目录的设置组ID是否有效,若有效则新创建的文件的组ID为该目录的组ID;否则为进程的有效组ID

6.访问权限测试 access和faccessat

func Access(path string, mode uint32) (err error)func Faccessat(dirfd int, path string, mode uint32, flags int) (err error)//R_OK=4, W_OK=2, X_OK=1, F_OK=0   mode只可以为对应的整数值

注意:golang中的Access参数mode不可用C中的测试宏(R_OK等),等效可用对应的整数值。如上边的注释内容

如果想自行进行访问权限的检测,如通过实际ID来进行检测等
Access与Faccessat区别:

  • Faccessat的dirfd可以指定某目录fd,当fd=_AT_FDCWD时二者访问路径相同
  • flags=AT_EACCESS 通过进程有效ID检测,默认是使用实际ID检测

7.屏蔽字umask

func Umask(mask int) (oldmask int)

4-7

当创建文件时,将和umask进行与非操作(类似网络掩码),使创建的文件不含有某些权限

注意:修改进程的umask不会影响其父进程(通常为shell)

8.修改文件模式属性 Chmod、Fchmod、Fchmodat

func Chmod(path string, mode uint32) (err error)func Fchmod(fd int, mode uint32) (err error)func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)

3个函数区别:

  • Fchmod可指定已打开的文件
  • Fchmodeat可指定文件夹描述符
    • 参数flags可指定AT_SYMLINK_NOFOLLOW以不追踪符号链接
    • 参数dirfd可指定为AT_FDCWD以使用相对路径

mode 常量
VTX

粘着位 S_ISVTX:

  • 设置文件:会保存程序正文副本保存至交换分区(目前流行操作系统无需此操作,意义不大)
  • 设置目录:只有满足下列要求的用户才可删除该目录下的文件
    • 拥有待删除文件
    • 拥有该目录
    • 是超级用户

9.修改文件属主(组) chown系列

func Chown(path string, uid int, gid int) (err error)func Fchown(fd int, uid int, gid int) (err error)func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)func Lchown(path string, uid int, gid int) (err error)

这四个函数与其他类似函数的变种概念相近
除了Fchown(根据打开的文件)其他的均可由Fchownat来包装形成
影响Fchownat行为的参数:

  • AT_SYMLINK_NOFOLLOW 不追踪符号链接
  • AT_FDCWD 相对路径

10.文件长度

文件属性中的Size描述了文件的长度

  • 针对普通文件通常是一个数(16或512)的整数倍
  • 针对符号链接,长度是在文件名的实际字符数

文件属性中的Blocks描述了文件所占512字节块(或其他)数目
关于产生文件空洞的现象(Size>>Blocks*N),空洞未分配实际磁盘空间,但使用Read函数会把空洞位读出0,既会读出Size个字符

11.文件截断

func Truncate(path string, length int64) (err error)func Ftruncate(fd int, length int64) (err error)

根据指定的length将目标文件进行截断,使文件长度变成length,若原长度小于length的话将产生空洞

12.文件系统*

以Berkeley快速文件系统为例
123

磁盘可划分为多个分区,每个分区包含一个文件系统。本章值得注意的是i节点和数据块(含目录块)
i节点包含文件stat结构中的大多数信息
目录块含目录中各文件名和对应的i节点地址
i节点

当创建一个新目录testdir后文件系统内相关结构
结构

func Link(oldpath string, newpath string) (err error)func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error)func Unlink(path string) errorfunc Unlinkat(dirfd int, path string, flags int) (err error)

如上文文件系统的描述,任何一个文件可以有多个目录项指向其i节点

创建硬链接(目录项)

  • Link和Linkat,会使文件属性的Nlink+1
  • linkat可以指定目录的文件描述符
  • flags可设置AT_SYMLINK_NOFOLLOW或AT_SYMLINK_FOLLOW来指定是否跟随符号链接

删除硬链接

  • Unlink和Unlinkat,会使文件属性的Nlink-1,当Nlink减少至0时,该文件可以被删除
    • 该操作需要有包含该目录项的目录具有写和执行权限,注意粘着位
    • 当关闭一个文件时内核会检查当前同时打开该文件的进程数,若为0再检查Nlink若也为0则删除该文件的内容
  • Unlinkat可以指定目录的文件描述符
  • Unlinkat的flags可以指定为AT_REMOVEDIR,以支持删除目录
  • 不会跟随符号链接

14 重命名 rename和renameat

func Rename(oldpath string, newpath string) (err error)func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)

针对待重命名文件的类型(文件或目录)有如下几种情况

  • 当oldpath为文件时且newpath存在时,删除newpath的目录项然后将oldpath重命名为newpath
    • 对其所包含的目录进程需要有写和执行权限
  • 当oldpath为目录时且newpath存在,则需要newpath为空目录,删除newpath再将oldpath重命名
    • newpath不能包含oldpath作为前缀

15 符号链接

一种特殊的文件类型,是类似于文件硬链接的文件间接指针,与硬链接不同:

  • 符号链接可以跨文件系统,而硬链接通常要求文件位于同一文件系统中
  • 任何用户都可以创建符号链接,而硬链接只可以是root操作

不同的系统调用对于符号链接是否跟随情况不一,如图
跟随情况

创建符号链接

func Symlink(oldpath string, newpath string) (err error)func Symlinkat(oldpath string, newdirfd int, newpath string) (err error)

创建oldpath指向newpath的符号链接,Symlinkat的newdirfd为AT_FDCWD时两个函数相同

因为open函数会跟随符号链接,所以读取符号链接的内容存在独立的函数

func Readlink(path string, buf []byte) (n int, err error)func Readlinkat(dirfd int, path string, buf []byte) (n int, err error)

函数会将符号链接的内容读入buf中,值为oldpath的路径名(不以null结尾)

16 文件的时间

Atim      Timespec //访问时间Mtim      Timespec //修改内容时间Ctim      Timespec //修改文件属性时间type Timespec struct {        Sec  int64 //秒        Nsec int64 //纳秒}

正如前文描述的文件属性

  • Atim为最近一次读取文件正文操作的时间
  • Mtim为最近一次修改文件正文操作的时间
  • Ctim为最近一次修改文件属性的时间
    • 修改文件属性就是修改关联i节点的值
    • 系统并不维护i节点最后访问的时间,所以access stat这些函数不会影响这三种时间

各种函数对文件时间的影响:
对时间影响

修改文件时间:

func Futimes(fd int, tv []Timeval) (err error) //打开的描述符func Futimesat(dirfd int, path string, tv []Timeval) error //可指定目录描述符和pathfunc Utimes(path string, tv []Timeval) error //相对路径AT_FDCWD或绝对路径type Timeval struct {    Sec  int64    Usec int64}

17 创建目录

func Mkdir(path string, mode uint32) (err error)func Mkdirat(dirfd int, path string, mode uint32) (err error)func Rmdir(path string) error

注意创建目录时umask的影响,和是否支持设置组
Rmdir实际由Unlinkat实现:

func Rmdir(path string) error {    return Unlinkat(AT_FDCWD, path, AT_REMOVEDIR)}

18 更改(获取)当前工作目录 chdir fchdir getcwd

func Chdir(path string) (err error)func Fchdir(fd int) (err error)func Getcwd(buf []byte) (n int, err error)

19.文件访问权限小结

这里写图片描述

原创粉丝点击