正文
4.1 函數stat
函數stat返回與此命名文件有關的信息結構。下面的代碼實現了一個工具,顯示樹形目錄結構,需要加兩個參數,一個為目錄名,一個為顯示目錄的深度。
#include <sys/stat.h>#include <sys/types.h>#include <stdio.h>#include <dirent.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <pwd.h>#include <grp.h>#include <time.h>/***************************************************************/ /*struct stat {*/ /* unsigned long st_dev; */ /* Device. */ /* unsigned long st_ino;*/ /* File serial number. */ /* unsigned int st_mode; */ /* File mode. */ /* unsigned int st_nlink; */ /* Link count. */ /* unsigned int st_uid; */ /* User ID of the file's owner. */ /* unsigned int st_gid; */ /* Group ID of the file's group. */ /* unsigned long st_rdev; *//* Device number, if device. */ /* unsigned long __pad1; */ /* long st_size; *//* Size of file, in bytes. */ /* int st_blksize; *//* Optimal block size for I/O. */ /* int __pad2; */ /* long st_blocks;*/ /* Number 512-byte blocks allocated. */ /* long st_atime; */ /* Time of last access. */ /* unsigned long st_atime_nsec; */ /* long st_mtime; */ /* Time of last modification. */ /* unsigned long st_mtime_nsec;*/ /* long st_ctime; */ /* Time of last status change. */ /* unsigned long st_ctime_nsec; */ /* unsigned int __unused4; */ /* unsigned int __unused5;*/ /* }; */ /* *************************************************************/void printMode(unsigned int st_mode,int indent){ int num = 0; for(;num<indent;num++) { printf(" "); } printf(S_ISDIR(st_mode)?"d":"-"); printf(st_mode&S_IRUSR?"r":"-"); printf(st_mode&S_IWUSR?"w":"-"); printf(st_mode&S_IXUSR?"x":"-"); printf(st_mode&S_IRGRP?"r":"-"); printf(st_mode&S_IWGRP?"w":"-"); printf(st_mode&S_IXGRP?"x":"-"); printf(st_mode&S_IROTH?"r":"-"); printf(st_mode&S_IWOTH?"w":"-"); printf(st_mode&S_IXOTH?"x":"-"); }void printFileName(char *name){ printf(" %s\n",name); }void printUserName(unsigned int userId){ struct passwd *pwd = getpwuid(userId); printf(" %s", pwd->pw_name); }void printGroupName(unsigned int grpId){ struct group *grp = getgrgid(grpId); printf(" %s" ,grp->gr_name); }void printSize(long size){ printf(" %lu",size); }void printModifyTime(long mtime){ /*char buf[100]={0}; ctime_s(buf,26,mtime); printf(" %s",buf);*/ printf(" %lu",mtime); }int ls(char *path,int depth,int indent){ DIR *dhandle; struct dirent *file; struct stat st; if(!(dhandle=opendir(path))) { printf("error opendir %s\n",path); return -1; } while((file = readdir(dhandle))!=NULL) { int fullPathLen = strlen(path)+strlen(file->d_name)+1; if(strncmp(file->d_name,".",1)==0) continue; char *fullpath = (char*)malloc(fullPathLen+1); memset(fullpath,0,fullPathLen+1); strcpy(fullpath,path); strcat(fullpath,"/"); strcat(fullpath,file->d_name); int rv = stat(fullpath,&st); if(rv<0) { return -1; } printMode(st.st_mode,indent); printUserName(st.st_uid); printGroupName(st.st_gid); printSize(st.st_size); printModifyTime(st.st_mtime); printFileName(file->d_name); if(S_ISDIR(st.st_mode)&& (depth-1>0)) { ls(fullpath,depth-1,indent+1); } free(fullpath); } closedir(dhandle); return 0; }int main(int argc,char *argv[]){ int dep = atoi(argv[2]); ls(argv[1],dep,0); return 0; }
運行如下命令
gcc stat.c
生成一個a.out可執(zhí)行文件,運行如下命令:
harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ./a.out /github/ 2 drwxrwxrwx harlan harlan 0 1494143291 3202C drwxrwxrwx harlan harlan 0 1494143273 Doc -rw-rw-rw- harlan harlan 828 1494143273 Readme.txt drwxrwxrwx harlan harlan 0 1494143279 SRC drwxrwxrwx harlan harlan 0 1494143281 inc -rw-rw-rw- harlan harlan 9700 1494143282 m3327.mdf -rw-rw-rw- harlan harlan 1182 1494143282 m3327boot.mdf drwxrwxrwx harlan harlan 0 1494143290 prj drwxrwxrwx harlan harlan 0 1494143292 sdk drwxr-xr-x harlan harlan 0 1495673220 APUE -rw-r--r-- harlan harlan 6 1493303590 README.md -rwxrwxrwx root root 17478 1494424916 a.out -rw-rw-rw- harlan harlan 4352 1494167949 apue.h -rw-rw-rw- harlan harlan 2660400 1493735585 apue.h.gch drwxrwxrwx harlan harlan 0 1494248815 chapter_1 drwxrwxrwx harlan harlan 0 1495117067 chapter_2 drwxrwxrwx harlan harlan 0 1494509690 chapter_3 drwxrwxrwx harlan harlan 0 1495113400 chapter_4 drwxrwxr-x harlan harlan 0 1494944116 chapter_5 -rw-rw-rw- harlan harlan 2220 1494167949 err.c drwxrwxr-x harlan harlan 0 1494769702 foo -rw-rw-r-- harlan harlan 399 1494424891 go.c -rw------- harlan harlan 1675 1494512317 key -rw-r--r-- harlan harlan 404 1494512317 key.pub -rw-rw-rw- harlan harlan 1501 1494116048 print.c -rwx------ harlan harlan 1457 1493733958 tags drwxrwxr-x harlan harlan 0 1494769702 testdir -rw-r--r-- harlan harlan 4790 1495671977 vimrc.txt -rw------- harlan harlan 1679 1493304485 pub -rw-r--r-- harlan harlan 402 1493304485 pub.pub drwxrwxr-x harlan harlan 0 1494511444 test
4.2 文件類型
文件類型包括以下幾種:
普通文件
目錄文件
塊特殊文件
字符特殊文件
FIFO
套接字
符號鏈接
可以用圖4-1中的宏確定文件類型,這些宏的參數是stat結構中的st_mode成員。
可以用圖4-2中的宏來從stat結構中確定IPC對象的類型。,它們的參數是指向stat結構的指針。
4.3 設置用戶ID和設置組ID
實際用戶ID和實際組ID標識我們究竟是誰。
有效用戶ID、有效組ID以及附屬組ID決定了我們的文件訪問權限。
保存的設置用戶ID和保存的設置組ID在執(zhí)行一個程序時包含了有效用戶ID和有效組ID的副本。
通常,有效用戶ID等于實際用戶ID,有效組ID等于實際組ID。
我們可以在文件模式字(st_mode)中設置一個特殊標志,其含義是“當執(zhí)行此文件時,將進程的有效用戶ID設置為文件所有者的用戶ID(st_uid)”,組ID也一樣。在文件模式字中的這兩位被稱為設置用戶組ID(set-user=ID)位和設置組ID(set-group-ID)位。
例如,passwd允許任意用戶改變其口令,該程序是一個設置用戶ID程序。見下面的展示:
harlan@DESKTOP-KU8C3K5:~$ ll /etc/passwd -rw-r--r-- 1 root root 1219 5月 8 21:34 /etc/passwd
harlan@DESKTOP-KU8C3K5:~$ ll /usr/bin/passwd -rwsr-xr-x 1 root root 47032 1月 27 2016 /usr/bin/passwd
任意用戶修改口令需要寫入/etc/passwd文件中,而此文件只有root用戶才有寫權限,/usr/bin/passwd用來執(zhí)行寫操作,可以看到這個程序將root用戶指定為設置用戶組ID,因此任意用戶當執(zhí)行此程序進行寫文件的時候將擁有root權限。
4.5 文件訪問權限
所有文件類型(目錄·字符特別文件等)都有訪問權限(access permission)。每個文件有9個訪問權限,將它們分為3類,見圖4-6。
我們用chmod命令修改這9個權限位。它允許我們用u表示用戶,用g表示組,用o表示其他。
圖4-6中的3類訪問權限(讀、寫和執(zhí)行)以各種不同的方式由不同函數使用。
規(guī)則一,我們用名字打開任一類型的文件時,對該名字中包含的每一個目錄,包括它可能隱含的當前工作目錄都應具有執(zhí)行權限。這就是為什么對于目錄其執(zhí)行權限位常被稱為搜索位的原因。
讀權限允許我們讀目錄,獲得在該目錄中所有文件名的列表,這是原書中的話,看下面的例子:
drwxr-xr-- root root 0 1496278552 test -rw-r--r-- root root 0 1496278548 1.txt -rw-r--r-- root root 0 1496278552 2.txt
test文件夾的路徑為/,我們現在在普通用戶(harlan)下執(zhí)行ls,看是否可以將test下面的文件名列出來??梢钥吹絫est文件夾和下面的兩個文件對于其他用戶有讀權限。
先執(zhí)行一個cd.
harlan@DESKTOP-KU8C3K5:~$ cd /testbash: cd: /test: 權限不夠
可見cd是需要執(zhí)行權限的。
harlan@DESKTOP-KU8C3K5:~$ ls /test1.txt 2.txt harlan@DESKTOP-KU8C3K5:~$ ls -l /testls: 無法訪問/test/1.txt: 權限不夠ls: 無法訪問/test/2.txt: 權限不夠 總用量 0-????????? ? ? ? ? ? 1.txt -????????? ? ? ? ? ? 2.txt
可見普通的ls是可以的,以列表方式列出文件信息就只列出了文件名。
為文件夾加上執(zhí)行權限:
drwxr-xr-x root root 0 1496278552 test -rw-r--r-- root root 0 1496278548 1.txt -rw-r--r-- root root 0 1496278552 2.txt
harlan@DESKTOP-KU8C3K5:/$ cd /test harlan@DESKTOP-KU8C3K5:/test$ harlan@DESKTOP-KU8C3K5:/test$cd .. harlan@DESKTOP-KU8C3K5:/$ ls -l /test 總用量 0-rw-r--r-- 1 root root 0 6月 1 08:55 1.txt -rw-r--r-- 1 root root 0 6月 1 08:55 2.txt
cd執(zhí)行成功,ls -l 也執(zhí)行成功。
對于一個文件的讀權限決定了我們是否能夠打開現有文件進行讀操作。這與open函數的O_RDONLY和O_RDWR標志相關。
對于一個文件的寫權限決定了我們是否能夠打開現有文件進行寫操作。這與open函數的O_WRONLY和O_RDWR標志相關。
為了在open函數中對一個文件指定O_TRUNC標志,必須對該文件具有寫權限。
為了在一個目錄中創(chuàng)建新文件,必須對該目錄具有寫權限和執(zhí)行權限。
為了刪除一個現有文件,必須對包含該文件的目錄具有寫和執(zhí)行權限。對該文件不需要有讀寫權限。
看下面的例子:drwxr-xrwx root root 0 1496278552 test -rw-r----- root root 0 1496278548 1.txt -rw-r--r-- root root 0 1496278552 2.txt
在普通用戶下刪除1.txt:
harlan@DESKTOP-KU8C3K5:/test$ ll 總用量 0-rw-r----- 1 root root 0 6月 1 08:55 1.txt -rw-r--r-- 1 root root 0 6月 1 08:55 2.txt harlan@DESKTOP-KU8C3K5:/test$ rm 1.txt rm:是否刪除有寫保護的普通空文件 "1.txt"? y harlan@DESKTOP-KU8C3K5:/test$ ll 總用量 0-rw-r--r-- 1 root root 0 6月 1 08:55 2.txt
如果用7個exec函數中的任何一個執(zhí)行某個文件,都必須對該文件具有執(zhí)行權限。該文件還必須是一個普通文件。
進程每打開、創(chuàng)建或者刪除一個文件時,內核就進行文件訪問權限測試,而這種測試可能涉及文件的所有者(st_uid和st_gid)、進程的有效ID(有效用戶ID和有效組ID)以及進程的附屬組ID(若支持的話)。兩個所有者ID是文件的性質,而兩個有效ID和附屬組ID則是進程的性質。內核進行的具體測試如下。
作者: HarlanC
博客地址: http://www.cnblogs.com/harlanc/
個人博客: http://www.harlancn.me/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出, 原文鏈接 .
http://www.cnblogs.com/harlanc/p/6931620.html