Add a high-level async function to read the export list
[deb_libnfs.git] / lib / libnfs.c
index e4a19a853d52e52a0ed40074790179237e887275..4b63a704ec9faf911bf5d1d407a7d61fd1bee240 100644 (file)
@@ -18,7 +18,9 @@
  * High level api to nfs filesystems
  */
 
+#define _GNU_SOURCE
 #include <stdio.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
 #include "libnfs-raw.h"
 #include "libnfs-raw-mount.h"
 #include "libnfs-raw-nfs.h"
+#include "libnfs-private.h"
+
+struct nfsdir {
+       struct nfsdirent *entries;
+       struct nfsdirent *current;
+};
 
 struct nfsfh {
        struct nfs_fh3 fh;
@@ -40,9 +48,13 @@ struct nfsfh {
        off_t offset;
 };
 
-struct nfsdir {
-       struct nfsdirent *entries;
-       struct nfsdirent *current;
+struct nfs_context {
+       struct rpc_context *rpc;
+       char *server;
+       char *export;
+       struct nfs_fh3 rootfh;
+       size_t readmax;
+       size_t writemax;
 };
 
 void nfs_free_nfsdir(struct nfsdir *nfsdir)
@@ -58,15 +70,6 @@ void nfs_free_nfsdir(struct nfsdir *nfsdir)
        free(nfsdir);
 }
 
-struct nfs_context {
-       struct rpc_context *rpc;
-       char *server;
-       char *export;
-       struct nfs_fh3 rootfh;
-       size_t readmax;
-       size_t writemax;
-};
-
 struct nfs_cb_data;
 typedef int (*continue_func)(struct nfs_context *nfs, struct nfs_cb_data *data);
 
@@ -855,7 +858,7 @@ static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command
                        data->error = 1;
                } else {
                        memcpy(&data->buffer[mdata->offset], res->READ3res_u.resok.data.data_val, res->READ3res_u.resok.count);
-                       if (data->max_offset < mdata->offset + res->READ3res_u.resok.count) {
+                       if ((unsigned)data->max_offset < mdata->offset + res->READ3res_u.resok.count) {
                                data->max_offset = mdata->offset + res->READ3res_u.resok.count;
                        }
                }
@@ -2855,3 +2858,180 @@ size_t nfs_get_writemax(struct nfs_context *nfs)
 {
        return nfs->writemax;
 }
+
+void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
+{
+        va_list ap;
+       char *str;
+
+       if (nfs->rpc->error_string != NULL) {
+               free(nfs->rpc->error_string);
+       }
+        va_start(ap, error_string);
+       vasprintf(&str, error_string, ap);
+       nfs->rpc->error_string = str;
+        va_end(ap);
+}
+
+
+
+struct mount_cb_data {
+       rpc_cb cb;
+       void *private_data;
+       char *server;
+};
+
+static void free_mount_cb_data(struct mount_cb_data *data)
+{
+       if (data->server != NULL) {
+               free(data->server);
+               data->server = NULL;
+       }
+
+       free(data);
+}
+
+static void mount_export_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       data->cb(rpc, 0, command_data, data->private_data);
+       if (rpc_disconnect(rpc, "normal disconnect") != 0) {
+               rpc_set_error(rpc, "Failed to disconnect\n");
+       }
+       free_mount_cb_data(data);
+}
+
+static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_mount_export_async(rpc, mount_export_5_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+       uint32_t mount_port;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       mount_port = *(uint32_t *)command_data;
+       if (mount_port == 0) {
+               rpc_set_error(rpc, "RPC error. Mount program is not available");
+               data->cb(rpc, -ENOENT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       rpc_disconnect(rpc, "normal disconnect");
+       if (rpc_connect_async(rpc, data->server, mount_port, mount_export_4_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, mount_export_3_cb, private_data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_pmap_null_async(rpc, mount_export_2_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
+{
+       struct mount_cb_data *data;
+
+       data = malloc(sizeof(struct mount_cb_data));
+       if (data == NULL) {
+               return -1;
+       }
+       bzero(data, sizeof(struct mount_cb_data));
+       data->cb           = cb;
+       data->private_data = private_data;
+       data->server       = strdup(server);
+       if (data->server == NULL) {
+               free_mount_cb_data(data);
+               return -1;
+       }       
+       if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
+               free_mount_cb_data(data);
+               return -1;
+       }
+
+       return 0;
+}
+