1. stat结构的基本形式:

  1. struct stat {
  2. mode_t st_mode; /* file type & mode (permissions), suid, sgid */
  3. ino_t st_ino; /* i-node number (serial number) */
  4. dev_t st_dev; /* device number (file system) */
  5. dev_t st_rdev; /* device number for special files */
  6. nlink_t st_nlink; /* number of links */
  7. uid_t st_uid; /* user ID of owner */
  8. gid_t st_gid; /* group ID of owner */
  9. off_t st_size; /* size in bytes, for regular files */
  10. struct timespec st_atim; /* time of last access */
  11. struct timespec st_mtim; /* time of last modification */
  12. struct timespec st_ctim; /* time of last file status change */
  13. blksize_t st_blksize; /* best I/O block size */
  14. blkcnt_t st_blocks; /* number of disk blocks allocated , 512B */
  15. };
  16. struct timespec {
  17. time_t tv_sec;
  18. long tv_nsec;
  19. }

2. 函数stat、fstat、fstatat、lstat

  • 函数名首位的“f”常常代表“该函数是通过文件描述符fd(而不是路径名)对文件进行操作的”
  1. #include <sys/stat.h>
  2. int stat(const char *restrict pathname, struct stat *restrict buf );
  3. int fstat(int fd, struct stat *buf );
  4. int lstat(const char *restrict pathname, struct stat *restrict buf ); // 返回该符号链接本身的有关信息
  5. int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);
  6. All four return: if OK, − on error

3. 文件类型

  • 普通文件 -
  • 目录文件 d
  • 块特殊文件 b
  • 字符特殊文件 c
  • FIFO p
  • 套接字 s
  • 符号链接 l

  • 文件类型宏:参数为stat结构中的st_mode成员(文件模式字)

  • IPC类型宏:参数为stat结构的指针

4. 设置用户ID(SUID) 和 设置组ID(SGID)

  • 每个进程关联的用户ID和组ID,包括实际用户ID、有效用户ID、保存的设置用户ID。
  • 实际用户ID指的是执行该程序的用户的ID。注意区别于文件的所有者

  • 每个文件有一个所有者和组所有者,由stat结构中的st_uid, st_gid指定。

  • 当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID。但是,可以在文件模式字(st_mode)中设置一个标志,使其“当执行该程序文件时,将进程的有效用户ID设置为文件所有者的ID(st_uid)”。进程的有效组ID类似,在文件模式字st_mode中的这两位标志被称为SUID和SGID。可使用常量S_ISUID和S_ISGID测试。
  • 应用:passwd命令

5. 文件访问权限

  • 所有文件类型都有访问权限

  • 进程每次打开、创建或删除一个文件时,内核就进行文件访问权限测试,这种测试可能涉及文件的所有者(st_uid和st_gid)、进程的有效ID(有效用户ID和有效组ID)、进程的附属组ID。两个所有者ID是文件的性质,而两个有效ID和附属组ID则是进程的性质。

  • 内核进行的测试具体如下:
  1. 若进程的有效用户ID是0(超级用户),则运行访问
  2. 若进程的有效用户ID等于文件的所有者ID(即进程拥有此文件),那么如果所有者适当的访问权限位被设置,则运行访问;否则拒绝访问。适当的访问权限位指的是:若进程为读而打开该文件,则用户读位应为1;若进程为写而打开该文件,则用户写位应为1;若进程将执行该文件,则用户执行位应为1。
  3. 若进程的有效组ID或进程的附属组ID之一等于文件的组ID,那么如果组适当的访问权限位被设置,则允许访问;否则拒绝访问。
  4. 若其他用户适当的访问权限位被设置,则允许访问;否则拒绝访问。
    按顺序执行这4步。一旦前面的被拒绝了,即使后面的组、其他用户拥有相应权限也白搭。

6. 新文件和新目录的所有权

  • 新文件的用户ID设置为进程的有效用户ID
  • 新目录的组ID有两种选择:1. 设置为进程的有效组ID;2. 设置为它的父目录的组ID。

    Linux下如果新目录的父目录的SUID被设置,则选择2

7. 函数access 和 faccessat

当open函数打开一个文件时,内核以进程的有效用户ID和有效组ID为基础执行其访问权限测试。
有时,进程希望以进程的实际用户ID和实际组ID为基础来执行其访问权限测试。这使用以下两个函数:

  1. #include <unistd.h>
  2. int access(const char *pathname, int mode);
  3. int faccessat(int fd, const char *pathname, int mode, int flag);
  4. Both return: if OK, − on error

测试文件是否存在,mode为F_OK;测试读/写/执行权限,mode为R_OK、W_OK、X_OK的按位与

