(四)Seafile FUSE 虚拟文件系统开发---功能1
通过对源代码的阅读,现在终于可以进入对功能的开发了,在这周主要完成了第一个功能(列出文件的最后修改时间信息)开发。主要考虑到了以下3种情况:
* 1. /user --> 用户目录
* 2. /user/repo-id_name/ --> 仓库根目录
* 3. /user/repo-id_name/repo_path --> 仓库内文件或者目录
下面对这三种情况逐个分析,并给出对应的实现。
1) 用户目录
对于用户目录的最后修改时间,我认为是该用户的创建时间。通过RPC获取从ccnet模块获取用户信息,进一步获取用户创建时间。
emailuser = get_user_from_ccnet (client, user);
if (!emailuser) {
ccnet_rpc_client_free (client);
return -ENOENT;
}
user_ctime = ccnet_email_user_get_ctime(emailuser);
g_object_unref (emailuser);
ccnet_rpc_client_free (client);
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
stbuf->st_size = 4096;
stbuf->st_mtime = user_ctime;
2) 仓库根目录和仓库内目录和文件
对于仓库根目录,因为每次commit对应一次更新,其最后的修改时间应该是对应最近的一次commit的时间。而在 getattr_repo 这个函数中,已经通过一系列的操作获取到了该仓库对应的最新一次commit信息,所以处理起来相对简单。而要获取仓库内的目录或文件的修改信息,则需要先获取到该目录或文件的Dirent ,在原系统中并没有对应的函数,所以需要自己重新实现。代码如下:
if (S_ISDIR(mode)) { //如果是目录
//此次省略若干代码
dir = seaf_fs_manager_get_seafdir(seaf->fs_mgr,
repo->store_id, repo->version, id); //此次省略若干代码
if(strcmp(repo_path,"/") == 0){ //如果是仓库根目录
//the dir is the root of the libary ,we obtain its last modify time from the infomation of last commit
mtime = commit->ctime; //最后一次commit的时间及最后修改时间
}else{
//get dirent of the dir
SeafDirent * dirent;
//通过路径获得其dirent 结构
dirent = fuse_get_dirent_by_path(seaf->fs_mgr,
repo->store_id,
repo->version,
commit->root_id,
repo_path);
//新版本的 repo 格式,dirent 才包含最后修改时间
if((dirent != NULL)&&(repo->version != 0))
stbuf->st_mtime = dirent->mtime; // 设置返回的 struct stat 结构
seaf_dirent_free ((SeafDirent *)dirent); // 释放dirent数据结构
}
//此次省略若干代码
stbuf->st_mtime = mtime; // 设置返回的 struct stat 结构
seaf_dir_free (dir); // 释放dir数据结构
} else if (S_ISREG(mode)) { //如果是文件
Seafile *file;
SeafDirent * dirent;
//此次省略若干代码
//通过路径获得其dirent 结构
dirent = fuse_get_dirent_by_path(seaf->fs_mgr,
repo->store_id,
repo->version,
commit->root_id,
repo_path);
if((dirent != NULL)&&(repo->version != 0))
stbuf->st_mtime = dirent->mtime; // 设置返回的 struct stat 结构
seaf_dirent_free ((SeafDirent *)dirent); // 释放dir数据结构
seafile_unref (file); //减少引用计数
} else {
return -ENOENT;
seaf_warning ("Unknown type.\n");
}
fuse_get_dirent_by_path函数首先获得该文件或目录的上一级目录的dir结构,然后遍历该上级目录的dirent项,查找对应名称的dirent项 ,代码如下:
SeafDirent *
fuse_get_dirent_by_path (SeafFSManager *mgr,
const char *repo_id,
int version,
const char *root_id,
const char *path)
{
//此处省略若干代码
parent_dir = g_path_get_dirname(path);//父目录
file_name = g_path_get_basename(path);//文件名
if(strcmp(parent_dir,".") == 0)
//若父目录为根目录,这直接获取该根目录结构
dir = seaf_fs_manager_get_seafdir (mgr, repo_id, version, root_id);
else
//根据路径获取父目录结构
dir = seaf_fs_manager_get_seafdir_by_path (mgr,
repo_id, version,
root_id,
parent_dir, NULL);
//此处省略若干代码
//遍历该目录下的所有dirent,若找到该文件名对应的dirent则退出
GList *p;
for (p = dir->entries; p; p = p->next) {
SeafDirent *d = p->data;
int r = strcmp (d->name, file_name);
if (r == 0) {
dent = seaf_dirent_dup(d);
break;
}
}
//此处省略若干代码
return dent;
}