第四章-文件和目录

…衆ロ難τιáo~ 提交于 2020-01-14 02:26:18

引言

本章内容覆盖

  1. 文件的所有属性
  2. 修改这些属性的各个函数
  3. unix文件系统的结构以及符号链接
  4. 对目录进行操作的各个函数

函数stat、fstat、fstatat和lstat

   #include <sys/types.h>
       #include <sys/stat.h>
       #include <unistd.h>
       int stat(const char *pathname, struct stat *buf); //返回命名文件有关的信息结构
       int fstat(int fd, struct stat *buf);//返回fd上打开文件的有关信息
       int lstat(const char *pathname, struct stat *buf);//该符号链接的有关信息
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <sys/stat.h>
       int fstatat(int dirfd, const char *pathname, struct stat *buf,
                   int flags);//相对于当前打开目录的路径名返回文件统计信息,dirfd

文件类型

  1. 普通文件,unix内核不区分文件内容是文本还是二进制,交给处理该文件的应用程序去解释
  2. 目录文件,只有内核可以直接写,它包含了其他文件名及指向与这些文件有关信息的指针
  3. 块设备文件,对设备(如磁盘)带缓冲的访问
  4. 字符特殊文件,对设备不带缓冲的访问
  5. FIFO,命名管道,用于进程间通信
  6. 套接字(socket),用于进程间的网络通信
  7. 符号链接(symbolic link),指向另一个文件
    以下示例程序实现“针对每一个命令行参数打印其文件类型”
#include "apue.h"

int
main(int argc, char *argv[])
{
        int                     i;
        struct stat     buf;
        char            *ptr;

        for (i = 1; i < argc; i++) {
                printf("%s: ", argv[i]);
                if (lstat(argv[i], &buf) < 0) {
                        err_ret("lstat error");
                        continue;
                }
                if (S_ISREG(buf.st_mode))
                        ptr = "regular";
                else if (S_ISDIR(buf.st_mode))
                        ptr = "directory";
                else if (S_ISCHR(buf.st_mode))
                        ptr = "character special";
                else if (S_ISBLK(buf.st_mode))
                        ptr = "block special";
                else if (S_ISFIFO(buf.st_mode))
                        ptr = "fifo";
                else if (S_ISLNK(buf.st_mode))
                        ptr = "symbolic link";
                else if (S_ISSOCK(buf.st_mode))
                        ptr = "socket";
                else
                        ptr = "** unknown mode **";
                printf("%s\n", ptr);
        }
        exit(0);
}

设置用户ID和设置组ID

与每个进程相关联的用户ID和组ID
在这里插入图片描述
通常有效用户ID就是实际用户ID,有效组ID就是实际组ID,st_mode
中设置特殊标志,使进程有效用户ID用文件所有者用户ID(st_uid),有效组ID用文件的组所有者ID(st_gid)

文件访问权限

st_mode包含了对文件的访问权限位,对于所有文件类型,总共9个访问权限位:在这里插入图片描述
chomod命令修改这9个访问权限位,

  1. 目录执行权限使能打开该目录下的文件
  2. 目录读权限使能获得该目录下的所有文件名的列表
  3. 文件读权限使能打开和读该文件
  4. 文件写权限使能打开和写该文件
  5. 文件所在目录的写权限和执行权限使能删除该文件
    进程打开、创建或删除一个文件操作会触发内核进行文件访问权限测试(所有者ID sh是文件属性,有限ID和附属组ID是进程属性)
    下图是内核的大致测试流程
    在这里插入图片描述
    J1:进程的有效用户ID是0(超级用户)?
    J2:进程的有效用户ID等于文件的所有者ID(进程拥有此文件)?
    J3:所有者适当的访问权限位被设置?
    J4:进程的有效组ID或进程的附属组ID之一等于文件的组ID(进程属于某个组)?
    J5:组适当的访问权限位被设置?
    J6:其他用户适当的访问权限位被设置?