8. 函数umask

  • 在进程创建一个新文件或新目录时,一定会使用文件模式创建屏蔽字。在文件模式创建屏蔽字中为1的位,在文件mode中的相应位一定被关闭。
  • 常用的几种umask值是002、022、027
  • 命令umask [-S]
  1. #include <sys/stat.h>
  2. mode_t umask(mode_t cmask);
  3. Returns: previous file mode creation mask

9. 函数chmod、fchmod和fchmodat

  1. #include <sys/stat.h>
  2. int chmod(const char *pathname, mode_t mode);
  3. int fchmod(int fd, mode_t mode);
  4. int fchmodat(int fd, const char *pathname, mode_t mode, int flag);
  5. All three return: if OK, − on error
  • 为了改变一个文件的权限位,进程的有效用户ID必须等于文件的所有者ID,或者该进程具有root权限

10. 粘着位(Sticky bit)

  • 针对文件
    历史上,一个设置了粘着位的程序文件在其终止时,程序正文部分的一个副本仍保存在交换区,这使得下次执行该程序时能较快地将其载入内存。因为在系统再次重启前,文件的正文部分总是在交换区中,这正是名字“粘着”的由来。现今较新的UNIX系统大多配置了虚拟存储系统以及快速文件系统,所以不再需要该技术。
  • 针对目录
    如果对一个目录设置了粘着位,只有对该目录具有写权限的用户并且满足下列条件之一,才能删除或重命名该目录下的文件:
    1. 拥有此文件;2. 拥有此目录;3. 是超级用户
    • 目录/tmp 和 /var/tmp 是设置粘着位的典型候选者。

11. 函数chown、fchown、fchownat和lchown

  1. #include <unistd.h>
  2. int chown(const char *pathname, uid_t owner, gid_t group);
  3. int fchown(int fd, uid_t owner, gid_t group);
  4. int fchownat(int fd, const char *pathname, uid_t owner, gid_t group, int flag);
  5. int lchown(const char *pathname, uid_t owner, gid_t group);
  6. All four return: if OK, − on error
  • 如果这些函数由非root进程调用,则在成功返回时,该文件的SUID和SGID位都被清除。

12. 文件长度

  • stat结构成为st_size表示以字节为单位的文件的长度。此字段只对普通文件、目录文件和符号链接有意义。
  • 对于普通文件,其文件长度可以是0
  • 对于目录,文件长度通常是一个数(如512,4096)的整数倍
  • 对于符号链接,文件长度是文件名中的实际字节数,不包含通常C语言用作名字结尾的null字节
  • 大多数现代的UNIX系统提供字段st_blksize和st_blocks。第一个是对文件I/O较合适的块长度,第二个是所分配的实际512字节块块数。

  • 文件中的空洞

    空洞是由所设置的偏移量超过文件尾端,并写入了某些数据后造成的。对于没有写过的字节位置,read函数读到的字节是0

13. 文件截断

  1. #include <unistd.h>
  2. int truncate(const char *pathname, off_t length);
  3. int ftruncate(int fd, off_t length);
  4. Both return: if OK, − on error

14. 文件系统

15. 函数link(硬链接)、linkat、unlink、unlinkat、remove

  1. #include <unistd.h>
  2. int link(const char *existingpath, const char *newpath); // 只创建newpath中的最后一个分量,路径中的其他部分应当已经存在
  3. int linkat(int efd, const char *existingpath, int nfd, const char *newpath, int flag);
  4. Both return: if OK, − on error
  • 大多数实现要求现有的和新建的两个路径名在同一个文件系统中。
  • 很多文件系统实现不允许对于目录的硬链接。
  1. #include <unistd.h>
  2. int unlink(const char *pathname); // 若其父目录设置了粘着位,参见上面“粘着位”
  3. int unlinkat(int fd, const char *pathname, int flag);
  4. Both return: if OK, − on error
  • 关闭一个文件时,内核首先检查打开盖文件的进程个数;如果这个计数达到0,内核再去检查其链接计数;如果计数也是0,那么就删除该文件的内容。
  • unlink的这种特性进程被程序用来确保即使在程序崩溃时,它所创建的临时文件也不会遗留下来。进程用open或creat创建一个文件,然后立即调用unlink
  1. #include <stdio.h>
  2. int remove(const char *pathname);
  3. Returns: if OK, − on error
  • remove函数解除对一个文件或目录的链接。对于文件,等同于unlink;对于目录,等同于rmdir。

16. 函数rename和renameat

  1. #include <stdio.h>
  2. int rename(const char *oldname, const char *newname);
  3. int renameat(int oldfd, const char *oldname, int newfd, const char *newname);
  4. Both return: if OK, − on error

