zoukankan      html  css  js  c++  java
  • UNIX_文件&目录

    除了对文件进行打开,读写等操作。文件系统还有其他的特征和性质等着我们去研究哦。

    stat、fstat、lstat函数

    #include <sys/stat.h>
    int stat(const char *restrice pathname, struct stat *restrict buf);
    int fstat(int fieldes, struct stat *buf);
    int lstat(const char *restrice pathname, struct stat *restrict buf);

    成功,返回0;否则,返回-1。

    第一个参数,一旦给出pathname, stat函数就返回与此命名文件有关的信息结构。

    第二个参数,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 */

      time_t   st_atime;   /* time of last access */

      time_t   t_mtime;  /* time of last modification */

      time_t   st_ctime;   /* time of last file status change */

      blksize_t   st_blksize;   /* best I/O block size */

      blkcnt_t   st_blocks;   /* number of disk blocks allocated */

    };

    程序:对每个命令行参数打印文件类型

    #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
    ", ptr);
        }
        exit(0);
    }

    文件访问权限

    9个访问权限位,可看做三类,u表示用户(所有者user),g表示组(group),o表示其他(other)。每个类中三个访问权限(即读(R),写(W),执行(X))。

    进程是根据有效用户ID判断当前用户是否有无权限的。进程每次打开,创建,删除一个文件时,内核就进行文件访问权限测试。 超级用户的有效ID是0。

    如果进程拥有此文件,则按照用户访问权限批准或拒绝该进程对文件的访问(不查看组访问权限);若不拥有该文件,但进程属于某个适当的组,则按照组访问权限批准或拒绝该进程对文件的访问。

     access函数

    #include <unistd.h>
    int access(const char* pathname, int mode);
    

    成功,返回0;失败,返回-1。

    该函数按实际用户ID和实际组ID进行访问权限测试,也就是想验证一个进程的实际用户能否访问一个给定的文件。其中mode是如下所列常量的按位或。

    R_OK 测试读权限

    W_OK 测试写权限

    X_OK 测试执行权限

    F_OK 测试文件是否存在

    umask函数

    mode_t  umask(mode_t  cmask)

    cmask是由9个访问权限位(S_IRUSR, S_IWUSR,...)中的若干个按位“或”构成的。

    该函数为进程设置文件模式创建屏蔽字,也就是给一个文件设置权限,比如:禁止掉组和其他用户的读写权限等, 并返回以前的值。该函数无出错返回。

    #include "apue.h"
    #include <fcntl.h>
    
    #define RWRWRW (S_IRUSR) | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH)
    
    int main()
    {
        umask(0); //创建第一个文件,umask为0
        if(creat("foo", RWRWRW) < 0)
            err_sys("creat error for foo");
        umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); //创建第二个,umask值禁止所有组和其他用户的读写访问权
        if(creat("bar", RWRWRW) < 0)
            err_sys("creat error for bar");
        exit(0);
    }

    上面的程序创建两个文件,创建第一个时,umask为0,这是任何用户都可以读文件;创建第二个时,umask值禁止所有组和其他用户的读写访问权限。

    umask值是一个八进制数,每一位都代表一种要屏蔽的权限(u=rwx, g=rwx, o=rwx)。设置了相应位之后,它所对应的权限就会被拒绝。常用的是002(其他用户写),022(同组成员和其他用户写),027(同组成员写和其他用户读、写或执行)。

    Single UNIX Specification要求shell支持符号形式的umask命令。该格式与八进制格式刚好相反,即设置了的相应位表示非拒绝。

    chmod、fchmod函数

    这两个函数用于更改现有文件的访问权限。

    #include <sys/stat.h>
    int chmod(const char *pathname, mode_t mode);
    int fchmod(int fieldes, mode_t mode);
    

    成功,返回0;失败,返回-1。

    chmod在指定的文件上操作,fchmod则是对已经打开的文件操作。

    S_ISVTX(sticky bit)  :保存文本(粘住位)。用于目录,使多个用户可以共享一个目录而不会彼此影响。只有超级用户才可以设置粘住位。现在不需要这种技术了。

    文件系统

    硬链接与软链接(符号链接)

    硬链接:每个i节点都有一个链接计数,其值是指向该i节点的目录项数。只有当链接计数为0时,才可以删除该文件,所以删除文件用unlink, 不是delete。在stat结构中,连接计数包含在st_nlink中。这种链接叫硬链接。硬链接说白了是一个指针,指向文件i节点。

    符号链接:是指向一个文件的间接指针。建立软链接就是建立了一个新文件。 软链接文件有点类似于Windows的快捷方式。它实际上是特殊文件的一种。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息,可以是任意文件或目录,可以链接不同文件系统的文件。

    引入符号链接是为了避开硬链接的限制:

    1.硬链接通常要求链接和文件位于同一个文件系统中。

    2.只有超级用户才能创建指向目录的硬链接。因为这样做可能在文件系统中形成循环。软连接中也能形成循环,但是在软链接中这种循环用unlink就很好消除。

    如何形成循环的?如下:

    $mkdir  foo  //创建目录
    $touch  foo/a  //创建0长文件
    $ln  -s  ../foo  foo/testdir  //创建符号链接
    $ls   -l   foo

    这里创建了一个目录foo,它包含一个名字为a的文件以及一个指向foo的符号链接。

    下图中,圆表示目录,方表示文件。使用Solaris的标准函数ftw(3)以降序遍历文件结构,则打印出的路径名如下:

     因为unlink不跟随软连接,所以可以unlink文件foo/testdir,从而消除这个循环。

    什么叫不跟随软连接呢?

    当使用以名字引用文件的函数时,我们应当了解函数是否跟随这个软链接到达它所链接的文件,也可以说是否处理符号链接,如果有这种功能,则其路径名参数就引用这个软连接指向的文件;否则就只是引用这个链接本身(就是个路径名)。

    link、symlink、readlink函数

    #include <unistd.h>
    int link(const char *existingpath, const char *newpath);
    int unlink(const char *pathname)

     link产生硬链接,即链接文件与目标文件是等价的,只是名字不同。目标文件必须存在。通常目标文件不允许是目录,也不允许跨越文件系统。成功,返回0;失败,返回-1.

    #include <unistd.h>
    int symlink(const char *actualpath, const char *sympath);
    ssize_t readlink(const char* restrict pathname, char *restrict buf);

    symlink产生软链接,即链接文件是将目标文件名作为字符序列存储起来,因此对目标文件没有任何限制。可以用readlink读取符号链接所存储的目标文件名.成功,返回0;失败,返回-1.

    读目录

    DIR *opendir(const char *pathname);  // 返回值:NULL表示出错,非空指针指向的对象为打开的目录数据结构(目录流)。

    struct dirent *readdir(DIR *dp);  // 返回值: NULL表示读到目录尾部或出错,非空指针指向的对象为读取的目录项结构,目录流的内部指针指向下一个目录项。

     一个dirent结构体至少包含下列两个成员:

    struct   dirent {    /*目录项结构 */

      ino_t   d_ino;   /* i-结点号 */

      char   d_name[NAME_MAX + 1]; /* null结尾的文件名 */

     }

    void rewinddir(DIR *dp);   // 使readdir从目录的开头读(即目录流的内部指针指向第一个目录项)。

    int closedir(DIR *dp);  // 返回值: 0 if OK, 1 on error.

    DIR是一个内部结构,上述6个函数用这个内部结构保存当前正在被读的目录所在的有关信息。

    opendir返回的指向DIR结构的指针由另外的5个函数使用。

    只包含 ... 的目录为一个空目录。

    一个递归降序遍历目录层次结构,并按照文件类型计数的程序如下:

      1 #include "apue.h"
      2 #include <dirent.h>
      3 #include <limits.h>
      4 
      5 /* function type that is called for each filename */
      6 typedef    int    Myfunc(const char *, const struct stat *, int);
      7 
      8 static Myfunc    myfunc;
      9 static int        myftw(char *, Myfunc *);
     10 static int        dopath(Myfunc *);
     11 
     12 static long    nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;
     13 
     14 int
     15 main(int argc, char *argv[])
     16 {
     17     int        ret;
     18 
     19     if (argc != 2)
     20         err_quit("usage:  ftw  <starting-pathname>");
     21 
     22     ret = myftw(argv[1], myfunc);        /* does it all */
     23 
     24     ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;
     25     if (ntot == 0)
     26         ntot = 1;        /* avoid divide by 0; print 0 for all counts */
     27     printf("regular files  = %7ld, %5.2f %%
    ", nreg,
     28       nreg*100.0/ntot);
     29     printf("directories    = %7ld, %5.2f %%
    ", ndir,
     30       ndir*100.0/ntot);
     31     printf("block special  = %7ld, %5.2f %%
    ", nblk,
     32       nblk*100.0/ntot);
     33     printf("char special   = %7ld, %5.2f %%
    ", nchr,
     34       nchr*100.0/ntot);
     35     printf("FIFOs          = %7ld, %5.2f %%
    ", nfifo,
     36       nfifo*100.0/ntot);
     37     printf("symbolic links = %7ld, %5.2f %%
    ", nslink,
     38       nslink*100.0/ntot);
     39     printf("sockets        = %7ld, %5.2f %%
    ", nsock,
     40       nsock*100.0/ntot);
     41     exit(ret);
     42 }
     43 
     44 /*
     45  * Descend through the hierarchy, starting at "pathname".
     46  * The caller's func() is called for every file.
     47  */
     48 #define    FTW_F    1        /* file other than directory */
     49 #define    FTW_D    2        /* directory */
     50 #define    FTW_DNR    3        /* directory that can't be read */
     51 #define    FTW_NS    4        /* file that we can't stat */
     52 
     53 static char    *fullpath;        /* contains full pathname for every file */
     54 static size_t pathlen;
     55 
     56 static int                    /* we return whatever func() returns */
     57 myftw(char *pathname, Myfunc *func)
     58 {
     59     fullpath = path_alloc(&pathlen);    /* malloc PATH_MAX+1 bytes */
     60                                         /* ({Prog pathalloc}) */
     61     if (pathlen <= strlen(pathname)) {
     62         pathlen = strlen(pathname) * 2;
     63         if ((fullpath = realloc(fullpath, pathlen)) == NULL)
     64             err_sys("realloc failed");
     65     }
     66     strcpy(fullpath, pathname);
     67     return(dopath(func));
     68 }
     69 
     70 /*
     71  * Descend through the hierarchy, starting at "fullpath".
     72  * If "fullpath" is anything other than a directory, we lstat() it,
     73  * call func(), and return.  For a directory, we call ourself
     74  * recursively for each name in the directory.
     75  */
     76 static int                    /* we return whatever func() returns */
     77 dopath(Myfunc* func)
     78 {
     79     struct stat        statbuf;
     80     struct dirent    *dirp;
     81     DIR                *dp;
     82     int                ret, n;
     83 
     84     if (lstat(fullpath, &statbuf) < 0)    /* stat error */
     85         return(func(fullpath, &statbuf, FTW_NS));
     86     if (S_ISDIR(statbuf.st_mode) == 0)    /* not a directory */
     87         return(func(fullpath, &statbuf, FTW_F));
     88 
     89     /*
     90      * It's a directory.  First call func() for the directory,
     91      * then process each filename in the directory.
     92      */
     93     if ((ret = func(fullpath, &statbuf, FTW_D)) != 0)
     94         return(ret);
     95 
     96     n = strlen(fullpath);
     97     if (n + NAME_MAX + 2 > pathlen) {    /* expand path buffer */
     98         pathlen *= 2;
     99         if ((fullpath = realloc(fullpath, pathlen)) == NULL)
    100             err_sys("realloc failed");
    101     }
    102     fullpath[n++] = '/';
    103     fullpath[n] = 0;
    104 
    105     if ((dp = opendir(fullpath)) == NULL)    /* can't read directory */
    106         return(func(fullpath, &statbuf, FTW_DNR));
    107 
    108     while ((dirp = readdir(dp)) != NULL) {
    109         if (strcmp(dirp->d_name, ".") == 0  ||
    110             strcmp(dirp->d_name, "..") == 0)
    111                 continue;        /* ignore dot and dot-dot */
    112         strcpy(&fullpath[n], dirp->d_name);    /* append name after "/" */
    113         if ((ret = dopath(func)) != 0)        /* recursive */
    114             break;    /* time to leave */
    115     }
    116     fullpath[n-1] = 0;    /* erase everything from slash onward */
    117 
    118     if (closedir(dp) < 0)
    119         err_ret("can't close directory %s", fullpath);
    120     return(ret);
    121 }
    122 
    123 static int
    124 myfunc(const char *pathname, const struct stat *statptr, int type)
    125 {
    126     switch (type) {
    127     case FTW_F:
    128         switch (statptr->st_mode & S_IFMT) {
    129         case S_IFREG:    nreg++;        break;
    130         case S_IFBLK:    nblk++;        break;
    131         case S_IFCHR:    nchr++;        break;
    132         case S_IFIFO:    nfifo++;    break;
    133         case S_IFLNK:    nslink++;    break;
    134         case S_IFSOCK:    nsock++;    break;
    135         case S_IFDIR:    /* directories should have type = FTW_D */
    136             err_dump("for S_IFDIR for %s", pathname);
    137         }
    138         break;
    139     case FTW_D:
    140         ndir++;
    141         break;
    142     case FTW_DNR:
    143         err_ret("can't read directory %s", pathname);
    144         break;
    145     case FTW_NS:
    146         err_ret("stat error for %s", pathname);
    147         break;
    148     default:
    149         err_dump("unknown type %d for pathname %s", type, pathname);
    150     }
    151     return(0);
    152 }
    View Code

    chdir、fchdir、getcwd函数

    每个进程都有一个当前工作目录,此目录是搜索所有相对路径的起点(不以斜杠开始的路径为相对路径)。

    通过chdir和fchdir函数可以更改当前工作路径。

    #include <unistd.h>
    int chdir(const char *pathname);
    int fchdir(int filedes);

    成功,返回0;失败,返回-1.

    But,内核为每个进程只保存指向该目录v节点的指针等目录本身的信息,并不保存该目录的完整路径名。

    Luckily,getcwd函数则提供了得到当前工作目录完整的绝对路径名的功能。成功,返回buf; 失败,返回NULL。

    #include <unistd.h>
    char *getcwd(char *buf, size_t  size);

    第一个参数是缓冲地址buf, 第二是缓冲的长度size(单位:字节)。该缓冲必须有足够长度以容纳绝对路径名再加上一个null终止字符,否则返回出错。

     1 #include "apue.h"
     2 
     3 int
     4 main(void)
     5 {
     6     char    *ptr;
     7     size_t        size;
     8 
     9     if (chdir("/usr/spool/uucppublic") < 0)
    10         err_sys("chdir failed");
    11 
    12     ptr = path_alloc(&size);    /* our own function */
    13     if (getcwd(ptr, size) == NULL)
    14         err_sys("getcwd failed");
    15 
    16     printf("cwd = %s
    ", ptr);
    17     exit(0);
    18 }

    在更换目录之前我们可以先调用getcwd函数获得路径名,然后将这个路径名作为调用参数传送给chdir.

    fchdir函数更便捷。在更换到文件系统的不同位置之前,使用open函数打开当前工作目录,然后保存文件描述符,当希望回到原工作目录时,只要将这个文件描述符传递给fchdir即可。

  • 相关阅读:
    2020.07.01
    2020年5月9日
    2020年4月25日
    2020年4月24日
    2020年4月23日
    2020年4月22日
    2020年3月29日
    2020.3.25
    nacos源码解析(三)-注册中心服务注册处理
    nacos源码解析(二)-客户端如何访问注册中心
  • 原文地址:https://www.cnblogs.com/beatrice7/p/4072167.html
Copyright © 2011-2022 走看看