[APUE]再讀之文件和目錄

本章討論了不帶緩存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函數族需要具有執行權限
5. 新文件的所有權
新文件所有權用戶跟隨進程uid,組ID可以跟隨進程gid,或者所在目錄gid.

6. access 函數
測試文件權限
#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]);
}
7. umask屏蔽位
#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 則不一樣
12. 文件截短

截短一個文件
#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只能超級用戶使用
unlink用於進程崩潰前刪除文件的 demo
#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. 符號鏈接

硬鏈接的限制爲:1. 不能跨文件系統 2. 只能root用戶做。 符號鏈接是一個間接的文件指針,沒有這些限制。
int syslink(const char* actualpath,const char* syspath)
int readlink(const char* syspath, char* buf, int bufsize)

16.   utime函數
可以使用一個文件的存取和修改時間可以用utime來修改
#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;
    }
}

17. 目錄操作
#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. 切換目錄
每個進程都有當前工作目錄。通過chdir函數可以更改當前目錄。
#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 性能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章