文件和目录
一、stat、fstat和lstat函数
#include <sys/stat.h>
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);
三个函数返回值:成功返回0,出错返回-1
参数介绍:
1. Pathname表示要查看其详细信息的那个文件的路径名,filedes表示打开该文件得到的文件描述符。
2. Fiedes表示文件描述符,其通过open(),create()函数返回值得到。
3. Buf为指针,其指向一个我们必须提供的结构。这些函数填写由buf指向的结构,该结构提供了文件的所有详细信息,其每一个成员都是基本系统数据类型,其基本形式为:
Struct stat{
Mode_t st_mode; //文件类型&访问权限
Ino_t st_ino; //文件i节点号
Dev_t st_dev; //文件系统设备号
Dev_t st_rdev; //特殊文件设备号
Nlink_t st_nlink;//连接数
Uid_t st_uid; //用户ID
Gid_t st_gid; //用户组ID
Off_t st_size; //普通文件大小(以字节为单位)
Time_t st_atime; //文件的最后访问时间
Time_t st_mtime;//文件的最后修改时间
Time_t st_ctime; //文件状态最后修改时间
Blksize_t st_blksize;//对文件I/O较适合的块长度
Blkcnt_t st_blocks; //所以分配的实际512字节块数量
};
说明:
1. 一旦给出pathname, stat函数就会返回与此命名文件有关的信息结构。
2. Fstat函数获取已在描述符filedes上打开的文件的有关信息。
3. Lstat函数类似于stat,但当命名文件是一个符号链接时,lstat返回该符号链接的有关信息。
二、文件类型
文件类型信息包含在stat结构的st_mode成员中,可以用下表中的宏测试确定文件类型。宏的参数为stat结构中的st_mode。
宏 | 文件类型 |
S_ISREG(st_mode) | 普通文件 |
S_ISDIR(st_mode) | 目录文件 |
S_ISCHR(st_mode) | 字符特殊文件 |
S_ISBLK(st_mode) | 块特殊文件 |
S_ISFIFO(st_mode) | 管道或FIFO |
S_ISLNK(st_mode) | 符号链接文件 |
S_ISSOCK(st_mode) | 套接字文件 |
文件类型有如下几种:
(1) 普通文件:
最常用的文件类型,包含了某种形式的数据;数据是文本还是二进制数据对于UNIX内核而言无区别。
(2) 目录文件:
该文件包含了其他文件的名字以及指向与这些文件有关信息的指针。对一个目录有读权限的任一进程都可读该目录内容;但只有内核可以直接写目录。
(3) 块特殊文件:
这种文件类型提供对设备(如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。
(4) 字符特殊文件:
这种文件类型提供对设备不带缓冲的访问,每次访问长度可变。系统中所有设别要么是字符特殊文件,要么是块特殊文件。
(5) FIFO:
这种文件类型用于进程间通信,有时也称其为命名管道。
(6) 套接字文件:
这种文件类型用于进程间的网络通信。套接字也可用于在一台宿主机上进程间的非网络通信。
(7) 符号链接:
这种文件类型用于指向另一个文件。
三、设置用户ID和设置组ID
与一个进程相关联的ID有6个或更多,如下表所示:
与每个进程相关联的用户ID和组ID | |
实际用户ID 实际组ID | 我们实际上是谁,这两个字段在登录时取自口令文件中的登录项,通常在登录会话期间这些值不会改变,但root进程可改变他们。 |
有效用户ID 有效组ID 附加组ID | 规定其文件访问权限,用户文件访问权限检查。 |
保存的设置用户ID 保存的设置组ID | 有exec函数保存 |
通常情况下:有效用户ID=实际用户ID(有效组ID=实际组ID); 但当设置用户ID标识(st_mode中的一个特殊标志)打开时,有效用户ID=文件所有者用户ID。
四、文件访问权限
St_mode值也包含了针对文件的访问权限位,所有文件类型都有访问权限。每个文件有9个访问权限位,如下表所示:
文件的9个访问权限位 | |
St_mode屏蔽 | 意义 |
S_IRUSR S_IWUSR S_IXUSR | 用户-读 用户-写 用户-执行 |
S_IRUSR S_IWUSR S_IXGRP | 组-读 组-写 组-执行 |
S_IROTH S_IWOTH S_IXOTH | 其他-读 其他-写 其他-执行 |
说明:
(1) 我们用名字打开任一类型的文件时,对该名字中包含的每一个目录,包括它可能隐含的当前工作目录都应具有执行权限。注意:对目录的读权限和执行权限的意义是不同的:读权限允许我们读目录,获得该目录中所有文件名的列表;而对目录的执行权限使我们可以通过该目录。
(2) 对于一个文件的读权限决定了我们是否能够打开该文件进行读操作;这与open函数的O_RDONLY和O_RDWR标志相关。
(3) 对于一个文件的写权限决定了我们是否能够打开该文件进行写操作;这与open函数的O_WRONLY和O_RDWR标志相关。
(4) 为了在open函数中对一个文件指定O_TRUNC标志,必须对该文件具有写权限。
(5) 为了在一个目录中创建一个新文件,必须对该目录具有写权限和执行权限。
(6) 为了删除一个现有的文件,必须对包含该文件的目录具有写权限和执行权限。对该文件本身则不需要有读、写权限。
(7) 如果用6个exec函数中的任何一个执行文件,都必须对该我呢间具有执行权限。且该文件还必须是普通文件。
五、access函数
即使一个进程可能已经因设置用户ID以超级用户权限运行,它仍可能想验证其实际用户能否访问一个给定的文件。access函数是按实际用户ID和实际组ID进行访问权限测试的。
#include <unistd.h>
Int access(const char *pathname, int mode);
返回值:成功返回0,出错返回-1
参数介绍:
1. Pathname表示要测试其权限的那个文件的路径名
2. Mode表示要测试文件的哪个权限。其mode常量见下表所示:
Access函数的mode常量 | |
mode | 说明 |
R_OK W_OK X_OK F_OK | 测试读权限 测试写权限 测试执行权限 测试文件是否存在 |
六、umask函数
下面我们将说明与每个进程相关联的文件模式创建屏蔽字,umask函数为进程设置文件模式创建屏蔽字,并返回以前的值。Umask函数实现禁止(屏蔽)所属组或其他用户的访问权限。
#include <sys/stat.h>
Mode_t umask(mode_t cmask);
返回值:以前的文件模式创建屏蔽字
参数介绍:
Cmask是由9个文件访问权限位中的若干个按位或构成的。
说明:
在进程创建一个新文件或新目录时,就一定会使用文件模式创建屏蔽字,对于任何在文件模式创建屏蔽字中为1的位,在文件mode中的相应位则一定被关闭。如:设置cmask值为002,则阻止其他用户写你的文件(000000010)。
七、chmod和fchmod函数
Chmod函数和fchmod函数是我们可以更改现有文件的访问权限。
#include <sys/stat.h>
Int chmod(const char *pathname, mode_t mode);
Int fchmod(int filedes, mode_t mode);
两个函数返回值:成功返回0;出错返回-1。
参数介绍:
1. Pathname表示要更改其访问权限的那个文件所在路径名;filedes则表示要更改其访问权限的文件的文件描述符。
2. Mode常量的值如下表所示:mode值为其中按位或运算构成。
Chmod函数的mode常量 | |
mode | 说明 |
S_ISUID S_ISGID S_ISVIX | 执行时设置用户ID 执行时设置组ID 保存正文(粘住位) |
S_IRWXU S_IRUSR S_IWUSR S_IXUSR | 用户(所有者)读、写和执行 用户(所有者)读 用户(所有者)写 用户(所有者)执行 |
S_IRWXG S_IRGRP S_IWGRP S_IXGRP | 组读、写和执行 组读 组写 组执行 |
S_IRWXO S_IROTH S_IWOTH S_IXOTH | 其他读、写和执行 其他读 其他写 其他执行 |
说明:
1. 要保留其权限则可用st_mode&(与)该位,否则与该位的非; 例:st_mode &~S_IXGRP | S_ISGID;也可以直接或上要设置的那几位;例:S_IRUSR|S_IWUSR|S_IRGRP|SIROTH等
2. 新文件的组ID可能是父目录的组ID。特别地,如果新文件的组ID不等于进程的有效组ID或者进程附加组ID中的一个,以及进程没有超级用户特权,那么设置组ID位将自动被关闭。
八、粘住位
S_ISVTX位被称为粘住位。如果一个可执行程序文件的这一位被设置了,那么在该程序第一次被执行并结束时,其程序正文部分的一个副本仍被保存在交换区中,这使得下次执行该程序时能较快地将其装入内存区。其原因是:
交换区占用连续磁盘空间,可将它视为连续文件,而且一个程序的正文部分在交换区中也是连续存放的,而在一般的UNIX文件系统中,文件的各数据块很可能是随机存放的。
现今较新的UNIX系统大多都配置有虚拟存储系统以及快速文件系统,所以不再需要使用这种技术。
如果对一个目录设置了粘住位,则只有对该目录具有写权限的用户在满足下列条件之一的情况下,才能删除或更名该目录下的文件:1.拥有该文件 2. 拥有该目录 3. 是超级用户
示例:目录/tmp和/var/spool/uucppublic是设置粘住位的典型候选者——任何用户都可在这两个目录中创建文件。任一用户(用户、组和其他)对这两个目录的权限通常都是读、写和执行。但用户不应删除或更名属于其他人的文件,为此在这两个目录的文件模式中都设置了粘住位。
九、chown、fchown和lchown函数
chown、fchown和lchown函数可用于更改文件用户ID和组ID。
#include <unistd.h>
Int chown(const char *pathname, uid_t owner, gid_t group);
Int fchown(int filedes, uid_t owner, gid_t group);
Int lchown(const char *pathname, uid_t owner, gid_t group);
三个函数返回值:成功返回0;出错返回-1。
参数介绍:
1. Pathname表示要更改其用户ID和组ID的那个文件的路径名;filedes表示要更改其用户ID和组ID的那个文件的文件描述符。
2. Owner表示所要更改的用户ID;group表示所要更改的组ID。
说明:
1. 除了所引用的文件是符号链接以外,这三个函数操作相似;在符号链接的情况下,lchown更改符号链接本身的所有者,而不是该符号链接所指向的文件。
2. _POSIX_CHOWN_RESTRICTED常量可选地定义在头文件<unistd.h>中,其起作用时,则:
(1) 只有超级用户进程能更改该文件的用户ID
(2) 若满足下列条件,一个非超级用户进程就可以更改该文件的组ID:
a. 进程拥有此文件(其有效用户ID等于该文件的用户ID)。
b. 参数owner等于-1或文件的用户ID,并且参数group等于进程的有效组ID或进程的附加组ID之一。
即当_POSIX_CHOWN_RESTRICTED起作用时,你不能更改其他用户文件的用户ID。你可以更改你所拥有的文件的组ID,但只鞥改到你所属的组。
十、文件长度
Stat结构成员st_size表示以字节为单位的文件长度。此字段只对普通文件、目录文件和符号链接文件有意义:
对于普通文件,其文件长度可以为0,在读这种文件时,将得到文件结束(end-of-file)指示。
对于目录,文件长度通常是一个数(如16或512)的倍数。
对于符号链接,文件长度是文件命中的实际字节数。
文件空洞:
空洞是由所设置的偏移量超过了文件尾端,并写入了某些数据后造成的。如果使用实用程序复制这种文件,那么所有这些空洞都会被填满,其中所有实际数据字节都将被填写为0。
十一、文件截短
有时我们需要在文件尾端处截去一些数据以缩短文件。将一个文件清空为0是一个特例,在打开文件时使用O_TRUNC 标志可以做到这一点。
#include <unistd.h>
Int truncate(const char *pathname, off_t length);
Int ftruncate(int filedes, off_t length);
两个函数的返回值:成功返回0,出错返回-1.
参数介绍:
1. Pathname表示要截短其文件长度的那个文件的路径名;filedes表示要截短其文件长度的那个文件的文件描述符。
2. Length表示将现有的文件长度截短为length字节。
说明:
这两个函数将把现有的文件长度截短为length字节。如果该文件以前长度大于length,则超过length以外的数据就不再能访问。若文件以前的长度短于length,则其效果与系统有关;遵循XSI的系统将增加该文件的长度。若UNIX系统实现扩展了该文件,则在以前的文件尾端和新的文件尾端之间的数据将读做0。
十二、文件系统
传统的基于BSD的UNIX文件系统(UFS,UNIX file system)是以BSD快速文件系统为基础的。我们可以把一个磁盘分成一个或多个分区。每个分区包含一个文件系统,其中i节点是固定长度的记录项,它包含有关文件的大部分信息。
其磁盘、分区和文件系统关系图如图所示:
若更仔细地观察一个柱面组的i节点和数据部分,则可以看到较详细的柱面组的i节点和数据块图如图所示:
说明:
1. 在图中有两个目录项均指向同一i节点。每个i节点中都有一个链接计数,其值是指向该i节点的目录项数。只有当链接计数减少至0时才可删除该文件(也即释放该文件占用的数据块)。这就是为什么”解除对一个文件的链接”操作并不总是意味着”释放该文件占用的磁盘块”的原因。这也是为什么删除一个目录项的函数被称为unlink而不是delete的原因。在stat结构中,链接计数包含在st_nlink成员中,其基本系统数据类型是nlink_t。这种链接类型称为硬链接。对应在POSIX.1中常量LINK_MAX指定了一个文件连接数的最大值。
2. 另外一种链接类型称为符号链接(symbolic link)。对于这种链接,该文件的实际内容(在数据块中)包含了该符号链接所指向的文件的名字。该i节点中的文件类型是S_IFLNK,于是系统知道这是一个符号链接。
3. i节点包含了大多数与文件有关的信息:文件类型、文件访问权限位、文件长度和指向该文件所占用的数据块的指针等等。Stat结构中的大多数信息都取自i节点。只有两项数据存放在目录项中:文件名和i节点编号。I节点编号的数据类型是ino_t。
4. 每个文件系统各自对它们的i节点进行编号,因此目录项中的i节点编号数指向同一文件系统中的相应i节点,不能使一个目录项指向另一个文件系统的i节点。这就是为什么ln命令(构造一个指向一个现有文件的新目录项)不能给你跨越文件系统的原因。
5. 当在不更换文件系统的情况下为一个文件更名时,该文件的实际内容并未移动,只需构造一个指向现有i节点的新目录项,并删除与旧目录项的链接。
十三、link、unlink、remove和rename函数
1. link函数
任何一个文件可以有多个目录项指向其i节点。创建一个指向现有文件的链接的方法是使用link函数。
#include <unistd.h>
Int link(const char *exitingpath, const char *newpath);
返回值:成功返回0,出错返回-1。
参数介绍:
1. Exitingpath表示现有的文件的路径名;
2. Newpath表示所创建的新目录项newpath,其硬链接指向exitingpath。
说明:
该函数创建一个新目录项newpath,它引用现有的文件exitingpath。若newpath已经存在,则返回出错。若只创建newpath中的最后一个分量,路径中的其他部分应当已经存在。若实现支持创建指向一个目录的硬链接,那么仅限于超级用户才可以这样做。
2.unlink函数
为了删除一个现有的目录项,可以调用unlink函数。
#include <unistd.h>
Int unlink(const char *pathname);
返回值:成功返回0,出错返回-1。
参数介绍:
Pathname表示所要删除其向其他文件的那个文件链接的路径名。
说明:
1. 该函数删除目录项,并将由pathname所引用文件的链接计数减1。如果还有指向该文件的其他链接,则仍可通过其他链接访问该文件的数据。如果出错,则不对该文件作任何更改。
2. 只有当链接计数达到0时,该文件的内容才可被删除。另一个条件也会阻止删除文件的内容——只要有进程打开了该文件,其内容也不能删除。关闭一个文件时,内核首先检查打开该文件的进程数;如果该数达到0,然后内核检查其链接数,如果这个数也是0,那么就删除该文件的内容。
3. unlink的这种性质经常被程序用来确保即使是在该程序崩溃时,他所创建的临时文件也不会遗留下来。进程用open或create创建一个文件,然后立即调用unlink。因为该文件仍旧是打开的,所以不会将其内容删除。只有当进程关闭该文件或终止时(这种情况下,内核会关闭该进程打开的全部文件),该文件的内容才会被删除。
3. remove函数
#include <stdio.h>
Int remove(const char *pathname);
返回值:成功返回0;出错返回-1。
参数介绍:
Pathname表示要解除的链接的路径名。
说明:
我们也可以用remove函数解除对一个文件或目录的链接,对于文件,remove的功能与unlink相同;对于目录,remove的功能与rmdir相同。
4.rename函数
文件或目录用rename函数更名。
#include <stdio.h>
Int rename(const char *oldname, const char *newname);
返回值:成功返回0;出错返回-1。
参数说明:
oldname表示文件或目录更名前的旧名字;newname表示文件或目录更名后的新名字。
说明:
(1) 若oldname指的是一个文件而不是目录,那么为该文件或符号链接更名。在这种情况下,若newname已经存在,则它不能引用一个目录。如果newname已经存在,而且不是一个目录,则先将该目录项删除然后将oldname更名为newname。对包含oldname的目录以及包含newname的目录,调用进程必须具有写权限,因为将更改者两个目录。
(2) 若oldname指的是一个目录,那么为该目录更名。若newname已存在,则必须引用一个目录,而且该目录应当是空目录(只该目录中只有.和..项)。如果newname存在(而且是一个空目录)。则先将其删除,然后将oldname更名为newname。另外当为一个目录更名时,newname不能包含oldname作为其路径前缀。
(3) 若oldname或newname引用符号链接,则处理的是符号链接本身,而不是它所引用的文件。
(4) 作为一个特例,如果oldname和newname引用同一个文件,则函数不做任何更改而成功返回。
十四、符号链接
符号链接是指向一个文件的间接指针,其与硬连接的区别为硬连接直接指向文件的i节点。
硬链接:1.硬链接通常要求链接和文件位于同一文件系统中。
2.只有超级用户才能创建指向目录的硬链接。
符号链接:1. 对符号链接以及它指向何种对象并无任何文件系统限制。
2. 任何用户都可创建指向目录的符号链接
符号链接一般用于将一个文件或整个目录结构移到系统中的另一个位置。
十五、symlink和readlink函数
1. symlink函数
Sysmlink函数创建一个符号链接。
#include <unistd.h>
Int symlink(const char *actualpath, const char *sympath);
返回值:成功返回0;出错返回-1。
参数介绍:
actualpath表示符号链接所指向的那个文件路径名;sympath表示符号链接的路径名。
说明:
该函数创建了一个指向actualpath的新目录项sympath,在创建此符号链接时,并不要求actualpath已经存在。并且,actualpath和sympath并不需要位于同一文件系统中。
2. readlink函数
因为open函数跟随符号链接,所以需要有一种方法打开该符号链接本身,并读该链接中的名字。Readlink函数实现这样的功能。
#include <unistd.h>
Ssize_t readlink(const char * reastrict pathname, char * restrict buf,size_t bufsize);
返回值:成功返回读到的字节数,出错返回-1。
参数介绍:
pathname表示符号链接的路径名;buf表示读到的符号链接内容放到buf中;bufsize表示读到buf中内容字节数。
说明:
若此函数执行成功,则返回读入buf的字节数。在buf中返回的符号链接的内容不以null字符终止。
十六、文件的时间
对每个文件保持有三个时间字段,其值如下表所示:
与每个文件相关的三个时间值 | |||
字段 | 说明 | 例子 | Ls(l)选项 |
St_atime | 文件数据的最后访问时间 | read | -u |
St_mtime | 文件数据的最后修改时间 | write | 默认 |
St_ctime | i节点状态的最后更改时间 | Chmod,chown | -c |
说明:
1. 注意修改时间(st_mtime)和更改状态时间(st_ctime)之间的区别:修改时间是文件数据内容最后一次被修改的时间。更改状态时间则是该文件的i节点最后一次被修改的时间,例如:更改文件的访问权限、用户ID、链接数等,它们改变了i节点,但并没有更改文件的实际内容。因为i节点中的所有信息都是与文件的实际内容分开存放的,所以除了文件数据修改时间以外,还需要文件更改状态时间。
2. 注意系统并不保存对一个i节点的最后一次访问时间,所以access和stat函数并不更改这三个时间中的任一个。只有更改了文件的i节点信息才能更改st_ctime。
3. 系统管理员常常使用访问时间来删除在一定的时间范围内没有访问过的文件。
4. ls命令按这三个时间值中的一个排序进行显示。按系统默认(-l或-t选项调用时),它按文件数据的修改时间的先后排序显示。-u选项使其用访问时间排序;-c选项则使其用更改状态时间排序。
十七、utime函数
一个文件的访问和修改时间可以用utime函数更改。
#include <utime.h>
Int utime(const char *pathname, const struct utimebuf *times);
返回值:成功返回0;出错返回-1。
参数介绍:
Pathname表示要修改器访问和修改时间的文件的路径名;times结构体表示要更改称为的访问和修改时间。
Utimebuf结构体表示如下:
Struct utimebuf{//该结构中的两个时间值是日历时间
Time_t actime; // 表示文件数据的最后访问时间。
Time_t modtime;//表示文件数据的最后修改时间。
}
说明:
1. 如果times是一个空指针,则访问时间和修改时间两者都设置为当前时间。要能执行该操作,要么进程的有效用户ID必须等于该文件的所有者ID,要么进程对该文件具有写权限。
2. 如果times是非空指针,则访问时间和修改时间被设置为times所指向结构中的值。此时,进程的有效用户ID必须等于该文件的所有者ID,或者进程为一个超级用户进程。仅仅对进程具有写权限是不够的。
3. 注意:我们不能对更改状态时间st_ctime指定一个值,当调用utime函数时,此字段将被自动更新。
十八、mkdir和rmdir函数
1. mkdir函数
用mkdir函数创建目录。
#include <sys/stat.h>
Int mkdir(const char *pathname, mode_t mode);
返回值:成功返回0,出错返回-1。
参数介绍:
Pathname表示所要创建的空目录的路径名;mode表示对新创建目录所指定的文件访问权限。
说明:
1. 此函数创建一个新的空目录。其中.和..目录项是自动创建的。所指定的文件访问权限mode由进程的文件模式创建屏蔽字修改。
2. 常见的错误是指定与文件相同的mode(只指定读、写权限)。但是,对于目录通常至少要设置1个执行权限位,以允许访问该目录的文件名。
2. rmdir函数
用rmdir函数可以删除一个空目录。空目录是只包含.和..这两项的目录。
#include <unistd.h>
Int rmdir(const char * pathname);
返回值:成功返回0;出错返回-1。
参数介绍:
Pathname表示所要删除的空目录的路径名。
说明:
若调用此函数使目录的链接计数成为0,并且也没有其他进程打开此目录,则释放由此目录占用的空间。如果在链接计数达到0时,有一个或几个进程打开了此目录,则在此函数返回前删除最后一个链接及.和..项。另外,在此目录中不能再创建新文件。但是在最后一个进程关闭它之前并不释放此目录。
十九、读目录
对某个目录具有访问权限的任一用户都可读该目录,但是,为了防止文件系统产生混乱,只有内核才能写目录。
#include <dirent.h>
DIR *opendir(const char *pathname); 返回值:成功返回指针;出错返回NULL。
Struct dirent *readdir(DIR *dp); 返回值:成功返回指针;在目录结尾或出错返回NULL。
Void rewinddir(DIR *dp);
Int clostdir(DIR *dp); 返回值:成功返回0;出错返回-1.
long telldir(DIR *dp); 返回值:与dp关联的目录中的当前位置。
Void seekdir(DIR *dp, long loc);
参数介绍:
Pathname表示要打开的那个目录的路径名;dp表示指向DIR结构的指针;loc表示在目录中的当前位置。
说明:
1. telldir和seekdir函数不是基本POSIX.1标准的组成部分,它们是Single UNIX Specification中的XSI 扩展。
2. 头文件<dirent.h>中定义的dirent结构与实现有关。集中典型的UNIX实现对此结构所做的定义至少包含下列两个成员:Struct dirent{
Ino_t d_ino; //表示目录的i节点号
Char d_name[NAME_MAX+1]; //表示不以null作为结束符的目录名
}因为文件名是以null字符结束的,所以在头文件中如何定义数组d_name并无多大关系,数组大小并不表示文件名的长度。
3. DIR结构是一个内部结构,上面的6个函数用这个内部结构保存当前正被读的目录的有关信息。其作用类似于FIFO结构。
4. 由opendir返回的指向DIR结构的指针由另外5个函数使用。Opentdir执行初始化操作,使第一个readdir读目录中的第一个目录项。目录中各目录项的顺序与实现有关,通常不按字母排序。
二十、chdir、fchdir和getcwd函数
每个进程都有一个当前工作目录,此目录是搜索所有相对路径名的起点。当用户登录到UNIX系统时,其当前工作目录里通常是口令文件中该用户登录项的第6个字段——用户的起始目录。当前工作目录是进程的一个属性,起始目录则是登录名的一个属性。
1. chdir和fchdir函数
进程可通过调用chdir或fchdir函数来更改当前工作目录。
#include <unistd.h>
Int chdir(const char* pathname);
Int fchdir(int filedes);
两个函数的返回值:成功返回0;出错返回-1。
参数介绍:
Pathname表示指定的新的当前工作目录的路径名;filedes则表示通过打开文件描述符来指定新的当前工作目录。
说明:
因为当前工作目录是进程的一个属性,所以它只影响调用chdir的进程本身,而不影响其他进程。
2. getcwd函数
因为内核保持有当前工作目录的信息,所以我们应能取其当前值。但是,内核为每个进程只保存指向该目录v节点的指针等目录本身的信息,并不保存该目录的完整路径名。
故而我们需要一个函数,其从当前工作目录(.)开始,用..目录项找到其上一级的目录,然后读其目录项,直到该目录项中的i节点编号与工作目录里i节点编号相同,这样就找到了其对应的文件名。按照这种方法逐层上移,直到遇到根,这样就得到了当前工作目录完整的绝对路径名。而getcwd函数就提供这种功能。
#include <unistd.h>
Char *getcwd(char *buf, size_t size);
返回值:成功返回buf;出错返回NULL。
参数介绍:
Buf表示将绝对路径写到缓冲地址buf开始的缓冲区中;size表示缓冲区长度(以字节为单位)。
说明:
缓冲区必须有足够的长度以容纳绝对路径名再加上一个null终止字符,否则返回出错。