• 1. Linux环境高级编程
  • 2. 第二讲 文件的操作
  • 3. 第二讲 文件的操作文件I/O(第三章) 文件和目录(第四章)
  • 4. 第二讲 文件的操作文件I/O(第三章) 文件和目录(第四章)
  • 5. 文件I/O文件的基本操作(打开、定位、读写、关闭) I/O效率 文件共享 其他重要I/O函数
  • 6. 文件I/O文件的基本操作(打开、定位、读写、关闭) I/O效率 文件共享 其他重要I/O函数
  • 7. 文件操作基本顺序打开 open 创建 creat 定位 lseek 读 read 写 write 关闭 close
  • 8. open函数用于打开或者创建一个文件 函数原型 #include int open(const char* pathname, int oflag, ...) 参数 第一个参数pathname:要打开或者创建的文件名 第二个参数oflag:用于指定文件打开模式、标志等信息。
  • 9. open函数第二个参数oflag: Linux头文件已经为文件打开模式、标志等定义了若干的宏 oflag需要指定这些宏 宏定义在/usr/include/bits/fcntl.h中 在该头文件中,只读打开标志被定义为: #define O_RDONLY 00
  • 10. open函数oflag: 文件打开模式标志 以下三个标志必须指定一个且只能指定一个 O_RDONLY : 只读打开 O_WRONLY : 只写打开 O_RDWR : 读写打开 其他文件标志 下面的标志是可以选择的,可通过C语言的或运算与文件打开标志进行组合
  • 11. open函数oflag 其他文件标志: O_APPEND:每次写的数据都添加到文件尾 O_TRUNC:若此文件存在,并以读写或只写打开,则文件长度为0 O_CREAT:若文件不存在,则创建该文件。此时,open函数需要第三个参数,用于指定该文件的访问权限位(后面描述) O_EXCL:若同时指定了O_CREAT标志,而文件已经存在,则会出错。可用于测试文件是否存在
  • 12. open函数返回值 int open(const char* pathname, int oflag, …) 返回值:整型数据 成功时,返回文件描述符 出错时,返回-1
  • 13. open函数返回值 int open(const char* pathname, int oflag, …) 返回值:整型数据 成功时,返回文件描述符 出错时,返回-1 什么是文件 描述符?
  • 14. open函数返回值 int open(const char* pathname, int oflag, …) 返回值:整型数据 成功时,返回文件描述符 出错时,返回-1 什么是文件 描述符?已打开文件 的索引
  • 15. open函数返回值 int open(const char* pathname, int oflag, …) 返回值:整型数据 成功时,返回文件描述符 出错时,返回-1 什么是文件 描述符?已打开文件 的索引通过索引找 到已打开文件
  • 16. 文件描述符文件描述符的本质是什么? 通过文件描述符怎么样能找到需访问的文件? 需要了解进程打开文件时,内核创建或涉及到的一系列数据结构
  • 17. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志............dentryd_inode索引节点号文件各信息inode..............
  • 18. 进程打开文件的内核数据结构task_struct.........进程控制块 PCB
  • 19. 进程打开文件的内核数据结构task_struct.........files.........struct task_struct{ ............. struct files_struct *files; ............. };
  • 20. 进程打开文件的内核数据结构task_struct.........files...................files_structfiles_struct该结构体包含了: 进程已打开文件表
  • 21. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]files_struct..............struct file **fd;
  • 22. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfile..............文件对象:代表 一个已打开的文件
  • 23. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志..............文件偏移量各种文 件标志文件相关目录项struct dentry *f_dentry;
  • 24. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志............dentry..............
  • 25. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志............dentryd_inode..............struct inode *d_inode;
  • 26. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志............dentryd_inode索引节点号文件各信息inode..............
  • 27. 索引节点文件系统索引节点的信息,存储在磁盘上 当需要时,调入内存,填写VFS的索引节点(即inode结构) 每个文件都对应了一个索引节点 通过索引节点号,可以唯一的标识文件系统中的指定文件
  • 28. 索引节点struct inode{ ........................ unsigned long i_no; umode_t i_mode; uid_t i_uid; gid_t i_gid; off_t i_size; time_t i_atime; time_t i_mtime; };
  • 29. 索引节点struct inode{ ........................ unsigned long i_no; umode_t i_mode; uid_t i_uid; gid_t i_gid; off_t i_size; time_t i_atime; time_t i_mtime; }; 索引节点号
  • 30. 索引节点struct inode{ ........................ unsigned long i_no; umode_t i_mode; uid_t i_uid; gid_t i_gid; off_t i_size; time_t i_atime; time_t i_mtime; }; 文件类型访问权限
  • 31. 索引节点struct inode{ ........................ unsigned long i_no; umode_t i_mode; uid_t i_uid; gid_t i_gid; off_t i_size; time_t i_atime; time_t i_mtime; }; 文件拥有者ID
  • 32. 索引节点struct inode{ ........................ unsigned long i_no; umode_t i_mode; uid_t i_uid; gid_t i_gid; off_t i_size; time_t i_atime; time_t i_mtime; }; 文件拥有者 所在组ID
  • 33. 索引节点struct inode{ ........................ unsigned long i_no; umode_t i_mode; uid_t i_uid; gid_t i_gid; off_t i_size; time_t i_atime; time_t i_mtime; }; 文件大小
  • 34. 索引节点struct inode{ ........................ unsigned long i_no; umode_t i_mode; uid_t i_uid; gid_t i_gid; off_t i_size; time_t i_atime; time_t i_mtime; }; 文件最后访问时间
  • 35. 索引节点struct inode{ ........................ unsigned long i_no; umode_t i_mode; uid_t i_uid; gid_t i_gid; off_t i_size; time_t i_atime; time_t i_mtime; }; 文件最后修改时间
  • 36. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志............dentryd_inode索引节点号文件各信息inode
  • 37. 文件描述符task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志............dentryd_inode索引节点号文件各信息inodeopen函数返回的文件描述符 已打开文件表的索引
  • 38. 文件描述符文件描述符是已打开文件的索引,通过该值可以在fd_array表中检索相应的文件对象 文件描述符是一个非负的整数 文件描述符0、1、2分别对应于标准输入、标准输出、标准出错,在进程创建时,已经打开。
  • 39. Open函数(续)Open函数在内核完成的工作: 39
  • 40. Namei 40
  • 41. 程序演示 open函数出错处理(2.1) errno.h头文件中,定义了errno:当API调用出错时,errno说明出错的具体原因 可简单地将errno理解成整型数据 出错信息转换成可读字符串 #include char* strerror(int errno);
  • 42. 程序演示 open函数出错处理 以前的定义:extern int errno; 多线程环境: extern int * __errno_location(); #define errno (*__errno_location())
  • 43. perror函数perror函数根据当前的errno,输出一条出错信息 函数原型 #include void perror(const char* msg); 该函数输出: msg指向的字符串: errno对应的出错信息43
  • 44. 文件操作基本顺序打开 open 创建 creat 定位 lseek 读 read 写 write 关闭 close
  • 45. creat 函数用于创建一个新文件 函数原型 int creat(const char *pathname, mode_t mode) 参数 pathname:要创建的文件名(包括路径信息) mode:同open的第三个参数,讨论文件的访问权限位时分析 返回值 成功返回只写打开的文件描述符 出错返回-1
  • 46. creat函数creat函数的功能可以用open函数实现 open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode); 为什么需要指定O_TRUNC标志 当文件存在时,调用creat函数,会将文件的大小变为0(程序演示2.2)
  • 47. creat函数 creat函数缺点:它以只写方式打开所创建的文件。若要创建一个临时文件,并先写该文件,然后又读该文件,则必须先调用creat,close,然后再open。简便方法: open(pathname, O_RDWR | O_CREAT | O_TRUNC, mode);
  • 48. 文件操作基本顺序打开 open 创建 creat 定位 lseek 读 read 写 write 关闭 close
  • 49. lseek函数lseek函数用于修改当前文件偏移量 当前文件偏移量的作用 规定了从文件什么地方开始进行读、写操作 通常,读、写操作结束时,会使文件偏移量增加读写的字节数 当打开一个文件时,除非指定了O_APPEND标志,否则偏移量被设置为0
  • 50. lseek函数函数原型: off_t lseek(int filedes, off_t offset, int whence) 参数 第一个参数filedes:open/creat函数返回的文件描述符 第二个参数offset: 相对偏移量:需结合whence才能计算出真正的偏移量 类型off_t:通常情况下是32位数据类型
  • 51. lseek函数参数 第三个参数Whence:该参数取值是三个常量之一 SEEK_SET: 当前文件偏移量为: 距文件开始处的offset个字节SEEK_CUR: 当前文件偏移量为: 当前文件偏移量+offset(可正可负)SEEK_END: 当前文件偏移量为: 当前文件长度+offset(可正可负)
  • 52. lseek函数返回值: 若成功,返回新的文件偏移量 若出错,返回-1 获得当前的偏移量 off_t CurrentPosition; CurrentPosition = lseek(fd, 0, SEEK_CUR); lseek操作并不引起任何I/O操作,只是修改内核中的记录
  • 53. 进程打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志............dentryd_inode索引节点号文件各信息inode
  • 54. 空洞文件使用lseek修改文件偏移量后,当前文件偏移量有可能大于文件的长度 在这种情况下,对该文件的下一次写操作,将加长该文件 这样文件中形成了一个空洞。对空洞区域进行读,均返回00100150200lseek(fd, 50, SEEK_END) write(fd, buf, 50)文件长度是多少? 200?150?
  • 55. 空洞文件演示程序(2.3) #od file.hole
  • 56. 文件操作基本顺序打开 open 创建 creat 定位 lseek 读 read 写 write 关闭 close
  • 57. read函数用于从文件中读出数据 函数原型 ssize_t read(int fd, void *buff, size_t nbytes) 参数 第一个参数fd:文件描述符 第二个参数buff:指向缓冲区,用于存放从文件读出的数据 第三个参数nbytes:unsigned int;需要从文件中读出的字节数 缓冲区的大小>=nbytes
  • 58. read函数返回值 返回值类型:ssize_t,即int 出错:返回-1 成功:返回从文件中实际读到的字节数 当读到文件结尾时,则返回0
  • 59. read函数很多情况下,read实际读出的字节数都小于要求读出的字节数 读普通文件,在读到要求的字节数之前,就到达了文件尾端 当从终端设备读时,通常一次最多读一行 当从网络读时,网络中的缓冲机构可能造成read函数返回值小于所要求读出的字节数 某些面向记录的设备,如磁带,一次最多返回一个记录 ........................
  • 60. Read算法60
  • 61. 文件操作基本顺序打开 open 创建 creat 定位 lseek 读 read 写 write 关闭 close
  • 62. write函数用于向文件里面,写入数据 函数原型 ssize_t write(int fd, const void *buff, size_t nbytes); 参数 第一个参数fd:文件描述符 第二个参数buff:指向缓冲区,存放了需要写入文件的数据 第三个参数nbytes:需要写入文件的字节数
  • 63. write函数返回值 返回值类型:ssize_t,即int 出错:返回-1 成功:返回实际写入文件的字节数 write出错的原因 磁盘满 没有访问权限 超过了给定进程的文件长度限制 .....................
  • 64. write函数当从文件中间某处写入数据时,是插入操作?覆盖操作?还是不能写?(程序演示2.4) 当以O_APPEND选项打开一个文件时,能否使用lseek指定文件偏移量?指定之后,从文件什么地方开始进行写?读操作又是如何?(程序演示2.5)
  • 65. 文件操作基本顺序打开 open 创建 creat 定位 lseek 读 read 写 write 关闭 close
  • 66. close函数用于关闭一个已打开的文件 函数原型 int close(int filedes) 返回值 成功返回0 出错返回-1 参数 filedes:文件描述符
  • 67. close函数当clsoe函数关闭文件时,会释放进程加在该文件上的所有记录锁 内核会对进程打开文件表、文件对象、索引节点表项等结构进行修改,释放相关的资源 当进程退出时,会关闭当前所有已打开的文件描述符
  • 68. 文件操作基本顺序打开 open 创建 creat 定位 lseek 读 read 写 write 关闭 close
  • 69. 文件I/O文件的基本操作(打开、定位、读写、关闭) I/O效率 文件共享 其他重要I/O函数
  • 70. I/O效率程序3-3#define BUFFSIZE 4096 int main() { int n; char buf[BUFFSIZE]; while((n = read(STDIN_FILENO, buf, BUFFSIZE))>0) if(write(STDOUT_FILENO, buf, n) != n) err_sys(“write error”); return 0; }从标准输入读数据 然后写至标准输出对标准输入和标准输出 进行了重定向: $ ./test < file1 >/dev/null从文件file1读数据 然后写至设备/dev/null程序中,影响效率的关键: BUFFSIZE的取值
  • 71. I/O效率BUFFSIZE的取值系统CPU时间
  • 72. I/O效率原因 Linux文件系统采用了某种预读技术 当检测到正在进行顺序读取时,系统就试图读入比应用程序所要求的更多数据 并假设应用程序很快就会读这些数据 当BUFFSIZE增加到一定程度后,预读就停止了
  • 73. 文件I/O文件的基本操作(打开、定位、读写、关闭) I/O效率 文件共享 其他重要I/O函数
  • 74. 打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志............dentryd_inode索引节点号文件各信息inode
  • 75. 打开文件的内核数据结构task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志索引节点号文件各信息inode
  • 76. 文件共享进程之间的文件共享 进程内的文件共享
  • 77. 两个独立进程各自打开同一个文件task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志索引节点号文件各信息inodetask_struct.........files.......................files_structfd[0]fd[1]................fd[4]...........files_structfilef_posf_dentry文件标志进程A进程B
  • 78. 两个独立进程各自打开同一个文件每个进程都有自己的当前文件偏移量 在完成每个write后,当前文件偏移量即增加所写的字节数 如果用O_APPEND标志打开了一个文件,则该标志存储在file结构体中。每次执行写操作时,当前偏移量首先被设置为文件长度
  • 79. 不同进程共享文件对象task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志索引节点号文件各信息inodetask_struct.........files.......................files_structfd[0]fd[1]................fd[4]files_struct进程A进程B进程A进程B 共享了文件偏移量存在竞争
  • 80. 进程内共享文件task_struct.........files.......................files_structfd[0]fd[1]fd[2]fd[3]...........files_structfilef_posf_dentry文件标志索引节点号文件各信息inode造成的原因,通常是 调用了dup或dup2函数
  • 81. dup函数用于复制一个已经存在的文件描述符 函数原型 int dup(int filedes); 返回值 成功返回新的文件描述符 出错返回-1 参数 filedes:文件描述符
  • 82. dup函数的作用task_struct.........files.......................files_structfd[0]fd[1]fd[2].........................files_structfilef_posf_dentry文件标志索引节点号文件各信息inode调用dup函数之前int fd = dup(1);fd[3]当前未占用文件描述符中的最小值
  • 83. dup函数的作用task_struct.........files.......................files_structfd[0]fd[1]fd[2].........................files_structfilef_posf_dentry文件标志索引节点号文件各信息inodefd[3]使新老文件描述符,都指向 同一个文件对象
  • 84. dup2函数用于复制一个已经存在的文件描述符 函数原型 int dup2(int filedes, int filedes2); dup和dup2的区别 dup返回的新文件描述符一定是当前可用描述符中的最小值 dup2则将文件描述符复制到指定位置,即将filedes复制到filedes2 如果filedes2已经打开,dup2则先将其关闭;若filedes2等于filedes,则直接返回filedes,而不关闭
  • 85. dup与dup2的区别假设进程已打开文件描述符0、1、2 调用dup2(1, 6),dup2返回值是多少? 然后再调用dup(6),dup返回值是多少? 程序演示验证(2.6)
  • 86. dup函数的作用task_struct.........files.......................files_structfd[0]fd[1]fd[2].........................files_structfilef_posf_dentry文件标志索引节点号文件各信息inode...............fd[6]
  • 87. dup函数的作用task_struct.........files.......................files_structfd[0]fd[1]fd[2].........................files_structfilef_posf_dentry文件标志索引节点号文件各信息inodefd[3]..............fd[6]
  • 88. 文件I/O文件的基本操作(打开、定位、读写、关闭) I/O效率 文件共享 其他重要I/O函数
  • 89. 其他重要的I/O函数sync、fsync、fdatasync函数 fcntl函数 ioctl函数
  • 90. sync/fsync/fdatasync函数通常Linux实现在内核中设有缓冲区高速缓存或页面高速缓存 大多数的磁盘I/O都通过缓冲区进行 当将数据写入文件时,内核通常先将数据复制到某一个缓冲区中 如果该缓冲区满或者内核需要重用该缓冲区,则将该缓冲排入到输出队列 等到其达到队首时,才进行实际的磁盘读写操作 延迟写
  • 91. sync/fsync/fdatasync函数磁 盘文件系统 高速缓存应 用 程 序用户模式内核模式
  • 92. sync/fsync/fdatasync函数延迟写优点 减少了磁盘读写次数 延迟写缺点 降低了文件内容的更新速度 当系统发生故障,高速缓冲区中的内容可能丢失 解决办法 对缓冲区进行清理,希望将数据写入到磁盘 sync、fsync、fdatasync起到了刷缓存的作用
  • 93. sync函数sync 原型: void sync(); 将所有修改过的缓冲区排入写队列,然后就返回 并不等待实际的写磁盘操作结束 sync函数针对的是所有修改过的缓冲区,并不仅仅针对某个被修改过的文件 通常称为update的系统守护进程会周期性地调用sync函数,即保证定期冲洗内核缓冲区
  • 94. fsync函数函数原型: int fsync(int filedes); 参数与返回值: filedes:文件描述符 返回值:成功返回0,出错返回-1 fsync函数只对文件描述符filedes指定的单一文件起作用 并且等待写磁盘操作结束后才返回
  • 95. fdatasync函数函数原型 int fdatasync(int filedes); 参数与返回值 filedes:文件描述符 返回值:成功返回0,出错返回-1 fdatasync和fsync类似,但它只影响文件的数据部分;而fync不仅影响文件的数据,还同步更新文件的属性。
  • 96. 对比syncfsyncfdatasync是否等待写否是是是否更新数据否是是是否更新属性否是否
  • 97. 其他重要的I/O函数sync、fsync、fdatasync函数 fcntl函数 ioctl函数
  • 98. fcntl函数用于改变已经打开文件的性质 函数原型 int fcntl(int filedes, int cmd, .../* int arg */); 返回值 成功时,返回值依赖于第二个参数cmd 出错时,返回-1 参数 第一个参数filedes:已打开文件的文件描述符
  • 99. fcntl函数第二个参数cmd的五种取值方式: 复制一个现存的描述符(cmd=F_DUPFD) 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD) 获得/设置文件状态标志(cmd=F_GETFL或F_SETFL) 获得/设置异步I/O信号接收进程(cmd=F_GETOWN或F_SETOWN) 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)
  • 100. cmd五种取值方式F_DUPFD 复制文件描述符filedes,与dup(2)类似 fcntl返回新文件描述符 新描述符是尚未打开的各描述符中,大于或等于第三个参数值中,各值的最小值 例子:假设文件描述符0、1、2被占用, fcntl(1, F_DUPFD, 5)返回什么??? fcntl(2, F_DUPFD, 1)返回什么???
  • 101. 与dup、dup2的异同fcntl函数与dup、dup2函数均用于复制文件描述符,即使不同的文件描述符指向同一个文件对象 dup(filedes)等价于 fcntl(filedes, F_DUPFD, 0); dup2(filedes, filedes2)不完全等价于 close(filedes2); fcntl(filedes, F_DUPFD, filedes2);
  • 102. 与dup、dup2的异同fcntl与dup2不完全等价 dup2是一个原子操作,而close与fcntl则包括两个函数调用。 在close和fcntl之间可能被信号打断 dup2与fcntl之间有某些不同的errno
  • 103. cmd五种取值方式F_DUPFD F_GETFD 将文件描述符filedes对应的标志,作为返回值返回。 当前只定义了一个文件描述符标志FD_CLOEXEC F_SETFD 设置文件描述符filedes对应的标志。新标志按照第三个参数设置。
  • 104. cmd五种取值方式F_GETFL fcntl函数返回文件描述符filedes对应的文件状态标志 文件状态标志包括: O_RDONLY O_WRONLY O_RDWR O_APPEND O_NONBLOCK 非阻塞方式 O_SYNC 等待写方式 O_ASYNC 异步方式(仅4.3+BSD)
  • 105. cmd五种取值方式F_SETFL 将fcntl函数的第三个参数,设置为文件状态标志 可以更改的标志包括:O_APPEND、O_NONBLOCK、O_SYNC、O_ASYNC F_GETOWN 获取当前接收SIGIO和SIGURG信号的进程ID或进程组ID
  • 106. cmd五种取值方式F_SETOWN 设置接收SIGIO和SIGURG信号的进程ID或进程组ID 第三个参数arg: arg>0时,表示一个进程ID arg<0时,其绝对值表示一个进程组ID
  • 107. fcntl函数--实例1(2.7)实例1:获取文件状态标志 代码演示 int fd = open(.......); int val = fcntl(fd, F_GETFL); int accmode = val & O_ACCMODE;O_ACCMODE=3 0......0011O_RDONLY=0 O_WRONLY=1 O_RDWR=2 对应的是最低的两位bit取val最低的两位即获取了文件打开模式
  • 108. fcntl函数--实例1对于非打开模式标志: if(val & O_APPEND) {//文件状态标志中包括O_APPEND }O_APPEND=1024 第11个bit为1,其余为0. 即第11位对应了O_APPEND标志取val第11位查看是否为1
  • 109. fcntl函数--实例2实例2:添加或删除某个文件状态标志 添加或删除某个文件描述符标志或文件状态标志时, 先将现有标志值存放在某个变量中,再对该变量进行修改,最后将该变量设置为新的标志。 不能只是执行F_SETFD或F_SETFL命令,这样会关闭以前设置的标志位。
  • 110. fcntl函数--实例2代码:void set_fl(int fd, int flags) { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0) err_sys("fcntl F_GETFL error"); val |= flags; if (fcntl(fd,F_SETFL,val) < 0) err_sys("fcntl F_SETFL error"); }若清除某标志: val &= ~flags;
  • 111. 其他重要的I/O函数sync、fsync、fdatasync函数 fcntl函数 ioctl函数
  • 112. ioctl函数I/O操作的杂物箱 其实现的功能往往和具体的设备有关系 设备可以自定义自己的ioctl命令 操作系统提供了通用的ioctl命令 ioctl类似于windows的DeviceIoControl函数
  • 113. 第三章 文件I/O小节文件的基本操作(打开、定位、读写、关闭) I/O效率 文件共享 其他重要I/O函数
  • 114. 第二讲 文件的操作文件I/O(第三章) 文件和目录(第四章)
  • 115. 文件和目录ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号链接 目录操作
  • 116. 文件和目录ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号链接 目录操作
  • 117. ext2文件系统在磁盘上的组织ext2文件系统是Linux土生土长的文件系统 ext2是ext(Extended File System)的完善,因此,ext2为The Second Extended File System ext2文件系统加上日志支持,即ext3 ext2和ext3在磁盘上的布局大致相同,只是ext3多出了一个特殊的inode,用于记录文件系统日志
  • 118. 磁盘布局假设ext2文件系统所占的分区
  • 119. 磁盘布局分区被划分成一个个的块block,每个块均有编号 同一个文件系统中,block的大小都是相同的 不同的文件系统,block的大小可以不同 典型的block大小为1k或者4k块1.........块m-1块m..........块p块0
  • 120. 磁盘布局分区被划分成一个个的块block块1.........块m-1块m..........块p块0块组0块组1块组2..........块组n-1块组n 若干块聚集在一起,形成一个块组 分区被划分成若干个块组 每个块组所包括的块个数相同
  • 121. 磁盘布局分区被划分成一个个的块block块1.........块m-1块m..........块p块0块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块
  • 122. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块 每个块组都包含有一个相同的超级块 超级块重复的主要目的:灾难恢复 超级块用于存放文件系统的基本信息
  • 123. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块 s_magic:ext2文件系统标识0xef53 s_log_block_size:可由它得出块大小 块组包括的块个数、包括的索引节点个数,总的块个数
  • 124. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块 bg_block_bitmap:指向块位图 bg_inode_bitmap:指向索引节点位图 bg_inode_table:指向索引节点表
  • 125. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块 当某个bit为1,表示该bit对应的数据块被占用 当某个bit为0,表示该bit对应的数据块未被占用
  • 126. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块 当某个bit为1,表示该bit对应的索引节点被占用 当某个bit为0,表示该bit对应的索引节点未被占用
  • 127. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块 索引节点表由若干个索引节点组成 一个索引节点对应了一个文件(目录也是一种文件) 每个索引节点都有一个编号,这个编号是全局的,从1开始计数
  • 128. 索引节点包含的信息struct ext3_inode { __u16 i_mode; //File mode __u16 i_uid; //Low 16 bits of Owner Uid __u32 i_size; //文件大小 __u32 i_atime; //Access time __u32 i_ctime; //Creation time __u32 i_mtime; //Modification time __u16 i_gid; //Low 16 bits of Group Id __u16 i_links_count; //Links count __u32 i_flags; //File flags __u32 i_block[EXT3_N_BLOCKS]; //一组 block 指针, //存储了文件的内容 ................................................ };
  • 129. 目录目录也是一种文件 通过其索引节点中的i_block字段,可以找到存放目录文件内容的数据块 目录的内容具有固定的格式 目录文件按照固定的格式记录了目录包含了哪些文件
  • 130. 目录项目录中每个文件,都对应了一个目录项 若干个目录项构成了目录文件的内容 struct ext3_dir_entry_2 { __u32 inode; /* Inode 号数 */ __u8 file_type; char name[EXT3_NAME_LEN]; //File name .......................... };
  • 131. 问题如何在ext2文件系统中找到一个文件? 假设查找文件/root/test 假设/root的索引节点号已知,为1400
  • 132. 磁盘布局超级块组描述 符块位图索引节 点位图索引节 点表数据块 s_magic:ext2文件系统标识0xef53 s_log_block_size:可由它得出块大小 块组包括的块个数、块组包括的索引节点个数,总的块个数 s_inodes_per_group1400-13001399商4,余199
  • 133. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块 bg_block_bitmap:指向块位图 bg_inode_bitmap:指向索引节点位图 bg_inode_table:指向索引节点表
  • 134. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块.........索引节 点1300..........索引节 点1400..........
  • 135. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块.........索引节 点1300..........索引节 点1400..........块指针..........
  • 136. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块.........索引节 点1300..........索引节 点1400..........块指针...................数据块..........数据块..........
  • 137. 磁盘布局块组0块组1块组2..........块组n-1块组n超级块组描述 符块位图索引节 点位图索引节 点表数据块.........索引节 点1300..........索引节 点1400..........块指针...................数据块..........数据块..........索引节点号2300文件名test....................
  • 138. 文件和目录ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号链接 目录操作
  • 139. stat函数用于获取有关文件的信息结构 函数原型 int stat(const char* restrict pathname, struct stat* restrict buf);
  • 140. restrict关键字restrict关键字C99标准引入的 只能用于限定指针 表明指针是访问一个数据对象的唯一且初始的方式
  • 141. restrict关键字int ar[10]; int* restrict restar=(int *)malloc(10*sizeof(int)); int* par=ar; for(int n=0; n<10; n++) { par[n]+=5; restar[n]+=5; ar[n]*=2; par[n]+=3; restar[n]+=3; }对于malloc分配的这段内存 只能通过restar访问int* pnew = restar;
  • 142. restrict关键字int ar[10]; int* restrict restar=(int *)malloc(10*sizeof(int)); int* par=ar; for(int n=0; n<10; n++) { par[n]+=5; restar[n]+=5; ar[n]*=2; par[n]+=3; restar[n]+=3; }对于malloc分配的这段内存 只能通过restar访问int* pnew = restar;
  • 143. restrict关键字int ar[10]; int* restrict restar=(int *)malloc(10*sizeof(int)); int* par=ar; for(int n=0; n<10; n++) { par[n]+=5; restar[n]+=5; ar[n]*=2; par[n]+=3; restar[n]+=3; }对restar的操作进行优化, restar[n] += 8 无法对par的操作优化 par[n] += 8 什么是编译单元?
  • 144. stat函数用于获取有关文件的信息结构 函数原型 int stat(const char* restrict pathname, struct stat* restrict buf); 参数与返回值 第一个参数pathname:文件名,需要获取该文件的信息 第二个参数buf:stat函数将pathname对应的文件信息,填入buf指向的stat结构中 返回值:0成功;-1出错
  • 145. stat结构体struct stat { ....................................................... ino_t st_ino; /* inode number*/ mode_t st_mode; /* file type & mode */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* total size, in bytes */ unsigned long st_blksize; /* blocksize */ unsigned long st_blocks; /* number of blocks allocated time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of inode last change };
  • 146. fstat、lstat函数用于获取有关文件的信息结构 函数原型 int stat(const char* restrict pathname, struct stat* restrict buf); int fstat(int filedes, struct stat *buf); int lstat(const char* restrict pathname, struct stat* restrict buf); lstat返回符号链接本身的信息 stat返回符号链接所引用的文件信息
  • 147. fstat、lstat函数用于获取有关文件的信息结构 函数原型 int stat(const char* restrict pathname, struct stat* restrict buf); int fstat(int filedes, struct stat *buf); int lstat(const char* restrict pathname, struct stat* restrict buf); Stat通过文件名返回文件的信息 fstat通过文件描述符
  • 148. 程序演示演示stat的使用(2.8)
  • 149. 文件和目录ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号链接 目录操作
  • 150. 文件的基本性质文件类型 用户ID和组ID 文件访问权限 新文件和目录的所有权 文件时间
  • 151. 文件的基本性质文件类型 用户ID和组ID 文件访问权限 新文件和目录的所有权 文件时间
  • 152. 文件类型UNIX或Linux系统中的常见文件类型有: 普通文件 目录文件 字符特殊文件 提供对设备不带缓冲的访问 块特殊文件 提供对设备带缓冲的访问 FIFO文件 用于进程间的通信,命名管道 套接口文件 用于网络通信 符号链接 使文件指向另一个文件152
  • 153. stat结构体struct stat { ....................................................... ino_t st_ino; /* inode number*/ mode_t st_mode; /* file type & mode */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* total size, in bytes */ unsigned long st_blksize; /* blocksize */ unsigned long st_blocks; /* number of blocks allocated time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of inode last change };包含了文件 类型信息
  • 154. 文件类型的判定使用如下的宏,判断文件类型 普通文件 S_ISREG() 目录文件 S_ISDIR() 字符特殊文件 S_ISCHR() 块特殊文件 S_ISBLK() FIFO文件 S_ISFIFO() 套接口文件 S_ISSOCK() 符号连接 S_ISLINK()154
  • 155. 文件类型示例代码: struct stat buf; lstat( filename, &buf); if (S_ISDIR(buf.st_mode)) cout << “directory” << endl; 注意,此处必须用lstat获取文件信息,而不用stat, 为什么? 155
  • 156. 程序演示文件类型的判定(2.9)156
  • 157. 文件的基本性质文件类型 用户ID和组ID 文件访问权限 新文件和目录的所有权 文件时间
  • 158. 用户ID和组ID第一种ID: Linux是一个多用户的操作系统。每个用户都有一个ID,用以唯一标识该用户。这个ID,被称为UID。 每个用户都属于某一个组,组也有一个ID。这个ID,被称为组ID,GID。 第二种ID:文件所有者相关 文件所有者ID:拥有某文件的用户的ID 文件所有者组ID:拥有某文件的用户所属组的ID
  • 159. stat结构体struct stat { ....................................................... ino_t st_ino; /* inode number*/ mode_t st_mode; /* file type & mode */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* total size, in bytes */ unsigned long st_blksize; /* blocksize */ unsigned long st_blocks; /* number of blocks allocated time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of inode last change };
  • 160. 用户ID和组ID第三种ID:实际用户ID和实际组ID 进程的实际用户ID:运行该进程的用户的ID 进程的实际组ID:运行该进程的用户所属的组ID 第四种ID:有效用户ID和有效组ID 进程的有效用户ID:用于文件访问权限的检查 进程的有效组ID: 程序演示(2.10)大多数情况下 有效用户/组ID=实际用户/组ID
  • 161. 用户ID和组ID设置用户ID位和设置组ID位 在可执行文件的权限标记中,有一个“设置用户ID位” 若该位被设置,表示:执行该文件时,进程的有效用户ID变为文件的所有者 对于设置组ID位类似 通过命令行设置用户ID位(2.11) chmod u+s filename chmod g+s filename chmod u-s filename chmod g-s filename
  • 162. 用户ID和组ID第五种ID: 保存的设置用户ID 保存的设置组ID 上述两者在执行一个程序时包含了有效用户ID和有效组ID的副本
  • 163. 文件的基本性质文件类型 用户ID和组ID 文件访问权限 新文件和目录的所有权 文件时间
  • 164. 文件访问权限什么是文件访问权限?为什么要有访问权限? 每一个文件都有访问权限位,可将其分成三类
  • 165. 文件访问权限针对文件所有者针对与文件所有者 同组的用户针对非同组的用户指定所有者是否可读指定组用户是否可读指定其他用户 是否可读指定所有者是否可写指定组用户是否可写指定其他用户 是否可写指定所有者 是否可执行指定组用户 是否可执行指定其他用户 是否可执行
  • 166. stat结构体struct stat { ....................................................... ino_t st_ino; /* inode number*/ mode_t st_mode; /* file type & mode */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* total size, in bytes */ unsigned long st_blksize; /* blocksize */ unsigned long st_blocks; /* number of blocks allocated time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of inode last change };包含了文件 访问权限位
  • 167. st_mode字段76543210111098 st_mode的低11bit
  • 168. st_mode字段76543210111098 st_mode的低11bit针对文件所有者的访问权限
  • 169. st_mode字段76543210111098 st_mode的低11bit指示文件所有者是否可执行指示文件所有者是否可写指示文件所有者是否可读
  • 170. st_mode字段76543210111098 st_mode的低11bit针对与文件所有者同组的用户的访问权限
  • 171. st_mode字段76543210111098 st_mode的低11bit指示组用户是否可执行指示组用户是否可写指示组用户是否可读
  • 172. st_mode字段76543210111098 st_mode的低11bit针对其他用户的访问权限
  • 173. st_mode字段76543210111098 st_mode的低11bit指示其他用户是否可执行指示其他用户是否可写指示其他用户是否可读
  • 174. st_mode字段76543210111098 st_mode的低11bit9个文件访问权限位
  • 175. 判定文件访问权限的屏蔽字(2.13)st_mode屏蔽意义S_IRUSR用户-读S_IWUSR用户-写S_IXUSR用户-执行S_IRGRP组-读S_IWGRP组-写S_IXGRP组-执行S_IROTH其他-读S_IROTH其他-写S_IWOTH其他-执行if(buf.st_mode & S_IRUSR) {用户可读} open的第三个参数 creat的第二个参数
  • 176. st_mode字段76543210111098 st_mode的低11bit9个文件访问权限位设置用户ID设置组ID粘住位
  • 177. 文件存取许可权(续)当打开一个任意类型的文件时,对该文件路径名中包含的每一个目录都应具有执行许可权; 读许可权允许读目录,获得该目录中所有文件名的列表。 目录具有执行权,表示可以搜索该目录(或进入该目录);177
  • 178. 文件存取许可权(续)为了在open函数中对一个文件指定O_TRUNC标志,必须对该文件具有写许可权; 为了在一个目录中创建一个新文件,必须对该目录具有写许可权和执行许可权; 为了删除一个文件,必须对包含该文件的目录具有写许可权和执行许可权,对该文件本身则不需要有读、写许可权; 如果用6个exec函数中的任何一个执行某个文件,都必须对该文件具有执行许可权。178
  • 179. 文件存取许可权(续)进程访问文件时,内核就进行文件存取许可权测试。这种测试可能涉及到文件的所有者ID、进程有效ID以及进程的添加组ID。两个所有者ID是文件的性质,而有效ID与添加组ID是进程的性质: 若进程的有效用户ID是0,则允许存取; 若进程的有效用户ID等于文件的所有者ID(即该进程拥有文件) 若所有者存取许可权被设置,则允许存取 否则拒绝存取179
  • 180. 文件存取许可权(续)若进程的有效组ID或进程的添加组ID之一等于文件组ID: 若组存取许可权被设置,则允许存取 否则拒绝存取 若其他用户存取许可权被设置,则允许存取,否则拒绝存取180
  • 181. 文件存取许可权(续)综上所述,内核按顺序执行上述4步测试。若进程拥有此文件,则按用户存取许可权批准或拒绝该进程对文件的存取-不查看组存取许可权。相类似,若进程并不拥有该文件,但进程属于某个适当的组,则按组存取许可权批准或拒绝该进程对文件的存取-不查看其他用户的许可权。181
  • 182. 为什么需要设置用户/组ID(2.12)每个用户都可以使用passwd命令修改密码 passwd命令需要修改/etc/passwd文件 ls -l /etc/passwd 该文件属于超级用户,非超级用户无修改权限 ls -l /usr/bin/passwd passwd设置了设置用户ID位182
  • 183. 文件的基本性质文件类型 用户ID和组ID 文件访问权限 新文件和目录的所有权 文件时间
  • 184. 新文件和目录的所有权新文件的所有者ID:即创建该文件的进程的有效用户ID 新文件的组ID:两种方式 创建该文件的进程的有效组ID 新文件所在目录的组ID Linux中的处理 取决于新文件所在目录的设置组ID是否被设置 若设置,新文件的组ID即目录的组ID 演示(2.14)
  • 185. 文件的基本性质文件类型 用户ID和组ID 文件访问权限 新文件和目录的所有权 文件时间
  • 186. 文件时间struct stat { ....................................................... ino_t st_ino; /* inode number*/ mode_t st_mode; /* file type & mode */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* total size, in bytes */ unsigned long st_blksize; /* blocksize */ unsigned long st_blocks; /* number of blocks allocated time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of inode last change };
  • 187. 文件时间字段说明st_atime文件数据的最后访问时间st_mtime文件数据的最后修改时间st_ctimei节点状态的最后更改时间i节点状态改变: 更改文件的访问权限、用户ID等等 但并未改变文件的实际内容
  • 188. utime函数用于更改一个文件的访问时间、修改时间 函数原型 int utime(const char* pathname, const struct utimbuf *times); 参数与返回值 返回值:0成功;-1出错 第一个参数pathname:文件名,即需要修改时间属性的文件
  • 189. utime函数参数与返回值 第二个参数times:指向utimbuf结构的常指针 struct utimbuf { time_t actime; //访问时间 time_t modtime; //修改时间 }; 当times=NULL时,使用当前时间更改文件的最后访问时间、最后修改时间 否则,使用utimbuf中相关字段进行修改自1970年1月1日 00:00:00,经过的秒数
  • 190. 文件的基本性质文件类型 用户ID和组ID 文件访问权限 新文件和目录的所有权 文件时间
  • 191. 文件和目录ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号链接 目录操作
  • 192. 修改文件属性的函数access函数 umask函数 chmod和fchmod函数 chown、fchown和lchown函数 truncate、ftruncate函数
  • 193. 修改文件属性的函数access函数 umask函数 chmod和fchmod函数 chown、fchown和lchown函数 truncate、ftruncate函数
  • 194. access函数用于按实际用户ID和实际组ID进行存取许可权测试 注意:此时不管设置用户ID和设置组ID 函数原型: int access(const char* pathname, int mode);
  • 195. access函数参数 第一个参数pathname:要测试的文件名 第二个参数mode:四种取值方式 R_OK 测试读许可权 W_OK 测试写许可权 X_OK 测试执行许可权 F_OK 测试文件是否存在 返回值 若成功则为0,出错则为-1open函数的O_CREAT 和O_EXCL合用
  • 196. access函数程序演示(2.15)
  • 197. 修改文件属性的函数access函数 umask函数 chmod和fchmod函数 chown、fchown和lchown函数 truncate、ftruncate函数
  • 198. umask函数用于为进程设置文件方式创建屏蔽字,即参与指定文件的访问权限 函数原型: mode_t umask(mode_t cmask); 参数和返回值 cmask:9个权限常量的组合(通过或运算,177页) 返回值:以前的文件方式创建屏蔽字
  • 199. umask函数程序演示(2.16) umask(0) 未设置任何屏蔽字,creat或open相关参数即指定了文件的访问权限 umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) 禁止所有组和其他用户的存取许可权 即使open/creat设置了也无用
  • 200. 修改文件属性的函数access函数 umask函数 chmod和fchmod函数 chown、fchown和lchown函数 truncate、ftruncate函数
  • 201. chmod函数用于改变现有文件的存取许可权 函数原型: int chmod(const char* pathname, mode_t mode); 参数和返回值 第一个参数pathname:要改变权限的文件 第二个参数mode:新的存取权限位组合 返回值:成功则为0,出错则为-1
  • 202. mode的取值--通过或运算组合常数说明对普通文件的影响对目录的影响S_ISUID设置-用户-ID执行时设置有效用户ID(不使用)S_ISGID设置-组-ID若组执行位设置, 则执行时置有效组ID将在目录中创建新文件的 组ID设置为目录的组IDS_ISVTX粘住位在交换区保存程序正文禁止在目录中删除和更名文件S_IRUSR用户读许可用户读文件许可组用户目录项S_IWUSR用户写许可用户写文件许可用户在目录中删除或创建文件S_IXUSR用户执行许可用户执行文件许可用户在目录中搜索给定路径名S_IRGRP组读许可组读文件许可组读目录项S_IWGRP组写许可组写文件许可组写目录项S_IXGRP组执行许可组执行文件许可组在目录中删除或创建文件S_IROTH其他读许可其他读文件许可其他读目录项S_IWOTH其他写许可其他写文件许可其他在目录中删除或创建文件S_IXOTH其他执行许可其他执行文件许可其他在目录中搜索给定路径名
  • 203. chmod函数进程的有效用户ID等于文件的所有者,或者进程具有超级用户权限,才能改变文件的许可权位。 chmod在下列条件下自动清除两个许可权位 如果试图设置普通文件的粘住位(S_ISVTX),而且又没有超级用户权限,则mode中的粘住位自动被关闭。这意味着只有超级用户才能设置普通文件的粘住位。
  • 204. chmod函数chmod在下列条件下自动清除两个许可权位 新创建文件的组ID可能不是调用进程所属的组(新文件的组ID可能是父目录的组ID),如果新文件的组ID不等于进程的有效组ID,以及进程没有超级用户权限,那么设置-组-ID位自动关闭。这就防止了用户创建一个设置-组-ID文件,而该文件是由并非该用户所属的组拥有的。
  • 205. 粘住位--st_mode字段76543210111098 st_mode的低11bit9个文件访问权限位设置用户ID设置组ID粘住位
  • 206. 粘住位在UNIX早期版本中,有一位被称为粘住位,如果一可执行程序文件的这一位被设置了,那么在该程序第一次执行并结束时,该程序正文被保存在交换区中,这使得下次执行该程序时能较快地将其装入内存。 正文:机器指令部分 交换区中,文件所占用的数据块是连续存放的;在文件系统中,数据块是随机存放的206
  • 207. fchmod函数用于改变现有文件的存取许可权 函数原型: int fchmod(int filedes, mode_t mode); 参数和返回值 第一个参数filedes:要改变权限的文件描述符 第二个参数mode:新的存取权限位组合 返回值:成功则为0,出错则为-1
  • 208. 修改文件属性的函数access函数 umask函数 chmod和fchmod函数 chown、fchown和lchown函数 truncate、ftruncate函数
  • 209. chown函数用于更改文件的用户ID和组ID 函数原型 int chown(const char* pathname, uid_t owner, gid_t group); 参数与返回值 第一个参数pathname:被改的文件名 第二个参数owner:文件新的所有者ID 第三个参数group:文件新的所有者所在组的ID 返回值:0成功;-1出错
  • 210. fchown、lchown函数函数原型 int fchown(int fd, uid_t owner, gid_t group); int lchown(const char *pathname, uid_t owner, gid_t group); lchown更改符号链接本身的所有者,而不是符号链接所指向的文件
  • 211. 权限问题超级用户进程可以更改文件的用户ID 非超级用户进程拥有某文件,可以更改该文件用户ID 程序演示(2.17)
  • 212. 权限问题非超级用户进程更改文件ID 进程有用该文件(有效用户ID等于文件的所有者ID) owner等于文件的用户ID,group等于进程的有效组ID或进程的添加组ID之一 你可以修改你所拥有的文件的组ID,但只能改到你所属于的组 若非超级用户进程调用成功后,文件的设置用户ID和设置组ID都被清除
  • 213. 修改文件属性的函数access函数 umask函数 chmod和fchmod函数 chown、fchown和lchown函数 truncate、ftruncate函数
  • 214. truncate函数用于改变文件的长度 函数原型 int truncate(const char* pathname, off_t length); 参数和返回值 pathname:欲改变长度的文件的文件名 length:要设置的文件的新长度 返回值:成功返回0,出错返回-1
  • 215. truncate函数当文件以前的长度>length时, 则超过length以外的数据将不复存在 当文件以前的长度
  • 216. ftruncate函数用于改变文件的长度 函数原型 int ftruncate(int fd, off_t length) 参数和返回值 fd:欲改变长度的文件的文件描述符 length:要设置的文件的新长度 返回值:成功返回0,出错返回-1
  • 217. 修改文件属性的函数access函数 umask函数 chmod和fchmod函数 chown、fchown和lchown函数 truncate、ftruncate函数
  • 218. 文件和目录ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号连接 目录操作
  • 219. 硬链接和符号连接link、unlink、remove、rename函数 符号连接 symlink、readlink函数
  • 220. 硬链接和符号连接link、unlink、remove、rename函数 符号连接 symlink、readlink函数
  • 221. link函数用于创建一个指向现存文件的连接 函数原型 int link(const char* existingpath, const char* newpath); 创建一个新目录项newpath,它引用现存文件existingpath。 若newpath已经存在,则返回出错 增加被引用文件的连接技术
  • 222. stat结构体struct stat { ....................................................... ino_t st_ino; /* inode number*/ mode_t st_mode; /* file type & mode */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* total size, in bytes */ unsigned long st_blksize; /* blocksize */ unsigned long st_blocks; /* number of blocks allocated time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of inode last change };
  • 223. 磁盘布局.........索引节 点1300..........索引节 点1400..........块指针...................数据块..........数据块..........索引节点号2300文件名test....................块指针..........数据块..........索引节点号2300文件名oth....................在这个目录中 创建连接
  • 224. Unlink和remove函数int unlink ( const char *pathname); int remove( const char *pathname); remove函数删除一个现存目录项,并将pathname 所引用的文件的连接计数减1。如果该文件还有其他连接,则仍可以通过其他连接存取该文件的数据。如果是最后一个连接,则内核还要删除文件的内容。但,如果有进程打开了该文件,其内容也不能删除。当进程关闭一个文件时,内核首先检查打开该文件的进程计数,如果为0,然后内核检查其连接计数,如果也为0,那么删除该文件内容。224
  • 225. Unlink和remove函数要解除对文件的连接,必须对包含该目录项的目录具有写和执行许可权。 如果pathname是符号连接,那么unlink的是符号连接文件本身,而不是该连接所引用的文件。 unlink是系统调用,而remove是库函数。remove的参数为普通文件时等价于unlink,为目录时等价于rmdir。225
  • 226. unlink函数程序演示 unlink创建临时文件(2.19) 能否用unlink实现程序的自我删除226
  • 227. rename函数用于更名文件或目录 函数原型 int rename(const char *oldname, const char * newname); 将原来的文件名oldname,更改为newname 成功返回0,出错返回-1227
  • 228. rename函数如果oldname是一个文件而不是目录,那么为该文件更名。如果newname已存在,而且是一个目录,则出错,如果不是目录,则先将该目录项删除,然后将oldname更名为newname 如果oldname是一个目录,那么为该目录更名。如果newname已存在,则它必须引用一个目录,而且该目录应当是空目录,此时,内核先将其删除,然后将oldname更名为newname。另外,当为一个目录更名时,newname不能包含oldname作为其路径前缀228
  • 229. rename函数作为一个特例,如果oldname和newname引用同一文件,则函数不做任何更改而成功返回。 应对包含两个文件的目录具有写和执行许可权。229
  • 230. 硬链接和符号连接link、unlink、remove、rename函数 符号连接 symlink、readlink函数
  • 231. 符号连接符号连接是对一个文件的间接指针。与硬连接不同的是,硬连接文件直接指向文件的i节点,并增加文件的引用计数。但符号连接是一种特殊类型的文件,其文件内容是被连接文件的路径名 创建符号连接(2.20) ln -s a.txt syma.txt
  • 232. 符号连接对于符号连接的处理,有些系统调用直接处理符号连接文件本身,而有些系统调用则跟踪符号连接文件到其所指向的文件。(如chown、remove、unlink等就直接处理符号连接文件,而大多数系统调用则跟随符号连接,如chmod、open、stat等)
  • 233. 硬链接和符号连接link、unlink、remove、rename函数 符号连接 symlink、readlink函数
  • 234. symlink函数用于创建符号连接 函数原型 int symlink(const char* actualpath, const char* sympath); 该函数创建了一个指向actualpath的新目录项sympath 并不要求actualpath已经存在,且actualpath和sympath不一定位于同一文件系统
  • 235. readlink函数用于读符号文件本身的内容 函数原型 int readlink(const char* pathname, char* buf, int bufsize); 成功返回读入buf的字节数,出错返回-1
  • 236. 文件和目录ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号连接 目录操作
  • 237. 目录操作mkdir、rmdir函数 读目录 chdir、fchdir、getcwd函数
  • 238. 目录操作mkdir、rmdir函数 读目录 chdir、fchdir、getcwd函数
  • 239. mkdir函数用于创建目录 函数原型 int mkdir(const char *pathname, mode_t mode); 参数与返回值 pathname:目录名 mode:指定目录的存取许可权 成功返回0,出错返回-1 .和..目录项自动创建
  • 240. rmdir函数用于删除空目录 函数原型 int rmdir(const char *pathname); 参数与返回值 pathname:目录名 成功返回0,出错返回-1
  • 241. 目录操作mkdir、rmdir函数 读目录 chdir、fchdir、getcwd函数
  • 242. 读目录的基本操作打开目录(opendir) 逐一读出目录项(readdir、rewinddir) 关闭目录(closedir)
  • 243. opendir函数用于打开目录 函数原型: DIR* opendir(const char* pathname); 返回值和参数 返回值:返回打开目录的索引结构,出错返回NULL pathname:要打开的目录名
  • 244. readdir函数用于读取目录项 函数原型: struct dirent *readdir(DIR *dp); 参数与返回值 dp:由opendir返回的 返回值:dp对应的目录中包含的一个目录项
  • 245. readdir函数dirent结构 struct dirent{ ino_t d_ino; //索引节点号 char d_name[NAME_MAX + 1]; //文件名 ................ }
  • 246. 获得目录下的所有文件DIR *dir; struct dirent *ptr; dir=opendir("/etc/rc.d"); while((ptr=readdir(dir))!=NULL) { printf("d_name: %s\n", ptr->d_name); }
  • 247. rewinddir函数用来设置目录流目前的读取位置为原来开头的读取位置 函数原型 void rewinddir(DIR *dp); 参数 dp:由opendir返回
  • 248. closedir函数用于关闭目录 函数原型: int closedir(DIR *dp); 参数与返回值 dp:由opendir返回 返回值:成功返回0,出错返回-1
  • 249. 目录操作mkdir、rmdir函数 读目录 chdir、fchdir、getcwd函数
  • 250. chdir、fchdir函数进程的当前工作目录 搜索所有相对路径名的起点 例如:open(“./a/b.txt”,.............); 假设当前工作目录为/home/test open打开的路径即:/home/test/a/b.txt chdir、fchdir用于改变进程的当前工作目录
  • 251. chdir、fchdir函数函数原型 int chdir(const char *pathname); int fchdir(int filedes); 进程的当前工作目录改为pathname或filedes对应的路径 成功返回0,出错返回-1
  • 252. getcwd返回当前工作目录的绝对路径 即以“/”开头的路径 函数原型 char *getcwd(char *buf, size_t size); 参数与返回值 buf:存放绝对路径 size:buf的大小(注意包括结尾的null字符) 成功返回buf,失败返回NULL
  • 253. 目录操作mkdir、rmdir函数 读目录 chdir、fchdir、getcwd函数
  • 254. 文件和目录ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号连接 目录操作
  • 255. 文件的操作文件的基本操作(打开、定位、读写、关闭) I/O效率 文件共享 其他重要I/O函数 ext2文件系统在磁盘的组织 stat、fstat、lstat函数 文件的基本性质 修改文件属性的函数 硬链接与符号连接 目录操作