文件系统(二)
1.目录操作
mkdir
#include<sys/stat.h>
#include<sys/types.h>
int mkdir(const char *pathname,mode_t mode);
创建一个目录
rmdir
#include<unistd.h>
int rmdir(const char *pathname);
删除一个目录
opendir/fdopendir
#include<sys/types.h>
#include<dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
打开一个目录
readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
struct dirent { long d_ino; /* inode number 索引节点号 */ off_t d_off; /* offset to this dirent 在目录文件中的偏移 */ unsigned short d_reclen; /* length of this d_name 文件名长 */ unsigned char d_type; /* the type of d_name 文件类型 */ char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */
readdir每次返回一条记录项,DIR* 指针指向下一条记录项。
rewinddir
#include<sys/types.h>
#include <dirent.h>
void rewinddir(DIR *dirp);
把目录指针恢复到目录的起始位置
telldir/seekdir
#include<dirent.h>
long telldir(DIR *dirp);
#include <dirent.h>
void seekdir(DIR *dirp,long offset);
closedir
#include<sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
练习:递归遍历目录(实现tree命令)
#include<stdio.h> #include <errno.h> #include<stdlib.h> #include<string.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #define MAX_PATH 512 void dirwalk(char *dir,void(*fcn)(char *)) { DIR *dfd; char name[MAX_PATH]; struct dirent *dp;
if ((dfd = opendir(dir)) == NULL) { fprintf(stderr,"dir_walk: can't open %s %s", dir); return; } while ((dp = readdir(dir)) != NULL) { if (strcmp(dp->d_name, ".") == 0||strcmp(dp->d_name,".."==0) continue; /* 跳过当前目录和上一层目录以及隐藏文件*/ if (strlen(pathname) + strlen(dp->d_name) + 2 > sizeof(name)) { fprintf(stderr,"dir_order: name %s %s too long ", dir, dp->d_name); }
else { memset(name, 0, sizeof(name)); sprintf(name, "%s/%s", dir, dp->d_name); (*fcn)(name); } } closedir(dfd); } void fsize(char *name) { struct stat stbuf; if (stat(name, &stbuf) == -1) { fprintf(stderr,"fsize:can't access %s ", name); return; } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) //与后留下文件类型,若==S_IFDIR表示是一个目录 { dirwalk(name,fsize); } printf("%s %8ld ", stbuf.st_size, name); } int main(int argc, char **argv) { if (argc == 1) /*default:current directory /.app*/ { fsize("."); }
else
while(--argc>0) { fsize(*++argv); } return 0; }
2.VFS虚拟文件系统
Linux 中允许众多不同的文件系统共存,如 ext2, ext3, vfat 等。通过使用同一套文件 I/O 系统 调用即可对 Linux 中的任意文件进行操作而无需考虑其所在的具体文件系统格式;更进一步,对文件的 操作可以跨文件系统而执行。我们可以使用 cp 命令从 vfat 文件系统格式的硬盘拷贝数据到 ext3 文件系统格式的硬盘;而这样的操作涉及到两个不同的文件系统。“一切皆是文件”是 Unix/Linux 的基本哲学之一。不仅普通的文件,目录、字符设备、块设备、 套接字等在 Unix/Linux 中都是以文件被对待;它们虽然类型不同,但是对其提供的却是同一套操作界面。
而虚拟文件系统正是实现上述两点 Linux 特性的关键所在。虚拟文件系统(Virtual File System, 简称 VFS), 是 Linux 内核中的一个软件层,用于给用户空间的程序提供文件系统接口;同时,它也提供了内核中的一个 抽象功能,允许不同的文件系统共存。系统中所有的文件系统不但依赖 VFS 共存,而且也依靠 VFS 协同工作。
VFS
VFS2
打开一个文件首先是打开文件描述符,每个对应创建一个file结构体,f_op指向一组函数open,close,read,write...(是驱动层的操作,和应用层的不是一回事),这组函数对应具体的硬件操作,f_dentry指向磁盘文件,对应一组文件系统驱动。文件系统驱动和驱动层等这些都属于内核,上图的众多结构体相关联组成虚拟文件系统VFS。两个进程打开同一个文件,后写的覆盖前写的。若两个描述符指向同一个结构体,追加型。
dup/dup2
#include<unistd.h>
int dup(int oldfd)
int dup2(int oldfd,int newfd);
dup和dup2都可用来复制现存的文件描述符,使两个文件描述符指向同一个file结构体。如果两个文件描述符指向同一个file结构体,file status flag和读写位置只保存一份在file结构体中,并且file结构体的引用计数会变为2。
示例: