-
fcntl.h,是一个计算机用语,用来避免一些系统安全问题。
-
中文名
-
fcntl.h
-
定 义
-
open,fcntl函数原型
-
表头文件
-
#include<unistd.h>
-
旗标
-
避免一些系统安全问题
简介
编辑
fcntl.h与unistd.h
fcntl.h定义了很多宏和open,fcntl函数原型
unistd.h定义了更多的函数原型
close(关闭文件)
表头文件#include<unistd.h>
定义函数int close(int fd);
函数说明当使用完文件后若已不再需要则可使用close()关闭该文件,二
close()会让数据写回磁盘,并释放该文件所占用的资源。参数fd为
先前由open()或creat()所返回的 文件描述词。
返回值若文件顺利关闭则返回0,发生错误时返回-1。
错误代码EBADF 参数fd 非有效的文件描述词或该文件已关闭。
附加说明虽然在进程结束时,系统会自动关闭已打开的文件,但仍建议自行
关闭文件,并确实检查返回值。(系统可能有缓冲,在适当的时候才写入,特别是NFS 网络文件系统)
open(打开文件)
表头文件
编辑
#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);
函数说明参数pathname 指向欲打开的文件路径字符串。下列是参数flags 所能使用的 旗标:
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以可读写方式打开文件。上述三种旗标是互斥的,也就是不可同时使用,
但可与下列的旗标利用OR(|)运算符组合。
O_CREAT 若欲打开的文件不存在则自动建立该文件。
O_EXCL 如果O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若
O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败。
O_NOCTTY 如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。
O_TRUNC 若文件存在并且以可写的方式打开时,此 旗标会令文件长度清为0,而原来存于该文件的资料也会消失。
O_APPEND 当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。
O_NONBLOCK 以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。
O_NDELAY 同O_NONBLOCK。
O_SYNC 以同步的方式打开文件。
O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接,则会令打开文件失败。
O_DIRECTORY 如果参数pathname 所指的文件并非为一目录,则会令打开文件失败。
O_NOATIME 从linux 2.6.8 内核开始,读文件不更新文件最后访问时间
此为Linux2.2以后特有的 旗标,以避免一些系统安全问题。参数mode 则有下列数种组合,只有在建立新文件时才会生效,此外真正建文件时的权限会受到umask值所影响,因此该文件权限应该为(mode-umaks)。
The argument mode specifies the permissions to use in case a new file is created. It is modified by the pro-cess's umask in the usual way: the permissions of the created file are (mode & ~umask). Note that this mode only applies to future accesses of the newly created file; the open call that creates a read-only file may well return a read/write file descriptor.
S_IRWXU00700 权限,代表该文件 所有者具有可读、可写及可执行的权限。
S_IRUSR 或S_IREAD,00400权限,代表该文件所有者具有可读取的权限。
S_IWUSR 或S_IWRITE,00200 权限,代表该文件所有者具有可写入的权限。
S_IXUSR 或S_IEXEC,00100 权限,代表该文件所有者具有可执行的权限。
S_IRWXG 00070权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。
S_IWGRP 00020权限,代表该文件用户组具有可写入的权限。
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。
S_IRWXO 00007权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH 00004 权限,代表其他用户具有可读的权限
S_IWOTH 00002权限,代表其他用户具有可写入的权限。
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。
返回值若所有欲核查的权限都通过了检查则返回0 值,表示成功,只要有一个权限被禁止则返回-1。
错误代码EEXIST 参数pathname 所指的文件已存在,却使用了O_CREAT和O_EXCL 旗标。
EACCESS 参数pathname所指的文件不符合所要求测试的权限。
EROFS 欲测试写入权限的文件存在于只读文件系统内。
EFAULT 参数pathname 指针超出可存取内存空间。
EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太长。
ENOTDIR 参数pathname不是目录。
ENOMEM 核心内存不足。
ELOOP 参数pathname有过多符号连接问题。
EIO I/O 存取错误。
附加说明使用access()作 用户认证方面的判断要特别小心,例如在access()后再作open()空文件可能会造成系统安全上的问题。
范例
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
main()
{
int fd,size;
char s [ ]=”Linux Programmer!\n”,buffer[80];
fd=open(“/tmp/temp”,O_WRONLY|O_CREAT);
write(fd,s,sizeof(s));
close(fd);
fd=open(“/tmp/temp”,O_RDONLY);
size=read(fd,buffer,sizeof(buffer));
close(fd);
printf(“%s”,buffer);
}
执行Linux Programmer!
creat(建立文件)
表头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
定义函数int creat(const char * pathname, mode_tmode);
函数说明参数pathname指向欲建立的文件路径字符串。Creat()相当于使用下列的调用方式调用open(),
open(const char * pathname ,(O_CREAT|O_WRONLY|O_TRUNC));
错误代码关于参数mode请参考open()函数。
返回值creat()会返回新的 文件描述词,若有错误发生则会返回-1,并把错
误代码设给errno。
EEXIST 参数pathname所指的文件已存在。
EACCESS 参数pathname 所指定的文件不符合所要求测试的权限
EROFS 欲打开写入权限的文件存在于只读文件系统内
EFAULT 参数pathname 指针超出可存取的内存空间
EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太长。
ENOTDIR 参数pathname为一目录
ENOMEM 核心内存不足
ELOOP 参数pathname有过多符号连接问题。
EMFILE 已达到进程可同时打开的文件数上限
ENFILE 已达到系统可同时打开的文件数上限
附加说明creat()无法建立特别的装置文件,如果需要请使用mkmod()。
dup(复制 文件描述词)
表头文件#include<unistd.h>
定义函数int dup (int oldfd);
函数说明dup()用来复制参数oldfd所指的文件描述词,并将它返回。此新的文件描述词和参数oldfd指的是同一个文件,共享所有的锁定、读写位置和各项权限或 旗标。例如,当利用lseek()对某个文件描述词作用时,另一个文件描述词的读写位置也会随着改变。不过,文件描述词之间并不共享close-on-exec旗标。
返回值当复制成功时,则返回最小及尚未使用的文件描述词。若有错误则
返回-1,errno会存放 错误代码。错误代码EBADF参数fd非有效的文
件描述词,或该文件已关闭。
dup2(复制 文件描述词)
表头文件#include<unistd.h>
定义函数int dup2(int odlfd,int newfd);
函数说明dup2()用来复制参数oldfd所指的文件描述词,并将它拷贝至参数newfd后一块返回。若参数newfd为一已打开的文件描述词,则newfd所指的文件会先被关闭。dup2()所复制的文件描述词,与原来的文件描述词共享各种文件状态,详情可参考dup()。
返回值当复制成功时,则返回最小及尚未使用的文件描述词。若有错误则返回-1,errno会存放 错误代码。
附加说明 dup2()相当于调用fcntl(oldfd,F_DUPFD,newfd);请参考fcntl()。
错误代码EBADF 参数fd 非有效的 文件描述词,或该文件已关闭
fcntl(文件描述词操作)
相关函数open,flock
表头文件#include<unistd.h>
#include<fcntl.h>
定义函数int fcntl(int fd , int cmd);
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock * lock);
函数说明fcntl()用来操作 文件描述词的一些特性。参数fd代表欲设置的文件
描述词,参数cmd代表欲操作的指令。
有以下几种情况:
F_DUPFD用来查找大于或等于参数arg的最小且仍未使用的文件描述
词,并且复制参数fd的文件描述词。执行成功则返回新复制的文件
描述词。请参考 dup2()。F_GETFD取得close-on-exec 旗标。若此旗
标的FD_CLOEXEC位为0,代表在调用exec()相关函数时文件将不会关
闭。
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的
FD_CLOEXEC位决定。
F_GETFL 取得 文件描述词状态旗标,此旗标为open()的参数
flags。
F_SETFL 设置文件描述词状态旗标,参数arg为新旗标,但只允许
O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影
响。
F_GETLK 取得文件锁定的状态。
F_SETLK 设置文件锁定的状态。此时flock 结构的l_type 值必须是
F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误
代码为EACCES 或EAGAIN。
F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直
等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会
立即返回-1,错误代码为EINTR。参数lock 指针为flock 结构指针,
定义如下
struct flock
{
short int l_type; /* 锁定的状态*/
short int l_whence;/*决定l_start位置*/
off_t l_start; /*锁定区域的开头位置*/
off_t l_len; /*锁定区域的大小*/
pid_t l_pid; /*锁定动作的进程*/
};
l_type 有三种状态:
F_RDLCK 建立一个供读取用的锁定
F_WRLCK 建立一个供写入用的锁定
F_UNLCK 删除之前建立的锁定
l_whence 也有三种方式:
SEEK_SET 以文件开头为锁定的起始位置。
SEEK_CUR 以目前文件读写位置为锁定的起始位置
SEEK_END 以文件结尾为锁定的起始位置。
返回值成功则返回0,若有错误则返回-1,错误原因存于errno.
flock(锁定文件或解除锁定)
相关函数open,fcntl
表头文件#include<sys/file.h>
定义函数int flock(int fd,int operation);
函数说明flock()会依参数operation所指定的方式对参数fd所指的文件做各
种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文
件的某一区域。
参数operation有下列四种情况:
LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作 共享锁
定。
LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。
LOCK_UN 解除文件锁定状态。
LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通
常与LOCK_SH或LOCK_EX 做OR(|)组合。
单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork
()时 文件描述词不会继承此种锁定。
返回值返回0表示成功,若有错误则返回-1, 错误代码存于errno。
fsync(将缓冲区数据写回磁盘)
相关函数sync
表头文件#include<unistd.h>
定义函数int fsync(int fd);
函数说明fsync()负责将参数fd所指的文件数据,由系统缓冲区写回磁盘,以
确保数据同步。
返回值成功则返回0,失败返回-1,errno为错误代码。
lseek(移动文件的读写位置)
表头文件#include<sys/types.h>
#include<unistd.h>
定义函数off_t lseek(int fildes,off_t offset ,int whence);
函数说明每一个已打开的文件都有一个读写位置,当打开文件时通常其读写
位置是指向文件开头,若是以附加的方式打开文件(如O_APPEND),
则读写位置会指向文件尾。当read()或write()时,读写位置会随之
增加,lseek()便是用来控制该文件的读写位置。参数fildes 为已
打开的 文件描述词,参数offset 为根据参数whence来移动读写位置
的位移数。
参数whence为下列其中一种:
SEEK_SET 参数offset即为新的读写位置。
SEEK_CUR 以目前的读写位置往后增加offset个位移量。
SEEK_END 将读写位置指向文件尾后再增加offset个位移量。
当whence 值为SEEK_CUR 或SEEK_END时,参数offet允许负值的出
现。
下列是教特别的使用方式:
1) 欲将读写位置移到文件开头时:lseek(int
fildes,0,SEEK_SET);
2) 欲将读写位置移到文件尾时:lseek(int fildes,
0,SEEK_END);
3) 想要取得文件位置时:lseek(int fildes,0,SEEK_CUR);
返回值当调用成功时则返回读写位置,也就是距离文件开头多少个
字节。若有错误则返回-1,errno 会存放 错误代码。
附加说明Linux系统不允许lseek()对tty装置作用,此项动作会令lseek
()返回ESPIPE。
范例参考本函数说明
read(由已打开的文件读取数据)
定义函数ssize_t read(int fd,void * buf ,size_t count);
函数说明read()会把参数fd 所指的文件传送count个字节到buf 指针所指的内
存中。若参数count为0,则read()不会有作用并返回0。返回值为实
际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的
数据,此外文件读写位置会随读取到的字节移动。
附加说明如果顺利read()会返回实际读到的字节数,最好能将返回值与参数
count 作比较,若返回的字节数比要求读取的字节数少,则有可能
读到了文件尾、从管道(pipe)或终端机读取,或者是read()被信号
中断了读取动作。当有错误发生时则返回-1, 错误代码存入errno
中,而文件读写位置则无法预期。
错误代码EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则
返回此值。
EBADF 参数fd 非有效的 文件描述词,或该文件已关闭。
范例参考open()。
sync(将缓冲区数据写回磁盘)
相关函数fsync
表头文件#include<unistd.h>
定义函数int sync(void)
函数说明sync()负责将系统缓冲区数据写回磁盘,以确保数据同步。
返回值返回0。
write(将数据写入已打开的文件内)
定义函数ssize_t write (int fd,const void * buf,size_t count);
函数说明write()会把参数buf所指的内存写入count个字节到参数fd所指的文
件内。当然,文件读写位置也会随之移动。
返回值如果顺利write()会返回实际写入的字节数。当有错误发生时则返
回-1, 错误代码存入errno中。
错误代码EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则
返回此值。
EADF 参数fd非有效的 文件描述词,或该文件已关闭。
范例请参考open()。
Fork
传统方式下,Fork创建一个子进程,并为子进程创建一个 父进程 地址空间的拷贝。然而,由于许多子进程在创建之后通常马上会执行系统调用exec,所以父进程地址空间的复制可能没有必要,从而造成效率和内存的极大浪费。因此,就产生了一种称为“写时复制”的技术。
现在是写时复制
写 时复制允许子进程与父进程在开始时共享同一页面。但这些页面被标记为“写时复制”,即如果任何一个进程需要对页进行写操作,就会创建这个共享页的拷贝。例 如,假设子进程试图修改含有部分栈的页,且操作系统能够识别出该页为写时复制页,则操作系统就会创建该页的一个拷贝,并将它映射的子进程的 地址空间里。这 样,子进程修改的就是其复制的页,而不是 父进程的页。采用写时复制技术,只有被进程所修改的页才会复制,而所有非修改的页可为父进程和子进程共享。注意, 并不是所有的页都标记为写时复制,只有可能修改的页才需要标记为写时复制,对不能修改的页,如 代码页,可谓父进程和子进程所共享。
Vfork(Virtual memory fork)
Vfork不 同于写时复制的fork。对于 vfork,父进程会挂起,以确保子进程先运行。子进程使用父进程的地址空间。由于vfork不使用写时复制,因此如果子进 程修改地址空间的任何页,这些修改在父进程重启时都是可见的。所以,vfork必须小心使用,以确保子进程不会修改 父进程的 地址空间。Vfork主要用于 在进程创建后立即调用exec的情况,这样既没有出现复制页,也不会修改父进程的地址空间,所以是一种很有效的进程创建方法。
char *getcwd(char *buf, size_t size);
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
/*
* if limits.h no define PATH_MAX,I define.
*/
#ifndef PATH_MAX
#define PATH_MAX 255
#endif
int main(){
char workdir[PATH_MAX];
if(!getcwd(workdir,PATH_MAX))
perror("couldn't get current work directory!\n");
else
printf("workdir = %s\n",workdir);
return 0;
}
long pathconf(char *path, int name);
int chdir(const char* path);
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
int main(){
char *workdir;
long path_max;
if((path_max = pathconf("/",_PC_PATH_MAX)) == -1){
perror("couldn't get _PC_PATH_MAX!\n");
return -1;
}
printf("path_max is %d\n",path_max);
if((workdir = (char *)malloc(path_max)) == NULL){
perror("couldn't allocate memory for the workdir!\n");
return -1;
}
if(getcwd(workdir,path_max) == NULL){
perror("couldn't get current work directory!\n");
return -1;
}
printf("current dir is %s\n",workdir);
if(chdir("..") == -1){
perror("change directory error!\n");
return -1;
}
if(getcwd(workdir,path_max) == NULL){
perror("couldn't get current work directory!\n");
return -1;
}
printf("current dir is %s\n",workdir);
free(workdir);
return 0;
}
int rmdir(const char * pathname);
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
int unlink(const char *pathname);
int link(const char *oldpath, const char *newpath);
int symlink(const char *oldpath, const char *newpath); //Symbolic links软连接
char * ttyname(int fd);
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc,char *argv[]){
char * tty_out;
if( (tty_out = ttyname(STDOUT_FILENO) ) == NULL){
perror("cannot get tty name\n");
return -1;
}
printf("STDOUT_FILENO tty name is :%s\n",tty_out);
return 0;
}
void usleep(unsigned long usec);毫秒
pid_t getpid(void);
pid_t getppid(void);
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg, ..., char *const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);int execve(const char *path, char *const argv[], char *const envp[]);pid_t setsid(void);int lockf(int fd, int cmd, off_t len);unsigned int alarm(unsigned int seconds);int pipe(int pipefd[2]);