函数access和facessat

    #include <unistd.h>
       int access(const char *pathname, int mode);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <unistd.h>
       int faccessat(int dirfd, const char *pathname, int mode, int flags);

这两个函数按实际用户ID和实际组ID进行访问权限测试,看下面的示例

int
main(int argc, char *argv[])
{
        if (argc != 2)
                err_quit("usage: a.out <pathname>");
        if (access(argv[1], R_OK) < 0)//测试读权限位
                err_ret("access error for %s", argv[1]);
        else
                printf("read access OK\n");
        if (open(argv[1], O_RDONLY) < 0)
                err_ret("open error for %s", argv[1]);
        else
                printf("open for reading OK\n");
        exit(0);
}

接着看下面该程序运行的测试:

xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l access.c
-rwxrw-rw- 1 nobody nogroup 367 4月  27  2013 access.c
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ./access access.c 
read access OK
open for reading OK   //test1:用户xiangke可以读打开的文件“access.c ”
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1274 11月  8  2018 /etc/shadow
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ./access /etc/shadow
access error for /etc/shadow: Permission denied//test2:但是用户xiangke没有访问文件“/etc/shadow”权限
open error for /etc/shadow: Permission denied
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ sudo -i
[sudo] xiangke 的密码: 
root@xiangke-virtual-machine:~# cd /home/apue.3e/filedir/
root@xiangke-virtual-machine:/home/apue.3e/filedir# chown root access
root@xiangke-virtual-machine:/home/apue.3e/filedir# chmod u+s access
root@xiangke-virtual-machine:/home/apue.3e/filedir# ls -l access
-rwsr-xr-x 1 root root 13688 1月   4 16:45 access //accss文件的用户ID改为了root,已打开设置用户ID位
root@xiangke-virtual-machine:/home/apue.3e/filedir# exit
注销
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ./access /etc/shadow
access error for /etc/shadow: Permission denied //test4:用户xiangke能打开该文件了,因为设置了用户ID,但仍然不能正常读该文件
open for reading OK
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ 

函数umask

这里说明与每个进程相关联的文件模式创建屏蔽字,文件模式创建屏蔽字为1的位,在文件mode中的相应位一定被关闭。

  #include <sys/types.h>
       #include <sys/stat.h>
       mode_t umask(mode_t mask);

看下面这个实例

#include "apue.h"
#include <fcntl.h>
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
int
main(void)
{
        umask(0);
        if (creat("foo", RWRWRW) < 0)
                err_sys("creat error for foo");
        umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
        if (creat("bar", RWRWRW) < 0)
                err_sys("creat error for bar");
        exit(0);
}

运行此程序,如下

xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ umask //查看当前文件模式创建屏蔽字
0002
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ./umask 
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l foo bar
-rw------- 1 xiangke xiangke 0 1月   9 13:41 bar 
-rw-rw-rw- 1 xiangke xiangke 0 1月   9 13:41 foo
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ 

从程序运行结果来看可知umask函数禁止了所有组和其他用户的访问权限

函数chmod、fchmod和fchomodat

更改现有文件的访问权限

   #include <sys/stat.h>
       int chmod(const char *pathname, mode_t mode);
       int fchmod(int fd, mode_t mode);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <sys/stat.h>
       int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);

参数mode是下图中所示常量的按位与
在这里插入图片描述
以下实例修改了文件模式

#include "apue.h"

int
main(void)
{
        struct stat             statbuf;
        /* turn on set-group-ID and turn off group-execute */

        if (stat("foo", &statbuf) < 0)
                err_sys("stat error for foo");
        if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
                err_sys("chmod error for foo");
        /* set absolute mode to "rw-r--r--" */
        if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
                err_sys("chmod error for bar");

        exit(0);
}
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l bar foo
-rw------- 1 xiangke xiangke 0 1月   9 13:41 bar
-rw-rw-rw- 1 xiangke xiangke 0 1月   9 13:41 foo
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ./changemod 
//对文件foo关闭了组执行权限,打开了设置组ID位;对文件bar,其权限设置为一个绝对值
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l bar foo
-rw-r--r-- 1 xiangke xiangke 0 1月   9 13:41 bar
-rw-rwSrw- 1 xiangke xiangke 0 1月   9 13:41 foo
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$

