用 mkdir 和 mkdirat 函数可以创建目录,用 rmdir 函数可以删除空目录。
前两个函数创建一个新的空目录,其中“.”和“..”目录项是自动创建的。所指定的文件访问权限 mode 由进程的文件模式创建屏蔽字修改。常见的错误是指定与文件相同的 mode(只指定读、写权限)。但对于目录,通常至少要设置一个执行权限位,以允许访问该目录中的文件名。
mkdirat 和 mkdir 函数类似。当 fd 参数具有特殊值 AT_FDCWD 或者 pathname 参数指定了绝对路径名时,两者完全一样。否则,fd 参数是一个打开目录,相对路径名根据此打开目录进行计算。
如果调用 rmdir 函数使目录的链接计数减为 0,并且也没有其他进程打开此目录,则释放由此目录占用的空间。如果在链接计数变为 0 时,有一个或多个进程打开此目录,则在此函数返回前删除最后一个链接以及“.”和“..”项。另外,在此目录中不能再创建新文件,但在最后一个进程关闭它之前并不释放此目录(即使另一些进程打开该目录,它们也不能在此目录下执行其他操作,因为为了保证 rmdir 函数成功执行,该目录必须是空的)。
对某个目录具有访问权限的任一用户都可以读该目录,但为了防止文件系统产生混乱,只有内核才能写目录。一个目录的写权限位和执行权限位决定了在该目录中能否创建新文件以及删除文件,不过它们并不表示能否写目录本身。
为了简化读目录的过程,UNIX 在 POSIX.1 中提供了一套与目录有关的函数。
其中,fdopendir 函数可以把打开文件描述符转换成目录处理函数需要的 DIR 结构。DIR 结构是一个内部结构,用来保存目录的有关信息,类似于 FILE 结构。由 opendir 和 fdopendir 返回的指向 DIR 结构的指针由另外几个函数使用。opendir 执行初始化操作,使第一个 readdir 返回目录中的第一个目录项。DIR 结构由 fdopendir 创建时,readdir 返回的第一项取决于传给 fdopendir 函数的文件描述符相关联的文件偏移量。注意,目录中各目录项的顺序与实现有关,通常并不按字母顺序排列。
每个进程都有一个当前工作目录。当用户登录到 UNIX 系统时,其当前工作目录通常是口令文件 /etc/password 中该用户登录项的第 6 个字段----用户的起始目录。进程可调用 getcwd、chdir 或 fchdir 函数来获取或更改当前工作目录(跟随符号链接)。
起始目录是登录名的一个属性,而当前工作目录是进程的一个属性,所以它只影响调用 chdir 的进程本身,而不影响其他进程,因此在子进程中改变当前目录对于父进程来说是不可见的。
因为内核必须维护当前工作目录的信息,所以我们应当能获取其当前值。但遗憾的是,内核为每个进程只保存指向该目录 v 节点的指针等目录本身的信息,并不保存该目录的完整路径名(Linux 内核可以确定完整路径名。完整路径名的各个组成部分分布在 mount 表和 dcache 表中,然后进行重新组装,比如在读取 /proc/self/cwd 符号链接时)。因此 getcwd 就提供了一种功能,它需要两个参数,一个是缓冲区地址 buf,另一个是缓冲区的长度。从当前工作目录“.”开始,用“..”找到其上一级目录,然后读其目录项,直到该目录项中的 i 节点编号与工作目录的相同,这样就找到了其对应的文件名。按这种方法,逐层上移到根,这样就得到了当前工作目录网站的绝对路径名。
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
int mkdirat(int fd, const char *pathname, mode_t mode);
#include <unistd.h>
int rmdir(const char *pathname);
/* 三个函数返回值:若成功,返回 0;否则,返回 -1 */
前两个函数创建一个新的空目录,其中“.”和“..”目录项是自动创建的。所指定的文件访问权限 mode 由进程的文件模式创建屏蔽字修改。常见的错误是指定与文件相同的 mode(只指定读、写权限)。但对于目录,通常至少要设置一个执行权限位,以允许访问该目录中的文件名。
mkdirat 和 mkdir 函数类似。当 fd 参数具有特殊值 AT_FDCWD 或者 pathname 参数指定了绝对路径名时,两者完全一样。否则,fd 参数是一个打开目录,相对路径名根据此打开目录进行计算。
如果调用 rmdir 函数使目录的链接计数减为 0,并且也没有其他进程打开此目录,则释放由此目录占用的空间。如果在链接计数变为 0 时,有一个或多个进程打开此目录,则在此函数返回前删除最后一个链接以及“.”和“..”项。另外,在此目录中不能再创建新文件,但在最后一个进程关闭它之前并不释放此目录(即使另一些进程打开该目录,它们也不能在此目录下执行其他操作,因为为了保证 rmdir 函数成功执行,该目录必须是空的)。
对某个目录具有访问权限的任一用户都可以读该目录,但为了防止文件系统产生混乱,只有内核才能写目录。一个目录的写权限位和执行权限位决定了在该目录中能否创建新文件以及删除文件,不过它们并不表示能否写目录本身。
为了简化读目录的过程,UNIX 在 POSIX.1 中提供了一套与目录有关的函数。
#include <dirent.h>
DIR *opendir(const char *pathname);
DIR *fdopendir(int fd);
/* 两个函数的返回值:若成功,返回指针;否则,返回 NULL */
struct dirent *readdir(DIR *dp);
/* 返回值:若成功,返回指针;若在目录尾或出错,返回 NULL */
void rewinddir(DIR *dp);
int closedir(DIR *dp); /* 返回值:若成功,返回 0;否则,返回 -1 */
long telldir(DIR *dp); /* 返回值:与 dp 关联的目录中的当前位置 */
void seekdir(DIR *dp, long loc);
/*
struct dirent{
ino_t d_ino; // i-node 编号
char d_name[]; // null 字符结尾的文件名
...
};
*/
其中,fdopendir 函数可以把打开文件描述符转换成目录处理函数需要的 DIR 结构。DIR 结构是一个内部结构,用来保存目录的有关信息,类似于 FILE 结构。由 opendir 和 fdopendir 返回的指向 DIR 结构的指针由另外几个函数使用。opendir 执行初始化操作,使第一个 readdir 返回目录中的第一个目录项。DIR 结构由 fdopendir 创建时,readdir 返回的第一项取决于传给 fdopendir 函数的文件描述符相关联的文件偏移量。注意,目录中各目录项的顺序与实现有关,通常并不按字母顺序排列。
每个进程都有一个当前工作目录。当用户登录到 UNIX 系统时,其当前工作目录通常是口令文件 /etc/password 中该用户登录项的第 6 个字段----用户的起始目录。进程可调用 getcwd、chdir 或 fchdir 函数来获取或更改当前工作目录(跟随符号链接)。
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int fd);
/* 返回值:若成功,都返回 0;否则,都返回 -1 */
char *getcwd(char *buf, size_t size);
/* 返回值:若成功,返回 buf;否则,返回 NULL */
起始目录是登录名的一个属性,而当前工作目录是进程的一个属性,所以它只影响调用 chdir 的进程本身,而不影响其他进程,因此在子进程中改变当前目录对于父进程来说是不可见的。
因为内核必须维护当前工作目录的信息,所以我们应当能获取其当前值。但遗憾的是,内核为每个进程只保存指向该目录 v 节点的指针等目录本身的信息,并不保存该目录的完整路径名(Linux 内核可以确定完整路径名。完整路径名的各个组成部分分布在 mount 表和 dcache 表中,然后进行重新组装,比如在读取 /proc/self/cwd 符号链接时)。因此 getcwd 就提供了一种功能,它需要两个参数,一个是缓冲区地址 buf,另一个是缓冲区的长度。从当前工作目录“.”开始,用“..”找到其上一级目录,然后读其目录项,直到该目录项中的 i 节点编号与工作目录的相同,这样就找到了其对应的文件名。按这种方法,逐层上移到根,这样就得到了当前工作目录网站的绝对路径名。