1# NFS RPC client -- RFC 1094 2 3# XXX This is not yet complete. 4# XXX Only GETATTR, SETTTR, LOOKUP and READDIR are supported. 5 6# (See mountclient.py for some hints on how to write RPC clients in 7# Python in general) 8 9import rpc 10from rpc import UDPClient, TCPClient 11from mountclient import FHSIZE, MountPacker, MountUnpacker 12 13NFS_PROGRAM = 100003 14NFS_VERSION = 2 15 16# enum stat 17NFS_OK = 0 18# (...many error values...) 19 20# enum ftype 21NFNON = 0 22NFREG = 1 23NFDIR = 2 24NFBLK = 3 25NFCHR = 4 26NFLNK = 5 27 28 29class NFSPacker(MountPacker): 30 31 def pack_sattrargs(self, sa): 32 file, attributes = sa 33 self.pack_fhandle(file) 34 self.pack_sattr(attributes) 35 36 def pack_sattr(self, sa): 37 mode, uid, gid, size, atime, mtime = sa 38 self.pack_uint(mode) 39 self.pack_uint(uid) 40 self.pack_uint(gid) 41 self.pack_uint(size) 42 self.pack_timeval(atime) 43 self.pack_timeval(mtime) 44 45 def pack_diropargs(self, da): 46 dir, name = da 47 self.pack_fhandle(dir) 48 self.pack_string(name) 49 50 def pack_readdirargs(self, ra): 51 dir, cookie, count = ra 52 self.pack_fhandle(dir) 53 self.pack_uint(cookie) 54 self.pack_uint(count) 55 56 def pack_timeval(self, tv): 57 secs, usecs = tv 58 self.pack_uint(secs) 59 self.pack_uint(usecs) 60 61 62class NFSUnpacker(MountUnpacker): 63 64 def unpack_readdirres(self): 65 status = self.unpack_enum() 66 if status == NFS_OK: 67 entries = self.unpack_list(self.unpack_entry) 68 eof = self.unpack_bool() 69 rest = (entries, eof) 70 else: 71 rest = None 72 return (status, rest) 73 74 def unpack_entry(self): 75 fileid = self.unpack_uint() 76 name = self.unpack_string() 77 cookie = self.unpack_uint() 78 return (fileid, name, cookie) 79 80 def unpack_diropres(self): 81 status = self.unpack_enum() 82 if status == NFS_OK: 83 fh = self.unpack_fhandle() 84 fa = self.unpack_fattr() 85 rest = (fh, fa) 86 else: 87 rest = None 88 return (status, rest) 89 90 def unpack_attrstat(self): 91 status = self.unpack_enum() 92 if status == NFS_OK: 93 attributes = self.unpack_fattr() 94 else: 95 attributes = None 96 return status, attributes 97 98 def unpack_fattr(self): 99 type = self.unpack_enum() 100 mode = self.unpack_uint() 101 nlink = self.unpack_uint() 102 uid = self.unpack_uint() 103 gid = self.unpack_uint() 104 size = self.unpack_uint() 105 blocksize = self.unpack_uint() 106 rdev = self.unpack_uint() 107 blocks = self.unpack_uint() 108 fsid = self.unpack_uint() 109 fileid = self.unpack_uint() 110 atime = self.unpack_timeval() 111 mtime = self.unpack_timeval() 112 ctime = self.unpack_timeval() 113 return (type, mode, nlink, uid, gid, size, blocksize, \ 114 rdev, blocks, fsid, fileid, atime, mtime, ctime) 115 116 def unpack_timeval(self): 117 secs = self.unpack_uint() 118 usecs = self.unpack_uint() 119 return (secs, usecs) 120 121 122class NFSClient(UDPClient): 123 124 def __init__(self, host): 125 UDPClient.__init__(self, host, NFS_PROGRAM, NFS_VERSION) 126 127 def addpackers(self): 128 self.packer = NFSPacker() 129 self.unpacker = NFSUnpacker('') 130 131 def mkcred(self): 132 if self.cred is None: 133 self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default() 134 return self.cred 135 136 def Getattr(self, fh): 137 return self.make_call(1, fh, \ 138 self.packer.pack_fhandle, \ 139 self.unpacker.unpack_attrstat) 140 141 def Setattr(self, sa): 142 return self.make_call(2, sa, \ 143 self.packer.pack_sattrargs, \ 144 self.unpacker.unpack_attrstat) 145 146 # Root() is obsolete 147 148 def Lookup(self, da): 149 return self.make_call(4, da, \ 150 self.packer.pack_diropargs, \ 151 self.unpacker.unpack_diropres) 152 153 # ... 154 155 def Readdir(self, ra): 156 return self.make_call(16, ra, \ 157 self.packer.pack_readdirargs, \ 158 self.unpacker.unpack_readdirres) 159 160 # Shorthand to get the entire contents of a directory 161 def Listdir(self, dir): 162 list = [] 163 ra = (dir, 0, 2000) 164 while 1: 165 (status, rest) = self.Readdir(ra) 166 if status <> NFS_OK: 167 break 168 entries, eof = rest 169 last_cookie = None 170 for fileid, name, cookie in entries: 171 list.append((fileid, name)) 172 last_cookie = cookie 173 if eof or last_cookie is None: 174 break 175 ra = (ra[0], last_cookie, ra[2]) 176 return list 177 178 179def test(): 180 import sys 181 if sys.argv[1:]: host = sys.argv[1] 182 else: host = '' 183 if sys.argv[2:]: filesys = sys.argv[2] 184 else: filesys = None 185 from mountclient import UDPMountClient, TCPMountClient 186 mcl = TCPMountClient(host) 187 if filesys is None: 188 list = mcl.Export() 189 for item in list: 190 print item 191 return 192 sf = mcl.Mnt(filesys) 193 print sf 194 fh = sf[1] 195 if fh: 196 ncl = NFSClient(host) 197 attrstat = ncl.Getattr(fh) 198 print attrstat 199 list = ncl.Listdir(fh) 200 for item in list: print item 201 mcl.Umnt(filesys) 202