一、文件系统操作
1.文件存储
首先了解如下文件存储相关概念:inode、 dentry、 数据存储、文件系统。
1.1 inode
其本质为结构体,存储文件的属性信息。如:权限、类型、大小、时间、用户、盘块位置……也叫作文件属性管理结构,大多数的inode都存储在磁盘上。
少量常用、近期使用的inode会被缓存到内存中。
1.2 dentry
目录项,其本质依然是结构体,重要成员变量有两个 {文件名,inode,…},而文件内容(data)保存在磁盘盘块中。
dentry被删掉之后,inode还在,磁盘对应位置就不能被替换。说明文件并没有真正删除。
但是inode被删除以后,对应磁盘允许被替换,这样就会导致,文件真正可能被删除。
1.3 文件系统
文件系统是,一组规则,规定对文件的存储及读取的一般方法。文件系统在磁盘格式化过程中指定。 常见的文件系统有:fat32 ntfs exfat ext2 、ext3 、ext4
2. 文件操作
2.1 stat函数
获取文件属性,(从inode结构体中获取) int stat(const char *path, struct stat *buf); 成返回0;失败返回-1 设置errno为恰当值。 参数1:文件名 参数2:inode结构体指针 (传出参数) 文件属性将通过传出参数返回给调用者。 练习:使用stat函数查看文件属性 【stat.c】
The stat structure All of these system calls return a stat structure, which contains the following fields: struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* Inode number */ mode_t st_mode; /* File type and mode */ nlink_t st_nlink; /* Number of hard links */ uid_t st_uid; /* User ID of owner */ gid_t st_gid; /* Group ID of owner */ dev_t st_rdev; /* Device ID (if special file) */ off_t st_size; /* Total size, in bytes */ blksize_t st_blksize; /* Block size for filesystem I/O */ blkcnt_t st_blocks; /* Number of 512B blocks allocated */ /* Since Linux 2.6, the kernel supports nanosecond precision for the following timestamp fields. For the details before Linux 2.6, see NOTES. */ struct timespec st_atim; /* Time of last access */ struct timespec st_mtim; /* Time of last modification */ struct timespec st_ctim; /* Time of last status change */ #define st_atime st_atim.tv_sec /* Backward compatibility */ #define st_mtime st_mtim.tv_sec #define st_ctime st_ctim.tv_sec };
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <sys/stat.h> int main(int argc,char *argv[]) { struct stat sbuf; int ret =stat(argv[1],&sbuf); if(ret == -1){ perror("stat error"); exit(1); } printf("file size :%ld\n",sbuf.st_size); return 0; }
2.2 lstat函数
int lstat(const char *path, struct stat *buf); 成返回0; 失败返回-1 设置errno为恰当值。 练习:给定文件名,判断文件类型。 【get_file_type.c】 文件类型判断方法:st_mode 取高4位。 但应使用宏函数: S_ISREG(m) is it a regular file? S_ISDIR(m) directory? S_ISCHR(m) character device? S_ISBLK(m) block device? S_ISFIFO(m) FIFO (named pipe)? S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.) S_ISSOCK(m) socket? (Not in POSIX.1-1996.) 穿透符号链接:stat:会;lstat:不会
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <sys/stat.h> int main(int argc,char *argv[]) { struct stat sbuf; int ret =lstat(argv[1],&sbuf); if(ret == -1){ perror("stat error"); exit(1); } if(S_ISREG(sbuf.st_mode)){ printf("it's a regular\n"); }else if(S_ISDIR(sbuf.st_mode)){ printf("it's a dir\n"); }else if(S_ISFIFO(sbuf.st_mode)){ printf("it's a pipe"); }else if(S_ISLNK(sbuf.st_mode)){ printf("it's a sym link\n"); } return 0; }
2.3 特殊权限位
包含三个二进制位。依次是:设置组ID位setGID;设置用户ID位setID;黏住位sticky
2.3.1 黏住位
早起计算机内存紧,只有精要的常用的程序可以常驻物理内存,剩下的要暂存磁盘中。当内存不够用的时候会将该部分程序存回磁盘,腾出内存空间。若文件设置了黏住位,那么即使在内存比较吃紧的情况下,也不会将该文件回存到磁盘上。由于现阶段操作系统的虚拟内存管理分页算法完善。该功能已经被废弃。 但我们仍然可以对目录设置黏住位。被设置了该位的目录,其内部文件只有: ①超级管理员 ②该目录所有者 ③该文件的所有者 以上三种用户有权限做删除、修改操作。其他用户可以读、创建但不能随意删除。
2.3.2 setUID位
进程有两个ID:EID(有效用户ID),表示进程履行哪个用户的权限。 UID(实际用户ID),表示进程实际属于哪个用户。 多数情况下,EID和UID相同。但是,当文件的setID被设置后两个ID则有可能不一样。 例如:当进程执行一个root用户的文件,若该文件的setID位被设置为1, 那么执行该文件时,进程的UID不变。EID变为root,表示进程开始履行root用户权限。
setGID位于setID相类似。
2.4 access函数
测试指定文件是否存在/拥有某种权限。 int access(const char *pathname, int mode); 成功/具备该权限:0; 失败/不具备 -1 设置errno为相应值。 参数2:R_OK、W_OK、X_OK 通常使用access函数来测试某个文件是否存在。F_OK
2.5 chmod函数
修改文件的访问权限 int chmod(const char *path, mode_t mode); 成功:0; 失败:-1 设置errno为相应值 int fchmod(int fd, mode_t mode);