函数chown、fchown、fchownat和lchown

AT_SYMLINK_NOFOLLOW 被设置意味着是操作符号链接本身而不是它所指向的文件
这些函数用于更改文件的用户ID和组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);//操作fd参数指向的打开文件
       int lchown(const char *pathname, uid_t owner, gid_t group);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <unistd.h>
       int fchownat(int dirfd, const char *pathname,
                    uid_t owner, gid_t group, int flags);

以下是一个更改文件所有者的实例

void  test_chown()
{
     int iret = 0;
     struct stat buf;
     if (-1 == stat(FILE_NAME, &buf))
     {
         perror("stat errors!");
         exit(0);
     }
     printf("user ID group ID\n"
            "%-7d %-8d\n", buf.st_uid, buf.st_gid);

     iret = chown(FILE_NAME, 0, 0);
     if (-1 == iret)
     {
         perror("chown errors!");
         exit(0);
     }
     if (-1 == stat(FILE_NAME, &buf))
     {
         perror("stat errors!");
         exit(0);
     }
     printf("after chown:\n"
            "user ID group ID\n"
            "%-7d %-8d\n", buf.st_uid, buf.st_gid);
}
 int main(void)
 {
     test_chown();
 }

以下是该实例的执行效果

xiangke@xiangke-virtual-machine:/home/apue.3e/fileio$ whoami && id
xiangke //查看用户ID和组ID
uid=1000(xiangke) gid=1000(xiangke)=1000(xiangke),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
xiangke@xiangke-virtual-machine:/home/apue.3e/fileio$ 
xiangke@xiangke-virtual-machine:/home/apue.3e/fileio$ ./hole 
xiangke@xiangke-virtual-machine:/home/apue.3e/fileio$ ls -l file.hole 
-rw-r--r-- 1 xiangke xiangke 16394 1月   9 14:40 file.hole //新建的文件file.hole 文件用户ID和组ID均为1000
xiangke@xiangke-virtual-machine:/home/apue.3e/fileio$ 
xiangke@xiangke-virtual-machine:/home/apue.3e/fileio$ ./itest 
user ID group ID
1000    1000    
chown errors!: Operation not permitted //普通用户更改文件"file.hole的所有者的操作被禁止
xiangke@xiangke-virtual-machine:/home/apue.3e/fileio$ 
xiangke@xiangke-virtual-machine:/home/apue.3e/fileio$ sudo -i//切换到超级用户
root@xiangke-virtual-machine:/home/apue.3e/fileio# ./itest
user ID group ID
1000    1000    
after chown
user ID group ID
0       0       //超级用户成功的更改了该文件的所有者
root@xiangke-virtual-machine:/home/apue.3e/fileio# 

文件长度

  • 符号链接文件长度是在文件名中的实际字节数
root@xiangke-virtual-machine:/home/apue.3e/fileio# ln -s /usr/lib/ ilib
root@xiangke-virtual-machine:/home/apue.3e/fileio# ls -l ilib
lrwxrwxrwx 1 root root 9 1月   9 15:15 ilib -> /usr/lib/  //刚好9个字节
  • 普通文件长度可以是0
  • 目录文件长度一般是一个数(16或512)的整数倍
  • 文件中的空洞
