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; }
/*Traces the translator stack on the given underlying node until it finds the first translator called `name` and returns the port pointing to the translator sitting under this one.*/ error_t trace_find (mach_port_t underlying, const char *name, int flags, mach_port_t * port) { error_t err = 0; /*Identity information about the current process */ uid_t *uids; size_t nuids; gid_t *gids; size_t ngids; /*The name and arguments of the translator being passed now */ char *argz = NULL; size_t argz_len = 0; /*The current working directory */ char *cwd = NULL; /*The port to the directory containing the file pointed to by `underlying` */ file_t dir; /*The unauthenticated version of `dir` */ file_t unauth_dir; /*The control port of the current translator */ fsys_t fsys; /*The port to the translator we are currently looking at */ mach_port_t node = underlying; /*The port to the previous translator */ mach_port_t prev_node = MACH_PORT_NULL; /*The retry name and retry type returned by fsys_getroot */ string_t retry_name; retry_type retry; /*Finalizes the execution of this function */ void finalize (void) { /*If there is a working directory, free it */ if (cwd) free (cwd); /*If the ports to the directory exist */ if (dir) PORT_DEALLOC (dir); } /*finalize */ /*Obtain the current working directory */ cwd = getcwd (NULL, 0); if (!cwd) { LOG_MSG ("trace_find: Could not obtain cwd."); return EINVAL; } LOG_MSG ("trace_find: cwd: '%s'", cwd); /*Open a port to this directory */ dir = file_name_lookup (cwd, 0, 0); if (!dir) { finalize (); return ENOENT; } /*Try to get the number of effective UIDs */ nuids = geteuids (0, 0); if (nuids < 0) { finalize (); return EINVAL; } /*Allocate some memory for the UIDs on the stack */ uids = alloca (nuids * sizeof (uid_t)); /*Fetch the UIDs themselves */ nuids = geteuids (nuids, uids); if (nuids < 0) { finalize (); return EINVAL; } /*Try to get the number of effective GIDs */ ngids = getgroups (0, 0); if (ngids < 0) { finalize (); return EINVAL; } /*Allocate some memory for the GIDs on the stack */ gids = alloca (ngids * sizeof (gid_t)); /*Fetch the GIDs themselves */ ngids = getgroups (ngids, gids); if (ngids < 0) { finalize (); return EINVAL; } /*Obtain the unauthenticated version of `dir` */ err = io_restrict_auth (dir, &unauth_dir, 0, 0, 0, 0); if (err) { finalize (); return err; } char buf[256]; char *_buf = buf; size_t len = 256; io_read (node, &_buf, &len, 0, len); LOG_MSG ("trace_find: Read from underlying: '%s'", buf); /*Go up the translator stack */ for (; !err;) { /*retreive the name and options of the current translator */ err = file_get_fs_options (node, &argz, &argz_len); if (err) break; LOG_MSG ("trace_find: Obtained translator '%s'", argz); if (strcmp (argz, name) == 0) { LOG_MSG ("trace_find: Match. Stopping here."); break; } /*try to fetch the control port for this translator */ err = file_get_translator_cntl (node, &fsys); LOG_MSG ("trace_find: err = %d", (int) err); if (err) break; LOG_MSG ("trace_find: Translator control port: %lu", (unsigned long) fsys); prev_node = node; /*fetch the root of the translator */ err = fsys_getroot (fsys, unauth_dir, MACH_MSG_TYPE_COPY_SEND, uids, nuids, gids, ngids, flags | O_NOTRANS, &retry, retry_name, &node); LOG_MSG ("trace_find: fsys_getroot returned %d", (int) err); LOG_MSG ("trace_find: Translator root: %lu", (unsigned long) node); /*TODO: Remove this debug output. */ /*char buf[256]; char * _buf = buf; size_t len = 256; io_read(node, &_buf, &len, 0, len); LOG_MSG("trace_find: Read: '%s'", buf); */ } /*If the error occurred (most probably) because of the fact that we have reached the top of the translator stack */ if ((err == EMACH_SEND_INVALID_DEST) || (err == ENXIO)) /*this is OK */ err = 0; /*Return the port to read from */ *port = prev_node; /*Return the result of operations */ finalize (); return err; } /*trace_find */