设为首页 加入收藏

TOP

用Python写一个FUSE(用户态文件系统)文件系统(一)
2014-11-24 02:01:50 来源: 作者: 【 】 浏览:2
Tags:Python 一个 FUSE 用户 文件 系统

如果你是我的长期读者,那么你应该知道我在寻找一个完美备份程序,最后我写了一个基于bup的我自己的加密层。


在写encbup的时候,我对仅仅恢复一个文件就必须要下载整个巨大的档案文件的做法不甚满意,但仍然希望能将EncFS rdiff-backup一起使用来实现可远程挂载、加密、去重、版本化备份的功能。


再次试用obnam 后(啰嗦一句:它还是慢的出奇),我注意到了它有一个mount命令。深入研究后,我发现了fuse-pythonfusepy,感觉用Python写一个FUSE文件系统应该挺简单的。


聪明的读者可能已经意识到了我接下来要做的事情:我决定用Python写一个加密文件系统层!它与EncFS会非常相似,但也有一些重要的区别:


写这个脚本的第一步是写出一个纯粹的传递式的文件系统。它仅仅是接受一个目录,并在挂载点将其暴露出来,确保任何在挂载点的修改都会镜像到源数据中。


fusepy 要求你写一个类,里面定义了各种操作系统级别的方法。你可以选择定义那些你的文件系统想要支持的方法,其他的可以暂时不予定义,但是我需要定义全部的方法,因为我的文件系统是一个传递式的文件系统,它应该表现的与原有的文件系统尽可能一致。


写这段代码会非常简单有趣,因为大部分的方法只是对os模块的一些简单封装(确实,你可以直接给它们赋值,比如 open=os.open 等等,但是我的模块需要一些路径扩展)。不幸的是,fuse-python有一个bug(据我所知)是当打开和读文件的时候,它无法将文件句柄回传给文件系统。因而我的脚本不知道某个应用执行读写操作时对应的是哪个文件句柄,从而导致了失败。只需要对fusepy做极少的改动,它就可以很好地运行。它只有一个文件,所以你可以把它直接放到你的工程里。


在这里,我很乐意给出这段代码,当你打算自己实现文件系统的时候可以拿来参考。这段代码提供了一个很好的起点,你可以直接把这个类复制到你的工程中并且根据需要重写里面的一些方法。


接下来是真正的代码了:


#!/usr/bin/env python

from __future__ import with_statement

import os
import sys
import errno

from fuse import FUSE, FuseOSError, Operations

class Passthrough(Operations):
def __init__(self, root):
self.root = root

# Helpers
# =======

def _full_path(self, partial):
if partial.startswith("/"):
partial = partial[1:]
path = os.path.join(self.root, partial)
return path

# Filesystem methods
# ==================

def access(self, path, mode):
full_path = self._full_path(path)
if not os.access(full_path, mode):
raise FuseOSError(errno.EACCES)

def chmod(self, path, mode):
full_path = self._full_path(path)
return os.chmod(full_path, mode)

def chown(self, path, uid, gid):
full_path = self._full_path(path)
return os.chown(full_path, uid, gid)

def getattr(self, path, fh=None):
full_path = self._full_path(path)
st = os.lstat(full_path)
return dict((key, getattr(st, key)) for key in ('st_atime', 'st_ctime',
'st_gid', 'st_mode', 'st_mtime', 'st_nlink', 'st_size', 'st_uid'))

def readdir(self, path, fh):
full_path = self._full_path(path)

dirents = ['.', '..']
if os.path.isdir(full_path):
dirents.extend(os.listdir(full_path))
for r in dirents:
yield r

def readlink(self, path):
pathname = os.readlink(self._full_path(path))
if pathname.startswith("/"):
# Path name is absolute, sanitize it.
return os.path.relpath(pathname, self.root)
else:
return pathname

def mknod(self, path, mode, dev):
return os.mknod(self._full_path(path), mode, dev)

def rmdir(self, path):
full_path = self._full_path(path)
return os.rmdir(full_path)

def mkdir(self, path, mode):
return os.mkdir(self._full_path(path), mode)

def statfs(self, path):
full_path = self._full_path(path)
stv = os.statvfs(full_path)
return dict((key, getattr(stv, key)) for key in ('f_bavail', 'f_bfree',
'f_blocks', 'f_bsize', 'f_favail', 'f_ffree', 'f_files', 'f_flag',
'f_frsize', 'f_namemax'))

def unlink(self, path):
return os.unlink(self._full_path(path))

def symlink(self, target, name):
return os.symlink(self._full_path(target), self._full_path(name))

def rename(self, old, new):
return os.rename(self._full_path(old), self._full_path(new))

def link(self, target, name):
return os.li

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Lua 5.2.2编译安装 LuaSocket 库 下一篇Lua加入socket库支持

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: