課程目標(biāo)
- 編程目標(biāo):
(a)實(shí)現(xiàn)ls –l
全部功能。
(b)實(shí)現(xiàn)tree
工具全部功能篮幢。 - 理解文件系統(tǒng)對磁盤文件的管理策略丈积。
- 掌握文件屬性獲取與修改的API應(yīng)用鬼悠。
- 特殊文件的基本信息。
主要知識點(diǎn)
- VFS文件系統(tǒng)以及ext2/3/4文件系統(tǒng)結(jié)構(gòu)捌木。
- 文件信息存儲
inode
以及文件類型油坝,文件屬性的獲取。 - 文件屬性的獲取與修改刨裆。
- 編程應(yīng)用澈圈。
1—Linux一切都是文件及文件系統(tǒng)
- 一切皆文件的概念
Linux一切皆為文件的思想是基于虛擬文件系統(tǒng)(Virtual File System,VFS)實(shí)現(xiàn)帆啃。把底層的硬件實(shí)現(xiàn)全部隱藏瞬女,用戶操作普通文件或者其它的硬件設(shè)備,都基于文件系統(tǒng)的方式努潘,即基本上都可以使用open/read/write/close
這些文件操作的系統(tǒng)調(diào)用來訪問诽偷。便于應(yīng)用層的程序開發(fā)。 - Linux下根據(jù)設(shè)備的屬性將文件分為7類:
文件類型 | 類別 | 標(biāo)識符 |
---|---|---|
普通文件 | 磁盤文件 | - |
目錄文件 | 磁盤文件 | d |
鏈接文件 | 磁盤文件 | l |
字符設(shè)備文件 | 設(shè)備文件 | c |
塊設(shè)備文件 | 設(shè)備文件 | b |
管道文件 | 進(jìn)程通信文件 | p |
socket文件 | 網(wǎng)絡(luò)通信文件 | s |
- 磁盤文件系統(tǒng)怎么來管理文件疯坤?
struct inode
結(jié)構(gòu)體存儲了文件的**基本屬性报慕,這個屬性在內(nèi)核中定義。
在終端中輸入man 2 stat
查看stat相關(guān)信息:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
以上三個函數(shù)可以獲取某個文件的詳細(xì)的屬性压怠,
可以通過 strut stat結(jié)構(gòu)體查看
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */ 文件在當(dāng)前文件系統(tǒng)下的唯一編號
mode_t st_mode; /* protection */ 存放的是文件的類型以及權(quán)限
nlink_t st_nlink; /* number of hard links */ 硬鏈接個數(shù)
uid_t st_uid; /* user ID of owner */ 擁有者ID
gid_t st_gid; /* group ID of owner */ 擁有組ID
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */ 文件的大小
blksize_t st_blksize; /* blocksize for file system I/O */ 塊的大小
blkcnt_t st_blocks; /* number of 512B blocks allocated */ 塊的個數(shù)
time_t st_atime; /* time of last access */ 最近訪問時(shí)間
time_t st_mtime; /* time of last modification */ 最近修改熟悉的時(shí)間
time_t st_ctime; /* time of last status change */ 最近修改內(nèi)容的時(shí)間
};
查看文件編號ls -li
2—文件類型及文件模式
mode_t st_mode; /* protection */ 存放的是文件的類型以及權(quán)限
3個bit的權(quán)限修飾位
- setuid位
- setgid位
以上兩個bit被設(shè)置后眠冈,相應(yīng)的執(zhí)行這個文件時(shí),會提升它的執(zhí)行權(quán)限
以/usr/bin/passwd
可執(zhí)行文件為例刑峡。用戶的密碼存儲在/etc/passwd/shadow
文件中:
delphi@delphi-vm:~/code/test$ ll /etc/shadow
-rw-r----- 1 root shadow 1010 2014-08-26 21:53 /etc/shadow
從以上可以看出洋闽,普通用戶對這個文件沒有寫的權(quán)限,因此突梦,如果用vi編輯器修改肯定是不可以的诫舅。但是,普通用戶可以使用passwd
這個命令來修改自己的密碼宫患,也就是修改了/etc/shadow
這個文件刊懈。原因時(shí)/usr/bin/passwd
這個可執(zhí)行文件被設(shè)置了setuid
位。
delphi@delphi-vm:~/code/test$ ll /usr/bin/passwd
-rwsr-xr-x 1 root root 37100 2011-02-15 06:12 /usr/bin/passwd*
當(dāng)普通用戶執(zhí)行這個程序時(shí)娃闲,因?yàn)樵O(shè)置了setuid
位虚汛,相應(yīng)的這個進(jìn)程對文件的訪問權(quán)限上升到該可執(zhí)行文件擁有者的權(quán)限,在這個地方就是普通用戶執(zhí)行時(shí)皇帮,對文件的讀寫的權(quán)限被提升為這個文件的擁有者root的權(quán)限卷哩,而root用戶對/etc/shadow文件有寫的權(quán)限,因此属拾,可以修改密碼成功将谊。
- 粘貼位:在早期計(jì)算機(jī)冷溶,如果一個可執(zhí)行文件被設(shè)置此位,期望這個可執(zhí)行文件常駐內(nèi)存尊浓,提高運(yùn)行的速率
3—磁盤文件屬性讀取與修改編程
1. 權(quán)限的修改
man 2 chmod
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
man 2 umask
mode_t umask(mode_t mask);//修改和獲取當(dāng)前的umask值逞频。默認(rèn)0022
源碼中對于權(quán)限的宏定義
#define S_IRWXU 00700 //擁有者讀寫執(zhí)行的權(quán)限
#define S_IRUSR 00400 //擁有者讀的權(quán)限
#define S_IWUSR 00200 //擁有者寫的權(quán)限
#define S_IXUSR 00100 //擁有者執(zhí)行的權(quán)限
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
新創(chuàng)建的文件的權(quán)限
如果使用以下權(quán)限新創(chuàng)建文件
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
(octal 0666) when creating a new file, the permissions on the resultingfile will be:
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
(because 0666 & ~022 = 0644; i.e., rw-r--r--).
最終這個文件的權(quán)限:0666& ~022 = 0644,而~022就是umask值
- 默認(rèn)新創(chuàng)建文件的權(quán)限:
0666&~umask
- 默認(rèn)新創(chuàng)建的目錄的權(quán)限:
0777&~umask
2.用戶的信息
uid_t st_uid; /* user ID of owner */ 擁有者ID
gid_t st_gid; /* group ID of owner */ 擁有組ID
/etc/passwd
存儲的是用戶的ID以及相關(guān)信息栋齿。
/etc/group
存儲的是組的ID以及相關(guān)信息苗胀。
通過 stat返回的是用戶的ID,要獲取它的用戶名瓦堵,實(shí)際是讀取對應(yīng)的文件基协。
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);
返回的是一個struct passwd指針:
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* real name */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
#include <sys/types.h>
#include <grp.h>
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);
返回一個 struct group指針:
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};
3. 相關(guān)時(shí)間
在struct stat
中時(shí)間分為以下三種:
time_t st_atime; /* time of last access */ 最近訪問時(shí)間
time_t st_mtime; /* time of last modification */ 最近修改熟悉的時(shí)間
time_t st_ctime; /* time of last status change */ 最近修改內(nèi)容的時(shí)間
查找man 2 utime
#include <sys/types.h>
#include <utime.h>
int utime(const char *filename, const struct utimbuf *times);
struct utimbuf {
time_t actime; /* access time */
time_t modtime; /* modification time */
};
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
4. 文件大小
文件的大小:可以把一個文件截短或擴(kuò)展
- 截?cái)啵?code>truncate
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
如果length小于當(dāng)前文件大小菇用,截短堡掏;如果大于,依賴于系統(tǒng)刨疼,有些系統(tǒng)會擴(kuò)展泉唁。
5. 鏈接問題
- 硬鏈接:用
ln -d
來創(chuàng)建,實(shí)際上時(shí)增加某個為你教案的屬性中硬鏈接數(shù)值揩慕。
編程中用link()
函數(shù)實(shí)現(xiàn)
創(chuàng)建硬鏈接
NAME
link - make a new name for a file (為文件創(chuàng)建一個新名字即為硬鏈接)
SYNOPSIS
#include <unistd.h>
int link(const char *oldpath, const char *newpath);
========================
刪除硬鏈接
NAME
unlink - delete a name and possibly the file it refers to
SYNOPSIS
#include <unistd.h>
int unlink(const char *pathname);
僅僅是將某個文件的硬鏈接數(shù)自動減1亭畜,
有時(shí)候用來刪除文件是因?yàn)槲募]有
創(chuàng)建硬鏈接時(shí),硬鏈接數(shù)為1迎卤,而減去1
變?yōu)?拴鸵,從而刪除文件。
- 符號鏈接:類似于windows的快解方式類似蜗搔,創(chuàng)建了一個新文件劲藐,只是不分配新數(shù)據(jù)空間,符號鏈接文件的大小為源文件路徑字符串長度樟凄。
在控制臺中創(chuàng)建符號鏈接:
delphi@delphi-vm:~/code/test$ ln -s copy copy.lk
delphi@delphi-vm:~/code/test$ ll copy copy.lk
-rwxrw-r-- 1 delphi delphi 1000 2018-08-07 12:20 copy*
lrwxrwxrwx 1 delphi delphi 4 2018-08-07 15:36 copy.lk -> copy*
在編程中創(chuàng)建符號鏈接:
創(chuàng)建符號鏈接:
NAME
symlink - make a new name for a file
SYNOPSIS
#include <unistd.h>
int symlink(const char *oldpath, const char *newpath);
讀取符號鏈接:
NAME
readlink - read value of a symbolic link
SYNOPSIS
#include <unistd.h>
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
默認(rèn)情況下聘芜,讀取符號鏈接的內(nèi)容和屬性時(shí)得到源文件的信息,
因此缝龄,針對符號鏈接有專門的函數(shù):
stat ==> lstat
chmod ==> lchmod
6. 編程實(shí)現(xiàn)ls -l
參數(shù)列表問題
ls -l
后面可以跟一個或者多個文件和目錄汰现。要解決這個問題可以使用命令行參數(shù)解析的工具getopt/getopt_long
。
另外叔壤,遍歷非-l
其他參數(shù)瞎饲,有可能是目錄,有可能是文件炼绘,是目錄則讀取目錄下所有的子文件及子目錄信息嗅战;如果是普通文件,列出文件信息俺亮;如果沒有指定參數(shù)驮捍,則列出當(dāng)前目錄下的文件信息形庭。
怎么來判斷文件是文件還是目錄呢?**lstat()
函數(shù)能夠獲取給定的路徑類型厌漂。信息的問題