Linux 编程学习笔记(一):文件I/O-open,openat,creat与close
Linux 编程学习笔记(一):文件I/O-open,openat,creat与close
Linux 下文件I/O函数包括以下几个函数:
- open 和 openat
- creat
- close
- lseek
- read
- write
- dup,dup2
- sync,fsync,fdatasync
- fcntl,ioctl
其中,open openat creat 用于打开/创建文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
以上函数成功时返回文件描述符;失败时返回-1,并设置errno变量。
open openat函数用于打开文件,其中open打开是的相对于程序执行位置路径的文件,openat打开的是相对于给定文件路径下的的文件。
flags可以是下列常量或者是由下列常量或运算(“|”)组合得到:
O_RDONLY ;只读打开
O_WRONLY ;只写打开
O_RDWR ;读写打开
O_EXEC ;只执行打开
上面5个常量只能去一个组成flags。
O_APPEND ;追加模式,即每次写入都写入到文件尾
O_CREAT ;若文件不存在就自动创建。当使用该选项时,必须指定第三个参数mode(用以指定创建的文件的权限).
O_DIRECTORY ;若pathname不是目录,则出错。
O_EXCL ;若同时指定了O_CREAT,而文件已经存在,则报错。用这个可以测试一个文件是否存在,若不存在则创建文件。
O_NOCTTY ;若pathname是终端设备,则不将该设备分配作为这个进程的控制终端。
O_NOFOLLOW ;若pathname是链接,则报错。
O_SYNC ;同步模式,即每次写入都要等待写入操作完成。
O_TRUNC ;截断模式,即以可写模式打开文件后将文件截断(清空)
上面的常量可以使用”或”运算组合。
mode 是指创建文件时的文件权限,可以使用下列方式代表:
A)8进制表示法:
四位数字,第一位数表示文件的特殊权限(只有root才能赋予这些权限),第二位数字表示文件所有者拥有的权限,第三位数字代表群组成员拥有的权限,第四位数字代表系统其他用户拥有的权限,每一位都由几个表示特定权限的数字相加而成,加了表示某个权限的数字,表示拥有该权限。
第一位数:文件的特殊权限:4代表SUID,2代表SGID,1代表SBIT
第二位数:表示文件所有者拥有的权限:4代表R(读),2代表W(写),1代表X(执行).
第三位数:表示群组成员拥有的权限:4代表R(读),2代表W(写),1代表X(执行).
第四位数:表示其他用户拥有的权限:4代表R(读),2代表W(写),1代表X(执行).
举个例子,0777表示该文件没有特殊权限,所有用户(文件所有者、群组成员、其他用户)都具有读、写、执行权限(7=4+2+1)。
0755表示没有特殊权限,文件所有者 具有读、写、执行权限(7=4+2+1),群组用户和其他用户只拥有读、执行权限(5=4+1)。
4755表示具有SUID特殊权限,文件所有者 具有读、写、执行权限(7=4+2+1),群组用户和其他用户只拥有读、执行权限(5=4+1)。
B)常量表示法
其实在编写应用在UNIX/Linux程序的时候,涉及到文件权限时,我们可以用一组常量来代替8进制表示法:
基本格式:S_I<权限><指定对象:文件拥有者/群组成员/其他用户>
下面给出了一些常见的常量及释义:
| 常量 | 释义 |
|---|---|
| S_IRWXU | 文件拥有者(User)拥有读(R)、写(W)、执行(X) 的权限 |
| S_IRUSR | 文件拥有者(User)拥有读(R) 的权限 |
| S_IWUSR | 文件拥有者(User)拥有写(W) 的权限 |
| S_IXUSR | 文件拥有者(User)拥有执行(X) 的权限 |
| S_IRWXG | 群组成员(Group)拥有读(R)、写(W)、执行(X) 的权限 |
| S_IRGRP | 群组成员(Group)拥有读(R) 的权限 |
| S_IWGRP | 群组成员(Group)拥有写(W) 的权限 |
| S_IXGRP | 群组成员(Group)拥有执行(X) 的权限 |
| S_IRWXO | 其他用户(Other)拥有读(R)、写(W)、执行(X) 的权限 |
| S_IROTH | 其他用户(Other)拥有读(R) 的权限 |
| S_IWOTH | 其他用户(Other)拥有写(W) 的权限 |
| S_IXOTH | 其他用户(Other)拥有执行(X) 的权限 |
| S_SUID | 设置SUID特殊权限 |
| S_SGID | 设置SGID特殊权限 |
| S_SVTX | 设置SBIT特殊权限 |
creat 函数用于创建文件。实际上,使用:
int creat(const char *pathname, mode_t mode);
相当于使用:
open(pathname,O_WRONLY|O_CREAT|O_TRUNC,mode);
即以截断式创建文件并以只写方式打开文件。
close系统调用比较简单,它的功能就是要关闭已经打开的文件。它的参数只有一个,即打开的文件的文件描述符。
关于SUID、SGID、SBIT的补充说明:
SUID的意思是在运行被赋予了SUID特殊权限的程序(拥有可执行权限X)时,会暂时将运行着的程序用户权限提升至文件拥有者的权限。
举个栗子,Linux系统使用时我们会用sudo命令提权执行一些普通用户执行不了的操作,在使用sudo命令的提权之前需要用户输入密码确定使用者身份,这就需要访问/etc/shadow文件来验证加密过的用户密码是否与存储的一致了。可是这个文件的拥有者是root,权限是0700,除了root用户之外,其余用户不具有查看及修改这个文件的权限,也就是说,以普通用户身份运行的程序是无法查看这个文件的。实际上,sudo命令是被赋予了SUID特殊权限的,在运行过程中,运行者的权限会暂时提升到文件拥有者的权限(即root),这样,sudo就可以访问/etc/shadow文件来验证密码了。
SGID的作用跟SUID差不多,区别在于,SUID是将当前用户权限提升到文件拥有者权限,而SGID是将当前用户权限提升到群组成员拥有的权限。
SBIT是针对目录的,在多用户环境下,对一个目录设置了SBIT权限,则当 当前用户对该目录拥有执行与写入权限时(即可以进入该文件夹并写入文件),自己创建的文件、子目录只有自己和root用户才有权限删除,这一点非常适合用于文件夹共享的情况下防止误删除而导致数据丢失。
下面是一些使用的栗子:
int fd0=open("/tmp/test.txt",O_RDWR); //读写打开/tmp/test.txt
int fd1=open("/tmp",O_RDWR); //只读打开/tmp(目录)
int fd2=openat(fd1,“test2.txt”,O_WRONLY,S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); //在前面打开的目录(/tmp)下创建文件test.txt,并赋予权限0755(文件所有者 具有读、写、执行权限,群组用户和其他用户只拥有读、执行权限)。
int fd3=creat("/tmp/test3.txt",S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); //创建文件/tmp/test3.txt,权限0755
close(fd0);//关闭打开的文件fd0
close(fd1);
close(fd2);

浙公网安备 33010602011771号