1.概述

构成一个操作系统最重要的部分就是进程管理和文件系统了。

Linux最初采用的是minix的文件系统,minix是由Andrew S. Tanenbaum开发的用于实验性的操作系统,比如有一些局限性。后来经过一段时间的改进和发展,Linux开发出了ext2文件系统,当然后来逐渐发展除了ext3、ext4。为了使Linux支持各种不同的文件系统,Linux使用了所谓的虚拟文件系统VFS(Virtual Filesystem Switch),VFS提供一组标准的、抽象的文件操作,以系统调用的形式提供给用户程序,如read(),write(),lseek()等。这样,用户程序就可以把所有的文件都看作一致的、抽象的”VFS文件”,通过这些系统调用对文件进行操作,而无需关心具体的文件属于什么文件系统以及具体文件系统的设计和实现。VFS与具体文件系统的关系如图1所示。

2.各个结构

不同的文件系统通过不同的程序来实现其各种功能,但是与VFS之间的界面则是有明确的定义。这个界面的主体就是file_operations数据结构。定义在include/linux/fs.h中:

struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*flock) (struct file *, int, struct file_lock *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **);long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);
};

每个文件系统都有自己的file_operations结构,结构中的成分几乎全是函数指针,所以实际上是个函数跳转表,例如read就指向具体文件系统用来实现读文件操作的入口函数。

每个进程通过open()与具体的文件建立起连接,这种连接以一个file数据结构作为代表,结构中有个file_operations结构指针f_op。将file结构中的指针f_op设置成指向某个具体的file_operations结构,就指定了这个文件所属的文件系统。

struct files_struct {/** read mostly part*/atomic_t count;struct fdtable __rcu *fdt;struct fdtable fdtab;/** written part on a separate cache line in SMP*/spinlock_t file_lock ____cacheline_aligned_in_smp;int next_fd;struct embedded_fd_set close_on_exec_init;struct embedded_fd_set open_fds_init;struct file __rcu * fd_array[NR_OPEN_DEFAULT];
};

进程的task_struct中有一个类型为struct files_struct的files域,记录了具体已打开的文件信息。files_struct的主体就是一个file结构数组。每打开一个文件以后,进程就通过一个“打开文件号”fid来访问这个文件,而fid实际上就是相应file结构在数组中的下标。file结构中海油一个指针f_dentry,指向该文件的dentry数据结构。每一个文件只有一个dentry结构,而可能有多个进程打开它。

struct dentry {/* RCU lookup touched fields */unsigned int d_flags;     /* protected by d_lock */seqcount_t d_seq;      /* per dentry seqlock */struct hlist_bl_node d_hash;    /* lookup hash list */struct dentry *d_parent;  /* parent directory */struct qstr d_name;struct inode *d_inode;     /* Where the name belongs to - NULL is* negative */unsigned char d_iname[DNAME_INLINE_LEN]; /* small names *//* Ref lookup also touches following */unsigned int d_count;       /* protected by d_lock */spinlock_t d_lock;     /* per dentry lock */const struct dentry_operations *d_op;struct super_block *d_sb; /* The root of the dentry tree */unsigned long d_time;      /* used by d_revalidate */void *d_fsdata;           /* fs-specific data */struct list_head d_lru;       /* LRU list *//** d_child and d_rcu can share memory*/union {struct list_head d_child;  /* child of parent list */struct rcu_head d_rcu;} d_u;struct list_head d_subdirs;   /* our children */struct list_head d_alias; /* inode alias list */
};

dentry结构中有一个指向inode的指针。dentry与inode结构所描述的目标是不一样的,因为一个文件可能对应多个文件名(链接)。所以dentry结构代表的是逻辑意义上的文件,记录的是其逻辑上的属性。而inode结构所代表的是物理意义上的文件,记录的是其物理上的属性;它们之间的关系是多对一的关系。这是因为一个已经建立的文件可以被连接 (link) 到其他文件名。dentry中还有个d_parent指向父目录的dentry结构。

inode数据结构比较大,就不列出来了。要注意的是inode结构中有一个i_dentry是所有与这个inode关联的dentry。凡是代表着这个文件的所有目录项都通过其dentry结构中的d_alias挂入相应inode结构中的 i_dentry 队列。

下面是需要注意的几点:

  1. 进程每打开一个文件,就会有一个file结构与之对应。同一个进程可以多次打开同一个文件而得到多个不同的file结构,file结构描述被打开文件的属性,如文件的当前偏移量等信息。
  2. 两个不同的file结构可以对应同一个dentry结构。进程多次打开同一个文件时,对应的只有一个dentry结构。dentry结构存储目录项和对应文件(inode)的信息。
  3. 在存储介质中,每个文件对应唯一的inode结点,但是每个文件又可以有多个文件名。即可以通过不同的文件名访问同一个文件。这里多个文件名对应一个文件的关系在数据结构中表示就是dentry和inode的关系。
  4. inode中不存储文件的名字,它只存储节点号;而dentry则保存有名字和与其对应的节点号,所以就可以通过不同的dentry访问同一个inode。
  5. 不同的dentry则是同个文件链接(ln命令)来实现的。

因此关系就是:进程->task_struct->files_struct->file->dentry->inode->Data Area

3.从inode得到文件绝对路径

