UNIX_文件&目錄

除了對文件進行打開,讀寫等操做。文件系統還有其餘的特徵和性質等着咱們去研究哦。node

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。shell

第一個參數,一旦給出pathname, stat函數就返回與此命名文件有關的信息結構。數據結構

第二個參數,buf是指針,指向一個結構。結構的基本形式以下:app

struct stat {socket

  mode_t   st_mode;  /* file type & mode (permissions) */ide

  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 */ui

  nlink_t   st_nlink;   /* number of links */spa

  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\n", 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 %%\n", nreg,
 28       nreg*100.0/ntot);
 29     printf("directories    = %7ld, %5.2f %%\n", ndir,
 30       ndir*100.0/ntot);
 31     printf("block special  = %7ld, %5.2f %%\n", nblk,
 32       nblk*100.0/ntot);
 33     printf("char special   = %7ld, %5.2f %%\n", nchr,
 34       nchr*100.0/ntot);
 35     printf("FIFOs          = %7ld, %5.2f %%\n", nfifo,
 36       nfifo*100.0/ntot);
 37     printf("symbolic links = %7ld, %5.2f %%\n", nslink,
 38       nslink*100.0/ntot);
 39     printf("sockets        = %7ld, %5.2f %%\n", 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\n", ptr);
17     exit(0);
18 }

在更換目錄以前咱們能夠先調用getcwd函數得到路徑名,而後將這個路徑名做爲調用參數傳送給chdir.

fchdir函數更便捷。在更換到文件系統的不一樣位置以前,使用open函數打開當前工做目錄,而後保存文件描述符,當但願回到原工做目錄時,只要將這個文件描述符傳遞給fchdir便可。

相關文章
相關標籤/搜索