libnfs.c: always pass the attributes to the callback for recursive lookups
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Sun, 8 Jun 2014 16:45:22 +0000 (09:45 -0700)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Sun, 8 Jun 2014 18:24:09 +0000 (11:24 -0700)
Always pass a fattr3 structure to the callbacks for the internal function
to perform recursive lookups : nfs_lookuppath_async().
This will allow us to access for example the mtime for an object before we
start performing any expensive functions.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
lib/libnfs.c

index 59b30fdfffd3abc6b86c2ac3b5a38e618e6843cc..830e28e4e2df75ec2d08e9e92641d683cb9cf9f5 100644 (file)
@@ -112,7 +112,8 @@ void nfs_free_nfsdir(struct nfsdir *nfsdir)
 }
 
 struct nfs_cb_data;
-typedef int (*continue_func)(struct nfs_context *nfs, struct nfs_cb_data *data);
+typedef int (*continue_func)(struct nfs_context *nfs, fattr3 *attr,
+                            struct nfs_cb_data *data);
 
 struct nfs_cb_data {
        struct nfs_context *nfs;
@@ -147,7 +148,7 @@ struct nfs_mcb_data {
        int update_pos;
 };
 
-static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh);
+static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr, struct nfs_cb_data *data, struct nfs_fh3 *fh);
 
 void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth)
 {
@@ -640,9 +641,6 @@ static void free_nfs_cb_data(struct nfs_cb_data *data)
 }
 
 
-
-
-
 static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct nfs_cb_data *data = private_data;
@@ -848,6 +846,7 @@ static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *comm
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        LOOKUP3res *res;
+       fattr3 *attr;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -870,15 +869,17 @@ static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *comm
                return;
        }
 
-       if (nfs_lookup_path_async_internal(nfs, data, &res->LOOKUP3res_u.resok.object) != 0) {
-               rpc_set_error(nfs->rpc, "Failed to create lookup pdu");
-               data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
+       attr = res->LOOKUP3res_u.resok.obj_attributes.attributes_follow ?
+         &res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes :
+         NULL;
+
+       /* This function will always invoke the callback and cleanup
+        * for failures. So no need to check the return value.
+        */
+       nfs_lookup_path_async_internal(nfs, attr, data, &res->LOOKUP3res_u.resok.object);
 }
 
-static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh)
+static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data, struct nfs_fh3 *fh)
 {
        char *path, *slash;
        LOOKUP3args args;
@@ -917,11 +918,10 @@ static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb
                if (slash != NULL) {
                        *slash = '/';
                }
-               data->continue_cb(nfs, data);
+               data->continue_cb(nfs, attr, data);
                return 0;
        }
 
-
        memset(&args, 0, sizeof(LOOKUP3args));
        args.what.dir = *fh;
        args.what.name = path;
@@ -1038,9 +1038,45 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path)
        return 0;
 }
 
+static void nfs_lookup_path_getattr_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;
+       GETATTR3res *res;
+       fattr3 *attr;
+
+       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: GETATTR of %s failed with %s(%d)", data->saved_path, 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;
+       }
+
+       attr = &res->GETATTR3res_u.resok.obj_attributes;
+       /* This function will always invoke the callback and cleanup
+        * for failures. So no need to check the return value.
+        */
+       nfs_lookup_path_async_internal(nfs, attr, data, &nfs->rootfh);
+}
+
 static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data, continue_func continue_cb, void *continue_data, void (*free_continue_data)(void *), int continue_int)
 {
        struct nfs_cb_data *data;
+       struct GETATTR3args args;
 
        if (path[0] == '\0') {
                path = ".";
@@ -1086,18 +1122,27 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c
        }
 
        data->path = data->saved_path;
-
-       if (nfs_lookup_path_async_internal(nfs, data, &nfs->rootfh) != 0) {
-               /* return 0 here since the callback will be invoked if there is a failure */
+       if (data->path[0]) {
+               /* This function will always invoke the callback and cleanup
+                * for failures. So no need to check the return value.
+                */
+               nfs_lookup_path_async_internal(nfs, NULL, data, &nfs->rootfh);
                return 0;
        }
+
+       /* We have a request for "", so just perform a GETATTR3 so we can
+        * return the attributes to the caller.
+        */
+       memset(&args, 0, sizeof(GETATTR3args));
+       args.object = nfs->rootfh;
+       if (rpc_nfs3_getattr_async(nfs->rpc, nfs_lookup_path_getattr_cb, &args, data) != 0) {
+               free_nfs_cb_data(data);
+               return -1;
+       }
        return 0;
 }
 
 
-
-
-
 /*
  * Async stat()
  */
@@ -1159,7 +1204,7 @@ static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
-static int nfs_stat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_stat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct GETATTR3args args;
 
@@ -1239,7 +1284,7 @@ static void nfs_stat64_1_cb(struct rpc_context *rpc, int status, void *command_d
        free_nfs_cb_data(data);
 }
 
-static int nfs_stat64_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_stat64_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct GETATTR3args args;
 
@@ -1419,7 +1464,7 @@ static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data,
        free_nfs_cb_data(data);
 }
 
