日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux源码文件名,Linux中文件名解析处理源码分析

發(fā)布時間:2025/3/8 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux源码文件名,Linux中文件名解析处理源码分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Linux中文件名解析處理源碼分析

前言

Linux中對一個文件進行操作的時候,一件很重要的事情是對文件名進行解析處理,并且找到對應文件的inode對象,然后創(chuàng)建表示文件的file對象。在此,對文件名解析過程,并且如何找到對應inode的過程進行源碼分析。分析代碼基于Linux-3.2版本。

關鍵函數(shù)分析

不管是通過應用層的API函數(shù)還是在內核中打開一個文件,最終都需要調用filp_open函數(shù),該函數(shù)的主要職責就是解析文件名,找到文件對應的inode對象,然后分配內存創(chuàng)建file對象,最后執(zhí)行該文件對應的file->open函數(shù)。

filp_open的核心處理函數(shù)是path_openat,該函數(shù)分析如下:

static struct file *path_openat(int dfd, const char *pathname,

struct nameidata *nd, const struct open_flags *op, int flags)

{

struct file *base = NULL;

struct file *filp;

struct path path;

int error;

/* 創(chuàng)建一個file對象 */

filp = get_empty_filp();

if (!filp)

return ERR_PTR(-ENFILE);

.filp->f_flags = op->open_flag;

nd->intent.open.file = filp;

nd->intent.open.flags = open_to_namei_flags(op->open_flag);

nd->intent.open.create_mode = op->mode;

/* 初始化檢索的起始目錄,判斷起始目錄是根目錄還是當前目錄,并且初始化nd->inode對象,為link_path_walk函數(shù)的解析處理做準備。 */

error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);

if (unlikely(error))

goto out_filp;

.current->total_link_count = 0;

/* 關鍵的字符串解析處理函數(shù),其核心思想是分級解析字符串,通過字符串對應的目錄項找到下一級目錄的inode節(jié)點。該函數(shù)的具體分析如下。 */

error = link_path_walk(pathname, nd);

if (unlikely(error))

goto out_filp;

/* do_last函數(shù)創(chuàng)建或者獲取文件對應的inode對象,并且初始化file對象,至此一個表示打開文件的內存對象filp誕生 */

filp = do_last(nd, &path, op, pathname);

while (unlikely(!filp)) { /* trailing symlink */

struct path link = path;

void *cookie;

if (!(nd->flags & LOOKUP_FOLLOW)) {

path_put_conditional(&path, nd);

path_put(&nd->path);

filp = ERR_PTR(-ELOOP);

break;

}

nd->flags |= LOOKUP_PARENT;

nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);

error = follow_link(&link, nd, &cookie);

if (unlikely(error))

filp = ERR_PTR(error);

else

filp = do_last(nd, &path, op, pathname);

put_link(nd, &link, cookie);

}

out:

if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT))

path_put(&nd->root);

if (base)

fput(base);

release_open_intent(nd);

return filp;

.out_filp:

filp = ERR_PTR(error);

goto out;

}

link_path_walk函數(shù)完成了基本的名字解析功能,是名字字符串解析處理實現(xiàn)的核心。該函數(shù)的實現(xiàn)基于分級解析處理的思想。例如,當需要解析“/dev/mapper/map0”字符串時,其首先需要判斷從何處開始解析?根目錄還是當前目錄?案例是從根目錄開始解析,那么獲取根目錄的dentry對象并開始分析后繼字符串。以’/’字符為界按序提取字符串,首先我們可以提取”dev”字符串,并且計算該字符串的hash值,通過該hash值查找detry下的inode hash表,就可以得到/dev/目錄的inode對象。依次類推,最后解析得到”/dev/mapper/”目錄的inode對象以及文件名”map0”。至此,link_path_walk函數(shù)的使命完成,最后可以通過do_last函數(shù)獲取或者創(chuàng)建文件inode。link_path_walk函數(shù)分析如下:

