学习MFS有一段时间了, 分享下个人实现的python客户端连接MFS
<!-- lang: python -->
class MFSApi(object):
def __init__(self, host, port, mountfolder):
self.mountfolder=mountfolder if mountfolder.endswith('/') else mountfolder+'/'
self.mountfolder=self.mountfolder if self.mountfolder.startswith('/') else '/'+self.mountfolder
self.masterconn=socket.socket()
self.masterconn.connect((host,port))
leng=len(self.mountfolder)+1
mysend(self.masterconn,struct.pack(">LL64sBHBBL1sL%ss"%leng, CLTOMA_FUSE_REGISTER, 64+13+1+leng,
FUSE_REGISTER_BLOB_ACL, REGISTER_NEWSESSION, 1, 6, 26, 1, "/", leng, self.mountfolder+"\0"))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_FUSE_REGISTER or size != 25:
self.masterconn.close()
raise RuntimeError("Register to masterserver(%s:%s) failed" % (host, port))
self.versmaj,self.versmid,self.versmin,self.sessionid,self.sesflags,self.rootuid,self.rootgid,self.mapalluid,self.mapallgid=struct.unpack(">HBBLBLLLL", data)
crc_generate_main_tables()
def statfs(self):
mysend(self.masterconn,struct.pack(">LLL", CLTOMA_FUSE_STATFS, 4, 1))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_FUSE_STATFS or size != 40:
raise IOError("Error while getting statfs")
_,totalspace,availspace,trashspace,reservedspace,inodes=struct.unpack(">LQQQQL", data)
return {'totalspace':totalspace,
'availspace':availspace,
'trashspace':trashspace,
'reservedspace':reservedspace,
'inodes':inodes}
def _transfer2attr(self, data):
_type,mode,uid,gid,atime,mtime,ctime,nlink,length=struct.unpack(">BHLLLLLLQ", data)
return {'type':_type,
'mode':mode,
'uid':uid,
'gid':gid,
'atime':atime,
'mtime':mtime,
'ctime':ctime,
'nlink':nlink,
'length':length}
def _lookup(self, inode, fname):
leng=len(fname)
mysend(self.masterconn, struct.pack(">LLLLB%ssLL"%leng, CLTOMA_FUSE_LOOKUP, 17+leng,
1, inode, leng, fname, self.rootuid, self.rootgid))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_FUSE_LOOKUP or size != 43:
raise IOError("Error while lookingup of file name: '%s'" % fname)
_,newinode=struct.unpack(">LL", data[:8])
return {'inode':newinode,
'attr':data[8:]}
def ls(self, fpath):
result=self.ll(fpath)
subnames=[]
for sub in result:
subnames.append(sub['name'])
return subnames
def ll(self, fpath):
if fpath == '/': fpath='.'
_fpath=fpath if fpath.startswith('/') else '/'+fpath
nlist=_fpath.split('/')[1:]
if not nlist[-1]: nlist=nlist[0:-1]
inode=1
attr_v={}
for name in nlist:
value=self._lookup(inode, name)
inode=value['inode']
attr_v=self._transfer2attr(value['attr'])
subnames=[{'inode':inode,
'type':attr_v['type'],
'name':nlist[-1],
'uid':attr_v['uid'],
'gid':attr_v['gid'],
'atime':attr_v['atime'],
'mtime':attr_v['mtime'],
'ctime':attr_v['ctime'],
'length':attr_v['length']}]
if attr_v['type'] == ord('d'):
mysend(self.masterconn,struct.pack(">LLLLLLB", CLTOMA_FUSE_GETDIR, 17,
1, inode, self.rootuid, self.rootgid, 1))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_FUSE_GETDIR:
raise IOError("Error while getting dir of inode(%s)" % inode)
readed=4+83
subnames=[]
while readed < size:
nlen=struct.unpack('>B', data[readed])[0]
readed+=1
name=data[readed:readed+nlen]
readed+=nlen
node=struct.unpack('>L', data[readed:readed+4])[0]
readed+=4
attr_v=self._transfer2attr(data[readed:readed+35])
readed+=35
subnames.append({'inode':node,
'type':attr_v['type'],
'name':name,
'uid':attr_v['uid'],
'gid':attr_v['gid'],
'atime':attr_v['atime'],
'mtime':attr_v['mtime'],
'ctime':attr_v['ctime'],
'length':attr_v['length']})
return subnames
def mkdir(self, fpath):
if fpath in ['/', '.', '..'] or fpath.endswith('/'):
raise ValueError("Invalid path: '%s'" % fpath)
_fpath=fpath if fpath.startswith('/') else '/'+fpath
nlist=_fpath.split('/')[1:]
fname=nlist[-1]
nlist=nlist[:-1]
inode=1
attr_v={}
if not nlist: nlist.append('.')
for name in nlist:
value=self._lookup(inode, name)
inode=value['inode']
attr_v=self._transfer2attr(value['attr'])
if attr_v['type'] != ord('d'):
raise IOError("[Errno 20] Not a directory: '/%s'" % '/'.join(nlist))
nleng=len(fname)
mysend(self.masterconn,struct.pack(">LLLLB%ssHLL"%nleng, CLTOMA_FUSE_MKDIR, 19+nleng,
1, inode, nleng, fname, 0666, self.rootuid, self.rootgid))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_FUSE_MKDIR or size != 43:
raise IOError("Error while mkdir of path: '%s'" % fpath)
_,newinode=struct.unpack(">LL", data[:8])
dirinfo=self._transfer2attr(data[8:])
dirinfo['inode']=newinode
return dirinfo
def rmdir(self, fpath):
if fpath in ['/', '.', '..'] or fpath.endswith('/'):
raise ValueError("Invalid path: '%s'" % fpath)
_fpath=fpath if fpath.startswith('/') else '/'+fpath
nlist=_fpath.split('/')[1:]
fname=nlist[-1]
nlist=nlist[:-1]
inode=1
attr_v={}
if not nlist: nlist.append('.')
for name in nlist:
value=self._lookup(inode, name)
inode=value['inode']
attr_v=self._transfer2attr(value['attr'])
if attr_v['type'] != ord('d'):
raise IOError("[Errno 20] Not a directory: '/%s'" % '/'.join(nlist))
nleng=len(fname)
mysend(self.masterconn,struct.pack(">LLLLB%ssLL"%nleng, CLTOMA_FUSE_RMDIR, 17+nleng,
1, inode, nleng, fname, self.rootuid, self.rootgid))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_FUSE_RMDIR or size != 5:
raise IOError("Error while rmdir of path: '%s'" % fpath)
_,status=struct.unpack('>LB', data)
if status:
raise IOError("Failed while rmdir of path: '%s'" % fpath)
def mv(self, oldfpath, newfpath):
if oldfpath in ['/', '.', '..'] or oldfpath.endswith('/'):
raise ValueError("Invalid source path: '%s'" % oldfpath)
if newfpath in ['/', '.', '..'] or newfpath.endswith('/'):
raise ValueError("Invalid destination path: '%s'" % newfpath)
def _parse_node_info(fpath):
_fpath=fpath if fpath.startswith('/') else '/'+fpath
nlist=_fpath.split('/')[1:]
fname=nlist[-1]
nlist=nlist[:-1]
inode=1
if not nlist: nlist.append('.')
for name in nlist:
value=self._lookup(inode, name)
inode=value['inode']
return inode, fname
oldnode_info=_parse_node_info(oldfpath)
newnode_info=_parse_node_info(newfpath)
oldinode=oldnode_info[0]
oldfname=oldnode_info[1]
oldnleng=len(oldfname)
newinode=newnode_info[0]
newfname=newnode_info[1]
newnleng=len(newfname)
# old file not exist or new file exist
if not self._lookup(oldinode, oldfname):
raise IOError("The source file is not exist, path: '%s'" % oldfpath)
if self._lookup(newinode, newfname):
raise IOError("The destination file is exist, path: '%s'" % newfpath)
mysend(self.masterconn,struct.pack(">LLLLB%ssLB%ssLL"%(oldnleng, newnleng), CLTOMA_FUSE_RENAME, 22+oldnleng+newnleng,
1, oldinode, oldnleng, oldfname, newinode, newnleng, newfname, self.rootuid, self.rootgid))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_FUSE_RENAME or size != 43:
raise IOError("Error while moving file from '%s' to '%s'" % (oldfpath, newfpath))
_,newinode=struct.unpack(">LL", data[:8])
nodeinfo=self._transfer2attr(data[8:])
nodeinfo['inode']=newinode
return nodeinfo
def unlink(self, fpath):
if fpath in ['/', '.', '..'] or fpath.endswith('/'):
raise ValueError("Invalid path: '%s'" % fpath)
_fpath=fpath if fpath.startswith('/') else '/'+fpath
nlist=_fpath.split('/')[1:]
fname=nlist[-1]
nlist=nlist[:-1]
inode=1
attr_v={}
if not nlist: nlist.append('.')
for name in nlist:
value=self._lookup(inode, name)
inode=value['inode']
attr_v=self._transfer2attr(value['attr'])
if attr_v['type'] != ord('d'):
raise IOError("[Errno 20] Not a directory: '/%s'" % '/'.join(nlist))
nleng=len(fname)
mysend(self.masterconn,struct.pack(">LLLLB%ssLL"%nleng, CLTOMA_FUSE_UNLINK, 17+nleng,
1, inode, nleng, fname, self.rootuid, self.rootgid))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_FUSE_UNLINK or size != 5:
raise IOError("Error while unlink file '%s'" % fpath)
_,status=struct.unpack('>LB', data)
if status:
raise IOError("Failed while unlink file: '%s'" % fpath)
def open(self, fpath, mode):
outer_self = self
class _MFSFile(object):
def __init__(self, fpath, mode):
if mode not in ['r', 'rw', 'w', 'wr']:
raise ValueError("mode string must begin with one of 'r', 'w', not '%s'" % mode)
self.fpath=fpath if fpath.startswith('/') else '/'+fpath
nlist=self.fpath.split('/')[1:]
self.fname=nlist[-1]
self.parent_foldernlist=nlist[:-1]
if not self.parent_foldernlist: self.parent_foldernlist.append('.')
# open or create
_ = self.__open() if mode[0] == 'r' else self.__create()
self.readonly=True if mode=='r' else False
self.writeonly=True if mode=='w' else False
self.fleng=0
self.offset=0
self.chunksock=-1
self.chunkindx=-1
self.chunkid=-1
def __open(self):
inode=1
attr_v={}
for name in self.parent_foldernlist:
value=outer_self._lookup(inode, name)
if not value:
raise IOError("[Errno 2] No such file or directory: '%s'" % self.fpath)
inode=value['inode']
attr_v=outer_self._transfer2attr(value['attr'])
if attr_v['type'] != ord('d'):
raise IOError("[Errno 20] Not a directory: '%s'" % self.fpath)
value=outer_self._lookup(inode, self.fname)
if not value:
raise IOError("[Errno 2] No such file or directory: '%s'" % self.fpath)
inode=value['inode']
attr_v=outer_self._transfer2attr(value['attr'])
if attr_v['type'] != ord('f'):
raise IOError("[Errno 2] No such file or directory: '%s'" % self.fpath)
self.inode=inode
def __create(self):
inode=1
attr_v={}
for name in self.parent_foldernlist:
value=outer_self._lookup(inode, name)
if not value:
raise IOError("[Errno 2] No such file or directory: '%s'" % self.fpath)
inode=value['inode']
attr_v=outer_self._transfer2attr(value['attr'])
if attr_v['type'] != ord('d'):
raise IOError("[Errno 20] Not a directory: '%s'" % self.fpath)
value=outer_self._lookup(inode, self.fname)
if value:
attr_v=outer_self._transfer2attr(value['attr'])
if attr_v['type'] == ord('d'):
raise IOError("[Errno 21] Is a directory: '%s'" % self.fpath)
# exist file, delete
nleng=len(self.fname)
mysend(outer_self.masterconn,struct.pack(">LLLLB%ssLL"%nleng, CLTOMA_FUSE_UNLINK, 17+nleng,
1, inode, nleng, self.fname, outer_self.rootuid, outer_self.rootgid))
header = myrecv(outer_self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(outer_self.masterconn,size)
if cmd != MATOCL_FUSE_UNLINK or size != 5:
raise IOError("Error while delete the exist file for overwriting of file: '%s'" % self.fpath)
_,status=struct.unpack('>LB', data)
if status:
raise IOError("Failed while delete the exist file for overwriting of file: '%s'" % self.fpath)
# create a new file with new inode
nleng=len(self.fname)
mysend(outer_self.masterconn,struct.pack(">LLLLB%ssBHLLL"%nleng, CLTOMA_FUSE_MKNOD, 24+nleng,
1, inode, nleng, self.fname, ord('f'), 0666, outer_self.rootuid, outer_self.rootgid, 0))
header = myrecv(outer_self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(outer_self.masterconn,size)
if cmd != MATOCL_FUSE_MKNOD or size != 43:
raise IOError("Failed while creating a new file: '%s'" % self.fpath)
_,newinode=struct.unpack(">LL", data[:8])
self.inode = newinode
def __reset_chunksock(self):
if self.chunksock != -1:
self.chunksock.close()
self.chunksock = -1
def __read_chunk_loc(self):
self.__reset_chunksock()
mysend(outer_self.masterconn,struct.pack(">LLLLL", CLTOMA_FUSE_READ_CHUNK, 12,
1, self.inode, self.chunkindx))
header = myrecv(outer_self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(outer_self.masterconn,size)
if cmd != MATOCL_FUSE_READ_CHUNK:
raise IOError("There is error while reading chunk locations from masterserver of file: '%s'" % self.fpath)
if size-24 <= 0 or (size-24) % 6 != 0:
raise IOError("There is no chunkservers for reading of file: '%s'" % self.fpath)
_, self.fleng, self.chunkid, self.version=struct.unpack(">LQQL", data[:24])
loc_size=(size-24)/6
self.chunksock=socket.socket()
readed=24 + 6 * (random.randint(0, loc_size) % loc_size)
chunkip=data[readed:readed+4]
self.chunkport=struct.unpack(">H", data[readed+4:readed+6])[0]
self.chunkhost=socket.inet_ntoa(chunkip)
retried=0
while(retried<3):
try:
self.chunksock.connect((self.chunkhost, self.chunkport))
break
except socket.error:
retried+=1
if retried == 3:
self.__reset_chunksock()
raise IOError("Can not connect to chunk(%s:%s) after 3 times' retried for file: '%s'"
% (self.chunkhost, self.chunkport, self.fpath))
def __read_chunk_data(self, chunkoffset, chunksize):
mysend(self.chunksock,struct.pack(">LLQLLL", CLTOCS_READ, 20,
self.chunkid, self.version, chunkoffset, chunksize))
chunkdata=''
while True:
header = myrecv(self.chunksock,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.chunksock,size)
if cmd == CSTOCL_READ_STATUS:
if size==9:
chunkid, status=struct.unpack(">QB", data)
if self.chunkid == chunkid and not status:
return chunkdata
raise IOError("Error read_status while reading data from chunk(%s:%s) for file: '%s'"
% (self.chunkhost, self.chunkport, self.fpath))
elif cmd == CSTOCL_READ_DATA:
if size < 20:
raise IOError("Error read_data(size<20) while reading data from chunk(%s:%s) for file: '%s'"
% (self.chunkhost, self.chunkport, self.fpath))
chunkid, blocknum, blockoffset, blocksize, blockcrc=struct.unpack(">QHHLL", data[:20])
blockdata=data[20:]
breq = MFSBLOCKSIZE - blockoffset
if chunksize < breq: breq=chunksize
if self.chunkid != chunkid \
or size != 20+blocksize \
or not blocksize \
or blocknum != chunkoffset>>MFSBLOCKBITS \
or blockoffset != chunkoffset&MFSBLOCKMASK \
or blocksize != breq:
raise IOError("Error read_data(required not match) while reading data from chunk(%s:%s) for file: '%s'"
% (self.chunkhost, self.chunkport, self.fpath))
if blockcrc != mycrc32(0,blockdata,blocksize):
raise IOError("Error read_data(crc error) while reading data from chunk(%s:%s) for file: '%s'"
% (self.chunkhost, self.chunkport, self.fpath))
chunkoffset+=blocksize
chunksize-=blocksize
chunkdata+=blockdata
else:
raise IOError("Error unknown command(%s) while reading data from chunk(%s:%s) for file: '%s'"
% (cmd, self.chunkhost, self.chunkport, self.fpath))
#fail
self.__reset_chunksock()
def read(self, bufsize=1<<MFSBLOCKBITS):
if self.writeonly:
raise IOError("File not open for reading of file: '%s'" % self.fpath)
data=''
if self.offset>=self.fleng and self.fleng:
# the end of file
return data
readed=0
while readed<bufsize:
chunkindx = (self.offset>>MFSCHUNKBITS)
if self.chunksock == -1 or self.chunkindx != chunkindx:
self.chunkindx=chunkindx
self.__read_chunk_loc()
bufsize=bufsize if self.offset+bufsize<self.fleng else self.fleng-self.offset
if not bufsize:
# empty file
break
chunkoffset = self.offset & MFSCHUNKMASK
if chunkoffset+bufsize > MFSCHUNKSIZE:
chunksize = MFSCHUNKSIZE-chunkoffset
else:
chunksize=bufsize
chunkdata=self.__read_chunk_data(chunkoffset, chunksize)
self.offset+=chunksize
readed+=chunksize
data+=chunkdata
self.chunkindx=-1
return data
def seek(self, pos):
self.offset=pos
def close(self):
'''
Not Implement
'''
def __write_chunk_locs(self):
self.__reset_chunksock()
mysend(outer_self.masterconn,struct.pack(">LLLLL", CLTOMA_FUSE_WRITE_CHUNK, 12,
1, self.inode, self.chunkindx))
header = myrecv(outer_self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(outer_self.masterconn,size)
if cmd != MATOCL_FUSE_WRITE_CHUNK or size-24 <= 0 or (size-24) % 6 != 0:
raise IOError("Error while getting writing chunk for file: '%s'" % self.fpath)
_, self.fleng, self.chunkid, self.version=struct.unpack(">LQQL", data[:24])
self.chunksock=socket.socket()
chunkip=data[24:28]
self.chunkport=struct.unpack(">H", data[28:30])[0]
self.chunkhost=socket.inet_ntoa(chunkip)
retried=0
while(retried<3):
try:
self.chunksock.connect((self.chunkhost, self.chunkport))
break
except socket.error:
retried+=1
if retried == 3:
self.__reset_chunksock()
raise IOError("Can not connect to chunk(%s:%s) after 3 times' retried for file: '%s'"
% (self.chunkhost, self.chunkport, self.fpath))
# return other locations
return data[30:]
def __write_chunk_end(self):
self.fleng = max(self.offset, self.fleng)
mysend(outer_self.masterconn,struct.pack(">LLLQLQ", CLTOMA_FUSE_WRITE_CHUNK_END, 24,
1, self.chunkid, self.inode, self.fleng))
header = myrecv(outer_self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(outer_self.masterconn,size)
if cmd != MATOCL_FUSE_WRITE_CHUNK_END or size != 5:
raise IOError("Error while write chunk end of chunkid(%s) for file: '%s'"
% (self.chunkid, self.fpath))
_, status=struct.unpack(">LB", data)
if status:
raise IOError("Error response bad status(%s) while write chunk end of chunkid(%s) for file: '%s'"
% (status, self.chunkid, self.fpath))
def __write_block_data(self, blocknum, blockoffset, blocksize, blockdata, other_locs):
mysend(self.chunksock, struct.pack(">LLQL", CLTOCS_WRITE, 12+len(other_locs),
self.chunkid, self.version)+other_locs)
header = myrecv(self.chunksock,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.chunksock,size)
if cmd != CSTOCL_WRITE_STATUS and size != 13:
raise IOError("Error while writing block initialize for file: '%s'" % self.fpath)
chunkid, _, status=struct.unpack(">QLB", data)
if self.chunkid != chunkid:
raise IOError("Error response not required while writing block initialize"
"chunkid(%s:%s) for file: '%s'"
% (self.chunkid, chunkid, self.fpath))
if status:
raise IOError("Error response bad status(%s) while writing block initialize for file: '%s'"
% (status, self.fpath))
writeid=blocknum+1
crc=mycrc32(0, blockdata, blocksize)
mysend(self.chunksock, struct.pack(">LLQLHHLL", CLTOCS_WRITE_DATA, 24+blocksize,
self.chunkid, writeid, blocknum, blockoffset, blocksize, crc))
mysend(self.chunksock, blockdata)
header = myrecv(self.chunksock,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.chunksock,size)
if cmd != CSTOCL_WRITE_STATUS and size != 13:
raise IOError("Error while writing block data with blocknum: %s, "
"blockoffset: %s, blocksize: %s for file: '%s'"
% (blocknum, blockoffset, blocksize, self.fpath))
chunkid, reswriteid, status=struct.unpack(">QLB", data)
if self.chunkid != chunkid or writeid != reswriteid:
raise IOError("Error response not required while writing block data with blocknum: %s, "
"blockoffset: %s, blocksize: %s, chunkid(%s:%s), chunkindex:(%s:%s) for file: '%s'"
% (blocknum, blockoffset, blocksize, self.chunkid, chunkid, writeid, reswriteid, self.fpath))
if status:
raise IOError("Error response bad status(%s) while writing block data with blocknum: %s, "
"blockoffset: %s, blocksize: %s for file: '%s'"
% (status, blocknum, blockoffset, blocksize, self.fpath))
def write(self, data):
if self.readonly:
raise IOError("File not open for writing of file: '%s'" % self.fpath)
size=len(data)
chunkindx = self.offset >> MFSCHUNKBITS
blocknum = (self.offset&MFSCHUNKMASK) >> MFSBLOCKBITS
blockoffset = self.offset&MFSBLOCKMASK
writed_pos=0
other_locs=''
while writed_pos < size:
if self.chunkindx == -1 or self.chunkindx != chunkindx:
if self.chunkindx != -1:
self.__write_chunk_end()
self.chunkindx=chunkindx
other_locs=self.__write_chunk_locs()
remain_size=size-writed_pos
blocksize=min(MFSBLOCKSIZE-blockoffset, remain_size)
blockdata=data[writed_pos : writed_pos+blocksize]
self.__write_block_data(blocknum, blockoffset, blocksize, blockdata, other_locs)
if remain_size > MFSBLOCKSIZE-blockoffset:
blockoffset = 0
blocknum += 1
if blocknum == 1024:
blocknum = 0
chunkindx+=1
writed_pos += blocksize
self.offset += blocksize
self.__reset_chunksock()
self.__write_chunk_end()
self.chunkindx=-1
if fpath in ['/', '.', '..'] or fpath.endswith('/'):
raise ValueError("Invalid path: '%s'" % fpath)
return _MFSFile(fpath, mode)
def allexports(self):
mysend(self.masterconn,struct.pack(">LL", CLTOMA_EXPORTS_INFO, 0))
header = myrecv(self.masterconn,8)
cmd,size = struct.unpack(">LL",header)
data=myrecv(self.masterconn,size)
if cmd != MATOCL_EXPORTS_INFO:
raise IOError("Error while getting all exports")
servers = []
pos = 0
while pos<size:
fip1,fip2,fip3,fip4,tip1,tip2,tip3,tip4,pleng = struct.unpack(">BBBBBBBBL",data[pos:pos+12])
pos+=12
path = data[pos:pos+pleng]
pos+=pleng
v1,v2,v3,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">HBBBBLLLL",data[pos:pos+22])
pos+=22
servers.append({'version':'%d.%d.%d' % (v1,v2,v3),
'fromip':'%d.%d.%d.%d' % (fip1,fip2,fip3,fip4),
'toip':'%d.%d.%d.%d' % (tip1,tip2,tip3,tip4),
'path':path,
'exportflags':exportflags,
'sesflags':sesflags,
'rootuid':rootuid,
'rootgid':rootgid,
'mapalluid':mapalluid,
'mapallgid':mapallgid
})
return servers
def __del__(self):
self.metaconn.close()