X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Flibnfs.c;h=8d27a816b0fa079b6a28a090aa764a99767b08f1;hb=5e9910f0f0b2a1c71a08e910e7123efcadef46bf;hp=40b6a8dc18a1c2bd5bec7dc7c0c2ca6f6c5e23e6;hpb=1896d37bfaae78bfa0e6ee3e3fb19b0a92bb1adb;p=deb_libnfs.git diff --git a/lib/libnfs.c b/lib/libnfs.c index 40b6a8d..8d27a81 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -18,6 +18,7 @@ * High level api to nfs filesystems */ +#define _GNU_SOURCE #include #include #include @@ -645,6 +646,9 @@ static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command st.st_dev = -1; st.st_ino = res->GETATTR3res_u.resok.obj_attributes.fileid; st.st_mode = res->GETATTR3res_u.resok.obj_attributes.mode; + if (res->GETATTR3res_u.resok.obj_attributes.type == NF3DIR) { + st.st_mode |= S_IFDIR ; + } st.st_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink; st.st_uid = res->GETATTR3res_u.resok.obj_attributes.uid; st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid; @@ -855,10 +859,12 @@ static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command if (res->status != NFS3_OK) { rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status)); data->error = 1; - } else { - memcpy(&data->buffer[mdata->offset], res->READ3res_u.resok.data.data_val, 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; + } else { + if (res->READ3res_u.resok.count > 0) { + memcpy(&data->buffer[mdata->offset - data->start_offset], res->READ3res_u.resok.data.data_val, 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; + } } } } @@ -869,7 +875,6 @@ static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command return; } - if (data->error != 0) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -885,6 +890,7 @@ static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command data->nfsfh->offset = data->max_offset; data->cb(data->max_offset - data->start_offset, nfs, data->buffer, data->private_data); + free_nfs_cb_data(data); free(mdata); } @@ -920,6 +926,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, * reads and collect into a reassembly buffer. * we send all reads in parallell so that performance is still good. */ + data->max_offset = offset; data->start_offset = offset; data->buffer = malloc(count); @@ -947,7 +954,6 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, mdata->data = data; mdata->offset = offset; mdata->count = readcount; - if (rpc_nfs_read_async(nfs->rpc, nfs_pread_mcb, &nfsfh->fh, offset, readcount, mdata) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); @@ -2861,13 +2867,181 @@ size_t nfs_get_writemax(struct nfs_context *nfs) void nfs_set_error(struct nfs_context *nfs, char *error_string, ...) { va_list ap; - char *str; + char *str = NULL; + va_start(ap, error_string); + vasprintf(&str, error_string, ap); 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; +} + +struct rpc_context *nfs_get_rpc_context(struct nfs_context *nfs) +{ + return nfs->rpc; +} +