int rgw_build_bucket_policies(RGWRados* store, struct req_state* s)
{
  int ret = 0;
  rgw_obj_key obj;
  RGWUserInfo bucket_owner_info;
  RGWObjectCtx obj_ctx(store);

  string bi = s->info.args.get(RGW_SYS_PARAM_PREFIX "bucket-instance");
  if (!bi.empty()) {
    ret = rgw_bucket_parse_bucket_instance(bi, &s->bucket_instance_id, &s->bucket_instance_shard_id);
    if (ret < 0) {
      return ret;
    }
  }

  if(s->dialect.compare("s3") == 0) {
    s->bucket_acl = std::make_unique<RGWAccessControlPolicy_S3>(s->cct);
  } else if(s->dialect.compare("swift")  == 0) {
    /* We aren't allocating the account policy for those operations using
     * the Swift's infrastructure that don't really need req_state::user.
     * Typical example here is the implementation of /info. */
    if (!s->user->user_id.empty()) {
      s->user_acl = std::make_unique<RGWAccessControlPolicy_SWIFTAcct>(s->cct);
    }
    s->bucket_acl = std::make_unique<RGWAccessControlPolicy_SWIFT>(s->cct);
  } else {
    s->bucket_acl = std::make_unique<RGWAccessControlPolicy>(s->cct);
  }

  /* check if copy source is within the current domain */
  if (!s->src_bucket_name.empty()) {
    RGWBucketInfo source_info;

    if (s->bucket_instance_id.empty()) {
      ret = store->get_bucket_info(obj_ctx, s->src_tenant_name, s->src_bucket_name, source_info, NULL);
    } else {
      ret = store->get_bucket_instance_info(obj_ctx, s->bucket_instance_id, source_info, NULL, NULL);
    }
    if (ret == 0) {
      string& zonegroup = source_info.zonegroup;
      s->local_source = store->get_zonegroup().equals(zonegroup);
    }
  }

  struct {
    rgw_user uid;
    std::string display_name;
  } acct_acl_user = {
    s->user->user_id,
    s->user->display_name,
  };

  if (!s->bucket_name.empty()) {
    s->bucket_exists = true;
    if (s->bucket_instance_id.empty()) {
      ret = store->get_bucket_info(obj_ctx, s->bucket_tenant, s->bucket_name,
                                   s->bucket_info, &s->bucket_mtime,
                                   &s->bucket_attrs);
    } else {
      ret = store->get_bucket_instance_info(obj_ctx, s->bucket_instance_id,
                                            s->bucket_info, &s->bucket_mtime,
                                            &s->bucket_attrs);
    }
    if (ret < 0) {
      if (ret != -ENOENT) {
        string bucket_log;
        rgw_make_bucket_entry_name(s->bucket_tenant, s->bucket_name, bucket_log);
        ldout(s->cct, 0) << "NOTICE: couldn't get bucket from bucket_name (name=" << bucket_log << ")" << dendl;
        return ret;
      }
      s->bucket_exists = false;
    }
    s->bucket = s->bucket_info.bucket;

    if (s->bucket_exists) {
      ret = read_bucket_policy(store, s, s->bucket_info, s->bucket_attrs,
                               s->bucket_acl.get(), s->bucket);
      acct_acl_user = {
        s->bucket_info.owner,
        s->bucket_acl->get_owner().get_display_name(),
      };
    } else {
      s->bucket_acl->create_default(s->user->user_id, s->user->display_name);
      ret = -ERR_NO_SUCH_BUCKET;
    }

    s->bucket_owner = s->bucket_acl->get_owner();

    RGWZoneGroup zonegroup;
    int r = store->get_zonegroup(s->bucket_info.zonegroup, zonegroup);
    if (!r) {
      if (!zonegroup.endpoints.empty()) {
	s->zonegroup_endpoint = zonegroup.endpoints.front();
      } else {
        // use zonegroup's master zone endpoints
        auto z = zonegroup.zones.find(zonegroup.master_zone);
        if (z != zonegroup.zones.end() && !z->second.endpoints.empty()) {
          s->zonegroup_endpoint = z->second.endpoints.front();
        }
      }
      s->zonegroup_name = zonegroup.get_name();
    }
    if (r < 0 && ret == 0) {
      ret = r;
    }

    if (s->bucket_exists && !store->get_zonegroup().equals(s->bucket_info.zonegroup)) {
      ldout(s->cct, 0) << "NOTICE: request for data in a different zonegroup (" << s->bucket_info.zonegroup << " != " << store->get_zonegroup().get_id() << ")" << dendl;
      /* we now need to make sure that the operation actually requires copy source, that is
       * it's a copy operation
       */
      if (store->get_zonegroup().is_master_zonegroup() && s->system_request) {
        /*If this is the master, don't redirect*/
      } else if (s->op_type == RGW_OP_GET_BUCKET_LOCATION ) {
        /* If op is get bucket location, don't redirect */
      } else if (!s->local_source ||
          (s->op != OP_PUT && s->op != OP_COPY) ||
          s->object.empty()) {
        return -ERR_PERMANENT_REDIRECT;
      }
    }
  }

  /* handle user ACL only for those APIs which support it */
  if (s->user_acl) {
    map<string, bufferlist> uattrs;

    ret = rgw_get_user_attrs_by_uid(store, acct_acl_user.uid, uattrs);
    if (!ret) {
      ret = get_user_policy_from_attr(s->cct, store, uattrs, *s->user_acl);
    }
    if (-ENOENT == ret) {
      /* In already existing clusters users won't have ACL. In such case
       * assuming that only account owner has the rights seems to be
       * reasonable. That allows to have only one verification logic.
       * NOTE: there is small compatibility kludge for global, empty tenant:
       *  1. if we try to reach an existing bucket, its owner is considered
       *     as account owner.
       *  2. otherwise account owner is identity stored in s->user->user_id.  */
      s->user_acl->create_default(acct_acl_user.uid,
                                  acct_acl_user.display_name);
      ret = 0;
    } else {
      ldout(s->cct, 0) << "NOTICE: couldn't get user attrs for handling ACL (user_id="
                       << s->user->user_id
                       << ", ret="
                       << ret
                       << ")" << dendl;
      return ret;
    }
  }

  try {
    s->iam_policy = get_iam_policy_from_attr(s->cct, store, s->bucket_attrs,
					     s->bucket_tenant);
  } catch (const std::exception& e) {
    // Really this is a can't happen condition. We parse the policy
    // when it's given to us, so perhaps we should abort or otherwise
    // raise bloody murder.
    lderr(s->cct) << "Error reading IAM Policy: " << e.what() << dendl;
    ret = -EACCES;
  }

  bool success = store->get_redirect_zone_endpoint(&s->redirect_zone_endpoint);
  if (success) {
    ldout(s->cct, 20) << "redirect_zone_endpoint=" << s->redirect_zone_endpoint << dendl;
  }

  return ret;
}