首页 > 代码库 > unix环境高级编程笔记(4)—— 文件和目录(1)

unix环境高级编程笔记(4)—— 文件和目录(1)

1 引言

本文将描述文件系统的一些特征和文件的性质,从stat函数开始,逐个讲解stat结构的成员以了解文件的属性。

2 stat,fstat 和 lstat函数

#include <sys/stat.h>int stat(const char *restrict pathname,struct stat *restrict buf);int fstat(int filedes,struct stat *restrict buf);int lstat(const char *restrict pathname,struct stat *restrict buf);                                                                          成功返回0,失败返回-1。

以上三个函数在 buf 中返回文件的信息结构,fstat使用文件描述符,而不是pathname。lstat和stat差不多,当pathname是符号链接时,lstat返回的是符号链接的有关信息,而不是其所引用文件的信息。

buf  是一个struct stat结构指针,函数会自动填写结构内容。

struct stat{	mode_t       st_mode;	                /* file type & mode (permissions) */	ino_t        st_ino;			/* i-node 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 byte,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*/};

3 文件类型

  • 普通文件(regular file)   :最常用文件类型,二进制文件也是普通文件。UNIX不区分普通的文本文件和二进制文件。
  • 目录文件(directory file):包含其他文件的名字以及这些文件信息的指针。
  • 块特殊文件(block special file):这种文件提供对设备带缓冲的访问,每次访问长度固定。
  • 字符特殊文件(character special file):这种文件提供对设备不带缓冲的访问,每次访问长度可变。系统中的设备要么是block special file,要么是character special file。
  • FIFO:这种文件用于进程间通讯,也称为命名管道(named pipe)。
  • 套接字(socket):这种文件用于进程间的网络通讯,也可以用于一台计算机上进程间的非网络通讯。
  • 符号链接(symobic link):指向另一个文件。

文件类型的信息包含在stat结构的st_mode成员中,可以用下列宏进行测试,例如:S_ISREG(buf.st_mode)。

        S_ISREG( )      regular file

        S_ISDIR( )       directory file

        S_ISBLK( )         block special file

        S_ISCHR( )      character special file

        S_ISFIFO( )      FIFO

        S_ISLINK( )      symobic link

        S_ISSOCK( )      socket

另外进程间通信(IPC)对象也可作为文件。用相应的宏进行测试,不过不是用st_mode成员作为参数,而是指向stat的指针。

下面这个程序对每个参数打印文件类型。

#include <stdio.h>#include <sys/stat.h>int main(int argc,char* argv[]){    int i;    struct stat buf;    char *ptr;    for(i = 1;i < argc;i++)    {        if(lstat(argv[i],&buf)< 0)            {                printf("lstat error\n");                continue;            }        printf("%s: ",argv[i]);        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 special";        else if(S_ISBLK(buf.st_mode))            ptr = "block special";        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 = "unknow mode";        printf("%s\n",ptr);    }    return 0;}

编译执行:

root@debian:/program# ./4-1 /etc/passwd /etc /dev/log /dev/tty /dev/cdrom/etc/passwd: regular/etc: directory/dev/log: socket/dev/tty: character special/dev/cdrom: linkroot@debian:/program# 

4 设置用户和组ID

  • 实际用户ID和实际组ID:标识我们实际是谁,这两个字段一般在登录时取自口令文件中的登录项。
  • 有效用户ID,有效组ID和附加组ID:决定了我们对文件的访问权限。
  • 保存的设置用户ID和保存的设置组ID:执行了一个程序时包含了有效用户ID和有效组ID副本。

文件所有者由stat结构中的st_uid表示,组所有者由st_gid表示。

设置用户ID位和设置组ID位在stat结构的st_mode成员中,可由常量S_ISUID和S_ISGID测试。

5 文件访问权限

st_mode值也包含文件访问权限位,前面所提到的文件都有访问权限(access permission)。

每次打开,创建或删除一个文件时,内核都对文件访问权限进行测试,涉及到所有者(st_uid,st_gid)和 进程有效ID(有效用户ID和有效组ID),附加组ID。前两个是文件的性质,后面的是进程的性质,内核进行测试的过程:按顺序测试。

  1. 若进程的有效ID是0(超级用户),则允许访问。
  2. 若进程的有效用户ID等于文件的有效用户ID(也就是进程拥有此文件),那么,若所有者适当的访问权限位被设置则允许访问,否则拒绝访问。
  3. 若进程有效组ID或进程的附加组ID 等于文件的组ID,若适当的访问权限位被设置则允许访问。
  4. 若其他用户适当的访问权限位被设置,则允许访问。

6 新文件和目录的所有权

当创建新文件或目录时,其文件的用户ID为进程的有效ID,组ID由两种选择:

  1)进程的有效组ID。

  2)所在目录的组ID(如果所在目录的设置组ID位被设置的话)。

7 access 函数

也可以用access函数进行以实际用户或组进行测试(也是四步,有效改为实际)。

#include <unistd.h>int access(const char *pathname,int mode);                                                    若成功返回0,失败返回-1.

参数mode用以下常量按位或 取得:

      R_OK      可读

      W_OK      可写

      X_OK        可执行

      F_OK       测试文件是否存在

8 umusk 函数

umusk为进程设置文件模式创建屏蔽字,并返回以前的值。(此函数没有出错返回)

#include <sys/stat.h>mode_t umask(mode_t cmask);                    返回以前的文件模式创建屏蔽字

参数cmask的值是9个文件访问权限按位或构成的。

任何文件模式创建屏蔽字中为1 的位 ,在文件mode中相应的位都被关闭。

下面的程序创建两个文件,使用不同的文件模式创建屏蔽字。

#include <stdio.h>#include <fcntl.h>#include <sys/stat.h>#define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)int main(){    umask(0);    if(creat("foo",RWRWRW) < 0)        printf("creat foo error\n");    umask( S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );    if(creat("bar",RWRWRW) < 0)        printf("creat bar error\n");    return 0;}

第一个umask把文件创建模式屏蔽字清零,所以创建的文件就是指定的文件访问权限,第二个umask把组和其他用户的读,写权限屏蔽了,所以只有用户能读,写。

    root@debian:/program# ./4-3

root@debian:/program# ls -l bar foo-rw------- 1 root root 0 Nov  9 21:24 bar-rw-rw-rw- 1 root root 0 Nov  9 21:24 fooroot@debian:/program# 

 9 chmod 和 fchmod 函数

这两个函数可以更改现有文件的访问权限

#include<sys/stat.h>int chmod(const char *pathname,mode_t mode);int fchmod(int filedes,mode_t mode);            成功返回0,出错返回-1。

  

pathname :指定文件。

filedes:指定文件描述符。

mode:文件访问权限位。

10 chown fchown 和 lchown

这三个函数用于更改文件的用户ID和组ID

#include<unistd,h>int chown(const char *pathname,uid_t owner,gid_t group);int fchown(int filedes,uid_t owner,gid_t group);int lchown(const char *pathname,uid_t owner,gid_t group);              成功返回0,失败返回-1.

  

lchown 修改的是符号链接本身的所有者。

如果 owner 和group中任意一个为 -1 ,则对应的ID值不变。

如果这些函数由非超级用户调用,则该文件的设置用户ID位和设置组ID位被清除  

 

unix环境高级编程笔记(4)—— 文件和目录(1)