粘滞位 File文件内容
t權限(粘滯位):
是‘不可刪除’權限,就是說即使某用戶擁有這個文件的rwx權限,可以隨意修改文件內容,但是就是不能刪除,甚至不能修改文件名,只有root才行。t權限也可以直接用 chmod? o+t/a+t? filename 和chmod -t filename 來修改。
只針對目錄生效,它表示只能讓所屬主以及root可以刪除(重命名/移動)該目錄下的文件。比如/tmp目錄本來就是任何用戶都可以讀寫,如果別人可以任意刪除(重命名/移動)自己的文件,那豈不是很危險,所以這個t權限就是為了解決這個問題。
下面通過一個實例來體會這個t權限的用法:
(1) root用戶在/tmp目錄下創建一個test目錄,并設置test目錄的相關權限為1777(有特殊權限t)
[root@localhost tmp]# mkdir test [root@localhost tmp]# chmod1777 test [root@localhost tmp]# ls -ld test drwxrwxrwt. 2 root root 4096 Oct 1222:31 test(2) 切換到第一個用戶zhangming,在test目錄下創建一個新文件aaa.txt,并寫入數據
[root@localhost tmp]# su zhangming [zhangming@localhost tmp]$ touch test/aaa.txt [zhangming@localhost tmp]$ echo"hello" >> test/aaa.txt [zhangming@localhost tmp]$ ls -l test total 4 -rw-rw-r--. 1 zhangming zhangming 6 Oct 1222:34 aaa.txt(3)?切換到第二個用戶shuihuo379,嘗試刪除zhangming用戶創建的文件aaa.txt,此時提示無法刪除
[zhangming@localhost tmp]$ su shuihuo379 [shuihuo379@localhost tmp]$ ls -l test/aaa.txt-rw-rw-r--. 1 zhangming zhangming 6 Oct 1222:34 test/aaa.txt [shuihuo379@localhost tmp]$ rm test/aaa.txtrm: remove write-protected regular file `test/aaa.txt'? yrm: cannot remove `test/aaa.txt': Operation not permitted(4) 重新切換到root用戶,執行刪除權限位t操作
[shuihuo379@localhost tmp]$ su [root@localhost tmp]# chmod -t test [root@localhost tmp]# ls -ld test drwxrwxrwx. 2 root root 4096 Oct 1222:33 test(5) 再次切換到用戶shuihuo379,嘗試刪除zhangming用戶創建的文件aaa.txt,此時刪除成功,zhangming用戶創建的文件aaa.txt已經不存在了
[root@localhost tmp]# su shuihuo379 [shuihuo379@localhost tmp]$ ls -l test total 4 -rw-rw-r--. 1 zhangming zhangming 6 Oct 1222:34 aaa.txt [shuihuo379@localhost tmp]$ rm test/aaa.txtrm: remove write-protected regular file `test/aaa.txt'? y [shuihuo379@localhost tmp]$ ls -l test total 0粘滯位(粘著位)
上面所說的t權限就是我們在這里要講的粘滯位(sticky bit),我們給剛剛的cur目錄采用chmod o+t的方式給other用戶設置粘滯位。
然后我們繼續切換到dh用戶,看看我們能否繼續之前的刪除操作:
可以看到此時我們是沒有權限刪除root用戶創建的文件了,這也就是粘滯位的作用。
粘滯位權限便是針對此種情況設置,當?錄被設置了粘滯位權限以后,即便?戶對該?錄有寫?權限,也不能刪除該?錄中其他?戶的?件數據,?是只有該?件的所有者和root?戶才有權將其刪除。設置了粘滯位之后,正好可以保持?種動態的平衡:允許各?戶在?錄中任意寫?、刪除數據,但是禁?隨意刪除其他?戶的數據。
幾點說明
對于特殊權限的添加是添加在原有的執行權限上的,所以特殊權限添加的要求需要文件或者目錄本身具有可執行權限。
上圖中,我去掉了cur的other的執行權限,可以看到本來't'的位置變成了'T',此時dh用戶在cur目錄中是不具有權限來進行一系列操作的。
那么原來的執行標志x到哪里去了呢? 系統是這樣規定的, 假如本來在該位上有x, 則這些特別標志 (suid, sgid, sticky) 顯示為小寫字母 (s, s, t).否則, 顯示為大寫字母 (S, S, T) 。??
注意事項
粘滯位權限是針對目錄的,對文件無效
上述的這些操作是在root用戶下創建了一個test.c文件,然后添加了t權限,然而在dh用戶下還是可以直接進行刪除的。所以粘滯位是針對有執行權限的目錄的,對于文件添加粘滯位并沒有什么作用。
2.粘滯位權限(sticky)
作用:設置粘滯位權限后,即便用戶和對目錄有寫入權限,也不能刪除該目錄中其他用戶的文件
應用場景:對于公共可寫目錄,用戶可創建刪除自己的文件,但是不能刪除其他用戶的文件
表現形式:sticky表示為文件其它用戶執行權限位上的t或T:
x: t -:T
若之前在其它用戶執行位已有執行權限,則顯示為t,否則顯示為T
使用,如chmod o+t filename ...
chmodo-t filename ...
數字1表示增加粘滯位權限;數字0表示取消粘滯位權限;
使用,如:chmod 1755 filename ...
?
實例演示:(以上一次操作為前提)
(1)對/tmp/dirtest/設置粘滯位權限
1.[root@Liu ~]# chmod o+t /tmp/dirtest/
2.[root@Liu ~]# ll -d /tmp/dirtest/
3.drwxrwxr-t 2 root cloud 4096 Mar 1202:58 /tmp/dirtest/
?
(2)測試用戶是否能刪除非自己創建的文件
1.[docker@Liu dirtest]$touch?docker.txt
2.[docker@Liu dirtest]$rm?-rfopenstack.txt
3.rm: cannot remove `openstack.txt':Operation not permitted
4.[openstack@Liu dirtest]$touch?openstack.txt
5.[openstack@Liu dirtest]$rm?-rfdocker.txt
6.rm: cannot remove `docker.txt':Operation not permitted
答案是否定的。
這樣的話,用戶可以在此目錄中隨意創建文件和目錄,但是不能刪除非自己創建的文件或目錄
?
所以,最終解決方案是:
1.[root@Liu ~]# useradd openstack
2.[root@Liu ~]# useradd docker
3.[root@Liu ~]# groupadd cloud
4.[root@Liu ~]# gpasswd? -Mopenstack,docker cloud
5.[root@Liu ~]# chmod g+w /tmp/test/
6.[root@Liu ~]# chown .cloud/tmp/test
7.[root@Liu ~]# chmod g+s /tmp/test/
8.[root@Liu ~]# chmod o+t /tmp/test/
這樣,openstack和docker用戶都可以git目錄中創建文件,修改自己以及對方的文件,但是不能刪除對方的文件。如果連對方的文件都不允許修改,只要chmod g-s /tmp/test即可。
?
File_struct:
在具體介紹這幾個結構以前,我們需要解釋一下文件描述符、打開的文件描述、系統打開文件表、用戶打開文件表的概念以及它們的聯系。
1.文件對象
在Linux中,進程是通過文件描述符(file?descriptors,簡稱fd)而不是文件名來訪問文件的,文件描述符實際上是一個整數。Linux中規定每個進程能最多能同時使用NR_OPEN個文件描述符,這個值在fs.h中定義,為1024*1024(2.0版中僅定義為256)。
每個文件都有一個32位的數字來表示下一個讀寫的字節位置,這個數字叫做文件位置。每次打開一個文件,除非明確要求,否則文件位置都被置為0,即文件的開始處,此后的讀或寫操作都將從文件的開始處執行,但你可以通過執行系統調用LSEEK(隨機存儲)對這個文件位置進行修改。Linux中專門用了一個數據結構file來保存打開文件的文件位置,這個結構稱為打開的文件描述(openfile?description)。這個數據結構的設置是煞費苦心的,因為它與進程的聯系非常緊密,可以說這是VFS中一個比較難于理解的數據結構。
首先,為什么不把文件位置干脆存放在索引節點中,而要多此一舉,設一個新的數據結構呢?我們知道,Linux中的文件是能夠共享的,假如把文件位置存放在索引節點中,則如果有兩個或更多個進程同時打開同一個文件時,它們將去訪問同一個索引節點,于是一個進程的LSEEK操作將影響到另一個進程的讀操作,這顯然是不允許也是不可想象的。
另一個想法是既然進程是通過文件描述符訪問文件的,為什么不用一個與文件描述符數組相平行的數組來保存每個打開文件的文件位置?這個想法也是不能實現的,原因就在于在生成一個新進程時,子進程要共享父進程的所有信息,包括文件描述符數組。
我們知道,一個文件不僅可以被不同的進程分別打開,而且也可以被同一個進程先后多次打開。一個進程如果先后多次打開同一個文件,則每一次打開都要分配一個新的文件描述符,并且指向一個新的file結構,盡管它們都指向同一個索引節點,但是,如果一個子進程不和父進程共享同一個file結構,而是也如上面一樣,分配一個新的file結構,會出現什么情況了?讓我們來看一個例子:
假設有一個輸出重定位到某文件A的shellscript(shell腳本),我們知道,shell是作為一個進程運行的,當它生成第一個子進程時,將以0作為A的文件位置開始輸出,假設輸出了2K的數據,則現在文件位置為2K。然后,shell繼續讀取腳本,生成另一個子進程,它要共享shell的file結構,也就是共享文件位置,所以第二個進程的文件位置是2K,將接著第一個進程輸出內容的后面輸出。如果shell不和子進程共享文件位置,則第二個進程就有可能重寫第一個進程的輸出了,這顯然不是希望得到的結果。
至此,已經可以看出設置file結構的原因所在了。
file結構中主要保存了文件位置,此外,還把指向該文件索引節點的指針也放在其中。file結構形成一個雙鏈表,稱為系統打開文件表,其最大長度是NR_FILE,在fs.h中定義為8192。
file結構在include\linux\fs.h中定義如下:
structfile
{
struct?list_head f_list; /*所有打開的文件形成一個鏈表*/
struct?dentry *f_dentry; /*指向相關目錄項的指針*/
struct?vfsmount *f_vfsmnt; /*指向VFS安裝點的指針*/
structfile_operations *f_op; /*指向文件操作表的指針*/
mode_tf_mode; /*文件的打開模式*/
loff_tf_pos; /*文件的當前位置*/
unsignedshort f_flags; /*打開文件時所指定的標志*/
unsignedshort f_count; /*使用該結構的進程數*/
unsignedlong f_reada, f_ramax, f_raend, f_ralen, f_rawin;
/*預讀標志、要預讀的最多頁面數、上次預讀后的文件指針、預讀的字節數以及
預讀的頁面數*/
intf_owner; /*?通過信號進行異步I/O數據的傳送*/
unsignedint f_uid, f_gid; /*用戶的UID和GID*/
intf_error; /*網絡寫操作的錯誤碼*/
unsignedlong f_version; /*版本號*/
void*private_data; /* tty驅動程序所需 */
};
每個文件對象總是包含在下列的一個雙向循環鏈表之中:
·“未使用”文件對象的鏈表。該鏈表既可以用做文件對象的內存高速緩存,又可以當作超級用戶的備用存儲器,也就是說,即使系統的動態內存用完,也允許超級用戶打開文件。由于這些對象是未使用的,它們的f_count域是NULL,該鏈表首元素的地址存放在變量free_list中,內核必須確認該鏈表總是至少包含NR_RESERVED_FILES個對象,通常該值設為10。
·“正在使用”文件對的象鏈表:該鏈表中的每個元素至少由一個進程使用,因此,各個元素的f_count域不會為NULL,該鏈表中第一個元素的地址存放在變量anon_list中。
如果VFS需要分配一個新的文件對象,就調用函數get_empty_filp()。該函數檢測“未使用”文件對象鏈表的元素個數是否多于NR_RESERVED_FILES,如果是,可以為新打開的文件使用其中的一個元素;如果沒有,則退回到正常的內存分配。
2.用戶打開文件表
每個進程用一個files_struct結構來記錄文件描述符的使用情況,這個files_struct結構稱為用戶打開文件表,它是進程的私有數據。files_struct結構在include/linux/sched.h中定義如下:
struct?files_struct?{
atomic_tcount; /*?共享該表的進程數 */
rwlock_t?file_lock; /*?保護以下的所有域,以免在tsk->alloc_lock中的嵌套*/
intmax_fds; /*當前文件對象的最大數*/
intmax_fdset; /*當前文件描述符的最大數*/
intnext_fd;?/*已分配的文件描述符加1*/
structfile?** fd; /*?指向文件對象指針數組的指針 */
fd_set*close_on_exec; /*指向執行exec( )時需要關閉的文件描述符*/
fd_set*open_fds; /*指向打開文件描述符的指針*/
fd_setclose_on_exec_init;/*?執行exec( )時需要關閉的文件描述符的初 值集合*/
???????fd_set open_fds_init; /*文件描述符的初值集合*/
structfile?* fd_array[32];/* 文件對象指針的初始化數組*/
};
fd域指向文件對象的指針數組。該數組的長度存放在max_fds域中。通常,fd域指向files_struct結構的fd_array域,該域包括32個文件對象指針。如果進程打開的文件數目多于32,內核就分配一個新的、更大的文件指針數組,并將其地址存放在fd域中;內核同時也更新max_fds域的值。
對于在fd數組中有入口地址的每個文件來說,數組的索引就是文件描述符(file?descriptor)。通常,數組的第一個元素(索引為0)是進程的標準輸入文件,數組的第二個元素(索引為1)是進程的標準輸出文件,數組的第三個元素(索引為2)是進程的標準錯誤文件(參見圖8.3)。請注意,借助于dup( )、dup2( )和 fcntl( )系統調用,兩個文件描述符就可以指向同一個打開的文件,也就是說,數組的兩個元素可能指向同一個文件對象。當用戶使用shell結構(如2>&1)將標準錯誤文件重定向到標準輸出文件上時,用戶總能看到這一點。
open_fds域包含open_fds_init域的地址,open_fds_init域表示當前已打開文件的文件描述符的位圖。max_fdset域存放位圖中的位數。由于數據結構fd_set有1024位,通常不需要擴大位圖的大小。不過,如果確實必須的話,內核仍能動態增加位圖的大小,這非常類似文件對象的數組的情形。
當開始使用一個文件對象時調用內核提供的fget()函數。這個函數接收文件描述符fd作為參數,返回在current->files->fd[fd]中的地址,即對應文件對象的地址,如果沒有任何文件與fd對應,則返回NULL。在第一種情況下,fget( )使文件對象引用計數器f_count的值增1。
當內核完成對文件對象的使用時,調用內核提供的fput() 函數。該函數將文件對象的地址作為參數,并遞減文件對象引用計數器f_count的值,另外,如果這個域變為NULL,該函數就調用文件操作的“釋放”方法(如果已定義),釋放相應的目錄項對象,并遞減對應索引節點對象的i_writeaccess域的值(如果該文件是寫打開),最后,將該文件對象從“正在使用”鏈表移到“未使用”鏈表。
3.關于文件系統信息的fs_struct結構
第三個結構是fs_struct,在2.4以前的版本中在include/linux/sched.h中定義為:
struct?fs_struct?{
atomic_tcount;
intumask;
struct?dentry * root, * pwd;
};
在2.4中,單獨定義在include/linux/fs_struct.h中:
struct?fs_struct?{
atomic_tcount;
rwlock_tlock;
intumask;
struct?dentry * root, * pwd, * altroot;
struct?vfsmount * rootmnt, * pwdmnt, *altrootmnt;
};
count域表示共享同一fs_struct?表的進程數目。umask域由umask( )系統調用使用,用于為新創建的文件設置初始文件許可權。
fs_struct中的dentry結構是對一個目錄項的描述,root、pwd及 altroot三個指針都指向這個結構。其中,root所指向的dentry結構代表著本進程所在的根目錄,也就是在用戶登錄進入系統時所看到的根目錄;pwd指向進程當前所在的目錄;而altroot則是為用戶設置的替換根目錄。實際運行時,這三個目錄不一定都在同一個文件系統中。例如,進程的根目錄通常是安裝于“/”節點上的Ext2文件系統,而當前工作目錄可能是安裝于/msdos的一個DOS文件系統。因此,fs_struct結構中的rootmnt、 pwdmnt及 altrootmnt就是對那三個目錄的安裝點的描述,安裝點的數據結構為vfsmount。
?
?
3、驗證調用多個atexit函數時的輸出順序
? 源碼:
#include<stdio.h>
#include<stdlib.h>
?
void fun1()
{
?????? printf("thefun1\n");
}
void fun2()
{
?????? printf("thefun2\n");
}
void fun3()
{
?????? printf("thefun3\n");
}
?
?
int main()
{
?????? atexit(fun1);
?????? atexit(fun2);
?????? atexit(fun3);
?
?????? printf("the? main\n");
?????? return0;
}
結果:
總結
以上是生活随笔為你收集整理的粘滞位 File文件内容的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 获取当前ip_教程丨WIN10系统下设置
- 下一篇: 教你炒股票19:学习缠中说禅技术分析理论