text: ###
  # Copyright 2020 Hewlett Packard Enterprise, Inc. All rights reserved.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #  http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  ###
  
  # -*- coding: utf-8 -*-
  """Base implementation for interaction with blob store interface"""
  
  #---------Imports---------
  
  import os
  import sys
  import struct
  import random
  import string
  import logging
  
  from ctypes import c_char_p, c_ubyte, c_uint, cdll, POINTER, create_string_buffer, c_ushort
  
  from redfish.hpilo.rishpilo import HpIlo, HpIloInitialError
  from redfish.hpilo.rishpilo import BlobReturnCodes as hpiloreturncodes
  
  if os.name == 'nt':
      from ctypes import windll
  else:
      from _ctypes import dlclose
  
  #---------End of imports---------
  #---------Debug logger---------
  
  LOGGER = logging.getLogger(__name__)
  
  #---------End of debug logger---------
  #-----------------------Error Returns----------------------
  
  class UnexpectedResponseError(Exception):
      """Raise when we get data that we don't expect from iLO"""
      pass
  
  class HpIloError(Exception):
      """Raised when iLO returns non-zero error code"""
      pass
  
  class Blob2CreateError(Exception):
      """Raised when create operation fails"""
      pass
  
  class Blob2InfoError(Exception):
      """Raised when create operation fails"""
      pass
  
  class Blob2ReadError(Exception):
      """Raised when read operation fails"""
      pass
  
  class Blob2WriteError(Exception):
      """Raised when write operation fails"""
      pass
  
  class Blob2DeleteError(Exception):
      """Raised when delete operation fails"""
      pass
  
  class Blob2OverrideError(Exception):
      """Raised when delete operation fails because of it been overwritten"""
      pass
  
  class BlobRetriesExhaustedError(Exception):
      """Raised when max retries have been attempted for same operation"""
      pass
  
  class Blob2FinalizeError(Exception):
      """Raised when finalize operation fails"""
      pass
  
  class Blob2ListError(Exception):
      """Raised when list operation fails"""
      pass
  
  class Blob2SecurityError(Exception):
      """Raised when there is an issue with security"""
      pass
  
  class BlobNotFoundError(Exception):
      """Raised when blob not found in key/namespace"""
      pass
  
  class ChifDllMissingError(Exception):
      """Raised when unable to obtain ilorest_chif dll handle"""
      pass
  
  class EncryptionEnabledError(Exception):
      """Raised when high security encryption is enabled"""
      pass
  
  #----------------------------------------------------------
  
  #-------------------Helper functions-------------------------
  
  class BlobReturnCodes(object):
      """Blob store return codes.
  
      SUCCESS           success
      BADPARAMETER      bad parameter supplied
      NOTFOUND          blob name not found
      NOTMODIFIED       call did not perform the operation
  
      """
  
      SUCCESS = 0
      BADPARAMETER = 2
      NOTFOUND = 12
      NOTMODIFIED = 20
  
  class BlobStore2(object):
      """Blob store 2 class"""
      def __init__(self):
          lib = self.gethprestchifhandle()
          self.channel = HpIlo(dll=lib)
          self.max_retries = 3
  
      def __del__(self):
          """Blob store 2 close channel function"""
          if hasattr(self, 'channel'):
              self.channel.close()
  
      def create(self, key, namespace):
          """Create the blob
  
          :param key: The blob key to create.
          :type key: str.
          :param namespace: The blob namespace to create the key in.
          :type namespace: str.
  
          """
          lib = self.gethprestchifhandle()
          lib.create_not_blobentry.argtypes = [c_char_p, c_char_p]
          lib.create_not_blobentry.restype = POINTER(c_ubyte)
  
          name = create_string_buffer(key.encode('utf-8'))
          namespace = create_string_buffer(namespace.encode('utf-8'))
  
          ptr = lib.create_not_blobentry(name, namespace)
          data = ptr[:lib.size_of_createRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = struct.unpack("<I", bytes(resp[8:12]))[0]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def get_info(self, key, namespace, retries=0):
          """Get information for a particular blob
  
          :param key: The blob key to retrieve.
          :type key: str.
          :param namespace: The blob namespace to retrieve the key from.
          :type namespace: str.
  
          """
          lib = self.gethprestchifhandle()
          lib.get_info.argtypes = [c_char_p, c_char_p]
          lib.get_info.restype = POINTER(c_ubyte)
  
          name = create_string_buffer(key.encode('utf-8'))
          namspace = create_string_buffer(namespace.encode('utf-8'))
  
          ptr = lib.get_info(name, namspace)
          data = ptr[:lib.size_of_infoRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = struct.unpack("<I", bytes(resp[8:12]))[0]
          if errorcode == BlobReturnCodes.BADPARAMETER:
              if retries < self.max_retries:
                  self.get_info(key=key, namespace=namespace, retries=retries+1)
              else:
                  raise Blob2OverrideError(errorcode)
          elif errorcode == BlobReturnCodes.NOTFOUND:
              raise BlobNotFoundError(key, namespace)
  
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          response = resp[lib.size_of_responseHeaderBlob():]
  
          self.unloadchifhandle(lib)
  
          return response
  
      def read(self, key, namespace, retries=0):
          """Read a particular blob
  
          :param key: The blob key to be read.
          :type key: str.
          :param namespace: The blob namespace to read the key from.
          :type namespace: str.
  
          """
          lib = self.gethprestchifhandle()
          maxread = lib.max_read_size()
          readsize = lib.size_of_readRequest()
          readhead = lib.size_of_responseHeaderBlob()
  
          self.unloadchifhandle(lib)
  
          blob_info = self.get_info(key, namespace)
          blobsize = struct.unpack("<I", bytes(blob_info[0:4]))[0]
  
          bytes_read = 0
          data = bytearray()
  
          while bytes_read < blobsize:
              if (maxread - readsize) < (blobsize - bytes_read):
                  count = maxread - readsize
              else:
                  count = blobsize - bytes_read
  
              read_block_size = bytes_read
              recvpkt = self.read_fragment(key, namespace, read_block_size, count)
  
              newreadsize = readhead + 4
              bytesread = struct.unpack("<I", bytes(recvpkt[readhead:(newreadsize)]))[0]
  
              if bytesread == 0:
                  if retries < self.max_retries:
                      data = self.read(key=key, namespace=namespace, retries=retries+1)
                      return data
                  else:
                      raise BlobRetriesExhaustedError()
  
              data.extend(recvpkt[newreadsize:newreadsize + bytesread])
              bytes_read += bytesread
  
          return data
  
      def read_fragment(self, key, namespace, offset=0, count=1):
          """Fragmented version of read function for large blobs
  
          :param key: The blob key to be read.
          :type key: str.
          :param namespace: The blob namespace to read the key from.
          :type namespace: str.
          :param offset: The data offset for the current fragmented read.
          :type key: int.
          :param count: The data count for the current fragmented read.
          :type namespace: int.
  
          """
          lib = self.gethprestchifhandle()
          lib.read_fragment.argtypes = [c_uint, c_uint, c_char_p, c_char_p]
          lib.read_fragment.restype = POINTER(c_ubyte)
  
          name = create_string_buffer(key.encode('utf-8'))
          namespace = create_string_buffer(namespace.encode('utf-8'))
  
          ptr = lib.read_fragment(offset, count, name, namespace)
          data = ptr[:lib.size_of_readRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          resp = resp + b"\0" * (lib.size_of_readResponse() - len(resp))
  
          return resp
  
      def write(self, key, namespace, data=None):
          """Write a particular blob
  
          :param key: The blob key to be written.
          :type key: str.
          :param namespace: The blob namespace to write the key in.
          :type namespace: str.
          :param data: The blob data to be written.
          :type data: str.
  
          """
          lib = self.gethprestchifhandle()
          maxwrite = lib.max_write_size()
          writesize = lib.size_of_writeRequest()
  
          self.unloadchifhandle(lib)
  
          if data:
              data_length = len(data)
              bytes_written = 0
  
              while bytes_written < data_length:
                  if (maxwrite - writesize) < (data_length - bytes_written):
                      count = maxwrite - writesize
                  else:
                      count = data_length - bytes_written
  
                  write_blob_size = bytes_written
  
                  self.write_fragment(key, namespace=namespace, \
                              data=data[write_blob_size:write_blob_size+count], \
                              offset=write_blob_size, count=count)
  
                  bytes_written += count
  
          return self.finalize(key, namespace=namespace)
  
      def write_fragment(self, key, namespace, data=None, offset=0, count=1):
          """Fragmented version of write function for large blobs
  
          :param key: The blob key to be written.
          :type key: str.
          :param namespace: The blob namespace to write the key in.
          :type namespace: str.
          :param data: The blob data to be written to blob.
          :type data: str.
          :param offset: The data offset for the current fragmented write.
          :type key: int.
          :param count: The data count for the current fragmented write.
          :type count: int.
  
          """
          lib = self.gethprestchifhandle()
          lib.write_fragment.argtypes = [c_uint, c_uint, c_char_p, c_char_p]
          lib.write_fragment.restype = POINTER(c_ubyte)
  
          name = create_string_buffer(key.encode('utf-8'))
          namespace = create_string_buffer(namespace.encode('utf-8'))
  
          ptr = lib.write_fragment(offset, count, name, namespace)
          sendpacket = ptr[:lib.size_of_writeRequest()]
  
          dataarr = bytearray(sendpacket)
          dataarr.extend(memoryview(data))
  
          resp = self._send_receive_raw(dataarr)
  
          errorcode = struct.unpack("<I", bytes(resp[8:12]))[0]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def delete(self, key, namespace, retries=0):
          """Delete the blob
  
          :param key: The blob key to be deleted.
          :type key: str.
          :param namespace: The blob namespace to delete the key from.
          :type namespace: str.
  
          """
          lib = self.gethprestchifhandle()
          lib.delete_blob.argtypes = [c_char_p, c_char_p]
          lib.delete_blob.restype = POINTER(c_ubyte)
  
          name = create_string_buffer(key.encode('utf-8'))
          namspace = create_string_buffer(namespace.encode('utf-8'))
  
          ptr = lib.delete_blob(name, namspace)
          data = ptr[:lib.size_of_deleteRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = struct.unpack("<I", bytes(resp[8:12]))[0]
          if errorcode == BlobReturnCodes.BADPARAMETER:
              if retries < self.max_retries:
                  self.delete(key=key, namespace=namespace, retries=\
                                                      retries+1)
              else:
                  raise Blob2OverrideError(errorcode)
          elif not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return errorcode
  
      def list(self, namespace):
          """List operation to retrieve all blobs in a given namespace
  
          :param namespace: The blob namespace to retrieve the keys from.
          :type namespace: str.
  
          """
          lib = self.gethprestchifhandle()
          lib.list_blob.argtypes = [c_char_p]
          lib.list_blob.restype = POINTER(c_ubyte)
  
          namespace = create_string_buffer(namespace.encode('utf-8'))
  
          ptr = lib.list_blob(namespace)
          data = ptr[:lib.size_of_listRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = struct.unpack("<I", bytes(resp[8:12]))[0]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          resp = resp + "\0" * (lib.size_of_listResponse() - len(resp))
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def finalize(self, key, namespace):
          """Finalize the blob
  
          :param key: The blob key to be finalized.
          :type key: str.
          :param namespace: The blob namespace to finalize the key in.
          :type namespace: str.
  
          """
          lib = self.gethprestchifhandle()
          lib.finalize_blob.argtypes = [c_char_p, c_char_p]
          lib.finalize_blob.restype = POINTER(c_ubyte)
  
          name = create_string_buffer(key.encode('utf-8'))
          namespace = create_string_buffer(namespace.encode('utf-8'))
  
          ptr = lib.finalize_blob(name, namespace)
          data = ptr[:lib.size_of_finalizeRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = struct.unpack("<I", bytes(resp[8:12]))[0]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return errorcode
  
      def rest_immediate(self, req_data, rqt_key="RisRequest", \
              rsp_key="RisResponse", rsp_namespace="volatile"):
          """Read/write blob via immediate operation
  
          :param req_data: The blob data to be read/written.
          :type req_data: str.
          :param rqt_key: The blob key to be used for the request data.
          :type rqt_key: str.
          :param rsp_key: The blob key to be used for the response data.
          :type rsp_key: str.
          :param rsp_namespace: The blob namespace to retrieve the response from.
          :type rsp_namespace: str.
  
          """
          rqt_key = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(10))
          rsp_key = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(10))
  
          lib = self.gethprestchifhandle()
  
          if len(req_data) < (lib.size_of_restImmediateRequest() + lib.max_write_size()):
              lib.rest_immediate.argtypes = [c_uint, c_char_p, c_char_p]
              lib.rest_immediate.restype = POINTER(c_ubyte)
  
              name = create_string_buffer(rsp_key.encode('utf-8'))
              namespace = create_string_buffer(rsp_namespace.encode('utf-8'))
  
              ptr = lib.rest_immediate(len(req_data), name, namespace)
              sendpacket = ptr[:lib.size_of_restImmediateRequest()]
              mode = False
          else:
              self.create(rqt_key, rsp_namespace)
              self.write(rqt_key, rsp_namespace, req_data)
  
              lib.rest_immediate_blobdesc.argtypes = [c_char_p, c_char_p, c_char_p]
              lib.rest_immediate_blobdesc.restype = POINTER(c_ubyte)
  
              name = create_string_buffer(rqt_key.encode('utf-8'))
              namespace = create_string_buffer(rsp_namespace.encode('utf-8'))
              rspname = create_string_buffer(rsp_key.encode('utf-8'))
  
              ptr = lib.rest_immediate_blobdesc(name, rspname, namespace)
              sendpacket = ptr[:lib.size_of_restBlobRequest()]
              mode = True
  
          data = bytearray(sendpacket)
  
          if not mode:
              data.extend(req_data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = struct.unpack("<I", bytes(resp[8:12]))[0]
          if errorcode == BlobReturnCodes.NOTFOUND:
              raise BlobNotFoundError(rsp_key, rsp_namespace)
  
          recvmode = struct.unpack("<I", bytes(resp[12:16]))[0]
  
          fixdlen = lib.size_of_restResponseFixed()
          response = resp[fixdlen:struct.unpack("<I", bytes(resp[16:20]))[0] + fixdlen]
  
          tmpresponse = None
          if errorcode == BlobReturnCodes.SUCCESS and not mode:
              if recvmode == 0:
                  tmpresponse = ''.join(map(chr, response))
          elif errorcode == BlobReturnCodes.NOTMODIFIED and not mode:
              if recvmode == 0:
                  tmpresponse = ''.join(map(chr, response))
          elif errorcode == BlobReturnCodes.SUCCESS:
              if recvmode == 0:
                  tmpresponse = ''.join(map(chr, response))
          elif recvmode == 0:
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          if not tmpresponse and recvmode == 1:
              tmpresponse = self.read(rsp_key, rsp_namespace)
  
              try:
                  self.delete(rsp_key, rsp_namespace)
              except Exception as excp:
                  raise excp
          else:
              try:
                  self.delete(rsp_key, rsp_namespace)
              except Blob2OverrideError as excp:
                  pass
              except Exception as excp:
                  raise excp
  
          return tmpresponse
  
      def get_security_state(self):
          """Get information for the current security state"""
          lib = self.gethprestchifhandle()
          lib.get_security_state.argtypes = []
          lib.get_security_state.restype = POINTER(c_ubyte)
  
          ptr = lib.get_security_state()
          data = ptr[:lib.size_of_securityStateRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = struct.unpack("<I", bytes(resp[8:12]))[0]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          try:
              securitystate = struct.unpack("<c", bytes(resp[72]))[0]
          except:
              securitystate = int(resp[72])
  
          self.unloadchifhandle(lib)
  
          return securitystate
  
      def mount_blackbox(self):
          """Operation to mount the blackbox partition"""
          lib = self.gethprestchifhandle()
          lib.blackbox_media_mount.argtypes = []
          lib.blackbox_media_mount.restype = POINTER(c_ubyte)
  
          ptr = lib.blackbox_media_mount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def absaroka_media_mount(self):
          """Operation to mount the absaroka repo partition"""
          lib = self.gethprestchifhandle()
          lib.absaroka_media_mount.argtypes = []
          lib.absaroka_media_mount.restype = POINTER(c_ubyte)
  
          ptr = lib.absaroka_media_mount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def gaius_media_mount(self):
          """Operation to mount the gaius media partition"""
          lib = self.gethprestchifhandle()
          lib.gaius_media_mount.argtypes = []
          lib.gaius_media_mount.restype = POINTER(c_ubyte)
  
          ptr = lib.gaius_media_mount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def vid_media_mount(self):
          """Operation to mount the gaius media partition"""
          lib = self.gethprestchifhandle()
          lib.vid_media_mount.argtypes = []
          lib.vid_media_mount.restype = POINTER(c_ubyte)
  
          ptr = lib.vid_media_mount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def mountflat(self):
          """Operation to mount the gaius media partition"""
          lib = self.gethprestchifhandle()
          lib.flat_media_mount.argtypes = []
          lib.flat_media_mount.restype = POINTER(c_ubyte)
  
          ptr = lib.flat_media_mount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def media_unmount(self):
          """Operation to unmount the media partition"""
          lib = self.gethprestchifhandle()
          lib.media_unmount.argtypes = []
          lib.media_unmount.restype = POINTER(c_ubyte)
  
          ptr = lib.media_unmount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def bb_media_unmount(self):
          """Operation to unmount the media partition"""
          lib = self.gethprestchifhandle()
          lib.bb_media_unmount.argtypes = []
          lib.bb_media_unmount.restype = POINTER(c_ubyte)
  
          ptr = lib.bb_media_unmount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def vid_media_unmount(self):
          """Operation to unmount the media partition"""
          lib = self.gethprestchifhandle()
          lib.vid_media_unmount.argtypes = []
          lib.vid_media_unmount.restype = POINTER(c_ubyte)
  
          ptr = lib.vid_media_unmount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def gaius_media_unmount(self):
          """Operation to unmount the media partition"""
          lib = self.gethprestchifhandle()
          lib.gaius_media_unmount.argtypes = []
          lib.gaius_media_unmount.restype = POINTER(c_ubyte)
  
          ptr = lib.gaius_media_unmount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def absr_media_unmount(self):
          """Operation to unmount the media partition"""
          lib = self.gethprestchifhandle()
          lib.absaroka_media_unmount.argtypes = []
          lib.absaroka_media_unmount.restype = POINTER(c_ubyte)
  
          ptr = lib.absaroka_media_unmount()
          data = ptr[:lib.size_of_embeddedMediaRequest()]
          data = bytearray(data)
  
          resp = self._send_receive_raw(data)
  
          errorcode = resp[12]
          if not (errorcode == BlobReturnCodes.SUCCESS or errorcode == BlobReturnCodes.NOTMODIFIED):
              raise HpIloError(errorcode)
  
          self.unloadchifhandle(lib)
  
          return resp
  
      def _send_receive_raw(self, indata):
          """Send and receive raw function for blob operations
  
          :param indata: The data to be sent to blob operation.
          :type indata: str.
  
          """
          excp = None
          for _ in range(0, 3): # channel loop for iLO
              try:
                  resp = self.channel.send_receive_raw(indata, 10)
                  return resp
              except Exception as exp:
                  self.channel.close()
                  lib = self.gethprestchifhandle()
                  self.channel = HpIlo(dll=lib)
                  excp = exp
          if excp:
              raise excp
  
      @staticmethod
      def gethprestchifhandle():
          """Multi platform handle for chif hprest library"""
          excp = None
          libhandle = None
          libnames = ["ilorest_chif.dll", "hprest_chif.dll"] if os.name == \
                      'nt' else ["ilorest_chif_dev.so", "hprest_chif_dev.so", \
                                          "ilorest_chif.so", "hprest_chif.so"]
          for libname in libnames:
              try:
                  libpath = BlobStore2.checkincurrdirectory(libname)
                  libhandle = cdll.LoadLibrary(libpath)
                  if libhandle:
                      break
              except Exception as exp:
                  excp = exp
  
          if libhandle:
              BlobStore2.setglobalhprestchifrandnumber(libhandle)
              return libhandle
          raise ChifDllMissingError(excp)
  
      @staticmethod
      def setglobalhprestchifrandnumber(libbhndl):
          """Set the random number for the chif handle
          :param libbhndl: The library handle provided by loading the chif library.
          :type libbhndl: library handle.
          """
          rndval = random.randint(1, 65535)
          libbhndl.updaterandval.argtypes = [c_ushort]
          libbhndl.updaterandval(rndval)
  
      @staticmethod
      def initializecreds(username=None, password=None):
          """Get chif ready to use high security
          :param username: The username to login.
          :type username: str.
          :param password: The password to login.
          :type password: str.
          """
          #TODO: initialize credentials for certificate
          dll = BlobStore2.gethprestchifhandle()
          if LOGGER.isEnabledFor(logging.DEBUG):
              dll.enabledebugoutput()
          dll.ChifInitialize(None)
          if dll.ChifIsSecurityRequired() > 0:
              if not username or not password:
                  return False
              dll.initiate_credentials.argtypes = [c_char_p, c_char_p]
              dll.initiate_credentials.restype = POINTER(c_ubyte)
  
              usernew = create_string_buffer(username.encode('utf-8'))
              passnew = create_string_buffer(password.encode('utf-8'))
  
              dll.initiate_credentials(usernew, passnew)
              credreturn = dll.ChifVerifyCredentials()
              if not credreturn == BlobReturnCodes.SUCCESS:
                  if credreturn == hpiloreturncodes.CHIFERR_AccessDenied:
                      raise Blob2SecurityError()
                  else:
                      raise HpIloInitialError("Error %s occurred while trying " \
                                          "to open a channel to iLO" % credreturn)
          else:
              #so we don't have extra overhead if we don't have to
              dll.ChifDisableSecurity()
          BlobStore2.unloadchifhandle(dll)
  
          return True
  
      @staticmethod
      def checkincurrdirectory(libname):
          """Check if the library is present in current directory.
          :param libname: The name of the library to search for.
          :type libname: str."""
          libpath = libname
  
          if os.path.isfile(os.path.join(os.path.split(sys.executable)[0], libpath)):
              libpath = os.path.join(os.path.split(sys.executable)[0], libpath)
          elif os.path.isfile(os.path.join(os.getcwd(), libpath)):
              libpath = os.path.join(os.getcwd(), libpath)
          elif os.environ.get("LD_LIBRARY_PATH"):
              paths = os.getenv("LD_LIBRARY_PATH", libpath).split(';')
              libpath = [os.path.join(pat, libname) for pat in paths if \
                                                          os.path.isfile(os.path.join(pat, libname))]
              libpath = libpath[0] if libpath else libname
  
          return libpath
  
      @staticmethod
      def unloadchifhandle(lib):
          """Release a handle on the chif iLOrest library
  
          :param lib: The library handle provided by loading the chif library.
          :type lib: library handle.
  
          """
          try:
              libhandle = lib._handle
              if os.name == 'nt':
                  windll.kernel32.FreeLibrary(None, handle=libhandle)
              else:
                  dlclose(libhandle)
          except Exception:
              pass
  