17. 符号链接(软链接)

  • 引入符号链接是为了避开硬链接的一些限制:

    1. 硬链接通常要求链接和文件位于同一个文件系统中
    2. 只有超级用户才能创建指向目录的硬链接(在底层文件系统支持的情况下)
  • 各函数对符号链接的处理:follow 或 not follow

18. 创建和读取符号链接

  1. #include <unistd.h>
  2. int symlink(const char *actualpath, const char *sympath);
  3. int symlinkat(const char *actualpath, int fd, const char *sympath);
  4. Both return: if OK, − on error
  1. #include <unistd.h>
  2. ssize_t readlink(const char* restrict pathname, char *restrict buf, size_t bufsize);
  3. ssize_t readlinkat(int fd, const char* restrict pathname, char *restrict buf, size_t bufsize);
  4. Both return: number of bytes read if OK, − on error

19. 文件的时间

  • 各函数对3个文件时间的影响,包括:所操作的文件或目录本身、所操作的文件或目录的父目录

20. 函数futimens、utimensat、utimes

  1. #include <sys/stat.h>
  2. int futimens(int fd, const struct timespec times[]);
  3. int utimensat(int fd, const char *path, const struct timespec times[], int flag);
  4. Both return: if OK, − on error
  • times数组参数的第一个元素包含访问时间,第二个元素包含修改时间
  • futimens函数需要打开文件来更改它的时间;utimensat函数提供了一种使用文件名更改文件时间的方法。
  1. #include <sys/time.h>
  2. int utimes(const char *pathname, const struct timeval times[]);
  3. Returns: if OK, − on error
  • utimes函数对路径名进行操作,times参数指向访问时间和修改时间,状态更改时间自动更新

21. 函数mkdir、mkdirat、rmdir

  1. #include <sys/stat.h>
  2. int mkdir(const char *pathname, mode_t mode);
  3. int mkdirat(int fd, const char *pathname, mode_t mode);
  4. Both return: if OK, − on error
  1. #include <unistd.h>
  2. int rmdir(const char *pathname);
  3. Returns: if OK, − on error

22. 读目录

  1. #include <dirent.h>
  2. DIR *opendir(const char *pathname);
  3. DIR *fdopendir(int fd);
  4. Both return: pointer if OK, NULL on error
  5. struct dirent *readdir(DIR *dp);
  6. Returns: pointer if OK, NULL at end of directory or error
  7. void rewinddir(DIR *dp);
  8. int closedir(DIR *dp);
  9. Returns: if OK, − on error
  10. long telldir(DIR *dp);
  11. Returns: current location in directory associated with dp
  12. void seekdir(DIR *dp, long loc);
  1. dirent结构至少包含以下两个成员:
  2. struct dirent {
  3. ino_t d_ino; /* i-node number */
  4. char d_name[]; /* null-terminated filename */
  5. }

23. 函数chdir、fchdir、getcwd

  • 每个进程都有一个当前工作目录。
  • 当前工作目录是进程的一个属性,起始目录则是登陆名的一个属性。
  1. #include <unistd.h>
  2. int chdir(const char *pathname);
  3. int fchdir(int fd);
  4. Both return: if OK, − on error

24. 设备特殊文件

  • 每个文件系统所在的存储设备都由其主、次设备号表示。
  • 设备号所用的数据类型是基本系统数据类型dev_t。
  • 主设备号标识设备驱动程序,有时编码为与其通信的外设板;次设备号标识特定的子设备。
  • 在同一磁盘驱动器上的各文件系统通常具有相同的主设备号,但是次设备号却不同。
  • 可以使用两个宏:major和minor来访问主、次设备号。
  • 系统中与每个文件名关联的st_dev值是文件系统的设备号,该文件系统包含了这一文件名以及其对应的i节点。
  • 只有字符特殊文件和块特殊文件才有st_rdev值。此值包含实际设备的设备号。

25. 文件访问权限位小结

