| # NFS RPC client -- RFC 1094 | |
| # XXX This is not yet complete. | |
| # XXX Only GETATTR, SETTTR, LOOKUP and READDIR are supported. | |
| # (See mountclient.py for some hints on how to write RPC clients in | |
| # Python in general) | |
| import rpc | |
| from rpc import UDPClient, TCPClient | |
| from mountclient import FHSIZE, MountPacker, MountUnpacker | |
| NFS_PROGRAM = 100003 | |
| NFS_VERSION = 2 | |
| # enum stat | |
| NFS_OK = 0 | |
| # (...many error values...) | |
| # enum ftype | |
| NFNON = 0 | |
| NFREG = 1 | |
| NFDIR = 2 | |
| NFBLK = 3 | |
| NFCHR = 4 | |
| NFLNK = 5 | |
| class NFSPacker(MountPacker): | |
| def pack_sattrargs(self, sa): | |
| file, attributes = sa | |
| self.pack_fhandle(file) | |
| self.pack_sattr(attributes) | |
| def pack_sattr(self, sa): | |
| mode, uid, gid, size, atime, mtime = sa | |
| self.pack_uint(mode) | |
| self.pack_uint(uid) | |
| self.pack_uint(gid) | |
| self.pack_uint(size) | |
| self.pack_timeval(atime) | |
| self.pack_timeval(mtime) | |
| def pack_diropargs(self, da): | |
| dir, name = da | |
| self.pack_fhandle(dir) | |
| self.pack_string(name) | |
| def pack_readdirargs(self, ra): | |
| dir, cookie, count = ra | |
| self.pack_fhandle(dir) | |
| self.pack_uint(cookie) | |
| self.pack_uint(count) | |
| def pack_timeval(self, tv): | |
| secs, usecs = tv | |
| self.pack_uint(secs) | |
| self.pack_uint(usecs) | |
| class NFSUnpacker(MountUnpacker): | |
| def unpack_readdirres(self): | |
| status = self.unpack_enum() | |
| if status == NFS_OK: | |
| entries = self.unpack_list(self.unpack_entry) | |
| eof = self.unpack_bool() | |
| rest = (entries, eof) | |
| else: | |
| rest = None | |
| return (status, rest) | |
| def unpack_entry(self): | |
| fileid = self.unpack_uint() | |
| name = self.unpack_string() | |
| cookie = self.unpack_uint() | |
| return (fileid, name, cookie) | |
| def unpack_diropres(self): | |
| status = self.unpack_enum() | |
| if status == NFS_OK: | |
| fh = self.unpack_fhandle() | |
| fa = self.unpack_fattr() | |
| rest = (fh, fa) | |
| else: | |
| rest = None | |
| return (status, rest) | |
| def unpack_attrstat(self): | |
| status = self.unpack_enum() | |
| if status == NFS_OK: | |
| attributes = self.unpack_fattr() | |
| else: | |
| attributes = None | |
| return status, attributes | |
| def unpack_fattr(self): | |
| type = self.unpack_enum() | |
| mode = self.unpack_uint() | |
| nlink = self.unpack_uint() | |
| uid = self.unpack_uint() | |
| gid = self.unpack_uint() | |
| size = self.unpack_uint() | |
| blocksize = self.unpack_uint() | |
| rdev = self.unpack_uint() | |
| blocks = self.unpack_uint() | |
| fsid = self.unpack_uint() | |
| fileid = self.unpack_uint() | |
| atime = self.unpack_timeval() | |
| mtime = self.unpack_timeval() | |
| ctime = self.unpack_timeval() | |
| return (type, mode, nlink, uid, gid, size, blocksize, \ | |
| rdev, blocks, fsid, fileid, atime, mtime, ctime) | |
| def unpack_timeval(self): | |
| secs = self.unpack_uint() | |
| usecs = self.unpack_uint() | |
| return (secs, usecs) | |
| class NFSClient(UDPClient): | |
| def __init__(self, host): | |
| UDPClient.__init__(self, host, NFS_PROGRAM, NFS_VERSION) | |
| def addpackers(self): | |
| self.packer = NFSPacker() | |
| self.unpacker = NFSUnpacker('') | |
| def mkcred(self): | |
| if self.cred is None: | |
| self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default() | |
| return self.cred | |
| def Getattr(self, fh): | |
| return self.make_call(1, fh, \ | |
| self.packer.pack_fhandle, \ | |
| self.unpacker.unpack_attrstat) | |
| def Setattr(self, sa): | |
| return self.make_call(2, sa, \ | |
| self.packer.pack_sattrargs, \ | |
| self.unpacker.unpack_attrstat) | |
| # Root() is obsolete | |
| def Lookup(self, da): | |
| return self.make_call(4, da, \ | |
| self.packer.pack_diropargs, \ | |
| self.unpacker.unpack_diropres) | |
| # ... | |
| def Readdir(self, ra): | |
| return self.make_call(16, ra, \ | |
| self.packer.pack_readdirargs, \ | |
| self.unpacker.unpack_readdirres) | |
| # Shorthand to get the entire contents of a directory | |
| def Listdir(self, dir): | |
| list = [] | |
| ra = (dir, 0, 2000) | |
| while 1: | |
| (status, rest) = self.Readdir(ra) | |
| if status <> NFS_OK: | |
| break | |
| entries, eof = rest | |
| last_cookie = None | |
| for fileid, name, cookie in entries: | |
| list.append((fileid, name)) | |
| last_cookie = cookie | |
| if eof or last_cookie is None: | |
| break | |
| ra = (ra[0], last_cookie, ra[2]) | |
| return list | |
| def test(): | |
| import sys | |
| if sys.argv[1:]: host = sys.argv[1] | |
| else: host = '' | |
| if sys.argv[2:]: filesys = sys.argv[2] | |
| else: filesys = None | |
| from mountclient import UDPMountClient, TCPMountClient | |
| mcl = TCPMountClient(host) | |
| if filesys is None: | |
| list = mcl.Export() | |
| for item in list: | |
| print item | |
| return | |
| sf = mcl.Mnt(filesys) | |
| print sf | |
| fh = sf[1] | |
| if fh: | |
| ncl = NFSClient(host) | |
| attrstat = ncl.Getattr(fh) | |
| print attrstat | |
| list = ncl.Listdir(fh) | |
| for item in list: print item | |
| mcl.Umnt(filesys) |