root@xiangke-virtual-machine:/home/apue.3e/fileio# ls -l file.hole 
-rw-r--r-- 1 root root 16394 1月   9 14:40 file.hole
root@xiangke-virtual-machine:/home/apue.3e/fileio# du -s file.hole 
8       file.hole //该文件所用的磁盘空间总量是8x1024=8192字节,远小于实际文件的长度,所以该文件中有空洞,
root@xiangke-virtual-machine:/home/apue.3e/fileio# wc -c file.hole 
16394 file.hole
root@xiangke-virtual-machine:/home/apue.3e/fileio# cat file.hole > filehole.copy //空洞都会用0填满
root@xiangke-virtual-machine:/home/apue.3e/fileio# ls -l file.hole  filehole.copy 
-rw-r--r-- 1 root root 16394 1月   9 14:40 file.hole
-rw-r--r-- 1 root root 16394 1月   9 15:24 filehole.copy
root@xiangke-virtual-machine:/home/apue.3e/fileio# du -s file.hole filehole.copy 
8       file.hole
20      filehole.copy //需要额外的块存储指向实际数据块的各个指针

文件截断

打开文件时使用标志O_TRUNC
以下函数将一个现有文件长度截断为length

 #include <unistd.h>
       #include <sys/types.h>
       int truncate(const char *path, off_t length);
       int ftruncate(int fd, off_t length);

文件系统

以下讨论unxi文件系统UFS(以Berkeley快速文件系统为基础)

  1. 大小写敏感
  2. 磁盘\分区\文件系统关系
    在这里插入图片描述
    在这里插入图片描述
    关于柱面组的i节点和数据块部分,有
  • i节点链接计数其值是指向该i节点的目录项数, LINK_MAX指定了一个文件链接数的最大值
  • i节点编号和文件名存放在目录项中
  • i节点包含了文件有关的所有信息
  • 一个目录项不能指向另一个文件系统中的i节点,所以ln(1)命令(对于硬链接)不能跨越文件系统
  • mv命令重命名文件的通用操作是构造一个指向i节点的新目录项,并删除老的目录项

函数link、linkat、unlink、unlinkat和remove

创建新目录项和增加链接计数应当是一个原子操作
创建一个指向现有文件链接的方法

#include <unistd.h>
       int link(const char *oldpath, const char *newpath);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <unistd.h>
       int linkat(int olddirfd, const char *oldpath,
                  int newdirfd, const char *newpath, int flags);

删除一个现有的目录项

   #include <unistd.h>
       int unlink(const char *pathname);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <unistd.h>
       int unlinkat(int dirfd, const char *pathname, int flags);

解除对一个文件或目录的链接

  #include <stdio.h>
       int remove(const char *pathname);//对于文件,功能同unlink函数;对于目录,功能同rmdir函数

看以下示例:

#include "apue.h"
#include <fcntl.h>
int
main(void)
{
        if (open("tempfile", O_RDWR) < 0) //打开一个文件
                err_sys("open error");
        if (unlink("tempfile") < 0)
                err_sys("unlink error");
        printf("file unlinked\n");
        sleep(15);
        printf("done\n");
        exit(0);
}

按照如下操作运行该程序,

xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l tempfile 
-rw-r----- 1 xiangke xiangke 1940248 1月   9 16:23 tempfile
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ df ./
文件系统          1K-块    已用     可用 已用% 挂载点
/dev/sda1      19478204 5504084 12961640   30% /
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ./unlink &
[1] 18606
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ file unlinked

xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l tempfile
ls: 无法访问'tempfile': 没有那个文件或目录
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ df ./
文件系统          1K-块    已用     可用 已用% 挂载点
/dev/sda1      19478204 5504084 12961640   30% /
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ df done
./
文件系统          1K-块    已用     可用 已用% 挂载点
/dev/sda1      19478204 5502188 12963536   30% /
[1]+  已完成               ./unlink
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ 

从上述运行结果来看,解除文件链接后在该程序进程结束之前,文件tempfile已经删除了但磁盘空间并没有变化,说明文件内容还被保留,进程退出后,该文件内容才被删除,所以有更多的可用磁盘空间.

函数rename和renameat

这些函数对文件或目录进行重命名

 #include <stdio.h>
       int rename(const char *oldpath, const char *newpath);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <stdio.h>
       int renameat(int olddirfd, const char *oldpath,
                    int newdirfd, const char *newpath);
       int renameat2(int olddirfd, const char *oldpath,
                     int newdirfd, const char *newpath, unsigned int flags);
  • oldpath是目录,newpath不能是其子目录,newpath已存在则它必须是空目录。
  • 不能对.和…重命名
  • oldpath引用符号链接,则处理的是符号链接本身
  • oldpath是文件或符号链接,newpath必须是一个文件而不是目录
  • 调用进程需要堆包含oldpath和newpath的目录具有写和执行权限,对newname具有写权限。

创建和读取符号链接

符号链接是对一个文件的间接指针,不同于硬链接只能超级用户才能创建,任何用户都可创建,也没有任何文件系统限制
以下函数创建符号链接

/*1.don't care if target is existent*/
/*2.linkpath and target don't neet to be located in the same filesystem*/
 #include <unistd.h>
       int symlink(const char *target, const char *linkpath);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <unistd.h>
       int symlinkat(const char *target, int newdirfd, const char *linkpath);

以下函数读符号链接的值

/*1.the content in buf don't terminate by NULL*/
 #include <unistd.h>
       ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <unistd.h>
       ssize_t readlinkat(int dirfd, const char *pathname,
                          char *buf, size_t bufsiz);

文件的时间

对每个文件维护3个时间字段,如下在这里插入图片描述
以下列出了各种函数对访问、修改和状态更改时间的作用,特别强调状态更改时间是i节点最后一次被修改的时间。
在这里插入图片描述

函数futimens、utimensat和utimes

以下函数更改一个文件的访问时间和修改时间

/*1.times[0]包含访问时间,times[1]包含修改时间,时间值是日历时间*/
#include <fcntl.h> /* Definition of AT_* constants */
       #include <sys/stat.h>
       int utimensat(int dirfd, const char *pathname,
                     const struct timespec times[2], int flags);
       int futimens(int fd, const struct timespec times[2]);

这里涉及以下宏

  1. flags = AT_SYMLINK_NOFOLLOW, file’s time don’t follow the syslink’s
  2. dirfd=AT_FDCWD means that using the current work directory of the calling process
  3. times=NULL ,current time is set
    以下是一个示例
#include "apue.h"
#include <fcntl.h>

int
main(int argc, char *argv[])
{
        int                             i, fd;
        struct stat             statbuf;
        struct timespec times[2];

        for (i = 1; i < argc; i++) {
                if (stat(argv[i], &statbuf) < 0) {      /* fetch current times */
                        err_ret("%s: stat error", argv[i]);
                        continue;
                }
                if ((fd = open(argv[i], O_RDWR | O_TRUNC)) < 0) { /* truncate */
                        err_ret("%s: open error", argv[i]);
                        continue;
                }
                times[0] = statbuf.st_atim;
                times[1] = statbuf.st_mtim;
                if (futimens(fd, times) < 0)            /* reset times */
                        err_ret("%s: futimens error", argv[i]);
                close(fd);
        }
        exit(0);
}

open将文件长度截断为0,未改变该文件的访问时间和修改时间,按如下操作步骤执行测试

xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l changemod bar
-rw-r--r-- 1 xiangke xiangke     0 1月   9 13:41 bar
-rwxr-xr-x 1 root    root    13712 1月   4 16:45 changemod
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -l changemod unlink
-rwxr-xr-x 1 root root 13712 1月   4 16:45 changemod
-rwxr-xr-x 1 root root 13736 1月   4 16:45 unlink
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -lu changemod unlink
-rwxr-xr-x 1 root root 13712 1月   9 14:48 changemod
-rwxr-xr-x 1 root root 13736 1月   9 16:15 unlink
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ date
2020年 01月 10日 星期五 15:38:14 CST
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ./zap changemod unlink
changemod: open error: Permission denied
unlink: open error: Permission denied
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ sudo ./zap changemod unlink
[sudo] xiangke 的密码: 
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -lu changemod unlink
-rwxr-xr-x 1 root root 0 1月   9 14:48 changemod
-rwxr-xr-x 1 root root 0 1月   9 16:15 unlink //这里表明文件最后修改时间和访问时间未变.
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ls -lc changemod unlink 
-rwxr-xr-x 1 root root 0 1月  10 15:38 changemod
-rwxr-xr-x 1 root root 0 1月  10 15:38 unlink //这里表明文件状态更改时间改为了程序运行时的时间
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$

