本章討論了不帶緩存IO的各文件操作。
1. stat 函數族。
int stat(const char* pathname, struct stat* buf)
int fstat(int fd, struct stat* buf)
int lstat(const char* pathname,struct stat* buf) //lstat 返回連接的屬性
struct stat 結構體成員:
struct stat
{
mode_t st_mode; // file type & mode, permittion
ino_t st_ino ; //文件系統i節點號
dev_t st_dev ;//文件設備號
dev_t st_rdev; //特殊文件的文件設備號
nlink_t st_nlink; //鏈接數量
uid_t st_uid; // uid
gid_t st_gid; //gid
off_t st_size; //文件bytes.
time_t st_atime; //上次訪問時間, read操作便可
time_t st_mtime; //修改時間
time_t st_ctime; // chown, chmod,文件夾操作等
long st_blksize; //文件塊大小
long st_blocks; //512 byte 的塊數目
}
2. 文件類型
普通文件, 目錄,FIFO,socket, 字符特殊文件, 塊特殊文件,符號鏈接。
測試文件類型的demo.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc, char* argv[])
{
struct stat buf;
char* ptr;
int i;
for(i=1;i< argc;i++)
{
if (lstat(argv[i],&buf)==-1)
{
printf("can not lstat file. %s", argv[i]);
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";
else if (S_ISBLK(buf.st_mode)) ptr="bulk";
else if (S_ISFIFO(buf.st_mode)) ptr="FIFO";
else if (S_ISLNK(buf.st_mode)) ptr="LINK";
else if (S_ISSOCK(buf.st_mode)) ptr="SOCKET";
else
ptr ="unknown";
printf("file %s is %s\n",argv[i],ptr);
}
exit(0);
}
3. 用戶ID
用戶ID分爲實際用戶ID, 有效用戶ID,設置用戶ID。
文字描述蒼白無力,套用以前某領導一句話,上代碼。
#include <string.h>
#include <stdio.h>
int main()
{
printf("uid is %d\n", getuid());
printf("euid is %d\n", geteuid());
}
以非root用戶編譯,執行。
得到結果504 504
執行chown root:root a.out; chmod u+s a.out
再以非root 用戶運行
得到結果 504 0
4. 文件許可權限
st_mode 包含了9位的文件許可權限。
文件許可權限的6個規則:
- 訪問文件需要對文件夾具有執行權限
- 寫一個文件時需要對文件夾具有寫權限和執行權限
- 讀文件時需要有讀文件權限,O_RDONLY, O_RDWR
- 寫文件時需要有寫文件權限,O_WRONLY,O_RDWR,O_TRUNC
- 刪除文件必須對目錄具有寫許可權限和執行許可權限,對文件本身權限不做要求
- exec函數族需要具有執行權限
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
if(argc<2)
{
printf("need two argument\n");
exit(-1);
}
if(access(argv[1],O_RDONLY)<0)
{
printf("read %s not ok\n", argv[1]);
}
else
printf("read %s ok\n", argv[1]);
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
umask(0);
if(creat("foo", S_IRUSR| S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)<0)
{
printf("create file error\n");
}
umask(S_IRUSR| S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(creat("bar", S_IRUSR| S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)<0)
{
printf("create file error\n");
}
}
創建出來的foo 文件mode 爲 666, 而bar爲000
8. chmod 和fchmod函數
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char* pathname, mode_t mode)
int fchmod(int fileds, mode_t mode)
chmod改變文件mode 參數demo:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
struct stat buf;
if(stat("foo", &buf)<0)
{
printf("stat error. %d\n",errno);
exit(-1);
}
if(chmod("foo",buf.st_mode & ~ S_IWGRP)<0)
{
printf("chmode error. %d\n",errno);
exit(-1);
}
}
9. 粘住位
- 超級用戶
- 擁有此目錄
- 擁有此文件
粘住位的簡單demo
mkdir stick
chmod 777 stick
cd stick/
touch 1.txt
chmod 777 1.txt
su test
rm -rf 1.txt //成功
mkdir stick
chmod 777 stick
chmod +t stick/
cd stick/
touch 1.txt
chmod 777 1.txt
su test
rm -rf 1.txt //失敗
10 . chown 函數族
#include <sys/types.h>
#include <unistd.h>
int chown(const char* pathname,uid_t owner,gid_t group)
int fchown(int fd, uid_t owner, gid_t group)
int lchown(const char* pathname, uid_t owner, gid_t group)
11. 文件長度
- 普通文件長度可以爲0
- 目錄文件長度爲512倍數,比如我的系統的目錄文件長度爲4096
- 文件鏈接長度不爲鏈接文件的長度
- 空洞文件空洞部分不佔用磁盤空間,使用cat f1> f2會把空洞部分寫出0,cp 則不一樣
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
if (truncate("1.log",0)<0)
printf("truncate error\n");
}
13. 文件系統
文件自舉塊和超級塊作用:
超級快存儲了整個文件系統的信息。填滿和空的塊。
兩種經典的unix v系統文件系統的概圖
- 兩個目錄項可同時指向同一個i節點
- 符號鏈接,內容爲所指文件的名字
- i節點包含了所有文件相關信息:文件類型,文件存取許可權位,文件長度和指向該文件所佔用數據塊指針。
- i節點不能跨文件系統指
- 同文件系統下面mv,只是改變了目錄項,數據塊本身並沒有發生拷貝。
14. unlink和link函數
- 任何一個文件可以有多個目錄項指向其i節點,當指向其i節點的目錄項數量爲0時,纔可以被刪除。
- 內核會檢查當前是否有進程打開該文件,只要有進程打開文件,即使計數爲0也不被刪除
- link只能超級用戶使用
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <stdlib.h>
int main()
{
if(open("/tmp/t.log", O_RDWR | O_CREAT)<0)
{
printf("open file error\n");
exit(-1);
}
if(unlink("/tmp/t.log")<0)
{
printf("unlink file error\n");
exit(-1);
}
printf("unlink file \n");
sleep(15);
exit(0);
}
rename 和remove 函數
#include <stdio.h>
int rename(const char* oldname, const char* newname)
int remove(const char* pathname)
15. 符號鏈接
int syslink(const char* actualpath,const char* syspath)
int readlink(const char* syspath, char* buf, int bufsize)
#include <sys/types.h>
#include <utime.h>
int utime(const char* pathname,const struct utimebuf* buf)
struct utimbuf
{
time_t actime;
time_t modtime;
}
清除文件內容而不改變文件時間的demo:
#include <utime.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
int main()
{
const char* filepath = "/tmp/1.log";
struct stat buf;
if(stat(filepath,&buf)<0)
{
printf("stat error\n");
return -1;
}
if(open(filepath, O_RDWR|O_TRUNC)<0)
{
printf("truncate file error\n");
return -1;
}
struct utimbuf ub;
ub.actime = buf.st_atime;
ub.modtime= buf.st_mtime;
if(utime(filepath,&ub)<0)
{
printf("utmie error\n");
return -1;
}
}
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <dirent.h>
int mkdir(const char* path, mode_t mode)
int rmdir(const char* path)
DIR* opendir(const char* pathname)
struct dirent *readdir(DIR* dp)
void rewinddir(DIR* dp)
int closedir(DIR* dp)
18. 切換目錄
#include <unistd.h>
int chdir(const char* pathname)
int fchdir(int filedes)
char* getcwd(char* buf,size_t size)
獲得當前目錄demo:#include <unistd.h>
#include <stdio.h>
char buf[1024];
int main()
{
if(chdir("/tmp/")<0)
{
printf("change directory error\n");
return (-1);
}
if(getcwd(buf,1024)<0)
{
printf("getcwd directory error\n");
return (-1);
}
printf("directory is %s\n",buf);
}
19 sync 和fsync函數
大多數磁盤IO,都並非直接寫磁盤,而是當在內核中的緩衝區滿後,或者一定時間以後纔會沖洗磁盤。這樣可以減少讀寫磁盤的次數,提高IO 性能。