21、目录读取
对某个目录具有存取权限的任一用户都可读该目录,但是只有内核才能写目录(保持文件系统一致性)在前面说过,一个目录的写权限位和执行权限位决定了在该目录中能否创建新文件以及删除文件,但是它们并不表示能否写目录本身。
目录的实际格式依赖于UNIX的具体实现。UNIX现在包含了一套与读目录有关的例程,它们是POSIX.1的一部分。许多实现不允许应用程序使用 read
函数访问目录内容,这样就将目录的具体实现格式细节和应用程序隔离了起来。
#include <dirent.h>
DIR *opendir(const char *pathname);
返回:如果成功返回目录指针,如果错误返回空。
struct dirent *readdir(DIR *dp);
返回:如果成功返回目录指针,如果到达目录结尾或者错误返回空。
void rewinddir(DIR *dp);
int closedir(DIR *dp);
返回:如果成功返回0,如果错误返回1(其值一般为-1)。
long telldir(DIR *dp);
返回:和dp关联的目录的当前位置。
void seekdir(DIR *dp, long loc);
telldir
和 seekdir
函数不是基本的POSIX.1标准的一部分。它们是SUS的XSI扩展,所以所有遵循UNIX系统的实现都应该提供它们。
dirent
结构在文件 <dirent.h>
中定义,是依赖于具体实现(也就是系统实现)的。系统实现中,定义的 dirent
结构至少包含以下成员:
struct dirent {
ino_t d_ino; /* i-node number */
char d_name[NAME_MAX + 1]; /* null-terminated filename */
}
d_ino
并不是POSIX.1定义的,因为它是一个与实现相关的特性。但是,它在POSIX.1的XSI中定义了。POSIX.1只定义了这个结构的 d_name
成员。
DIR
结构是一个内部结构,它由这6个函数用来维护正被读取的目录的有关信息。其作用类似于由标准 I/O
库维护的 FILE
结构。
由 opendir
返回的指向 DIR
结构的指针由另外三个函数使用。 opendir
执行初始化操作,这样第一个 readdir
读取目录中的第一个目录项。目录中各目录项的顺序与实现有关。它们通常并不按字母顺序排列。本文参考资料中给出了使用这几个函数递归遍历一个目录的具体例子,这里不列举了。
译者注
原文参考
22、 chdir
, fchdir
,和 getcwd
函数
每个进程都有一个当前工作目录,此目录是所有相对路径名(不以斜线开始的路径名)的搜索起点。当用户登录到UNIX系统时,其当前工作目录通常是密码文件( /etc/passwd
)中该用户登录项的第6个字段所指定的目录(用户的起始目录)。当前工作目录是进程的属性,而起始目录则是登录名的一个属性。进程调用 chdir
或 fchdir
函数可以更改当前工作目录。它们的声明如下:
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
两者返回:如果成功返回0,如果错误返回1(其值一般为-1)。
这两个函数参数的含义类似前面, chdir
通过文件路径名指定,而 fchdir
通过文件描述符号来指定。其中 fchdir
不是POSIX.1中的一个部分,它是SUS的XSI扩展。
使用 chdir
函数的例子:
#include "apue.h"
int main(void)
{
if (chdir("/tmp") < 0)
err_sys("chdir failed");
printf("chdir to /tmp succeeded\n");
exit(0);
}
如果我们编译以上代码,生成 mycd
可执行程序,并且运行,那么结果如下:
$ pwd
/usr/lib
$ mycd
chdir to /tmp succeeded
$ pwd
/usr/lib
因为当前工作目录是进程的属性,所以子进程(例如下面的 mycd
)调用 chdir
不会影响父进程(运行 mycd
程序的 shell
)的当前工作路径,这也是为什么 cd
命令(切换路径命令)是 shell
的内建命令而不是一个独立的程序的原因。
因为内核保持有当前工作目录的信息,所以我们应能取其当前值。可是,内核为每个进程只保存其当前工作目录的i节点编号以及设备标识,并不保存该目录的完整路径名。
如果想要获取当前路径,那么我们需要从当前工作目录开始,找到其上一级的目录,然后读其目录项,直到该目录项中的i节点编号数与工作目录i节点编号数相同,这样地就找到了其对应的文件,然后按照这种方法,逐层上移,直到遇到根,这样就得到了当前工作目录的绝对路径名。其实,函数 getcwd
就提供了这种功能,其声明如下:
#include <unistd.h>
char *getcwd(char *buf, size_t size);
返回:如果成功返回 buf
,如果错误返回 NULL
。
使用 getcwd
函数的例子
#include "apue.h"
int main(void)
{
char *ptr;
int size;
if (chdir("/usr/spool/uucppublic") < 0)
err_sys("chdir failed");
ptr = path_alloc(&size); /* our own function */
if (getcwd(ptr, size) == NULL)
err_sys("getcwd failed");
printf("cwd = %s\n", ptr);
exit(0);
}
运行上述代码,得到如下结果:
$ ./a.out
cwd = /var/spool/uucppublic
$ ls -l /usr/spool
lrwxrwxrwx 1 root 12 Jan 31 07:57 /usr/spool -> ../var/spool
注意, chdir
会处理符号连接(即使是 getcwd
调用了它),但是当 getcwd
沿目录树上溯遇到 /var/spoo
目录时,它并不了解该目录由符号连接 /usr/spool
所指向(所以它就把这个符号链接作为目录看待了)。这是符号连接的一种特性。
译者注
原文参考
23、关于设备文件
和设备文件相关的 stat
成员是 dev_t st_dev
;和 dev_t st_rdev
。
- 每个文件系统通过主从设备号被获知,这两者属于基本系统类型
dev_t
(一般是一个整数类型的typedef
)。major
号标志驱动或者有时候标志和哪个外设板子相通信;minor
用来标志特定的从设备。例如一个磁盘通常有多个文件系统,那么在这个磁盘上面的文件系统具有共同的major
号,但是具有不同的minor
号。 - 为了访问
major
号和minor
号,一般都有两个宏来达到这个目的:major
和minor
。 我们不用考虑major
号和minor
号是怎么存放在dev_t
中的。在不同系统中dev_t
的位是不同的,那位存放什么也不同,具体参见文档。 - 在系统中一个文件的
st_dev
值是包含这个文件的文件系统的device number
. - 只有字符设备文件和块设备文件具有
s_rdev
值,这个值包含device number
和实际的设备。
举例:
- 对于一个文件,其
st_dev
的major
和minor
是这个文件所在的文件系统的major
和minor
. - 对于一个字符文件,会有
st_dev
和st_rdev.其中st_dev
是这个字符设备特殊文件的文件节点所在的文件系统的major
和minor
(虚拟文件系统),而st_rdev
是这个字符设备文件的实际设备的major
和minor
号码。
译者注
原文参考
24、文件访问权限位总结
我们已经讨论过所有文件访问的权限位,有些用于多个用途,下图列出了所有这些权限位,以及当它们应用在普通文件和目录文件时后的含义。
文件访问权限位大致的情况
+--------------------------------------------------------------------------------------------------------------------------+
|Constant| Description | Effect on regular file | Effect on directory |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_ISUID |set-user-ID |set effective user ID on execution |(not used) |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
| | |if group-execute set then set effective |set group ID of new files |
|S_ISGI |set-group-ID |effective group ID on execution;otherwise |created in directory to |
| | | enable mandatory record locking (if supported)|group ID of directory |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_ISVTX |sticky bit |control caching of file contents (if supported)|restrict removal and renaming of files in directory|
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IRUSR |user-read |user permission to read file |user permission to read directory entries |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IWUSR |user-write |user permission to write file |user permission to remove and create files in |
| | | |directory |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IXUSR |user-execute |user permission to execute file |user permission to search for given pathname in |
| | | |directory |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IRGRP |group-read |group permission to read file |group permission to read directory entries |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IWGRP |group-write |group permission to write file |group permission to remove and create files in |
| | | |directory |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IXGRP |group-execute|group permission to execute file |group permission to search for given pathname in |
| | | |directory |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IROTH |other-read |other permission to read file |other permission to read directory entries |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IWOTH |other-write |other permission to write file |other permission to remove and create files in |
| | | |directory |
|--------+-------------+-----------------------------------------------+---------------------------------------------------|
|S_IXOTH |other-execute|other permission to execute file |other permission to search for given pathname in |
| | | |directory |
+--------------------------------------------------------------------------------------------------------------------------+
译者注
原文参考
25、总结
本章以 stat
函数为中心,详细讨论了 stat
结构中的每个成员。这使得我们也看到了UNIX文件的所有属性。对一个文件的所有属性以及UNIX编程操作文件所需要的基本函数有了大体的了解。
网友评论