/* Start the translator TRANS (of length TRANS_LEN) on NODE, which should be locked, and will be unlocked when this function returns. PARENT_PORT is a send right to use as the parent port passed to the translator. */ error_t _treefs_node_start_translator (struct treefs_node *node, char *trans, unsigned trans_len, file_t parent_port) { error_t err; int mode = O_READ | O_EXEC; struct treefs_auth *auth; file_t node_port; uid_t uid, gid; err = treefs_node_get_trans_auth (node, &auth); if (err) return err; if (!node->fsys->readonly && treefs_node_type (node) == S_IFREG) mode |= O_WRITE; /* Create the REALNODE port for the new filesystem. */ node_port = treefs_node_make_right (node, mode, parent_port, auth); mach_port_insert_right (mach_task_self (), node_port, node_port, MACH_MSG_TYPE_MAKE_SEND); mutex_unlock (&node->lock); /* XXXX Change libfshelp so that it take more than 1 uid/gid? */ uid = auth->nuids > 0 ? auth->uids[0] : -1; gid = auth->ngids > 0 ? auth->gids[0] : -1; /* XXX this should use fshelp_start_translator_long. */ err = fshelp_start_translator (&node->active_trans, NULL, trans, trans_len, parent_port, node_port, uid, gid); treefs_node_auth_unref (node, auth); return err; }
error_t _treefs_s_fsys_getroot (struct treefs_fsys *fsys, mach_port_t dotdot, uid_t *uids, unsigned nuids, uid_t *gids, unsigned ngids, int flags, retry_type *retry, char *retry_name, file_t *result, mach_msg_type_name_t *result_type) { error_t err; mode_t type; struct treefs_node *root; struct treefs_auth *auth; flags &= O_HURD; err = treefs_fsys_get_root (fsys, &root); if (err) return err; if (!(flags & O_NOTRANS)) /* Try starting up any translator on the root node. */ { fsys_t child_fsys; do { err = treefs_node_get_active_trans (root, 0, 0, &dotdot, &child_fsys); if (err == 0 && child_fsys != MACH_PORT_NULL) /* We think there's an active translator; try contacting it. */ { err = fsys_getroot (child_fsys, dotdot, MACH_MSG_TYPE_COPY_SEND, uids, nuids, gids, ngids, flags, retry, retry_name, result); /* If we got MACH_SEND_INVALID_DEST or MIG_SERVER_DIED, then the server is dead. Zero out the old control port and try everything again. */ if (err == MACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED) treefs_node_drop_active_trans (root, control_port); } } while (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED); /* If we got a translator, or an error trying, return immediately. */ if (err || child_fsys) { if (!err && *result != MACH_PORT_NULL) *result_type = MACH_MSG_TYPE_MOVE_SEND; else *result_type = MACH_MSG_TYPE_COPY_SEND; if (!err) mach_port_deallocate (mach_task_self (), dotdot); treefs_node_unref (root); return err; } } pthread_mutex_lock (&root->lock); type = treefs_node_type (root); if (type == S_IFLNK && !(flags & (O_NOLINK | O_NOTRANS))) /* Handle symlink interpretation */ { int sym_len = 1000; char path_buf[sym_len + 1], *path = path_buf; err = treefs_node_get_symlink (root, path, &sym_len); if (err == E2BIG) /* Symlink contents won't fit in our buffer, so reallocate it and try again. */ { path = alloca (sym_len + 1); err = treefs_node_get_symlink (node, path, &sym_len); } if (err) goto out; if (*path == '/') { *retry = FS_RETRY_MAGICAL; *result = MACH_PORT_NULL; *result_type = MACH_MSG_TYPE_COPY_SEND; mach_port_deallocate (mach_task_self (), dotdot); } else { *retry = FS_RETRY_REAUTH; *result = dotdot; *result_type = MACH_MSG_TYPE_COPY_SEND; } strcpy (retry_name, path); goto out; } err = treefs_node_create_auth (root, uids, nuids, gids, ngids, &auth); if (err) goto out; *retry = FS_RETRY_NORMAL; *retry_name = '\0'; *result_type = MACH_MSG_TYPE_MAKE_SEND; err = treefs_node_create_right (root, dotdot, flags, auth, result); treefs_node_auth_unref (root, auth); out: treefs_node_release (root); return err; }