/* 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;
}
Example #2
0
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;
}