1. linux的文件结构
linux是一个基于文件的操作系统,对于每个文件都有访问权限的设置,可以通过系统调用或C语言的库函数进行对文件的操作。
文件包含两方面:一是文件本身包含的数据;另外就是文件的属性,也成为元数据,包括文件的访问权限,所有者,文件大小,创建日期等。
2. 文件的分类
2.1. linux中包含以下几种文件类型
2.1.1. 普通文件:常见的文件类型,包含某种形式的数据。
2.1.2. 目录文件:实质就是目录,目录同时具有访问权限,目录文件的内容就是该目录下的文件和子目录的信息,有读权限的进程可读取该目录的内容,但只有内核可以写目录文件。
2.1.3. 字符特殊文件:用于表示文件系统中字符类型的设备,如键盘,鼠标等,这些硬件对于操作系统来说只是一个文件。
2.1.4. 块特殊文件:用于表示系统中块类型的设备,如硬盘,光驱等。对这些设备上的数据访问通常已块的方式进行,即一次至少读写一个块。
2.1.5. FIFO:进程间的通信,也命名为通信管道。
2.1.6. 套接字:用于网络通信,也可用于一台主机上进程间的通信。
2.1.7. 符号链接:指向另一个文件,是另一个文件的引用。
3.文件的访问权限的控制
linux的安全基于用户访问权限的控制,在shell下可通过ls -l <filename>查看文件的属性,其中文件属性10位中第1位表示文件类型,其余9位表示文件的访问权限,按3个一组分为三组,3组依次是文件所有者,文件所属组的用户,其他用户的操作权限。r表示可读,w表示可写,x表示可执行。可通过chmod命令来更改文件的访问权限。
//功能:改变文件的访问权限
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
int main(int argc, char ** argv)
{
int mode; //权限
int mode_u; //所有者权限
int mode_g; //所属组权限
int mode_o; //其他用户的权限
char *path;
//检查参数个数的合法性
if(argc < 3)
{
printf("%s <mode num> <target file>\n", argv[0]);
exit(0);
}
//获取命令行参数
mode = atoi(argv[1]); //atoi(%s)函数将字符串转换成整形数
if(mode > 777 || mode < 0)
{
printf("mode num error!\n");
exit(0);
}
mode_u = mode / 100;
mode_g = (mode - (mode_u * 100)) / 10;
mode_o = mode - (mode_u * 100) - (mode_g * 10);
mode = (mode_u * 8 * 8) + (mode_g * 8) + mode_o; //八进制转换
path = argv[2];
if(chmod(path, mode) == -1)
{
perror("chmod error");
exit(1);
}
return 0;
}
在这段代码中 mode = (mode_u * 8 * 8) + (mode_g * 8) + mode_o; 是将所传入的参数对每一位进行解析之后,将连起来的数字按照一个8进制的数字进行转化得到10进制的结果,在chmod的参数mode实质就是一个10进制的数字,然后在chmod函数执行时,在其函数内部又转换为一个2进制的数,然后与代表着不同权限的字符常量(宏定义)的 2进制每位进行对比得出是否改变该权限,实质就是二进制的mode与各个权限的宏定义进行与运算(&)得出文件的操作权限的。
其中参数mode的数值如下:分别是 字符常量 字符常量对应的八进制值 含义
S_IRUSR(S_IREAD) 00400文件所有着具有可读取权限
S_IWUSR(S_IWRITE) 00200文件所有者具有可写入权限
S_IXUSR(S_IEXEC) 00100文件所有者具有可执行权限
S_IRGRP 00040用户组具有可读取权限
S_IWGRP 00020用户组具有可写入权限
S_IXGRP 00010用户组具有可执行权限
S_IROTH 00004其他用户具有可读取权限
S_IWOTH 00002其他用户具有可写入权限
S_IXOTH 00001其他用户具有可执行权限
S_ISUID 04000文件的(set user-id execution)位
S_ISGID 02000 文件的(setgroup-id execution)位
S_ISOTH 01000文件的sticky位
权限修改成功返回0,修改失败返回-1.
4. 对于文件的打开,有着不同的方式:
O_RDONLY:以只读方式打开文件
O_WRONLY:以只写方式打开文件
O_RDWR:以可读可写的方式打开文件
这些打开方式是互斥的,只能以其中一种方式打开,但也可与以下标志进行或运算
O_CREAT;如果文件按不存在自动建立该文件
O_EXCL:如果O_CREAT被设置,此时则会检查文件是否存在,文件不存在则创建,存在则出错
O_TRUNC:若文件存在并且以可写的方式打开时,此标志会将文件长度清零,即原文数据丢失,被空覆盖,单文件属性不变
O_APPEND:所写入的数据已追加的方式加入到文件后面
O_SYNC:以同步的方式打开文件按,任何对文件的修改都会阻塞直到物理磁盘数据同步以后才返回
O_NOFLOLLOW:若参数pathname所指文件为一符号连接,则打开失败
O_DIRECTORY:若参数pathname所指文件非目录,则会令打开失败
O_NONBLOCK / O_NDELAY:以非阻塞方式打开文件,对open以及随后的对文件的操作都会立即返回。
新文件的实际存取权限是mode与umask按照(mode & ~umask)运算后的结果,每个权限在mode的二进制位上实际只占一位,若本位为0则代表无此权限,1则反之
5.文件的创建与关闭
文件的创建可通过creat系统调用来完成
int creat(const char *pathname, ode_t mode);
若pathname指向的文件不存在,则创建一个新文件,若存在,则原文件被覆盖,成功返回一个文件描述符,失败返回-1
creat只能以只写的方式打开创建的文件,无法创建设备文件
文件打开操作完成之后需要关闭,调用close函数关闭,参数为打开时得到的文件描述符,但close调用成功并不保证数据能全部写回硬盘
6. 文件的读写
读数据可使用read系统调用,返回值为实际读取的字节数,若返回0表示已到达文件尾或无可读数据,文件读写指针也会随着读取到的字节移动。
写数据可调用write,返回值为写入字节数,文件读写指针也会随之移动。
7.文件读写指针的移动
每一个已打开的文件都有一个读写位置,当打开的文件时一般指向文件的开头,若是以添加的方式打开(O_APPEND),则读写位置指向文件尾。
文件指针的偏移,使用lseek来移动文件读写指针的位置:off_t lseek(int fildes, off_t offset, int whence);参数whence有以下3种取值:
SEEK_SET:从文件开始出计算偏移量,文件指针到文件开始处的距离为off_set
SEEK_CUR:从文件指针的当前位置开始计算偏移量,文件指针等于当前指针值加上offset的值,offset值允许取负数
SEEK_END:从文件结尾处开始就散偏移量,文件指针值等于当前指针值加上offset的值
lseek的常用用法:
将文件读写指针西东到文件开头: lseek(int fildes, 0, SEEK_SET);
将文件读写指针移动到文件结尾: lseek(int fildes, 0, SEEK_END);
获取文件读写指针当前的位置(相对于文件开头的偏离): lseek(int fildes, 0, SEEK_CUR);