有了上面的基础,从inode得到文件名就比较简单了,这里我假设文件只有一个路径,如果有很多路径改改就行了。

char *getfullpath(struct inode *inod,char* buffer,int len)
{struct list_head* plist = NULL;struct dentry* tmp = NULL;struct dentry* dent = NULL;struct dentry* parent = NULL;char* name = NULL;char* pbuf = buffer + PATH_MAX - 1;struct inode* pinode = inod;int length = 0;buffer[PATH_MAX - 1] = '\0';if(pinode == NULL)return NULL;list_for_each(plist,&pinode->i_dentry){tmp = list_entry(plist,struct dentry,d_alias);if(tmp->d_inode == pinode){dent = tmp;break;}}if(dent == NULL){return NULL;}name = (char*)(dent->d_name.name);name = name + strlen(name) - 4;if(!strcmp(name,".img")){while(pinode && pinode ->i_ino != 2 && pinode->i_ino != 1){if(dent == NULL)break;name = (char*)(dent->d_name.name);if(!name)break;pbuf = pbuf - strlen(name) - 1;*pbuf = '/';memcpy(pbuf+1,name,strlen(name));length += strlen(name) + 1;if((parent = dent->d_parent)){dent = parent;pinode = dent->d_inode;}}printk(KERN_INFO "the fullname is :%s \n",pbuf);}return pbuf;
}

linux内核中根据inode获取文件的完整路径相关推荐

  1. 论文中文翻译——Double-Fetch情况如何演变为Double-Fetch漏洞:Linux内核中的双重获取研究

    本论文相关内容 论文下载地址--Web Of Science 论文中文翻译--How Double-Fetch Situations turn into Double-Fetch Vulnerabil ...

  2. 如何获取文件的完整路径?

    有没有一种简单的方法可以打印file.txt的完整路径? file.txt = /nfs/an/disks/jj/home/dir/file.txt <command> dir> & ...

  3. linux内核中符号地址的获取

    有些内核函数或者内核变量是不导出的,但是确实需要用,那该怎么办?因此寻找内核符号地址就有必要进行一下总结,更有甚,如果想找一条特定的指令,比如movl的指令地址,那更需要投入一些精力!总的来说,我总结 ...

  4. Linux内核模块下载到板子,在Linux内核中增加新驱动模块

    开发环境 开发板:A33-Vstar 开发板系统: Linux/arm 3.4.39 Kernel Ubuntu版本:Ubuntu14.04 ----------------------------- ...

  5. linux 内核 遍历文件夹,Linux内核中通过文件描述符获取绝对路径

    背景 在Linux内核中,已知一个进程的pid和其打开文件的文件描述符fd,如何获取该文件的绝对路径?基本思路是先获取该文件在内核中的file结构体,再通过d_path()获取到整个文件的绝对路径. ...

  6. Linux中文件描述符1,linux内核中的文件描述符(一)--基础知识简介

    原标题:linux内核中的文件描述符(一)--基础知识简介 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blo ...

  7. linux内核中的文件描述符(一)--基础知识简介

    linux内核中的文件描述符(一)--基础知识简介 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.cs ...

  8. linux内核中的文件描述符(三)--fd的回收

    linux内核中的文件描述符(三)--fd的回收 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csd ...

  9. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

最新文章

  1. 6万广州人坐过无人出租车,过半月薪一万以上 | 中国首份Robotaxi乘客调研报告...
  2. Thymeleaf提取公共页面(从实例入手,以inspinia模板为例)
  3. 有一个能够统一的方式来画uml图的软件
  4. Python(39)_选出列表中的大于66的数字放在字典中
  5. 安装electron报错
  6. [Python] isinstance() for checking object type
  7. parallels网络初始化失败_33 个神经网络「炼丹」技巧
  8. Finding Gems
  9. php yii应用运维,Windows运维之Windows下用cmd命令实例讲解yii2.0在php命令行中运行的步骤...
  10. 最简单的DLL导出函数隐藏方式
  11. (77)--用框架爬取博客园信息并保存到数据库
  12. 基于李雅普诺夫函数的跟踪控制(三)
  13. 矢量控制开发笔记1—SVPWM基础
  14. Dojo 学习--ADM
  15. java zero fill_一次JavaAssist引发的生产环境CPU报警的问题
  16. Ubuntu 10.10安装配置指南Ubuntu 11.10 图形安装教程
  17. 从移动应用创作者到产品总监—专访微软MVP邹建峰
  18. 记录一次mongoDB错误 errmsg: cannot use the part () to traverse the element
  19. 鸡年的年度编程语言,非它莫属
  20. kylin启动时报错:failed to find metadata store by url kylin_metadata@hbase

热门文章

  1. C/C++ 盒子游戏
  2. 字王:大数据与黑天鹅算法2.0
  3. 【翻译】20180508利用 SSR信息在RTKLIB 中进行PPP解算
  4. TA进阶实例37(Unreal卡通风格化渲染效果)
  5. 大数据助力APP高效获客之道|互联网行业公会
  6. html落叶动画,HTML5 Canvas窗外秋日落叶动画
  7. PHP获取ip所在城市
  8. 12.聚类算法之层次聚类
  9. 十步学习 Redis 分布式锁
  10. vue中target和eventTarget的区别