static int link_path_walk(const char *name, struct nameidata *nd)

{

struct path next;

int err;

/* 移除’/’字符 */

while (*name=='/')

name++;

/* 如果解析已經完成,直接返回 */

if (!*name)

return 0;

./* At this point we know we have a real path component. */

for(;;) {

unsigned long hash;

struct qstr this;

unsigned int c;

int type;

/* inode訪問的permission檢查 */

err = may_lookup(nd);

if (err)

break;

.this.name = name;

c = *(const unsigned char *)name;

/* 初始化hash值 */

hash = init_name_hash();

do {

name++;

/* 累計計算名字字符串的hash值 */

hash = partial_name_hash(c, hash);

c = *(const unsigned char *)name;

/* 如果遇到’/’字符,結束一次hash計算統(tǒng)計 */

} while (c && (c != '/'));

/* 得到字符串長度和hash結果 */

this.len = name - (const char *) this.name;

this.hash = end_name_hash(hash);

.type = LAST_NORM;

/* LAST_DOT和LAST_DOTDOT情形判斷 */

if (this.name[0] == '.') switch (this.len) {

case 2: /* LAST_DOTDOT是上級目錄 */

if (this.name[1] == '.') {

type = LAST_DOTDOT;

nd->flags |= LOOKUP_JUMPED;

}

break;

case 1: /* LAST_DOT是當前目錄 */

type = LAST_DOT;

}

if (likely(type == LAST_NORM)) {

/* LAST_NORM標記說明是需要通過本地目錄進行字符串解析 */

struct dentry *parent = nd->path.dentry;

nd->flags &= ~LOOKUP_JUMPED;

if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {

/* 如果該標記有效,需要重新計算hash值 */

err = parent->d_op->d_hash(parent, nd->inode,

&this);

if (err <0)

break;

}

}

/* 如果字符串已經解析完畢,直接跳轉到last_component */

/* remove trailing slashes? */

if (!c)

goto last_component;

while (*++name == '/');

if (!*name)

goto last_component;

/* 通過walk_component函數(shù)找到解析字符串對應的inode,并且將nd->inode改稱最新inode,準備繼續(xù)解析后面的字符串信息。因為目錄項所管理的inode在系統(tǒng)中通過hash表進行維護,因此,通過hash值可以很容易的找到inode。如果內存中還不存在inode對象,對于ext3文件系統(tǒng)會通過ext3_lookup函數(shù)從磁盤上獲取inode的元數(shù)據(jù)信息,并且構造目錄項中所有的inode對象。 */

err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);

if (err <0)

return err;

.if (err) {

err = nested_symlink(&next, nd);

if (err)

return err;

}

if (can_lookup(nd->inode))

continue;

/* 字符串還沒有解析完畢,但是當前的inode已經繼續(xù)不允許解析處理了,所以,返回錯誤碼 */

err = -ENOTDIR;

break;

/* here ends the main loop */

.last_component:

/* 最后一個字符串不需要解析處理,需要由do_last函數(shù)來處理,此處結束解析,正確返回 */

nd->last = this;

nd->last_type = type;

return 0;

}

terminate_walk(nd);

return err;

}

小結

文件名解析處理是文件系統(tǒng)的必備功能,通過文件名的解析索引到表示文件的inode內存對象,并且創(chuàng)建文件對象file。在文件名解析的過程中,首先需要確定的是檢索起始點,然后通過hash table查找目錄項以及檢索文件。在查找的過程中,需要考慮文件訪問的權限以及符號連接等問題。總體來說這些代碼難度不是很大,但是需要有一個整體的思路,就可以更好的理解分析代碼了,這里只是對名字解析過程中的幾個關鍵函數(shù)進行拋磚引玉式的分析。不正之處,敬請指出。

總結

以上是生活随笔為你收集整理的linux源码文件名,Linux中文件名解析处理源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。