From 1e0ea4981981bb203eedcfd101ab55d533a83633 Mon Sep 17 00:00:00 2001 From: Kai Storbeck Date: Wed, 11 Feb 2015 19:56:41 +0100 Subject: [PATCH] Return a []byte pointing to the original C array This was taken from an example on Go's own wiki (cgo page). --- rados/conn.go | 22 +++++++++++++++------- rados/rados_test.go | 8 ++++---- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/rados/conn.go b/rados/conn.go index 7fb557a..f8e9984 100644 --- a/rados/conn.go +++ b/rados/conn.go @@ -7,6 +7,7 @@ import "C" import "unsafe" import "bytes" +import "reflect" // ClusterStat represents Ceph cluster statistics. type ClusterStat struct { @@ -261,7 +262,7 @@ func (c *Conn) DeletePool(name string) error { } // MonCommand sends a command to one of the monitors -func (c *Conn) MonCommand(args []byte) (buffer, info string, err error) { +func (c *Conn) MonCommand(args []byte) (buffer []byte, info string, err error) { argv := make([]*C.char, len(args)) for i, _ := range args { argv[i] = (*C.char)(unsafe.Pointer(&args[i])) @@ -283,19 +284,26 @@ func (c *Conn) MonCommand(args []byte) (buffer, info string, err error) { &outs, // report largenumber &outslen) - if outbuflen > 0 { - buffer = C.GoStringN(outbuf, C.int(outbuflen)) - // C.rados_buffer_free(outbuf) - C.free(unsafe.Pointer(outbuf)) - } if outslen > 0 { info = C.GoStringN(outs, C.int(outslen)) //C.rados_buffer_free(outs) C.free(unsafe.Pointer(outs)) } + if outbuflen > 0 { + length := int(outbuflen) + hdr := reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(outbuf)), + Len: length, + Cap: length, + } + // now goSlice is a Go slice backed by the C array + buffer = *(*[]byte)(unsafe.Pointer(&hdr)) + } if ret != 0 { err = RadosError(int(ret)) - return // info might contain hints as to why the error happened + return nil, info, err + // info might contain hints as to why the error happened } + return } diff --git a/rados/rados_test.go b/rados/rados_test.go index fe6e49e..2c404fa 100644 --- a/rados/rados_test.go +++ b/rados/rados_test.go @@ -382,15 +382,15 @@ func TestMonCommand(t *testing.T) { conn.Connect() command, err := json.Marshal(map[string]string{"prefix": "df", "format": "json"}) + assert.NoError(t, err) + buf, info, err := conn.MonCommand(command) assert.NoError(t, err) + assert.Equal(t, info, "") var message map[string]interface{} - err = json.Unmarshal([]byte(buf), &message) + err = json.Unmarshal(buf, &message) assert.NoError(t, err) - - fmt.Println("Use ", info) - os.Stdout.Write([]byte(buf)) } func TestObjectIterator(t *testing.T) {