

Files and Directories#
Intro#
- Session for “i-node” 裡面的資料
- Unix 系統裡面都有很多 header 可以查詢 file 的各種 attribute,就會放在 i-node 裡面
cstruct 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 st_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 * Block size might be 512 or 1024 */ };
int stat(const char *pathname, struct stat *buf);- 如果是 symbolic link 的話,你直接對他呼叫是跑不出來的,需要換另一個 function
int fstat(int filedes, struct stat *buf): for file statint lstat(const char *pathname, struct stat *buf);for link stat
File type#
- Regular file:
- Text file v.s. Binary file:
- text file 有換行改念,在不同系統中是用不同的方式表達的
\nor\r\n
- text file 有換行改念,在不同系統中是用不同的方式表達的
- Text file v.s. Binary file:
- Directory file:
- 只有 kernel 可以 編輯格式是
- 欄位內紀錄
{(filename, pointer)}, pointer 紀錄 i-node number - 讓 system 可以直接到資料夾裡面抓取 file metadata
- filename 並不是 metadata,一個 file 可以有多個 metadata
- Character Special Files:
tty,audio - Block Special Files:
disks - FIFO: 是一種 pipeline
- Socket file
- Symbolic Links
UID, GID and Access permission#
- 0 -> 8 進位
-
c#define S_IRWXU 00700 /* read, write, execute: owner */ #define S_IRUSR 00400 /* read permission: owner */ #define S_IWUSR 00200 /* write permission: owner */ #define S_IXUSR 00100 /* execute permission: owner */ #define S_IRWXG 00070 /* read, write, execute: group */ #define S_IRGRP 00040 /* read permission: group */ #define S_IWGRP 00020 /* write permission: group */ #define S_IXGRP 00010 /* execute permission: group */ #define S_IRWXO 00007 /* read, write, execute: other */ #define S_IROTH 00004 /* read permission: other */ #define S_IWOTH 00002 /* write permission: other */ #define S_IXOTH 00001 /* execute permission: other */ #define S_IRWXU 00700 /* read, write, execute: owner */ #define S_IRUSR 00400 /* read permission: owner */ #define S_IWUSR 00200 /* write permission: owner */ #define S_IXUSR 00100 /* execute permission: owner */ #define S_IRWXG 00070 /* read, write, execute: group */ #define S_IRGRP 00040 /* read permission: group */ #define S_IWGRP 00020 /* write permission: group */ #define S_IXGRP 00010 /* execute permission: group */ #define S_IRWXO 00007 /* read, write, execute: other */ #define S_IROTH 00004 /* read permission: other */ #define S_IWOTH 00002 /* write permission: other */ #define S_IXOTH 00001 /* execute permission: other */
-
Operation vs Permission#
- Directory
X: Search 權限R: 可以 list 出所有資料 (ls)W: 可以更新這個資料夾(delete, create)- Delete:
X+W,刪除一個 file 只是把他的 entry 從 directory 拿掉而已,因此只需要對 directory 有 Write 權限,file 無所謂,在 上 而已 - Create:
X+W /tmp: 永遠都是777permission
- Delete:
- File
X: 執行權限R:O_RDONLY,O_RDWRW:O_WRONLY,O_RDWR,O_TRUNC
GID, UID#
-
Real UID/GID
- 誰執行這個檔案以他為準
-
Effective UID/GID
- Check file access permission
-
Saved Set-User/Group-ID
- Effective UID/GID 可以變動所以要暫存 (Ch.8 細講)
-
Set GID/UID
- 開始執行的時候 Effective UID/GID 會變成執行檔 owner 的 UID/GID
--s --- ---表示被 set UIDS是不可執行--- --s ---表示被 set GID04000表示有外借 UID02000表示有外借 GID
-
File access test 是在 open/create/delete 檔案的瞬間就直接測過了,只要在那一瞬間有權限就好
- use
chmodto change the permission or set-uid
- use
Ownership#
- UID: 根據那個 create file 的 process 的 effective UID 來決定他的 ownership
- GID:
- Effect GID of the create process
- GID of Directory
- 有些系統會把他跟 locker 綁在一起
int access(const char *pathname, int mode);- 去 check 執行 process 對某個檔案有沒有
mode權限
- 去 check 執行 process 對某個檔案有沒有
mode_t umask(mode_t cmask);- 設定某個檔案的
umask - 與權限做
實際檔案權限 = 程式請求權限 & ~cmask但其實可以看作,也可以看作減去 - 必須要是 internal(built-in) command,也就是不需額外ㄎㄞ process 的 command(運行時可以改掉自己的 attribute,不可以 fork 出去)
- 設定某個檔案的
int chmod(const char *pathname, mode_t mode);int fchmod(int filedes, mode_t mode);- 呼叫這個 system call 的 process 必須擁有和 file 相同的 UID,若不同 system 會偷偷關掉
- 底層原理是 update i-node 並非 synchronize 不會動到 DISK
- 權限可收回浮動(Midterm 後
- Sticky Bit (Save-text bit)
- 原本目的是 mirror 一份到 swap area 裡面
- 以前沒有 Virtual Memory 但是要 handle 東西,我們可能會先放在 DISK 要拿回來的時候需要知道我們這次是不是 cold start,但現在已經被 Virtual memory 取代
- 檔案會變大變小,為了防止 memory fragment 出現,會預留一些 block,會讓 memory fragment 這種情況減少,也取代了 sticky bit
- 現在的用處: 如果一個 directory 的 sticky bit 被 set,裡面的檔案只有在 process 有
w權限並且符合以下其一才能刪除或 rename- Owner of file
- Owner of directory
- SU
/tmp雖然 777,但有開 sticky bit 所以只有 owner 可以對他的 file 做事--- --- --t表示 一樣用大小寫區分有沒有x
int chown(const char *pathname, uid_t owner, gid_t, grp);int fchown(int filedes, uid_t owner, gid_t, grp);int lchown(const char *pathname, uid_t owner, gid_t, grp);- 處理 未開啟 / 已開啟 / Symbolic link
Limit#
- Compiler-time: e.g. range of short
- Run-time limit:
long sysconf(int name);: 系統限制_SC_CHILD_MAX,_SC_OPEN_MAX
long pathconf(const char *pathname, int name);for file/directorylong fpathconf(int *filedes, int name);: for fd- 可以接
_PC_LINK_MAX,_PC_PATH_MAX,_PC_PIPE_BUF,_PC_NAME_MAX,_PC_SYMLINK_MAX來得到 limit
- 可以接
File Size#
- Regular files – 0~max (
off_t) - Directory files – multiples of 16/512
- Symbolic links – pathname length
- 有 File hole 可能導致邏輯大小與實際大小不一樣大
邏輯大小 > data block size: 用
lseek到很後面寫入會造成 hole 邏輯大小 < data block size: 占不完整的 block int truncate(const char *pathname, off_t length);,int ftruncate(int filedes, off_t length);
Unix file and directory#
Structure#
- 各種 file 連接在
/的下面 disk partition 可以 mount 到 directory,裝置也是一個 file - Partition
- 前面會有
bootblock - 在一個 super block (歷史淵源)
- 多個 cylinder groups 組成 (Hard Drive)
- 先 copy 一份 super block 然後紀錄 metadata,map 用來紀錄 usage
- i-nodes
- i-nodes map
- Data blocks
- Data blocks map

- 前面會有
- i-node list (fix list)

- 記錄佔用哪些 DISK block
- open 某個 file 就會被 mirror 到 buffer cache 裡面
- owner, type, file size
- Per file,不同的 filename 用 hard link 連接
- 裡面有一個
st_nlink紀錄 link count 類似於 Reference count
- 裡面有一個

- File operation
- move 檔案只需要改一改 i-node 的值就好了
- delete 就是 link count -1
- Example: 4.4BSD i-node

- direct block: 每個指向一個 block
- single indirect: 指向一個 block,其中都是 direct blocks (direct block 會用完),single indirect 的第一層 pointer 也可以存在 buffer cache
- double indirect,指向一個blcok,其中都是 single indirect blocks
- triple indirect,指向一個blcok,其中都是 double indirect blocks
- lock: 會在 i-node table 底下串 lock 對 process 的資料

Hard link & Soft link#
-
Hard link
- 只有 SU 可以對一個 directory create 一個 hard link
- 不能 Cross file system

-
Soft link (Symbolic link)
- 紀錄路徑
- 能 Cross file system
- 缺點是,被指到的人不知道自己被指了(可能出現 link 還在,但檔案已經爛掉了的情況)
- 還可能出現 traverse infinite loop:
- 紀錄 i-node number 解決
- 紀錄 走過幾次 soft-link 解決

-
int link(char *existingpath, char *newpath)- hard link
- 必須 atomic
- create 一個 entry -> link count +1
-
int unlink(char *pathname)- open 檔案後 unlink 你會
ls不到他,但卻可以 access
- open 檔案後 unlink 你會
-
int remove(const char *pathname);unlinkif is a filermdirif is a directory
-
int rename(const char *oldname, const char *newname);oldname,newname必須對齊,必須 file-to-file, directory-to-directory- If
oldname是 file- 對
oldnameunlink然後再換名字 - 要對兩個 directory contain
oldname/newname都要 有w+x權限
- 對
- If
oldname是 directory- 跟 file 的所有條件都一樣
oldname不可以是newname的 prefix/a/b->a/b/c會跳 Error
-
int symlink(const char *actualpath, const char *sympath);int readlink(const char *pathname, char *buf, int bufsize);- 用
open會直接開路徑上的檔案本人,要讀 symbolic link 本人要 callreadlink()
- 用
File time#
st_atime: last accessst_mtime: last modifyst_ctime: last modify i-node(chmod,chown),沒有system call可竄改- create、remove、rename、(un)link file 會設
a、m、c影響包含的 directory 的m、c- 原則: 要改 dir 的 dir block,因此 i-node 也要改大小
- 改 permission、owner 只會影響 i-node ->
c - open file:
- 還沒讀寫不會有a、m
O_CREAT才會有aO_TRUNC不需要a,只有m、c
- create、remove、rename、(un)link file 會設
int utime(const char *pathname, const struct utimbuf *times);- 要讀只要用
stat()就好,這個 function 通常用來 modify - 要有權限
- 要讀只要用
int mkdir(const char *pathname, mode_t mode);int rmdir(const char *pathname);rmdir()要 empty
DIR *opendir(const char *pathname);struct dirent *readdir(DIR *dp);void rewinddir(DIR *dp);int closedir(DIR *dp);int ftw(char* dir_path, *fn(char* f_path,stat *sb,type_flag), n_openfd)- dirpath 要開的資料夾
- fn 找到新檔案會呼叫的函數
- nopenfd 允許開啟的 fd 數量,太少 tree 又太深的話就會只留下面幾層,每次要換目錄就得要從dirpath重新開始,浪費時間
int chdir(const char *pathname);int fchdir(int filedes);- Change current working directory
- 一樣要是 built-in function,parent, child process 會擁有獨立參數
char *getcwd(char *buf, size_t size);- 只能 從當前目錄的 i-node traverse 上去,輸出是檔名
- 不可以用 soft
Back to the content
NTU PJ System Programming
2025 Fall
← Back to the content