Mini Shell
#
# This file is part of pysmi software.
#
# Copyright (c) 2015-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pysmi/license.html
#
import os
import sys
import time
import datetime
import zipfile
from pysmi.reader.base import AbstractReader
from pysmi.mibinfo import MibInfo
from pysmi.compat import decode
from pysmi import debug
from pysmi import error
class FileLike(object):
"""Stripped down, binary file mock to work with ZipFile"""
def __init__(self, buf, name):
self.name = name
self.buf = buf
self.null = buf[:0]
self.len = len(buf)
self.buflist = []
self.pos = 0
self.closed = False
self.softspace = 0
def close(self):
if not self.closed:
self.closed = True
self.buf = self.null
self.pos = 0
def seek(self, pos, mode = 0):
if self.buflist:
self.buf += self.null.join(self.buflist)
self.buflist = []
if mode == 1:
pos += self.pos
elif mode == 2:
pos += self.len
self.pos = max(0, pos)
def tell(self):
return self.pos
def read(self, n=-1):
if self.buflist:
self.buf += self.null.join(self.buflist)
self.buflist = []
if n < 0:
newpos = self.len
else:
newpos = min(self.pos + n, self.len)
r = self.buf[self.pos:newpos]
self.pos = newpos
return r
class ZipReader(AbstractReader):
"""Fetch ASN.1 MIB text by name from a ZIP archive.
*ZipReader* class instance tries to locate ASN.1 MIB files
by name, fetch and return their contents to caller.
"""
useIndexFile = False
def __init__(self, path, ignoreErrors=True):
"""Create an instance of *ZipReader* serving a ZIP archive.
Args:
path (str): path to ZIP archive containing MIB files
Keyword Args:
ignoreErrors (bool): ignore ZIP archive access errors
"""
self._name = path
self._members = {}
self._pendingError = None
try:
self._members = self._readZipDirectory(fileObj=open(path, 'rb'))
except Exception:
debug.logger & debug.flagReader and debug.logger(
'ZIP file %s open failure: %s' % (self._name, sys.exc_info()[1]))
if not ignoreErrors:
self._pendingError = error.PySmiError('file %s access error: %s' % (self._name, sys.exc_info()[1]))
def _readZipDirectory(self, fileObj):
archive = zipfile.ZipFile(fileObj)
if isinstance(fileObj, FileLike):
fileObj = None
members = {}
for member in archive.infolist():
filename = os.path.basename(member.filename)
if not filename:
continue
if (member.filename.endswith('.zip') or
member.filename.endswith('.ZIP')):
innerZipBlob = archive.read(member.filename)
innerMembers = self._readZipDirectory(FileLike(innerZipBlob, member.filename))
for innerFilename, ref in innerMembers.items():
while innerFilename in members:
innerFilename += '+'
members[innerFilename] = [[fileObj, member.filename, None]]
members[innerFilename].extend(ref)
else:
mtime = time.mktime(datetime.datetime(*member.date_time[:6]).timetuple())
members[filename] = [[fileObj, member.filename, mtime]]
return members
def _readZipFile(self, refs):
for fileObj, filename, mtime in refs:
if not fileObj:
fileObj = FileLike(dataObj, name=self._name)
archive = zipfile.ZipFile(fileObj)
try:
dataObj = archive.read(filename)
except Exception:
debug.logger & debug.flagReader and debug.logger('ZIP read component %s read error: %s' % (fileObj.name, sys.exc_info()[1]))
return '', 0
return dataObj, mtime
def __str__(self):
return '%s{"%s"}' % (self.__class__.__name__, self._name)
def getData(self, mibname, **options):
debug.logger & debug.flagReader and debug.logger('looking for MIB %s at %s' % (mibname, self._name))
if self._pendingError:
raise self._pendingError
if not self._members:
raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self)
for mibalias, mibfile in self.getMibVariants(mibname, **options):
debug.logger & debug.flagReader and debug.logger('trying MIB %s' % mibfile)
try:
refs = self._members[mibfile]
except KeyError:
continue
mibData, mtime = self._readZipFile(refs)
if not mibData:
continue
debug.logger & debug.flagReader and debug.logger(
'source MIB %s, mtime %s, read from %s/%s' % (mibfile, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(mtime)), self._name, mibfile)
)
if len(mibData) == self.maxMibSize:
raise IOError('MIB %s/%s too large' % (self._name, mibfile))
return MibInfo(path='zip://%s/%s' % (self._name, mibfile),
file=mibfile, name=mibalias, mtime=mtime), decode(mibData)
raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self)
Zerion Mini Shell 1.0