UNIX_文件目录
除了對文件進(jìn)行打開,讀寫等操作。文件系統(tǒng)還有其他的特征和性質(zhì)等著我們?nèi)パ芯颗丁?/span>
stat、fstat、lstat函數(shù)
#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。
第一個參數(shù),一旦給出pathname, stat函數(shù)就返回與此命名文件有關(guān)的信息結(jié)構(gòu)。
第二個參數(shù),buf是指針,指向一個結(jié)構(gòu)。結(jié)構(gòu)的基本形式如下:
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 */
};
程序:對每個命令行參數(shù)打印文件類型
#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";elseptr = "** unknown mode **";printf("%s\n", ptr);}exit(0); }文件訪問權(quán)限
9個訪問權(quán)限位,可看做三類,u表示用戶(所有者user),g表示組(group),o表示其他(other)。每個類中三個訪問權(quán)限(即讀(R),寫(W),執(zhí)行(X))。
進(jìn)程是根據(jù)有效用戶ID判斷當(dāng)前用戶是否有無權(quán)限的。進(jìn)程每次打開,創(chuàng)建,刪除一個文件時,內(nèi)核就進(jìn)行文件訪問權(quán)限測試。 超級用戶的有效ID是0。
如果進(jìn)程擁有此文件,則按照用戶訪問權(quán)限批準(zhǔn)或拒絕該進(jìn)程對文件的訪問(不查看組訪問權(quán)限);若不擁有該文件,但進(jìn)程屬于某個適當(dāng)?shù)慕M,則按照組訪問權(quán)限批準(zhǔn)或拒絕該進(jìn)程對文件的訪問。
?access函數(shù)
#include <unistd.h> int access(const char* pathname, int mode);成功,返回0;失敗,返回-1。
該函數(shù)按實(shí)際用戶ID和實(shí)際組ID進(jìn)行訪問權(quán)限測試,也就是想驗(yàn)證一個進(jìn)程的實(shí)際用戶能否訪問一個給定的文件。其中mode是如下所列常量的按位或。
R_OK 測試讀權(quán)限
W_OK 測試寫權(quán)限
X_OK 測試執(zhí)行權(quán)限
F_OK 測試文件是否存在
umask函數(shù)
mode_t ?umask(mode_t ?cmask)
cmask是由9個訪問權(quán)限位(S_IRUSR, S_IWUSR,...)中的若干個按位“或”構(gòu)成的。
該函數(shù)為進(jìn)程設(shè)置文件模式創(chuàng)建屏蔽字,也就是給一個文件設(shè)置權(quán)限,比如:禁止掉組和其他用戶的讀寫權(quán)限等, 并返回以前的值。該函數(shù)無出錯返回。
#include "apue.h" #include <fcntl.h>#define RWRWRW (S_IRUSR) | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH)int main() {umask(0); //創(chuàng)建第一個文件,umask為0if(creat("foo", RWRWRW) < 0)err_sys("creat error for foo");umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); //創(chuàng)建第二個,umask值禁止所有組和其他用戶的讀寫訪問權(quán)if(creat("bar", RWRWRW) < 0)err_sys("creat error for bar");exit(0); }上面的程序創(chuàng)建兩個文件,創(chuàng)建第一個時,umask為0,這是任何用戶都可以讀文件;創(chuàng)建第二個時,umask值禁止所有組和其他用戶的讀寫訪問權(quán)限。
umask值是一個八進(jìn)制數(shù),每一位都代表一種要屏蔽的權(quán)限(u=rwx, g=rwx, o=rwx)。設(shè)置了相應(yīng)位之后,它所對應(yīng)的權(quán)限就會被拒絕。常用的是002(其他用戶寫),022(同組成員和其他用戶寫),027(同組成員寫和其他用戶讀、寫或執(zhí)行)。
Single UNIX Specification要求shell支持符號形式的umask命令。該格式與八進(jìn)制格式剛好相反,即設(shè)置了的相應(yīng)位表示非拒絕。
chmod、fchmod函數(shù)
這兩個函數(shù)用于更改現(xiàn)有文件的訪問權(quán)限。
#include <sys/stat.h> int chmod(const char *pathname, mode_t mode); int fchmod(int fieldes, mode_t mode);成功,返回0;失敗,返回-1。
chmod在指定的文件上操作,fchmod則是對已經(jīng)打開的文件操作。
S_ISVTX(sticky bit) ?:保存文本(粘住位)。用于目錄,使多個用戶可以共享一個目錄而不會彼此影響。只有超級用戶才可以設(shè)置粘住位。現(xiàn)在不需要這種技術(shù)了。
?
文件系統(tǒng)
硬鏈接與軟鏈接(符號鏈接)
硬鏈接:每個i節(jié)點(diǎn)都有一個鏈接計數(shù),其值是指向該i節(jié)點(diǎn)的目錄項(xiàng)數(shù)。只有當(dāng)鏈接計數(shù)為0時,才可以刪除該文件,所以刪除文件用unlink, 不是delete。在stat結(jié)構(gòu)中,連接計數(shù)包含在st_nlink中。這種鏈接叫硬鏈接。硬鏈接說白了是一個指針,指向文件i節(jié)點(diǎn)。
符號鏈接:是指向一個文件的間接指針。建立軟鏈接就是建立了一個新文件。?軟鏈接文件有點(diǎn)類似于Windows的快捷方式。它實(shí)際上是特殊文件的一種。在符號連接中,文件實(shí)際上是一個文本文件,其中包含的有另一文件的位置信息,可以是任意文件或目錄,可以鏈接不同文件系統(tǒng)的文件。
引入符號鏈接是為了避開硬鏈接的限制:
1.硬鏈接通常要求鏈接和文件位于同一個文件系統(tǒng)中。
2.只有超級用戶才能創(chuàng)建指向目錄的硬鏈接。因?yàn)檫@樣做可能在文件系統(tǒng)中形成循環(huán)。軟連接中也能形成循環(huán),但是在軟鏈接中這種循環(huán)用unlink就很好消除。
如何形成循環(huán)的?如下:
$mkdir foo //創(chuàng)建目錄 $touch foo/a //創(chuàng)建0長文件 $ln -s ../foo foo/testdir //創(chuàng)建符號鏈接 $ls -l foo這里創(chuàng)建了一個目錄foo,它包含一個名字為a的文件以及一個指向foo的符號鏈接。
下圖中,圓表示目錄,方表示文件。使用Solaris的標(biāo)準(zhǔn)函數(shù)ftw(3)以降序遍歷文件結(jié)構(gòu),則打印出的路徑名如下:
?因?yàn)閡nlink不跟隨軟連接,所以可以unlink文件foo/testdir,從而消除這個循環(huán)。
什么叫不跟隨軟連接呢?
當(dāng)使用以名字引用文件的函數(shù)時,我們應(yīng)當(dāng)了解函數(shù)是否跟隨這個軟鏈接到達(dá)它所鏈接的文件,也可以說是否處理符號鏈接,如果有這種功能,則其路徑名參數(shù)就引用這個軟連接指向的文件;否則就只是引用這個鏈接本身(就是個路徑名)。
link、symlink、readlink函數(shù)
#include <unistd.h> int link(const char *existingpath, const char *newpath); int unlink(const char *pathname)?link產(chǎn)生硬鏈接,即鏈接文件與目標(biāo)文件是等價的,只是名字不同。目標(biāo)文件必須存在。通常目標(biāo)文件不允許是目錄,也不允許跨越文件系統(tǒng)。成功,返回0;失敗,返回-1.
#include <unistd.h> int symlink(const char *actualpath, const char *sympath); ssize_t readlink(const char* restrict pathname, char *restrict buf);symlink產(chǎn)生軟鏈接,即鏈接文件是將目標(biāo)文件名作為字符序列存儲起來,因此對目標(biāo)文件沒有任何限制。可以用readlink讀取符號鏈接所存儲的目標(biāo)文件名.成功,返回0;失敗,返回-1.
讀目錄
?
DIR *opendir(const char *pathname);? // 返回值:NULL表示出錯,非空指針指向的對象為打開的目錄數(shù)據(jù)結(jié)構(gòu)(目錄流)。
struct dirent *readdir(DIR *dp);? // 返回值: NULL表示讀到目錄尾部或出錯,非空指針指向的對象為讀取的目錄項(xiàng)結(jié)構(gòu),目錄流的內(nèi)部指針指向下一個目錄項(xiàng)。
?一個dirent結(jié)構(gòu)體至少包含下列兩個成員:
struct ? dirent {? ? /*目錄項(xiàng)結(jié)構(gòu) */
? ino_t ? d_ino; ? /* i-結(jié)點(diǎn)號 */
? char ? d_name[NAME_MAX + 1]; /* null結(jié)尾的文件名 */
?}
void rewinddir(DIR *dp); ? // 使readdir從目錄的開頭讀(即目錄流的內(nèi)部指針指向第一個目錄項(xiàng))。
int closedir(DIR *dp);? // 返回值: 0 if OK, 1 on error.
?
DIR是一個內(nèi)部結(jié)構(gòu),上述6個函數(shù)用這個內(nèi)部結(jié)構(gòu)保存當(dāng)前正在被讀的目錄所在的有關(guān)信息。
opendir返回的指向DIR結(jié)構(gòu)的指針由另外的5個函數(shù)使用。
只包含 .和.. 的目錄為一個空目錄。
一個遞歸降序遍歷目錄層次結(jié)構(gòu),并按照文件類型計數(shù)的程序如下:
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函數(shù)
每個進(jìn)程都有一個當(dāng)前工作目錄,此目錄是搜索所有相對路徑的起點(diǎn)(不以斜杠開始的路徑為相對路徑)。
通過chdir和fchdir函數(shù)可以更改當(dāng)前工作路徑。
#include <unistd.h> int chdir(const char *pathname); int fchdir(int filedes);成功,返回0;失敗,返回-1.
But,內(nèi)核為每個進(jìn)程只保存指向該目錄v節(jié)點(diǎn)的指針等目錄本身的信息,并不保存該目錄的完整路徑名。
Luckily,getcwd函數(shù)則提供了得到當(dāng)前工作目錄完整的絕對路徑名的功能。成功,返回buf; 失敗,返回NULL。
#include <unistd.h> char *getcwd(char *buf, size_t size);第一個參數(shù)是緩沖地址buf, 第二是緩沖的長度size(單位:字節(jié))。該緩沖必須有足夠長度以容納絕對路徑名再加上一個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 }在更換目錄之前我們可以先調(diào)用getcwd函數(shù)獲得路徑名,然后將這個路徑名作為調(diào)用參數(shù)傳送給chdir.
fchdir函數(shù)更便捷。在更換到文件系統(tǒng)的不同位置之前,使用open函數(shù)打開當(dāng)前工作目錄,然后保存文件描述符,當(dāng)希望回到原工作目錄時,只要將這個文件描述符傳遞給fchdir即可。
轉(zhuǎn)載于:https://www.cnblogs.com/beatrice7/p/4072167.html
總結(jié)
- 上一篇: JavaScript 对象与数组参考大全
- 下一篇: 9、数组知识点小结