| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> Files and Directories 文件和目录 -> 正文阅读 |
|
[C++知识库]Files and Directories 文件和目录 |
4.1介绍 Introduction? 前边一章介绍了?基础的?I/O 函数。 这些讨论都聚焦在?常规文件的I/O, 如?打开,读,写一个文件。 现在我们将看看??文件系统的其他功能, 和?文件的属性。我们将?以stat?函数开始,来过一遍?stat结构体的每一个成员,来看看文件的所有属性。 在这个过程, 我们将描述?每一个函数都修改那些属性: 改变owner, 改变?权限,等等。 这章的最后,看看操作目录的函数,并且我们开发一个函数,它往下(descends)遍历一个目录的结构。 4.2??stat, fstat, fstatat, and 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); ????????????????????????????????????????????????????????????????????????????????All four return: 0 if OK, -1 on error lstat?函数?和?stat?很类似,区别是?文件名是个?符号链接(symbolic link), lstat 返回的是symbolic link的信息,而不是?被符号链接引用的文件。(4.22, 4.17 又会描述到) fstatat 函数提供了一种方式,?返回?pathname 相对于?fd?的文件的信息。 flag参数控制?symbolic links 有如下的: AT_SYMLINK_NOFOLLOW ?flag ,fstatat 将不会跟随?symbolic links, 而是返回?link本身的信息。 其他,默认的是?跟随symbolic link ,返回?symbolic link 指向的文件。 如果fd?是?AT_FDCWD, 并且?pathname 是相对的路径名, fstatat 会使用?pathname 参数相对于当前目录。 如果pathname 是绝对路径名,那么?fd?参数会被忽略。 在flag 的这两种cases, fstatat 的行为?要么像?stat??,要么像?lstat。 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_atim; ???????????????????????????????? /* time of last access */ struct timespec ????????st_mtim; ???????????????????????????????? /* time of last modification */ struct timespec ????????st_ctim; ???????????????????????????????? /* 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; 4.3 ?File Types 文件类型
文件的类型?被编码在?stat?结构体的?st_mode 成员中。我们可以使用?如下4.1图中的?宏来检测?file?type。 这些宏?的参数?是??stat?结构体中的?st_mode 成员。
Figure 4.1 File type macros in <sys/stat.h> POSIX.1 允许?实现?去?将这些??进程间通信(IPC) 对象,例如?message?queues, semaphores. 视作?文件(file) 在下面图4.2的图中的宏,允许我们?去检测?IPC对象的类型。 不是传stat结构体的st_mode 成员作为参数,而是传一个?指针(它指向?stat?结构体)。
Figure 4.2 IPC type macros in <sys/stat.h> 然而,在这本书中讨论的?各种unix 系统的实现,还没有把些对象?视作文件。 4.3 打印文件类型,对于命令行中给出的参数 filedir/filetype.c
说明:我们尤其使用?lstat?而不是stat?来?侦测symbolic link, 如果我们使用?stat函数,我们将从不会看到?symbolic links。 历史地, 早期的unix system 版本不提供?S_ISXXX 宏, 替代地?,我们不得不?,在<sys/stat.h> 我们检查file, 我将发现这个?S_ISDIR 宏?定义?像如下: #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) ?4.4 Set-User-ID ?and ?Set-Group-ID每个进程?有六个或更多的ID??和它关联。这些展示在图4.5 中。
????????????????????????????????????????4.5 每个进程?关联的?User?IDs , group IDs
saved?IDs 在2001 POSIX.1 才是必要的。在更老的POSIX, 这是可选的。 一个应用可以在?编译时?测试?_POSIX_SAVED_IDS 或?在运行时?调用?sysconf , 参数是?_SC_SAVED_IDS , 来看实现?是否支持此功能。 通常地, effective user ID 等效于?real user ID, ?effective group ID 等效于?real?group ID。 每个文件都有?一个?owner?和?group owner 。 这个owner?是?stat结构体中的?st_uid 成员, group owner 是?stat结构体中的st_gid 成员。 当我们执行一个程序文件使, 进程的?the effective user ID ?通常就是??real?user ID, effective?group ID 通常是??real?group ID. ??然而我们?可以??在文件的?mode?(stat 的st_mode) 设置?一个?special flag 。含义就是说: 当这个文件被执行, 进程的effective user ID ?设置为?和?file的?owner?一样(stat?的st_uid)。 类似地,我们可以在file?的mode?word 设置另一个bit, 它将引起?进程的?effective group ID 设置为?和?file的?group?owner(即?stat的?st_gid) 一样。这两个bit?在file?mode?word 中被叫做?set-user-ID 位?和?set-group-ID 位。 例如,file的?owner?是superuser 并且?file的?set-user-ID 位被设置了,那么当程序(这个file)被执行?作为进程, ?这个进程?就有了?superuser privileges 。这种情况会发生,且?它?忽视不管??执行这个文件的?产生的进程的?real?user ID 是什么。 举个例子,unix 系统?有个程序(passwod(1)) 允许?任何人?可以改变?他或她的密码?, ?这个程序就是?一个set-user-ID 的程序。有需求去?write??/etc/passwd 或?/etc/shadow 文件, 正常地这些文件只能被?superuser 去write。( 这样的程序,第8章还会更详细的讨论)。 回到stat?函数的讨论, set-user-ID bit 和?set-group-ID 位?被包含在?file的st_mode 值中。这两个bits?可以依据?常量S_ISUID 和?S_ISGID?来测试。 4.5 File?Access Permissions ?文件访问权限st_mode 的值?也编码了?文件的?access?permission bits。 这里说的file?指的可以是是前面提到的任何文件类型。 所有的文件类型?,目录、character?special files,等等?都有权限. 每个文件有9个权限位,被分成了3类。它们如图4.6:
Figure 4.6 The nine fifile access permission bits, from <sys/stat.h> chmod(1) 命令可以修改这9种权限bits。 a.??首先规则是, 不管任何时候,我们想通过name去open任何类型的文件,我们必须有?对name中提到的每个目录?有执行权限,包括当前目录(如果它被含有)。这就是为什么对于目录的?execute permission bit 又常常被叫做?search?bit。 例如: ?为了去?打开?/usr/include/stdio.h, 我们需要?目录?/ 的?执行权限, 目录?/usr?上的执行权限, 目录?/usr/include 上的执行权限, 对文件本身也要有合适的权限(依赖于我们如何open文件是?read-only,read-write,等等. 如果当前目录是?/usr/include ,那么我们需要当前目录的执行权限。这有个当前目录的被包含(不明显的提及)例子。就是?./stdio.h 这样写法。 注意?一个目录的??读权限?和?执行权限?是很不同的。read 权限让我们?读目录,获取在目录下的所有文件名(filenames)。 执行权限?让我们?通过目录,当它是?一个pathname 的一个组成部分(我们需要去search目录来寻找特定的filename) 另一个不明显的隐含的目录引用是?PATH 环境变量(8.10 描述),指定了一个目录,但没有执行权限,在这种情况,在这个目录下就不能找到任何的?可执行文件。 b. 一个文件的?读权限?决定我们是否可以打开一个已存在的文件,来读。open函数O_RDONLY, 或?O_RDWR?flags c. ?一个文件的写?权限?决定我们是否可以打开一个已存在的文件, 来写。open函数O_WRONLY 或?O_RDWR flags d. 如果在open?中指定了?O_TRUNC flag ,那么我们必须对这个文件有?write?权限 e. ?如果想在一个目录下?创建一个新文件,那么我们必须对这个目录?有写?和?执行?权限。 f. ?为了去删除一个已存在的文件,我们需要?对文件所在的目录?有?写?和?执行权限。我们对文件本身不需要有?读?或?写?权限。 g. ?如果我们想用?7个?exec函数来执行?一个文件,那么文件的执行权限必须开启,并且这个文件要是一个?regular?file。 每次进程?open, create, 或delete 一个文件?,内核就会执行?file?access 检查,这个检查依据是: 文件的属主(st_uid, st_gid) , 进程的?effective IDs (包括?effective user ID 和?effective group ID), ?进程的补充group IDs (如果支持的话)。 两个owner?IDs 是文件的属性, 两个effective IDs 和?补充的group IDs ?是进程的属性, ?内核是按如下来检查的: 1. 如果进程的?effective user ID 是?0 ( 超级用户?superuser) , access 就是允许的。 这个使得超级用户?能?自由的?进入?整个文件系统。 2.? 如果?进程的?effective user ID 等于?文件的?owner ID ( 例如?进程?拥有这个文件); 并且?文件?的?合适的?用户访问权限位?被设置。 则?access?就是允许的, 其他情况下,access是被禁止的。 “合适的?访问权限bit” 含义是: 如果进程?要打开这个文件来读,那么?user-read bit 必须被打开;如果进程要打开这个文件来写, 那么user-write bit 必须被打开; 如果进程要执行这个文件,那么?user-execute bit 必须被打开。 3.? 如果进程的?effective?group ID ?或者?进程的补充group IDs中的一个??和文件的group ID 相等。 并且?合适的group 访问权限bit?被设置,那么?access 就是?允许的。否则access就是被禁止的。 4.? 如果?合适的?other access 权限bit?被设置, access?是允许的,否则access就是被禁止的。 这个四个步骤,是被尝试着按顺序来的。 注意如果?进程拥有文件(step?2) , ?access?被授权或?拒绝?取决于?user?access permissions bit, 就从来不看?group permissions bit了。类似地,如果进程?没有拥有文件,但是属于一个?合适的?group, access 是?被授权还是拒绝?取决于文件的?group access permissions bit , 就从来不看?other permissions bit?了 4. 6 ?ownership of new file and Directories ??新文件?和?新目录的属主新文件的?user?ID ?被设置为?和进程的?effective user ID 一样。POSIX.1 允许一个实现?去选择?如下的选项来?决定?一个新文件的?group ID:
Linux3.2.0 的默认行为,来决定新文件group ID ?取决于?文件所在的目录的?set-group ID bit 是否被设置。如果这个bit?被设置了,新文件的?group ID 就从?目录上?copy; ?否则新文件的?group ID 就设置的?和??进程的?effective group ID 一样。 4.7 access ?and?faccessat 函数有些时候,一个进程?想去?基于?real?user 和?group IDs 来测试?可访问性。access?和?faccessat 函数?来检查?是基于?real user 和?group IDs 的。 #include <unistd.h> int access(const char *pathname, int mode); int faccessat(int fd, const char *pathname, int mode, int flag); ????????????????????????????????????????????????????????????????????????????????????????Both return: 0 if OK, -1 on error mode??要么是?F_OK (测试一个文件是否存在) ,那么是?如下?flags 的?OR?组合??4.7:
faccessat 函数的行为和?access?是一样的,特别是当: pathname 是绝对的?或?fd 是AT_FDCWD 并且?pathname 是相对的。 否则??,faccessat 在计算pathname时?就会?相对着?这个目录(fd指向的目录)来。 flag?参数?可被?用于来?改变?facccessat 的行为。 如果?AT_EACCESS flag 被设置, access 检查就会使用?调用进程的?effective user ID , effective group ID 来检查?(而不是使用?进程的real user 和?group IDs)。 例子4.8 access?函数的使用。
4.8 umask 函数umask 函数?设置??进程的??file?mode creation mask , 并且?返回?先前的?value。 (这个函数?是少有的?没有?error返回的函数?之一) #include <sys/stat.h> mode_t umask(mode_t cmask); ????????????????????????????????????????????????????????????????????????Returns: previous file mode creation mask cmask参数的格式是: 9个?常量(S_IRUSR, S_IWUSR 等)的?OR?组合。 file?mode creation mask 通常?在进程创建?文件?或目录时?使用。 ?在file mode creation mask 中?被关闭的,在file的mode中?都被?打开。 例子:4.9 这个程序?创建两个文件: ?一个?带着?umask 0 来创建, 一个?带着?umask 禁用?所有group?和?other?permission bits 来创建。 filedir/umask.c
通常在登录的时候?shell的?start-up file 会设置一次?(使用umask) mask?, 并且不再改变。 当?程序在创建文件时,想确保指定的?access permission bit 被启用, 我们必须修改?正在运行着的进程的?umask value?。 在先前的例子,我们使用?shell的umask 命令?在程序运行前和?完成后去打印?file?mode creation?mask ?。 这向我们展示了??进程改变了?file?mode creation mask ?不会影响?parent?(常常是?shell) 的mask。 所有的shell 都有?一个内建的命令?来使我们可以使用它去打印或设置当前的?file?mode creation mask。 设置umask value 用?十六进制表示。 图4.10 ?通过设置相应位就可以?禁用/关闭?对应的?permissions bit (要创建文件的) , 例如??027 ?表示?阻止?group members 写, 阻止other 读,写, 执行你的文件。
????????????????????????????????????????4.10 ?the umask ??file access permission bits UNIX 规范?要求??umask 命令支持?符号表示?umask , 如下: $ umask ???????????????????????? first print the current file mode creation mask 002 $ umask -S ???????????????????????? print the symbolic form u=rwx,g=rwx,o=rx $ umask 027 ???????????????????????? change the file mode creation mask $ umask -S ???????????????????????????????? print the symbolic form u=rwx,g=rx,o= 4.9 chmod , fchmod, and fchmodat 函数#include <sys/stat.h> int chmod(const char *pathname, mode_t mode); int fchmod(int fd, mode_t mode); int fchmodat(int fd, const char *pathname, mode_t mode, int flag); ????????????????????????????????????????????????????????????????????????????????All three return: 0 if OK, -1 on error flag 参数通常用于改变?fchmodat 行为, 当?AT_SYMLINK_NOFOLLOW flag 被设置, fchmodat 不会?跟随?symbolic links。 为了改变?文件的?permission bits ?, 进程的?effective user ID 必须?等于?文件的?owner?ID, 或者进程?有?超级用户权限。 mode?参数?被指定?为??下面常量的?OR??4.11 :
4.11 The mode constants for chmod functions, from <sys/stat.h> 注意: 4.11 中的9个??和?4.6 的9个file?access permission bits 是一样的。这里?添加了?2个?set-ID ?常量(S_ISUID ?和?S_ISGID) ?, saved-text 常量(S_ISVTX), ?和?3个?合并常量( S_IRWXU, S_IRWXG, S_IRWXO). 4.12 例子: filedir/changemod.c
注意?ls命令?列出?foo的??group-execute 权限为?S??,表明了?set-group-ID bit?是被设置,并且没有group-execute bit 被设置。 最后, 注意?ls?命令?列出的?时间?和日期?在经过?./changemod 程序后?,并没有改变。 在下面的情况下: chmod 函数会自动?清除?2个权限bit a: 对?regular files 设置??sticky bit 时,如果我们不是?superuser privileges ,在mode中的sticky bit 设置?就会被自动的?关闭(turned off) 。为了防止恶意的用户?设置?sticky bit 并且?有害地影响系统性能, 只能是?superuser 可以设置?一个?regular file 的?sticky bit。 b: ?一个新的将要被创建的文件的?group ID 可能?和?调用的进程的group ID 不一样。回想下4.6 新文件的?group ID ?可以和?父目录的?group ID 一样。 尤其是特别地??,新文件的?group ID 不等于?进程的?effective group ID 或?也不是?补充group IDs 的其中一个,并且进程没有超级用户权限,那么?set-group-ID bit 就会自动地被关闭(turned off) 4.10 Sticky BitS_ISVTX bit??有一个有趣的历史。 如果对?一个可执行程序?设置了?sticky bit , 那么当程序被第一执行过, 程序的text?(程序机器指令) 的一份copy 就会被保存在?swap area。 下次它被执行时,程序将被很快地加载到?memory 中, 因为?swap area 是?个?连续的(contiguous file) ?(普通的?Unix file system 的data?blocks 是随机的). ??这个sticky bit 常常被设置在哪些?通用的公共的程序,如?text?editor , c编译器?等。 自然地?对?设置?sticky files的数量有限制的。 之后的?Unix system ?把?sticky?叫做?saved-text bit ,对应的常量是?S_ISVTX。 现在的系统,大部分有一个虚拟内存系统,并且有一个更快的file?system , 所以对这个技术的?需求已经消失了。 在当代的(contemporary system?) ,sticky bit 的使用已经被扩展了, Single Unix 规范允许?对 目录设置??sticky bit 。 如果一个目录?被设置了?, 在目录下的??文件?可以被删除?或重命名?,只需要?用户对目录有?写权限?并且?有如下其一标准(criteria): owns?这文件; owns?这个目录; 是超级用户。 /tmp , /var/tmp 是典型的使用?sticky bit 的目录。 在这个目录下用户可以创建文件,这两个目录的权限通常是: read, write, execute (user, group, other)。 但是用户不能删除或重命名?别人拥有的的文件。 drwxrwxrwt.? 28 root root 4096 2月? 23 10:35 tmp drwxrwxrwt. 17 root root 4096 2月? 23 10:06 tmp 4.11 chown, fchown, fchownat, lchown 函数chown 函数允许我们改变文件的?user?ID ?和?group ID. ?但是?如果参数??owner 或?group 是?-1, 那么对应的ID?就保持不变。 ?#include <unistd.h> int chown(const char *pathname, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group); int fchownat(int fd, const char *pathname, uid_t owner, gid_t group, int flag); int lchown(const char *pathname, uid_t owner, gid_t group); ????????????????????????????????????????????????????????????????????????????????All four return: 0 if OK, -1 on error lchown , fchownat( 带着/带随着??AT_SYMLINK_NOFOLLOW flag 被设置),他两只是改变?symbolic link 本身的?所有权,而不是改变?symbolic link 引用的文件的 fchown 函数?改变?fd?参数指向的?打开的文件?的?所有权。由于它操作的是一个已打开的文件,所以这个函数不能改变一个?symbolic link的?所有权(ownership) 只有超级用户进程可以改变?文件的?user?ID 非超级用户的进程?可以改变?文件的?group ID , 当?进程拥有文件( 进程的effective user ID 等于?文件的?user?ID), ?此时?owner?参数应该是?-1 或者?等于文件的user?ID, 并且?group 参数?等于?要么是?进程的?effective group ID ,要么是?进程的补充group IDs 中的一个。 在这些函数?被??非超级用户进程?调用后,成功返回后, set-user-ID bit 和?set-group-ID bit?都会被清除。 4.12 File Sizestat 结构体的成员st_size ?包含了?文件的大小(字节为单位),这个字段/成员?只对?regular files, 目录, symbolic links 是有意义的。 对regular?file , 文件的?大小?是?0 是被允许的。 对于目录, file size 通常是?一个数字的倍数,如?16 or?512。 我们在?4.22 部分讨论?reading 目录。 对于?symbolic link , file?size?就是?文件名filename的?字节数。例如,在下面的例子, 7 是?usr/lib 的长度 lrwxrwxrwx. ? 1 root root? ? 7 9月? 23 2020 lib?-> usr/lib lrwxrwxrwx. ? 1 root root? ? 9 9月? 23 2020 lib64?-> usr/lib64 注意?symbolic links 不包含?标准?C?里的?null byte (字符串末尾的),因为长度是?st_size 来指定的。 大多数现代Unix 系统?提供了?st_blksize 和?st_blocks 字段。 第一个是?对文件的I/O 来说是首选的?block?size。 第二个是?真实的?512 字节的?block?的数量。 Holes in File ?文件中的空洞 $ ls -l core -rw-r--r-- 1 sar 8483248 Nov 18 12:18 core $ du -s core 272 core size of file 是?超过了?8M, du命令?显示是?272 个?512-byte?blocks?(139264 字节)。明显地file 有许多holes. 在Linux 上?报告的单位?取决于?POSIXLY_CORRECT 环境是否被设置。如果被设置?报告单位就是?1024-byte?block units; 没有被设置时, 报告的就是?512-byte block?units。 就像我们在3.6 部分提到的, read?函数?对read的?任何位置上没有被写时,返回的都是?data?bytes of 0 : $ wc -c core 8483248 core wc(1) 命令?带上?-c ?选项统计??file中的?字符数量。 如果我们?copy 这个文件, 使用?cat(1), 所有的这些?holes 写出去的都写作??data?bytes of 0 : $ cat core > core.copy $ ls -l core* -rw-r--r-- 1 sar 8483248 Nov 18 12:18 core -rw-rw-r-- 1 sar 8483248 Nov 18 12:27 core.copy $ du -s core* 272 core 16592 core.copy 文件的真实?字节数是?8,495,104 (512 *?16,592) 4.13 File Truncation#include <unistd.h> int truncate(const char *pathname, off_t length); int ftruncate(int fd, off_t length); ????????????????????????????????????????????????????????????????????????????????Both return: 0 if OK, ?1 on error 这两个函数truncate?已存在文件?到?length?bytes。 如果之前的?文件大小?大于?参数length, 在length后边的数据就不再?可访问。 否则,如果之前的文件大小小于??参数?length , file size 将增加。 老文件末尾?和?新文件末尾之间的数据将被读做?0 ( 在这个文件中可能产生hole) 4.14 File Systems ?文件系统理解?一个?i-node ?和?一个?directory entry 之间的不同?是很有用的。 目前,有多种?UNIX file system . 我们可以把一个磁盘(disk) 分成一个或多个分区(partitions)。 每个分区都可以包含一个file?system 。i-nodes ?是固定长度的entries?,包含了?一个文件的大部分信息。 说明:cylinder group : 柱面组 i-node 和?data?block ?更详细的内容如下图: 上图说明: 两个?directory entries 指向/引用?相同的?i-node entry . 每个i-node 有?一个link count(连接数):“包含了directory entries 指向它的数量”。仅当?link?count 变成0时,文件才能被删除(删除指:释放文件关联的?blocks)。这就是?为什么“unlinking a file” 不总是意味着“删除文件关联的?blocks” 。 这就是为什么?移除一个?directory?entry 被叫做?unlink , 而不是?delete。在?stat?结构体?中?st_nlink member?代表了link?count。st_nlink 的数据类型?是?nlink_t。 这种链接类型?被叫做?hard?links 另一种?链接类型?叫做?symbolic link (符合链接)。一个symbolic link , 它的?文件内容/data?blocks : 存储了文件的名称。 下面例子中?directory entry 是包含了3个字符(lib) 的文件名。 lrwxrwxrwx 1 root 7 Sep 25 07:14 lib -> usr/lib 在i-node中的file?type 是S_IFLNK?目的是?让系统知道它的类型是?symbolic link. i-node 包含了文件的所有信息:文件类型,文件的访问权限位,文件大小,指向data?blocks的指针,等等。 在stat结构体中的大多数信息都是从i-node 获取的。只有两项重要的数据是?从?directory entry 中获取,就是?filename, i-node number。另外两项数据:文件名的长度,目录记录的长度?不在此讨论。i-node number 的数据类型是ino_t 一个directory entry 不能引用?不同文件系统的一个i-node. 这就是为什么ln(1) 命令(创建一个新的directory entry 它?指向一个已存在的文件)不能跨越?file?systems. 当重命名一个文件(前提不改变文件系统),实际的文件的内容不需要改变,仅仅是添加一个新的?directory entry 并且删除?老的?directory entry ,link count 保持相同。这是mv(1)命令通常的操作。 那么?一个目录的?link?count 又是什么概念? 假如我们如下创建一个目录: mkdir testdir 上图说明:i-node 它的?number是2549 ,它的link?count 等于?2。 任何叶子目录(里边不包含任何其它目录)总是?link?count 等于?2. 2的怎么来的一个?来自哪个包含名字的directory entry,另一个来自在那个目录的?dot?代表的directory?entry 。number?是?1267 它的link?count 肯定是?大于等于?3.??3怎么来的,一个是?他的名字对应的?directory entry (注意上图没有画出来!),一个是?dot?,一个是来自testdir 里边的?dot-dot。注意子目录每多一个都会引起本目录的link?count 增加?1 4.15 link , linkat, unlink, unlinkat, remove 函数就像在先前部分那样,一个file?可以?是??有多个directory entries 指向它的i-node。我们可以使用?link 或?linkat 函数来?对一个已存在的file?创建link。 #include <unistd.h> int link(const char *existingpath, const char *newpath); int linkat(int efd, const char *existingpath, int nfd, const char *newpath, int flag); ????????????????????????????????????????????????????????????????????????????????????????Both return: 0 if OK, -1 on error 如果newpath 已经存在, error 就会返回, 当existing file 是?symbolic link , flag参数?控制?linkat 函数是创建一个?symbolic link 的?link, 还是?创建一个?针对symbolic link 指向file?的?link 。如果AT_SYMLINK_FOLLOW flag 被设置,那么?创建的link?指向??symbolic link的目标。如果flag?被清除,那么?创建的link?指向的是?symbolic link 本身。 注意:新new?directory entry 的创建?和?link count 的增加?必须是一个?原子操作。 大多数实现?要求?两个pathnames 在同一个?file?system 上。 如果一个实现支持?对目录?创建?hard?links ,那么它一定是?仅对于?超级用户。这个约束存在的原因是?hard?links ?在file?system可能引起?loop。 基于如上?原因,许多file?system 的实现?都不允许?对目录?hard?links. 为了?移除?已存在的?directory entry ,我们可以调用unlink 函数 #include <unistd.h> int unlink(const char *pathname); int unlinkat(int fd, const char *pathname, int flag); ????????????????????????????????????????????????????????????????????????Both return: 0 if OK, -1 on error 这些函数?移除?directory entry 并且减少?文件( pathname指定的文件)的?link?count 。如果这里有其他link?指向这个文件, ?那么仍然可以通过其他link?来访问文件中的数据。 就像早先提到的, 去unlink 一个file?,我们必须?对??directory entry 所在的?目录?有write 和?execute 权限。也如?4.10提到的,如果?这个目录的?sticky bit 被设置了,我们必须?对?这个目录有?write?权限?并且?满足如下的标准之一: own 这个文件 own 这个目录 有超级用户权限 仅当?link?count 达到0 时,file的contents才可能被删除,另一个情况会阻止文件被删除的是: 只要有进程open??file?, 它的contents就不能被删除。当一个file被closed , 内核首先检查?进程打开此file的数量,如果这个数量达到0了,内核再检查?link count, 如果是0 ,file的内容就会被删除。 flag?参数?给了调用者?一种改变unlinkat 函数行为的方式。 当AT_REMOVEDIR flag?被设置, unlinkat函数通常被用来?移除?一个目录,类似?rmdir。 如果flag被清除,那么unlinkat 操作就像?unlink. 例子:
unlink?常常被用来?确保程序创建的?临时文件?不会被留下(在程序奔溃时)。调用unlink 后文件仍然没有被删除,因为?它仍然open, 仅当进程?要么关闭file?或者?终止(terminates), 这会引起?内核去关闭所有程序打开的?files。这个时候?file?被删除。 如果pathname 是?symbolic link , ?unlink 移除的是??symbolic link 不是?link指向的file. 这里没有函数?能?移除?symbolic link 指向的file. 我们可以?用remove 函数来?unlink 一个文件或??目录, 对于?文件?remove ?完全等效于??unlink。 对于目录,remove 完全等效于?rmdir。 #include <stdio.h> int remove(const char *pathname); ????????????????????????????????????????????????????????????????????????????????????????????????Returns: 0 if OK, -1 on error 4.16 ?rename??and ?renameat 函数一个文件或目录?要被重命名,要么使用rename, 要么使用?renameat 函数 #include <stdio.h> int rename(const char *oldname, const char *newname); int renameat(int oldfd, const char *oldname, int newfd, const char *newname); ????????????????????????????????????????????????????????????????????????????????????????????????Both return: 0 if OK, ?1 on error 对于这些函数,这里有几种情况?需要来描述,这些情况?取决于?oldname 指向的是?file ,是?directory 还是?symbolic link。我们也要描述下?如果?newname 已经存在了,会发生什么。
4.17 Symbolic Links |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 3:02:45- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |