#include "libnfs-raw.h"
#include "libnfs-raw-mount.h"
#include "libnfs-raw-nfs.h"
+#include "libnfs-raw-portmap.h"
#include "libnfs-private.h"
struct nfsdir {
static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
{
struct rpc_cb_data *data = private_data;
- uint32_t rpc_port;
+ struct pmap3_string_result *gar;
+ uint32_t rpc_port = 0;
+ unsigned char *ptr;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
return;
}
- rpc_port = *(uint32_t *)command_data;
+ switch (rpc->s.ss_family) {
+ case AF_INET:
+ rpc_port = *(uint32_t *)command_data;
+ break;
+ case AF_INET6:
+ /* ouch. portmapper and ipv6 are not great */
+ gar = command_data;
+ if (gar->addr == NULL) {
+ break;
+ }
+ ptr = strrchr(gar->addr, '.');
+ if (ptr == NULL) {
+ break;
+ }
+ rpc_port = atoi(ptr + 1);
+ *ptr = 0;
+ ptr = strrchr(gar->addr, '.');
+ if (ptr == NULL) {
+ break;
+ }
+ rpc_port += 256 * atoi(ptr + 1);
+ break;
+ }
if (rpc_port == 0) {
rpc_set_error(rpc, "RPC error. Program is not available on %s", data->server);
data->cb(rpc, RPC_STATUS_ERROR, rpc_get_error(rpc), data->private_data);
static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
{
struct rpc_cb_data *data = private_data;
+ struct pmap3_mapping map;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
return;
}
- if (rpc_pmap2_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
- data->cb(rpc, status, command_data, data->private_data);
- free_rpc_cb_data(data);
- return;
+ switch (rpc->s.ss_family) {
+ case AF_INET:
+ if (rpc_pmap2_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
+ data->cb(rpc, status, command_data, data->private_data);
+ free_rpc_cb_data(data);
+ return;
+ }
+ break;
+ case AF_INET6:
+ map.prog=data->program;
+ map.vers=data->version;
+ map.netid="";
+ map.addr="";
+ map.owner="";
+ if (rpc_pmap3_getaddr_async(rpc, &map, rpc_connect_program_3_cb, private_data) != 0) {
+ data->cb(rpc, status, command_data, data->private_data);
+ free_rpc_cb_data(data);
+ return;
+ }
+ break;
}
}
return;
}
- if (rpc_pmap2_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
- data->cb(rpc, status, command_data, data->private_data);
- free_rpc_cb_data(data);
- return;
+ switch (rpc->s.ss_family) {
+ case AF_INET:
+ if (rpc_pmap2_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
+ data->cb(rpc, status, command_data, data->private_data);
+ free_rpc_cb_data(data);
+ return;
+ }
+ break;
+ case AF_INET6:
+ if (rpc_pmap3_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
+ data->cb(rpc, status, command_data, data->private_data);
+ free_rpc_cb_data(data);
+ return;
+ }
+ break;
}
}
/* /$ -> \0 */
len = strlen(path);
- if (len >= 1) {
+ if (len > 1) {
if (path[len - 1] == '/') {
path[len - 1] = '\0';
len--;
/* steal the dirhandle */
nfsdir->current = nfsdir->entries;
- rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
- rdpe_cb_data->getattrcount = 0;
- rdpe_cb_data->status = RPC_STATUS_SUCCESS;
- rdpe_cb_data->data = data;
- for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
- struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
- LOOKUP3args args;
-
- rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
- rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
- rdpe_lookup_cb_data->nfsdirent = nfsdirent;
-
- memset(&args, 0, sizeof(LOOKUP3args));
- args.what.dir = data->fh;
- args.what.name = nfsdirent->name;
-
- if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
- rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
-
- /* if we have already commands in flight, we cant just stop, we have to wait for the
- * commands in flight to complete
- */
- if (rdpe_cb_data->getattrcount > 0) {
+ if (nfsdir->entries) {
+ rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
+ rdpe_cb_data->getattrcount = 0;
+ rdpe_cb_data->status = RPC_STATUS_SUCCESS;
+ rdpe_cb_data->data = data;
+ for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
+ struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
+ LOOKUP3args args;
+
+ rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
+ rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
+ rdpe_lookup_cb_data->nfsdirent = nfsdirent;
+
+ memset(&args, 0, sizeof(LOOKUP3args));
+ args.what.dir = data->fh;
+ args.what.name = nfsdirent->name;
+
+ if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
+
+ /* if we have already commands in flight, we cant just stop, we have to wait for the
+ * commands in flight to complete
+ */
+ if (rdpe_cb_data->getattrcount > 0) {
+ nfs_free_nfsdir(nfsdir);
+ data->continue_data = NULL;
+ free_nfs_cb_data(data);
+ rdpe_cb_data->status = RPC_STATUS_ERROR;
+ free(rdpe_lookup_cb_data);
+ return;
+ }
+
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
nfs_free_nfsdir(nfsdir);
data->continue_data = NULL;
free_nfs_cb_data(data);
- rdpe_cb_data->status = RPC_STATUS_ERROR;
free(rdpe_lookup_cb_data);
+ free(rdpe_cb_data);
return;
}
-
- data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
- nfs_free_nfsdir(nfsdir);
- data->continue_data = NULL;
- free_nfs_cb_data(data);
- free(rdpe_lookup_cb_data);
- free(rdpe_cb_data);
- return;
+ rdpe_cb_data->getattrcount++;
}
- rdpe_cb_data->getattrcount++;
}
}
}
}
-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;
-
- assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
- 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;
-
- assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
- 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_pmap2_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, 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;
-
- assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
- /* Dont want any more callbacks even if the socket is closed */
- rpc->connect_cb = NULL;
-
- 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_pmap2_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;
free_mount_cb_data(data);
return -1;
}
- if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
+ if (rpc_connect_program_async(rpc, data->server, MOUNT_PROGRAM, MOUNT_V3, mount_export_4_cb, data) != 0) {
+ rpc_set_error(rpc, "Failed to start connection");
free_mount_cb_data(data);
return -1;
}