函数mkdir、mkdirat和rmdir

函数mkdir、mkdirat创建目录

 #include <sys/stat.h>
       #include <sys/types.h>
       int mkdir(const char *pathname, mode_t mode);
       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <sys/stat.h>
       int mkdirat(int dirfd, const char *pathname, mode_t mode);
  • mode指定文件访问权限,对于目录至少要设置一个执行权限位
  • dirfd是一个打开文件,相对路径名根据此打开目录进行计算

函数rmdir删除目录

#include <unistd.h>
       int rmdir(const char *pathname);

必须是一个空目录

读目录

只有内核才能写目录,以下是与目录有关的例程

 #include <sys/types.h>
       #include <dirent.h>
       DIR *opendir(const char *name);//初始化结构DIR
       DIR *fdopendir(int fd);
       struct dirent *readdir(DIR *dirp);//返回目录中的第一个目录项
       int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
       void rewinddir(DIR *dirp)//复位目录
       int closedir(DIR *dirp);//关闭目录
       long telldir(DIR *dirp);
        void seekdir(DIR *dirp, long loc);
  • DIR结构保存当前正在被读的目录的有关信息

遍历文件层次结构

以下两个函数实现遍历一个文件层次结构

/*1.dirpath规定起始路径名*/
/*2.nopenf限制遍历目录时同时打开的文件数以避免永光调用进程的文件描述符,当然,它的值应该要大于等于1*/
/*3.函数fn会自然的操作目录下的每一个条目,fpath是当前条目路径名(相对路径或绝对路径,这取决于dirpath),flags(FTW_F,FTW_D,FTW_DNR,FTW_DP,FTW_NS,FTW_SL,FTW_SLN)*/
 #include <ftw.h>
       int nftw(const char *dirpath,
               int (*fn) (const char *fpath, const struct stat *sb,
                          int typeflag, struct FTW *ftwbuf),
               int nopenfd, int flags);
       #include <ftw.h>
       int ftw(const char *dirpath,
               int (*fn) (const char *fpath, const struct stat *sb,
                          int typeflag),
               int nopenfd);
  • ftw函数调用stat使程序跟随符号链接。
  • nftw提供给调用函数fn的第四个参数如下
struct FTW 
{
  int base;
  int level;
};

base是在fpath中给定的路径名中的文件名(basename)的偏移量。level是fpath在目录树中相对于根节点的深度(dirpath的深度为0)

  • 返回0:遍历完整个树
  • 返回-1: 错误
  • 返回非0值:让树的遍历停止

函数chdir、fchdir和getcwd

 #include <unistd.h>
 //以下两个函数更改调用进程的当前工作目录,而不影响其他进程的工作目录
       int chdir(const char *path);
       int fchdir(int fd); //fd指定新的当前工作目录
       //函数获得调用进程的当前工作目录
       char *getcwd(char *buf, size_t size);

看下面这个实例

#include "apue.h"
int
main(void)
{
	if (chdir("/tmp") < 0)
		err_sys("chdir failed");
	printf("chdir to /tmp succeeded\n");
	exit(0);
}
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ ./mycd 
chdir to /tmp succeeded
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ pwd
/home/apue.3e/filedir
xiangke@xiangke-virtual-machine:/home/apue.3e/filedir$ 

从该实例运行结果来看,shell的当前工作目录并没有改变。
getcwd函数常用于文件系统返回到它工作的出发点。

设备特殊文件

st_dev表示文件系统的设备号,通过使用宏major,minor分别获得主设备号(它标识设备驱动程序),次设备号(标识特定的子设备
st_rdev表示实际字符特殊设备或块特殊设备设备号。‘

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!