For the current set of examples this doesn't matter.  This also adds
another example where we use the Connection to store data, just to
check that actually works.

Thanks: James @ purpleidea, Dan Berrangé
---
 plugins/golang/nbdkit-golang-plugin.pod       |  10 +-
 plugins/golang/Makefile.am                    |   9 +
 plugins/golang/examples/disk/disk.go          | 168 ++++++++++++++++++
 .../golang/examples/dump-plugin/dumpplugin.go |   8 +-
 plugins/golang/examples/minimal/minimal.go    |   6 +-
 plugins/golang/examples/ramdisk/ramdisk.go    |  18 +-
 .../src/libguestfs.org/nbdkit/nbdkit.go       |  42 ++---
 plugins/golang/test/test.go                   |  14 +-
 8 files changed, 226 insertions(+), 49 deletions(-)

diff --git a/plugins/golang/nbdkit-golang-plugin.pod 
b/plugins/golang/nbdkit-golang-plugin.pod
index b15bb481..90732289 100644
--- a/plugins/golang/nbdkit-golang-plugin.pod
+++ b/plugins/golang/nbdkit-golang-plugin.pod
@@ -62,16 +62,16 @@ C<GetSize> and C<PRead>.  What connects the two is the 
C<Open>
 callback which is called when the client has connected and where you
 should return a new instance of your connection struct.  For example:
 
- func (p MyPlugin) Load() {
+ func (p *MyPlugin) Load() {
          // global callback used for initializing the plugin
  }
  
- func (p MyPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+ func (p *MyPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
          // new client has connected
          return &MyConnection{}, nil
  }
  
- func (c MyConnection) GetSize() (uint64, error) {
+ func (c *MyConnection) GetSize() (uint64, error) {
          // called per-client
          return virtual_size, nil
  }
@@ -106,11 +106,11 @@ unless you also implement a C<CanWrite> callback that 
returns true.
 The same applies to C<Flush> (C<CanFlush>), C<Trim> (C<CanTrim>) and
 C<Zero> (C<CanZero>).
 
- func (c MyConnection) CanWrite() (bool, error) {
+ func (c *MyConnection) CanWrite() (bool, error) {
          return true, nil
  }
  
- func (c MyConnection) PWrite(buf []byte, offset uint64,
+ func (c *MyConnection) PWrite(buf []byte, offset uint64,
         flags uint32) error {
          // ...
 }
diff --git a/plugins/golang/Makefile.am b/plugins/golang/Makefile.am
index 74ad4a72..91711724 100644
--- a/plugins/golang/Makefile.am
+++ b/plugins/golang/Makefile.am
@@ -42,6 +42,7 @@ EXTRA_DIST = \
        $(plugin_sources) \
        config-test.go \
        dump-plugin-examples.sh \
+       examples/disk/disk.go \
        examples/dump-plugin/dumpplugin.go \
        examples/minimal/minimal.go \
        examples/ramdisk/ramdisk.go \
@@ -58,11 +59,19 @@ if HAVE_GOLANG
 
 # Examples.
 noinst_DATA = \
+       examples/disk/nbdkit-godisk-plugin.so \
        examples/dump-plugin/nbdkit-godump-plugin.so \
        examples/minimal/nbdkit-gominimal-plugin.so \
        examples/ramdisk/nbdkit-goramdisk-plugin.so \
        $(NULL)
 
+examples/disk/nbdkit-godisk-plugin.so: \
+           $(plugin_sources) examples/disk/disk.go
+       cd examples/disk && \
+       
PKG_CONFIG_PATH="$(abs_top_builddir)/server/local$${PKG_CONFIG_PATH:+:$$PKG_CONFIG_PATH}"
 \
+       GOPATH="$(abs_builddir)" \
+       $(GOLANG) build -o nbdkit-godisk-plugin.so -buildmode=c-shared
+
 examples/dump-plugin/nbdkit-godump-plugin.so: \
            $(plugin_sources) examples/dump-plugin/dumpplugin.go
        cd examples/dump-plugin && \
diff --git a/plugins/golang/examples/disk/disk.go 
b/plugins/golang/examples/disk/disk.go
new file mode 100644
index 00000000..37f449e0
--- /dev/null
+++ b/plugins/golang/examples/disk/disk.go
@@ -0,0 +1,168 @@
+/* Example plugin.
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+package main
+
+import (
+       "C"
+       "io/ioutil"
+       "libguestfs.org/nbdkit"
+       "os"
+       "strconv"
+       "unsafe"
+)
+
+var pluginName = "disk"
+
+type DiskPlugin struct {
+       nbdkit.Plugin
+}
+
+type DiskConnection struct {
+       nbdkit.Connection
+       fd *os.File
+}
+
+var size uint64
+var size_set = false
+
+func (p *DiskPlugin) Config(key string, value string) error {
+       if key == "size" {
+               var err error
+               size, err = strconv.ParseUint(value, 0, 64)
+               if err != nil {
+                       return err
+               }
+               size_set = true
+               return nil
+       } else {
+               return nbdkit.PluginError{Errmsg: "unknown parameter"}
+       }
+}
+
+func (p *DiskPlugin) ConfigComplete() error {
+       if !size_set {
+               return nbdkit.PluginError{Errmsg: "size parameter is required"}
+       }
+       return nil
+}
+
+func (p *DiskPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+       // Open a temporary file.
+       fd, err := ioutil.TempFile("/var/tmp", "nbdkitdisk")
+       if err != nil {
+               return nil, err
+       }
+       os.Remove(fd.Name())
+
+       // Truncate it to the right size.
+       err = fd.Truncate(int64(size))
+       if err != nil {
+               return nil, err
+       }
+
+       // Store the file descriptor of the temporary file in the
+       // Connection struct.
+       return &DiskConnection{fd: fd}, nil
+}
+
+func (c *DiskConnection) Close() {
+       c.fd.Close()
+}
+
+func (c *DiskConnection) GetSize() (uint64, error) {
+       // Return the size of the disk.  We could just return the
+       // global "size" here, but make the example more interesting.
+       info, err := c.fd.Stat()
+       if err != nil {
+               return 0, err
+       }
+       return uint64(info.Size()), nil
+}
+
+// Multi-conn is NOT safe because each client sees a different disk.
+func (c *DiskConnection) CanMultiConn() (bool, error) {
+       return false, nil
+}
+
+func (c *DiskConnection) PRead(buf []byte, offset uint64,
+       flags uint32) error {
+       n, err := c.fd.ReadAt(buf, int64(offset))
+       if err != nil {
+               return err
+       }
+       // NBD requests must always read/write the whole requested
+       // amount, or else fail.  Actually we should loop here (XXX).
+       if n != len(buf) {
+               return nbdkit.PluginError{Errmsg: "short read"}
+       }
+       return nil
+}
+
+// Note that CanWrite is required in golang plugins, otherwise PWrite
+// will never be called.
+func (c *DiskConnection) CanWrite() (bool, error) {
+       return true, nil
+}
+
+func (c *DiskConnection) PWrite(buf []byte, offset uint64,
+       flags uint32) error {
+       n, err := c.fd.WriteAt(buf, int64(offset))
+       if err != nil {
+               return err
+       }
+       // NBD requests must always read/write the whole requested
+       // amount, or else fail.  Actually we should loop here (XXX).
+       if n != len(buf) {
+               return nbdkit.PluginError{Errmsg: "short write"}
+       }
+       return nil
+}
+
+//----------------------------------------------------------------------
+//
+// The boilerplate below this line is required by all golang plugins,
+// as well as importing "C" and "unsafe" modules at the top of the
+// file.
+
+//export plugin_init
+func plugin_init() unsafe.Pointer {
+       // If your plugin needs to do any initialization, you can
+       // either put it here or implement a Load() method.
+       // ...
+
+       // Then you must call the following function.
+       return nbdkit.PluginInitialize(pluginName, &DiskPlugin{})
+}
+
+// This is never(?) called, but must exist.
+func main() {}
diff --git a/plugins/golang/examples/dump-plugin/dumpplugin.go 
b/plugins/golang/examples/dump-plugin/dumpplugin.go
index 518be078..d30ec3f1 100644
--- a/plugins/golang/examples/dump-plugin/dumpplugin.go
+++ b/plugins/golang/examples/dump-plugin/dumpplugin.go
@@ -51,19 +51,19 @@ type DumpConnection struct {
 
 var size uint64 = 1024 * 1024
 
-func (p DumpPlugin) DumpPlugin() {
+func (p *DumpPlugin) DumpPlugin() {
        fmt.Println("golang_dump_plugin=1")
 }
 
-func (p DumpPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+func (p *DumpPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
        return &DumpConnection{}, nil
 }
 
-func (c DumpConnection) GetSize() (uint64, error) {
+func (c *DumpConnection) GetSize() (uint64, error) {
        return size, nil
 }
 
-func (c DumpConnection) PRead(buf []byte, offset uint64,
+func (c *DumpConnection) PRead(buf []byte, offset uint64,
        flags uint32) error {
        for i := 0; i < len(buf); i++ {
                buf[i] = 0
diff --git a/plugins/golang/examples/minimal/minimal.go 
b/plugins/golang/examples/minimal/minimal.go
index e010bfcb..0f862889 100644
--- a/plugins/golang/examples/minimal/minimal.go
+++ b/plugins/golang/examples/minimal/minimal.go
@@ -50,15 +50,15 @@ type MinimalConnection struct {
 
 var size uint64 = 1024 * 1024
 
-func (p MinimalPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) 
{
+func (p *MinimalPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, 
error) {
        return &MinimalConnection{}, nil
 }
 
-func (c MinimalConnection) GetSize() (uint64, error) {
+func (c *MinimalConnection) GetSize() (uint64, error) {
        return size, nil
 }
 
-func (c MinimalConnection) PRead(buf []byte, offset uint64,
+func (c *MinimalConnection) PRead(buf []byte, offset uint64,
        flags uint32) error {
        for i := 0; i < len(buf); i++ {
                buf[i] = 0
diff --git a/plugins/golang/examples/ramdisk/ramdisk.go 
b/plugins/golang/examples/ramdisk/ramdisk.go
index c848f575..78cb1f4c 100644
--- a/plugins/golang/examples/ramdisk/ramdisk.go
+++ b/plugins/golang/examples/ramdisk/ramdisk.go
@@ -53,7 +53,7 @@ var size uint64
 var size_set = false
 var disk []byte
 
-func (p RAMDiskPlugin) Config(key string, value string) error {
+func (p *RAMDiskPlugin) Config(key string, value string) error {
        if key == "size" {
                var err error
                size, err = strconv.ParseUint(value, 0, 64)
@@ -67,33 +67,33 @@ func (p RAMDiskPlugin) Config(key string, value string) 
error {
        }
 }
 
-func (p RAMDiskPlugin) ConfigComplete() error {
+func (p *RAMDiskPlugin) ConfigComplete() error {
        if !size_set {
                return nbdkit.PluginError{Errmsg: "size parameter is required"}
        }
        return nil
 }
 
-func (p RAMDiskPlugin) GetReady() error {
+func (p *RAMDiskPlugin) GetReady() error {
        // Allocate the RAM disk.
        disk = make([]byte, size)
        return nil
 }
 
-func (p RAMDiskPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) 
{
+func (p *RAMDiskPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, 
error) {
        return &RAMDiskConnection{}, nil
 }
 
-func (c RAMDiskConnection) GetSize() (uint64, error) {
+func (c *RAMDiskConnection) GetSize() (uint64, error) {
        return size, nil
 }
 
 // Clients are allowed to make multiple connections safely.
-func (c RAMDiskConnection) CanMultiConn() (bool, error) {
+func (c *RAMDiskConnection) CanMultiConn() (bool, error) {
        return true, nil
 }
 
-func (c RAMDiskConnection) PRead(buf []byte, offset uint64,
+func (c *RAMDiskConnection) PRead(buf []byte, offset uint64,
        flags uint32) error {
        copy(buf, disk[offset:int(offset)+len(buf)])
        return nil
@@ -101,11 +101,11 @@ func (c RAMDiskConnection) PRead(buf []byte, offset 
uint64,
 
 // Note that CanWrite is required in golang plugins, otherwise PWrite
 // will never be called.
-func (c RAMDiskConnection) CanWrite() (bool, error) {
+func (c *RAMDiskConnection) CanWrite() (bool, error) {
        return true, nil
 }
 
-func (c RAMDiskConnection) PWrite(buf []byte, offset uint64,
+func (c *RAMDiskConnection) PWrite(buf []byte, offset uint64,
        flags uint32) error {
        copy(disk[offset:int(offset)+len(buf)], buf)
        return nil
diff --git a/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go 
b/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go
index 155034d9..8e9e9bbd 100644
--- a/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go
+++ b/plugins/golang/src/libguestfs.org/nbdkit/nbdkit.go
@@ -145,83 +145,83 @@ type ConnectionInterface interface {
 type Plugin struct{}
 type Connection struct{}
 
-func (p Plugin) Load() {
+func (p *Plugin) Load() {
 }
 
-func (p Plugin) Unload() {
+func (p *Plugin) Unload() {
 }
 
-func (p Plugin) DumpPlugin() {
+func (p *Plugin) DumpPlugin() {
 }
 
-func (p Plugin) Config(key string, value string) error {
+func (p *Plugin) Config(key string, value string) error {
        return nil
 }
 
-func (p Plugin) ConfigComplete() error {
+func (p *Plugin) ConfigComplete() error {
        return nil
 }
 
-func (p Plugin) GetReady() error {
+func (p *Plugin) GetReady() error {
        return nil
 }
 
-func (p Plugin) PreConnect(readonly bool) error {
+func (p *Plugin) PreConnect(readonly bool) error {
        return nil
 }
 
-func (p Plugin) Open(readonly bool) (ConnectionInterface, error) {
+func (p *Plugin) Open(readonly bool) (ConnectionInterface, error) {
        panic("plugin must implement Open()")
 }
 
-func (c Connection) Close() {
+func (c *Connection) Close() {
 }
 
-func (c Connection) GetSize() (uint64, error) {
+func (c *Connection) GetSize() (uint64, error) {
        panic("plugin must implement GetSize()")
 }
 
-func (c Connection) CanWrite() (bool, error) {
+func (c *Connection) CanWrite() (bool, error) {
        return false, nil
 }
 
-func (c Connection) CanFlush() (bool, error) {
+func (c *Connection) CanFlush() (bool, error) {
        return false, nil
 }
 
-func (c Connection) IsRotational() (bool, error) {
+func (c *Connection) IsRotational() (bool, error) {
        return false, nil
 }
 
-func (c Connection) CanTrim() (bool, error) {
+func (c *Connection) CanTrim() (bool, error) {
        return false, nil
 }
 
-func (c Connection) CanZero() (bool, error) {
+func (c *Connection) CanZero() (bool, error) {
        return false, nil
 }
 
-func (c Connection) CanMultiConn() (bool, error) {
+func (c *Connection) CanMultiConn() (bool, error) {
        return false, nil
 }
 
-func (c Connection) PRead(buf []byte, offset uint64, flags uint32) error {
+func (c *Connection) PRead(buf []byte, offset uint64, flags uint32) error {
        panic("plugin must implement PRead()")
 }
 
-func (c Connection) PWrite(buf []byte, offset uint64, flags uint32) error {
+func (c *Connection) PWrite(buf []byte, offset uint64, flags uint32) error {
        panic("plugin CanWrite returns true, but no PWrite() function")
 }
 
-func (c Connection) Flush(flags uint32) error {
+func (c *Connection) Flush(flags uint32) error {
        panic("plugin CanFlush returns true, but no Flush() function")
 }
 
-func (c Connection) Trim(count uint32, offset uint64, flags uint32) error {
+func (c *Connection) Trim(count uint32, offset uint64, flags uint32) error {
        panic("plugin CanTrim returns true, but no Trim() function")
 }
 
-func (c Connection) Zero(count uint32, offset uint64, flags uint32) error {
+func (c *Connection) Zero(count uint32, offset uint64, flags uint32) error {
        panic("plugin CanZero returns true, but no Zero() function")
 }
 
diff --git a/plugins/golang/test/test.go b/plugins/golang/test/test.go
index 7186ffa8..e585a971 100644
--- a/plugins/golang/test/test.go
+++ b/plugins/golang/test/test.go
@@ -52,15 +52,15 @@ type TestConnection struct {
 var size uint64
 var size_set = false
 
-func (p TestPlugin) Load() {
+func (p *TestPlugin) Load() {
        nbdkit.Debug("golang code running in the .load callback")
 }
 
-func (p TestPlugin) Unload() {
+func (p *TestPlugin) Unload() {
        nbdkit.Debug("golang code running in the .unload callback")
 }
 
-func (p TestPlugin) Config(key string, value string) error {
+func (p *TestPlugin) Config(key string, value string) error {
        if key == "size" {
                var err error
                size, err = strconv.ParseUint(value, 0, 64)
@@ -74,24 +74,24 @@ func (p TestPlugin) Config(key string, value string) error {
        }
 }
 
-func (p TestPlugin) ConfigComplete() error {
+func (p *TestPlugin) ConfigComplete() error {
        if !size_set {
                return nbdkit.PluginError{Errmsg: "size parameter is required"}
        }
        return nil
 }
 
-func (p TestPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
+func (p *TestPlugin) Open(readonly bool) (nbdkit.ConnectionInterface, error) {
        nbdkit.Debug("golang code running in the .open callback")
        return &TestConnection{}, nil
 }
 
-func (c TestConnection) GetSize() (uint64, error) {
+func (c *TestConnection) GetSize() (uint64, error) {
        nbdkit.Debug("golang code running in the .get_size callback")
        return size, nil
 }
 
-func (c TestConnection) PRead(buf []byte, offset uint64, flags uint32) error {
+func (c *TestConnection) PRead(buf []byte, offset uint64, flags uint32) error {
        nbdkit.Debug("golang code running in the .pread callback")
        for i := 0; i < len(buf); i++ {
                buf[i] = 0
-- 
2.25.0

_______________________________________________
Libguestfs mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/libguestfs

Reply via email to