+ path = res->READLINK3res_u.resok.data;
+
+ /* Handle absolute paths, ensuring that the path lies within the
+ * export. */
+ if (path[0] == '/') {
+ if (strstr(path, nfs->export) == path) {
+ char *ptr = path + strlen(nfs->export);
+ if (*ptr == '/') {
+ newpath = strdup(ptr);
+ } else if (*ptr == '\0') {
+ newpath = strdup("/");
+ } else {
+ data->cb(-ENOENT, nfs, "Symbolic link points outside export", data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+ } else {
+ data->cb(-ENOENT, nfs, "Symbolic link points outside export", data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ if (!newpath)
+ goto nomem;
+ } else {
+ /* Handle relative paths, both the case where the current
+ * component is an intermediate component and when it is the
+ * final component. */
+ if (data->path[0]) {
+ /* Since path points to a component and saved_path
+ * always starts with '/', path[-1] is valid. */
+ data->path[-1] = '\0';
+ newpath = malloc(strlen(data->saved_path) + strlen(path) + strlen(data->path) + 6);
+ if (!newpath)
+ goto nomem;
+
+ sprintf(newpath, "%s/../%s/%s", data->saved_path, path, data->path);
+ } else {
+ newpath = malloc(strlen(data->saved_path) + strlen(path) + 5);
+ if (!newpath)
+ goto nomem;
+
+ sprintf(newpath, "%s/../%s", data->saved_path, path);
+ }
+ }
+ free(data->saved_path);
+ data->saved_path = newpath;
+
+ if (nfs_normalize_path(nfs, data->saved_path) != 0) {
+ data->cb(-ENOENT, nfs, "Symbolic link resolves to invalid path", data->private_data);
+ free_nfs_cb_data(data);
+ return;
+ }
+
+ data->path = data->saved_path;
+ nfs_lookup_path_async_internal(nfs, NULL, data, &nfs->rootfh);
+ return;
+
+nomem:
+ data->cb(-ENOMEM, nfs, "Failed to allocate memory for path", data->private_data);
+ free_nfs_cb_data(data);
+}
+
+static void nfs_lookup_path_1_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;
+ LOOKUP3res *res;
+ fattr3 *attr;
+
+ assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+ if (status == RPC_STATUS_ERROR) {
+ data->cb(-EFAULT, nfs, command_data, data->private_data);