《Unix环境高级编程》读书笔记 第4章-文件和目录的更多相关文章

  1. [置顶] 文件和目录(二)--unix环境高级编程读书笔记

    在linux中,文件的相关信息都记录在stat这个结构体中,文件长度是记录在stat的st_size成员中.对于普通文件,其长度可以为0,目录的长度一般为1024的倍数,这与linux文件系统中blo ...

  2. unix环境高级编程-读书笔记与习题解答-第一篇

    从这周开始逐渐的进入学习状态,每天晚上都会坚持写c程序,并且伴随对这本书的深入,希望能写出更高质量的读书笔记和程序. 本书的第一章,介绍了一些关于unix的基础知识,在这里我不想去讨论linux到底是 ...

  3. unix 环境高级编程-读书笔记与习题解答-第二篇

    第四节 输入与输出 上次的笔记中写到的 open, read, write, lseek 以及close ,都是不带缓存的IO函数,这些函数都使用文件描述符进行工作. 上一篇笔记用到的 read(ST ...

  4. [置顶] 文件io(一)--unix环境高级编程读书笔记

    unix-like(后面以linux为例)系统中的文件操作只需要五个函数就足够了,open.close.read.write以及lseek.这些操作被称为不带缓存的io,这里有必要说一下带缓存和不带缓 ...

  5. unix 环境高级编程 读书笔记与习题解答第四篇

    第一章 第六节 第一小节 这一章没有程序设计和API方面的深入学习,而是注重介绍了unix操作系统中的原始数据类型和系统原型函数,错误处理方面的知识. ____unistd.h____ 该文件包含了u ...

  6. unix进程的环境--unix环境高级编程读书笔记

    http://blog.csdn.net/xiaocainiaoshangxiao/article/category/1800937

  7. unix环境高级编程 读书笔记

    1.上班业余时间把书下载下来,第一章读完了,但是程序只能回家运行啦!Fighting!

  8. Unix环境高级编程学习笔记——fcntl

    写这篇文正主要是为了介绍下fcntl,并将我自己在学习过程中的一些理解写下来,不一定那么官方,也有错误,希望指正,共同进步- fcntl: 一个修改一打开文件的性质的函数.基本的格式是 int fcn ...

  9. 《UNIX环境高级编程》笔记--UNIX标准化及实现

    1.UNIX标准化 1.1.ISO C 1989 年后期,C程序设计语言的ANSI(American National Standards Institute) 标准X3. 15 9-1989得到批准 ...

随机推荐

  1. python课程设计笔记(一)开发环境配置

    今天开始学python,一个月后交成果?还是希望自己不要浮躁,认真地去学,有所付出也不期望太大回报. 现在还是一脸懵逼的状态,看着教程一点点来吧= = 毕竟我是最棒的最发光的阳光彩虹小白马! 1. 去 ...

  2. Android 自定义简单控件--星级评价

    效果图 实现 package com.easypass.carstong.view; import android.content.Context; import android.content.re ...

  3. 顺序容器之vector

    最近因为需要,在看C++ primer,哇,感觉这本书真不错,讲的细而且到位,而且大量的练习题,不愧为C++学习的经典书籍.今天看了顺序容器方面的内容,现在汇报一下: 一.什么是vector vect ...

  4. C++小程序(1)——文件整理工具

    网上下载的漫画是jpg或png之类的图片文件,用系统自带的图片管理器看不方便,想要能把图片想网页一样浏览的功能,找了很多图片管理器也没有带这个功能,于是就自己编写了一个小程序实现. 思想就是在图片目录 ...

  5. 话说普通的TPlink ip地址是192.168.1.2 在LAN里有台电脑共享打印机 ip 是192.168.0.2 计算机名为j02 然后我把这台电脑加到DMZ里,让根路由器同一网段的可以访问 但添加打印机的时候 提示 计算机名重复 后来在需要添加打印机电脑的hosts文件里加了 192.168.1.2 j02 式了一样不行 话说,这个打印机该怎么添加

    开启端口映射,从外网访问内网的文件共享: 已经在路由器里开了远端WEB管理设了端口,另外端口映射局域网里的一台电脑,比如WEB端口设的是8080,映射192.168.1.100到4877端口,现在我想 ...

  6. RabbitMQ学习笔记(3)----RabbitMQ Worker的使用

    1. Woker队列结构图 这里表示一个生产者生产了消息发送到队列中,但是确有两个消费者在消费同一个队列中的消息. 2. 创建一个生产者 Producer如下: package com.wangx.r ...

  7. BZOJ 4942 NOI2017 整数 (压位+线段树)

    题目大意:让你维护一个数x(x位数<=3*1e7),要支持加/减a*2^b,以及查询x的第i位在二进制下是0还是1 作为一道noi的题,非常考验写代码综合能力,敲+调+借鉴神犇的代码 3个多小时 ...

  8. JavaScript变量提升(Hoisting)的小案例

    变量提升(Hoisting)的小案例 执行以下代码的结果是什么?为什么? 答案 这段代码的执行结果是undefined 和 2. 这个结果的原因是,变量和函数都被提升(hoisted) 到了函数体的顶 ...

  9. 学渣乱搞系列之dp斜率优化

    学渣乱搞系列之dp斜率优化 By 狂徒归来 貌似dp的斜率优化一直很难搞啊,尤其是像我这种数学很挫的学渣,压根不懂什么凸包,什么上凸下凸的,哎...说多了都是泪,跟wdd讨论了下,得出一些结论.本文很 ...

  10. 保留全部Android crash信息

    保留全部Android crash信息 framework/base/core/java/com/android/internal/os/RuntimeInit.java 又一次以下这个函数,增加自己 ...