+
+ assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+ str = &str[strlen(str) + 1];
+
+ if (status == RPC_STATUS_ERROR) {
+ data->cb(-EFAULT, nfs, command_data, data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+ if (status == RPC_STATUS_CANCEL) {
+ data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ res = command_data;
+ if (res->status != NFS3_OK) {
+ rpc_set_error(nfs->rpc, "NFS: MKDIR of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
+ data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
+{
+ char *str = data->continue_data;
+ MKDIR3args args;
+
+ str = &str[strlen(str) + 1];
+
+ memset(&args, 0, sizeof(MKDIR3args));
+ args.where.dir = data->fh;
+ args.where.name = str;
+ args.attributes.mode.set_it = 1;
+ args.attributes.mode.set_mode3_u.mode = 0755;
+
+ if (rpc_nfs3_mkdir_async(nfs->rpc, nfs_mkdir_cb, &args, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send MKDIR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ char *new_path;
+ char *ptr;
+
+ new_path = strdup(path);
+ if (new_path == NULL) {
+ rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
+ return -1;
+ }
+
+ ptr = strrchr(new_path, '/');
+ if (ptr == NULL) {
+ free(new_path);
+ rpc_set_error(nfs->rpc, "Invalid path %s", path);
+ return -1;
+ }
+ *ptr = 0;
+
+ /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
+ if (nfs_lookuppath_async(nfs, new_path, 0, cb, private_data, nfs_mkdir_continue_internal, new_path, free, 0) != 0) {
+ rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path component");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * Async rmdir()
+ */
+static void nfs_rmdir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+ RMDIR3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ char *str = data->continue_data;
+
+ assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+ str = &str[strlen(str) + 1];
+
+ if (status == RPC_STATUS_ERROR) {
+ data->cb(-EFAULT, nfs, command_data, data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+ if (status == RPC_STATUS_CANCEL) {
+ data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ res = command_data;
+ if (res->status != NFS3_OK) {
+ rpc_set_error(nfs->rpc, "NFS: RMDIR of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
+ data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ data->cb(0, nfs, NULL, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static int nfs_rmdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
+{
+ char *str = data->continue_data;
+ RMDIR3args args;
+
+ str = &str[strlen(str) + 1];
+
+ args.object.dir = data->fh;
+ args.object.name = str;
+ if (rpc_nfs3_rmdir_async(nfs->rpc, nfs_rmdir_cb, &args, data) != 0) {
+ rpc_set_error(nfs->rpc, "RPC error: Failed to send RMDIR call for %s", data->path);
+ data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ return -1;
+ }
+ return 0;
+}
+
+int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
+{
+ char *new_path;
+ char *ptr;
+
+ new_path = strdup(path);
+ if (new_path == NULL) {
+ rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
+ return -1;
+ }
+
+ ptr = strrchr(new_path, '/');
+ if (ptr == NULL) {
+ free(new_path);
+ rpc_set_error(nfs->rpc, "Invalid path %s", path);
+ return -1;
+ }
+ *ptr = 0;
+
+ /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
+ if (nfs_lookuppath_async(nfs, new_path, 0, cb, private_data, nfs_rmdir_continue_internal, new_path, free, 0) != 0) {
+ rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * Async creat()
+ */
+struct create_cb_data {
+ char *path;
+ int flags;
+ int mode;
+};
+
+static void free_create_cb_data(void *ptr)
+{
+ struct create_cb_data *data = ptr;
+
+ free(data->path);
+ free(data);
+}
+
+static void nfs_create_trunc_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct nfsfh *nfsfh = data->nfsfh;
+ SETATTR3res *res;
+
+ assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+ if (status == RPC_STATUS_ERROR) {
+ data->cb(-EFAULT, nfs, command_data, data->private_data);
+ free_nfs_cb_data(data);
+ free_nfsfh(nfsfh);
+ return;
+ }
+ if (status == RPC_STATUS_CANCEL) {
+ data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+ free_nfs_cb_data(data);
+ free_nfsfh(nfsfh);
+ return;
+ }
+
+ res = command_data;
+ if (res->status != NFS3_OK) {
+ rpc_set_error(nfs->rpc, "NFS: Setattr failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
+ data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
+ free_nfs_cb_data(data);
+ free_nfsfh(nfsfh);
+ return;
+ }
+
+ data->cb(0, nfs, nfsfh, data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+ LOOKUP3res *res;
+ struct nfs_cb_data *data = private_data;
+ struct nfs_context *nfs = data->nfs;
+ struct nfsfh *nfsfh;
+ struct create_cb_data *cb_data = data->continue_data;
+ char *str = cb_data->path;
+
+ assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+ if (status == RPC_STATUS_ERROR) {
+ data->cb(-EFAULT, nfs, command_data, data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+ if (status == RPC_STATUS_CANCEL) {
+ data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+