mirror of
https://github.com/ceph/ceph
synced 2025-03-06 08:20:12 +00:00
pybind: Add decode_cstr helper function
This function attempts to decode a C-style string into a Python Unicode string. It accepts an optional "size" parameter for the string length, otherwise it is assumed that the string is NUL-terminated. If the pointer is NULL, then this function returns None. Signed-off-by: David Coles <dcoles@gaikai.com>
This commit is contained in:
parent
801ea73a69
commit
0b3435f114
src
@ -278,6 +278,7 @@ def cstr(val, encoding="utf-8"):
|
||||
Create a C-style string from a Python string
|
||||
|
||||
:param str val: Python string
|
||||
:param encoding: Encoding to use
|
||||
:rtype: c_char_p
|
||||
"""
|
||||
if val is None:
|
||||
@ -290,6 +291,24 @@ def cstr(val, encoding="utf-8"):
|
||||
return c_char_p(val.encode(encoding))
|
||||
|
||||
|
||||
def decode_cstr(addr, size=-1, encoding="utf-8"):
|
||||
"""
|
||||
Decode a C-style string into a Python string.
|
||||
|
||||
Return None if a the C string is a NULL pointer.
|
||||
|
||||
:param c_char_p addr: C-style string
|
||||
:param int: String size (assume NUL-terminated if size is -1)
|
||||
:param encoding: Encoding to use
|
||||
:rtype: str or None
|
||||
"""
|
||||
if not addr:
|
||||
# NULL pointer
|
||||
return None
|
||||
|
||||
return ctypes.string_at(addr, size).decode(encoding)
|
||||
|
||||
|
||||
class Rados(object):
|
||||
"""librados python wrapper"""
|
||||
def require_state(self, *args):
|
||||
@ -411,7 +430,7 @@ Rados object in state %s." % self.state)
|
||||
# cretargs was allocated with fixed length; collapse return
|
||||
# list to eliminate any missing args
|
||||
|
||||
retargs = [a for a in cretargs if a is not None]
|
||||
retargs = [decode_cstr(a) for a in cretargs if a is not None]
|
||||
self.parsed_args = args
|
||||
return retargs
|
||||
|
||||
@ -447,7 +466,7 @@ Rados object in state %s." % self.state)
|
||||
(self.cluster, cstr(option), ret_buf,
|
||||
c_size_t(length)))
|
||||
if (ret == 0):
|
||||
return ret_buf.value.decode("utf-8")
|
||||
return decode_cstr(ret_buf)
|
||||
elif (ret == -errno.ENAMETOOLONG):
|
||||
length = length * 2
|
||||
elif (ret == -errno.ENOENT):
|
||||
@ -501,7 +520,7 @@ Rados object in state %s." % self.state)
|
||||
|
||||
if ret != 0:
|
||||
raise make_ex(ret, "error calling ping_monitor")
|
||||
return my_outstr
|
||||
return decode_cstr(my_outstr)
|
||||
|
||||
def connect(self, timeout=0):
|
||||
"""
|
||||
@ -704,7 +723,7 @@ Rados object in state %s." % self.state)
|
||||
else:
|
||||
break
|
||||
|
||||
return [name for name in c_names.raw.decode("utf-8").split('\0') if len(name) > 0]
|
||||
return [decode_cstr(name) for name in c_names.raw.split(b'\0') if len(name) > 0]
|
||||
|
||||
def get_fsid(self):
|
||||
"""
|
||||
@ -771,7 +790,7 @@ Rados object in state %s." % self.state)
|
||||
|
||||
# copy returned memory (ctypes makes a copy, not a reference)
|
||||
my_outbuf = outbufp.contents[:(outbuflen.value)]
|
||||
my_outs = outsp.contents[:(outslen.value)]
|
||||
my_outs = decode_cstr(outsp.contents, outslen.value)
|
||||
|
||||
# free callee's allocations
|
||||
if outbuflen.value:
|
||||
@ -800,7 +819,7 @@ Rados object in state %s." % self.state)
|
||||
|
||||
# copy returned memory (ctypes makes a copy, not a reference)
|
||||
my_outbuf = outbufp.contents[:(outbuflen.value)]
|
||||
my_outs = outsp.contents[:(outslen.value)]
|
||||
my_outs = decode_cstr(outsp.contents, outslen.value)
|
||||
|
||||
# free callee's allocations
|
||||
if outbuflen.value:
|
||||
@ -829,7 +848,7 @@ Rados object in state %s." % self.state)
|
||||
|
||||
# copy returned memory (ctypes makes a copy, not a reference)
|
||||
my_outbuf = outbufp.contents[:(outbuflen.value)]
|
||||
my_outs = outsp.contents[:(outslen.value)]
|
||||
my_outs = decode_cstr(outsp.contents, outslen.value)
|
||||
|
||||
# free callee's allocations
|
||||
if outbuflen.value:
|
||||
@ -888,7 +907,7 @@ class OmapIterator(Iterator):
|
||||
raise make_ex(ret, "error iterating over the omap")
|
||||
if key_.value is None:
|
||||
raise StopIteration()
|
||||
key = key_.value.decode("utf-8")
|
||||
key = decode_cstr(key_)
|
||||
val = None
|
||||
if val_.value is not None:
|
||||
val = ctypes.string_at(val_, len_)
|
||||
@ -930,9 +949,9 @@ class ObjectIterator(Iterator):
|
||||
if ret < 0:
|
||||
raise StopIteration()
|
||||
|
||||
key = None if key_.value is None else key_.value.decode("utf-8")
|
||||
locator = None if locator_.value is None else locator_.value.decode("utf-8")
|
||||
nspace = None if nspace_.value is None else nspace_.value.decode("utf-8")
|
||||
key = decode_cstr(key_)
|
||||
locator = decode_cstr(locator_)
|
||||
nspace = decode_cstr(nspace_)
|
||||
return Object(self.ioctx, key, locator, nspace)
|
||||
|
||||
def __del__(self):
|
||||
@ -969,7 +988,7 @@ class XattrIterator(Iterator):
|
||||
in '%s'" % self.oid)
|
||||
if name_.value is None:
|
||||
raise StopIteration()
|
||||
name = ctypes.string_at(name_).decode("utf-8")
|
||||
name = decode_cstr(name_)
|
||||
val = ctypes.string_at(val_, len_)
|
||||
return (name, val)
|
||||
|
||||
@ -1025,7 +1044,7 @@ ioctx '%s'" % self.ioctx.name)
|
||||
elif (ret != -errno.ERANGE):
|
||||
raise make_ex(ret, "rados_snap_get_name error")
|
||||
name_len = name_len * 2
|
||||
snap = Snap(self.ioctx, name.value.decode("utf-8"), snap_id)
|
||||
snap = Snap(self.ioctx, decode_cstr(name), snap_id)
|
||||
self.cur_snap = self.cur_snap + 1
|
||||
return snap
|
||||
|
||||
|
@ -20,7 +20,7 @@ import ctypes
|
||||
import errno
|
||||
import sys
|
||||
|
||||
from rados import cstr
|
||||
from rados import cstr, decode_cstr
|
||||
|
||||
ANONYMOUS_AUID = 0xffffffffffffffff
|
||||
ADMIN_AUID = 0
|
||||
@ -343,7 +343,7 @@ class RBD(object):
|
||||
elif ret != -errno.ERANGE:
|
||||
raise make_ex(ret, 'error listing images')
|
||||
|
||||
return [name for name in c_names.raw.decode("utf-8").split('\0') if len(name) > 0]
|
||||
return [decode_cstr(name) for name in c_names.raw.split(b'\0') if len(name) > 0]
|
||||
|
||||
def remove(self, ioctx, name):
|
||||
"""
|
||||
@ -1025,7 +1025,7 @@ written." % (self.name, ret, length))
|
||||
cookies = [cookie.decode("utf-8") for cookie in c_cookies.raw[:cookies_size.value - 1].split(b'\0')]
|
||||
addrs = [addr.decode("utf-8") for addr in c_addrs.raw[:addrs_size.value - 1].split(b'\0')]
|
||||
return {
|
||||
'tag' : c_tag.value.decode("utf-8"),
|
||||
'tag' : decode_cstr(c_tag),
|
||||
'exclusive' : exclusive.value == 1,
|
||||
'lockers' : list(zip(clients, cookies, addrs)),
|
||||
}
|
||||
@ -1125,7 +1125,7 @@ class SnapIterator(Iterable):
|
||||
yield {
|
||||
'id' : self.snaps[i].id,
|
||||
'size' : self.snaps[i].size,
|
||||
'name' : self.snaps[i].name.decode("utf-8"),
|
||||
'name' : decode_cstr(self.snaps[i].name),
|
||||
}
|
||||
|
||||
def __del__(self):
|
||||
|
@ -660,6 +660,6 @@ class TestCommand(object):
|
||||
timeout=30)
|
||||
eq(ret, 0)
|
||||
assert len(err) > 0
|
||||
out = json.loads(err.decode("utf-8"))
|
||||
out = json.loads(err)
|
||||
eq(out['blocksize'], cmd['size'])
|
||||
eq(out['bytes_written'], cmd['count'])
|
||||
|
Loading…
Reference in New Issue
Block a user