nfsclient.py 4.31 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2
# NFS RPC client -- RFC 1094

3 4 5
# XXX This is not yet complete.
# XXX Only GETATTR, SETTTR, LOOKUP and READDIR are supported.

Guido van Rossum's avatar
Guido van Rossum committed
6 7 8
# (See mountclient.py for some hints on how to write RPC clients in
# Python in general)

9
import rpc
Guido van Rossum's avatar
Guido van Rossum committed
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
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):
Guido van Rossum's avatar
Guido van Rossum committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
		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)
Guido van Rossum's avatar
Guido van Rossum committed
115 116 117 118 119 120 121 122 123

	def unpack_timeval(self):
		secs = self.unpack_uint()
		usecs = self.unpack_uint()
		return (secs, usecs)


class NFSClient(UDPClient):

124 125
	def __init__(self, host):
		UDPClient.__init__(self, host, NFS_PROGRAM, NFS_VERSION)
Guido van Rossum's avatar
Guido van Rossum committed
126 127

	def addpackers(self):
128 129
		self.packer = NFSPacker()
		self.unpacker = NFSUnpacker('')
Guido van Rossum's avatar
Guido van Rossum committed
130

131
	def mkcred(self):
132 133 134 135
		if self.cred == None:
			self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default()
		return self.cred

Guido van Rossum's avatar
Guido van Rossum committed
136
	def Getattr(self, fh):
137 138 139
		return self.make_call(1, fh, \
			self.packer.pack_fhandle, \
			self.unpacker.unpack_attrstat)
Guido van Rossum's avatar
Guido van Rossum committed
140 141

	def Setattr(self, sa):
142 143 144
		return self.make_call(2, sa, \
			self.packer.pack_sattrargs, \
			self.unpacker.unpack_attrstat)
Guido van Rossum's avatar
Guido van Rossum committed
145 146 147 148

	# Root() is obsolete

	def Lookup(self, da):
149 150 151
		return self.make_call(4, da, \
			self.packer.pack_diropargs, \
			self.unpacker.unpack_diropres)
Guido van Rossum's avatar
Guido van Rossum committed
152 153 154 155

	# ...

	def Readdir(self, ra):
156 157 158
		return self.make_call(16, ra, \
			self.packer.pack_readdirargs, \
			self.unpacker.unpack_readdirres)
Guido van Rossum's avatar
Guido van Rossum committed
159 160 161 162

	# Shorthand to get the entire contents of a directory
	def Listdir(self, dir):
		list = []
163
		ra = (dir, 0, 2000)
Guido van Rossum's avatar
Guido van Rossum committed
164 165 166 167 168 169 170
		while 1:
			(status, rest) = self.Readdir(ra)
			if status <> NFS_OK:
				break
			entries, eof = rest
			last_cookie = None
			for fileid, name, cookie in entries:
171
				list.append((fileid, name))
Guido van Rossum's avatar
Guido van Rossum committed
172
				last_cookie = cookie
173
			if eof or last_cookie == None:
Guido van Rossum's avatar
Guido van Rossum committed
174 175 176 177 178 179 180 181 182 183 184 185
				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
186
	mcl = TCPMountClient(host)
Guido van Rossum's avatar
Guido van Rossum committed
187 188 189 190 191 192 193 194 195
	if filesys == None:
		list = mcl.Export()
		for item in list:
			print item
		return
	sf = mcl.Mnt(filesys)
	print sf
	fh = sf[1]
	if fh:
196
		ncl = NFSClient(host)
Guido van Rossum's avatar
Guido van Rossum committed
197 198 199 200
		as = ncl.Getattr(fh)
		print as
		list = ncl.Listdir(fh)
		for item in list: print item
201
		mcl.Umnt(filesys)