首页 > 代码库 > 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。前两个是文件的性质,后面的是进程的性质,内核进行测试的过程:按顺序测试。
- 若进程的有效ID是0(超级用户),则允许访问。
- 若进程的有效用户ID等于文件的有效用户ID(也就是进程拥有此文件),那么,若所有者适当的访问权限位被设置则允许访问,否则拒绝访问。
- 若进程有效组ID或进程的附加组ID 等于文件的组ID,若适当的访问权限位被设置则允许访问。
- 若其他用户适当的访问权限位被设置,则允许访问。
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)