-static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_open_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        int nfsmode = 0;
        ACCESS3args args;
@@ -1463,7 +1508,7 @@ int nfs_open_async(struct nfs_context *nfs, const char *path, int flags, nfs_cb
 /*
  * Async chdir()
  */
-static int nfs_chdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_chdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        /* steal saved_path */
        free(nfs->cwd);
@@ -2127,7 +2172,7 @@ int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t l
 /*
  * Async truncate()
  */
-static int nfs_truncate_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_truncate_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        uint64_t offset = data->continue_int;
        struct nfsfh nfsfh;
@@ -2198,7 +2243,7 @@ static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_data
        free_nfs_cb_data(data);
 }
 
-static int nfs_mkdir_continue_internal(struct nfs_context *nfs, struct 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;
@@ -2289,7 +2334,7 @@ static void nfs_rmdir_cb(struct rpc_context *rpc, int status, void *command_data
        free_nfs_cb_data(data);
 }
 
-static int nfs_rmdir_continue_internal(struct nfs_context *nfs, struct 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;
@@ -2434,7 +2479,7 @@ static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_da
        return;
 }
 
-static int nfs_creat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_creat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        char *str = data->continue_data;
        CREATE3args args;
@@ -2525,7 +2570,7 @@ static void nfs_unlink_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
-static int nfs_unlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_unlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        char *str = data->continue_data;
        struct REMOVE3args args;
@@ -2624,7 +2669,7 @@ static void nfs_mknod_cb(struct rpc_context *rpc, int status, void *command_data
        free_nfs_cb_data(data);
 }
 
-static int nfs_mknod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_mknod_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct mknod_cb_data *cb_data = data->continue_data;
        char *str = cb_data->path;
@@ -3046,7 +3091,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
        free_nfs_cb_data(data);
 }
 
-static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_opendir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        READDIRPLUS3args args;
 
@@ -3267,7 +3312,7 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_
        free_nfs_cb_data(data);
 }
 
-static int nfs_statvfs_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_statvfs_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        FSSTAT3args args;
 
@@ -3329,7 +3374,7 @@ static void nfs_readlink_1_cb(struct rpc_context *rpc, int status, void *command
        free_nfs_cb_data(data);
 }
 
-static int nfs_readlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_readlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        READLINK3args args;
 
@@ -3391,7 +3436,7 @@ static void nfs_chmod_cb(struct rpc_context *rpc, int status, void *command_data
        free_nfs_cb_data(data);
 }
 
-static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_chmod_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        SETATTR3args args;
 
@@ -3446,7 +3491,7 @@ int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs
        }
        memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
 
-       if (nfs_chmod_continue_internal(nfs, data) != 0) {
+       if (nfs_chmod_continue_internal(nfs, NULL, data) != 0) {
                return -1;
        }
 
@@ -3494,7 +3539,7 @@ struct nfs_chown_data {
        gid_t gid;
 };
 
-static int nfs_chown_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_chown_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        SETATTR3args args;
        struct nfs_chown_data *chown_data = data->continue_data;
@@ -3580,7 +3625,7 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int
        }
        memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
 
-       if (nfs_chown_continue_internal(nfs, data) != 0) {
+       if (nfs_chown_continue_internal(nfs, NULL, data) != 0) {
                return -1;
        }
 
@@ -3625,7 +3670,7 @@ static void nfs_utimes_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
-static int nfs_utimes_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_utimes_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        SETATTR3args args;
        struct timeval *utimes_data = data->continue_data;
@@ -3763,7 +3808,7 @@ static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
-static int nfs_access_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_access_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        int nfsmode = 0;
        ACCESS3args args;
@@ -3860,7 +3905,7 @@ static void nfs_symlink_cb(struct rpc_context *rpc, int status, void *command_da
        free_nfs_cb_data(data);
 }
 
-static int nfs_symlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_symlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_symlink_data *symlink_data = data->continue_data;
        SYMLINK3args args;
@@ -3996,7 +4041,7 @@ static void nfs_rename_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
-static int nfs_rename_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_rename_continue_2_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_rename_data *rename_data = data->continue_data;
        RENAME3args args;
@@ -4019,7 +4064,7 @@ static int nfs_rename_continue_2_internal(struct nfs_context *nfs, struct nfs_cb
 }
 
 
-static int nfs_rename_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_rename_continue_1_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_rename_data *rename_data = data->continue_data;
        char* newpath = strdup(rename_data->newpath);
@@ -4166,7 +4211,7 @@ static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_data,
        free_nfs_cb_data(data);
 }
 
-static int nfs_link_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_link_continue_2_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_link_data *link_data = data->continue_data;
        LINK3args args;
@@ -4189,7 +4234,7 @@ static int nfs_link_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_d
 }
 
 
-static int nfs_link_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_link_continue_1_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_link_data *link_data = data->continue_data;