We need to pass a filehandle back for open(O_TRUNC) or else the app will
[deb_libnfs.git] / lib / libnfs.c
index 303615a247dbbbb67de010377fb4adee4803e6a0..68e0d0343baa3a9fe0807a20f18ed19dead24be6 100644 (file)
@@ -143,7 +143,6 @@ struct nfs_mcb_data {
 
 static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh);
 
-
 void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth)
 {
        rpc_set_auth(nfs->rpc, auth);
@@ -1244,6 +1243,55 @@ int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *p
 /*
  * Async open()
  */
+static void nfs_open_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;
+       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);
+               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: 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);
+               return;
+       }
+
+       nfsfh = malloc(sizeof(struct nfsfh));
+       if (nfsfh == NULL) {
+               rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
+               data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+       memset(nfsfh, 0, sizeof(struct nfsfh));
+
+       if (data->continue_int & O_SYNC) {
+               nfsfh->is_sync = 1;
+       }
+
+       /* steal the filehandle */
+       nfsfh->fh = data->fh;
+       data->fh.data.data_val = NULL;
+
+       data->cb(0, nfs, nfsfh, data->private_data);
+       free_nfs_cb_data(data);
+}
+
 static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        ACCESS3res *res;
@@ -1297,6 +1345,28 @@ static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data,
                return;
        }
 
+       /* Try to truncate it if we were requested to */
+       if ((data->continue_int & O_TRUNC) &&
+           (data->continue_int & (O_RDWR|O_WRONLY))) {
+               SETATTR3args args;
+
+               memset(&args, 0, sizeof(SETATTR3args));
+               args.object = data->fh;
+               args.new_attributes.size.set_it = 1;
+               args.new_attributes.size.set_size3_u.size = 0;
+
+               if (rpc_nfs3_setattr_async(nfs->rpc, nfs_open_trunc_cb, &args,
+                               data) != 0) {
+                       rpc_set_error(nfs->rpc, "RPC error: Failed to send "
+                               "SETATTR call for %s", data->path);
+                       data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc),
+                               data->private_data);
+                       free_nfs_cb_data(data);
+                       return;
+               }
+               return;
+       }
+
        nfsfh = malloc(sizeof(struct nfsfh));
        if (nfsfh == NULL) {
                rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
@@ -1338,17 +1408,19 @@ static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_dat
        args.access = nfsmode;
 
        if (rpc_nfs3_access_async(nfs->rpc, nfs_open_cb, &args, data) != 0) {
-               rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
-               data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+               rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS "
+                               "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_open_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
+int nfs_open_async(struct nfs_context *nfs, const char *path, int flags, nfs_cb cb, void *private_data)
 {
-       if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_open_continue_internal, NULL, NULL, mode) != 0) {
+       if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_open_continue_internal, NULL, NULL, flags) != 0) {
                rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
        }