Пример #1
0
void
init_exception_processing (void)
{
  tree tmp;

  /* void std::terminate (); */
  push_namespace (std_identifier);
  tmp = build_function_type (void_type_node, void_list_node);
  terminate_node = build_cp_library_fn_ptr ("terminate", tmp);
  TREE_THIS_VOLATILE (terminate_node) = 1;
  TREE_NOTHROW (terminate_node) = 1;
  pop_namespace ();

  /* void __cxa_call_unexpected(void *); */
  tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
  tmp = build_function_type (void_type_node, tmp);
  call_unexpected_node
    = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);

  eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
					     ? "__gxx_personality_sj0"
					     : "__gxx_personality_v0");

  lang_eh_runtime_type = build_eh_type_type;
  lang_protect_cleanup_actions = &cp_protect_cleanup_actions;
}
Пример #2
0
void
init_rtti_processing ()
{
  push_namespace (std_identifier);
  type_info_type_node = xref_tag
    (class_type_node, get_identifier ("type_info"), 1);
  pop_namespace ();
  tinfo_decl_type = 
    build_qualified_type (type_info_type_node, TYPE_QUAL_CONST);
}
Пример #3
0
void
init_rtti_processing ()
{
  push_namespace (std_identifier);
  type_info_type_node 
    = xref_tag (class_type, get_identifier ("type_info"),
		/*attributes=*/NULL_TREE, 1);
  pop_namespace ();
  type_info_ptr_type = 
    build_pointer_type
     (build_qualified_type (type_info_type_node, TYPE_QUAL_CONST));

  create_tinfo_types ();
}
Пример #4
0
void
init_rtti_processing ()
{
    if (flag_honor_std)
        push_namespace (get_identifier ("std"));
    type_info_type_node = xref_tag
                          (class_type_node, get_identifier ("type_info"), 1);
    if (flag_honor_std)
        pop_namespace ();
    tinfo_fn_id = get_identifier ("__tf");
    tinfo_fn_type = build_function_type
                    (build_reference_type (build_qualified_type (type_info_type_node,
                                           TYPE_QUAL_CONST)),
                     void_list_node);
}
Пример #5
0
void
init_rtti_processing (void)
{
    tree type_info_type;

    push_namespace (std_identifier);
    type_info_type = xref_tag (class_type, get_identifier ("type_info"),
                               /*tag_scope=*/ts_current, false);
    pop_namespace ();
    const_type_info_type_node
        = build_qualified_type (type_info_type, TYPE_QUAL_CONST);
    type_info_ptr_type = build_pointer_type (const_type_info_type_node);

    unemitted_tinfo_decls = VEC_alloc (tree, 124);

    create_tinfo_types ();
}
Пример #6
0
void
init_exception_processing (void)
{
  tree tmp;

  /* void std::terminate (); */
  push_namespace (std_identifier);
  tmp = build_function_type_list (void_type_node, NULL_TREE);
  terminate_node = build_cp_library_fn_ptr ("terminate", tmp);
  TREE_THIS_VOLATILE (terminate_node) = 1;
  TREE_NOTHROW (terminate_node) = 1;
  pop_namespace ();

  /* void __cxa_call_unexpected(void *); */
  tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
  call_unexpected_node
    = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);
}
Пример #7
0
void
init_exception_processing (void)
{
  tree tmp;

  /* void std::terminate (); */
  push_namespace (std_identifier);
  tmp = build_function_type_list (void_type_node, NULL_TREE);
  terminate_fn = build_cp_library_fn_ptr ("terminate", tmp,
					   ECF_NOTHROW | ECF_NORETURN
					   | ECF_COLD);
  gcc_checking_assert (TREE_THIS_VOLATILE (terminate_fn)
		       && TREE_NOTHROW (terminate_fn));
  pop_namespace ();

  /* void __cxa_call_unexpected(void *); */
  tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
  call_unexpected_fn
    = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);
}
Пример #8
0
Файл: except.c Проект: qiyao/xcc
void
init_exception_processing ()
{
  /* void vtype () */
  tree vtype = build_function_type (void_type_node, void_list_node);
  
  if (flag_honor_std)
    push_namespace (get_identifier ("std"));
  terminate_node = build_cp_library_fn_ptr ("terminate", vtype);
  TREE_THIS_VOLATILE (terminate_node) = 1;
  TREE_NOTHROW (terminate_node) = 1;
  if (flag_honor_std)
    pop_namespace ();

  set_exception_lang_code (EH_LANG_C_plus_plus);
  set_exception_version_code (1);

  /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
     be protected with __terminate.  */
  protect_cleanup_actions_with_terminate = 1;
}
Пример #9
0
/* called from the GMarkupParser */
static void
start_element_handler  (GMarkupParseContext  *markup_context,
                        const gchar          *element_name,
                        const gchar         **attribute_names,
                        const gchar         **attribute_values,
                        gpointer              user_data,
                        GError              **error)
{
  XMPParseContext *context = user_data;
  gint             attr;

#ifdef DEBUG_XMP_PARSER
  g_print ("[%25s/%17s] %d <%s>\n",
           state_names[context->state],
           (context->saved_state == STATE_ERROR
            ? "-"
            : state_names[context->saved_state]),
           context->depth, element_name);
#endif
  context->depth++;
  for (attr = 0; attribute_names[attr] != NULL; ++attr)
    if (g_str_has_prefix (attribute_names[attr], "xmlns:"))
      push_namespace (context, attribute_values[attr],
                      attribute_names[attr] + sizeof ("xmlns:") - 1, error);
  switch (context->state)
    {
    case STATE_INSIDE_XPACKET:
      if (! strcmp (element_name, "x:xmpmeta")
	  || ! strcmp (element_name, "x:xapmeta")
          || matches_with_prefix (element_name, context->xmp_prefix,
                                  context->xmp_prefix_len, "xmpmeta"))
	context->state = STATE_INSIDE_XMPMETA;
      else if (matches_rdf (element_name, context, "RDF"))
        {
          /* the x:xmpmeta element is missing, but this is allowed */
          context->depth++;
          context->state = STATE_INSIDE_RDF;
        }
      else
	parse_error_element (context, error, "x:xmpmeta",
                             FALSE, element_name);
      break;

    case STATE_INSIDE_XMPMETA:
      if (matches_rdf (element_name, context, "RDF"))
	context->state = STATE_INSIDE_RDF;
      else
	parse_error_element (context, error, "rdf:RDF",
                             FALSE, element_name);
      break;

    case STATE_INSIDE_RDF:
      if (matches_rdf (element_name, context, "Description"))
	{
          XMLNameSpace *ns;
          gboolean      about_seen = FALSE;

	  context->state = STATE_INSIDE_TOPLEVEL_DESC;
	  for (attr = 0; attribute_names[attr] != NULL; ++attr)
	    {
              if (matches_rdf (attribute_names[attr], context, "about")
                  || ! strcmp (attribute_names[attr], "about") /* old style */)
                about_seen = TRUE;
	      else if (g_str_has_prefix (attribute_names[attr], "xmlns"))
                ; /* the namespace has already been pushed on the stack */
	      else
                {
                  ns = new_property_in_ns (context, attribute_names[attr]);
                  if (ns != NULL)
                    {
                      /* RDF shorthand notation */
                      add_property_value (context, XMP_PTYPE_TEXT, NULL,
                                          g_strdup (attribute_values[attr]));
                      propagate_property (context, error);
                    }
                  else
                    unknown_attribute (context, error, element_name,
                                       attribute_names[attr],
                                       attribute_values[attr]);
                }
            }
          if ((about_seen == FALSE)
              && (context->flags & XMP_FLAG_NO_MISSING_ABOUT))
            parse_error (context, error, XMP_ERROR_MISSING_ABOUT,
                             _("Required attribute rdf:about missing in <%s>"),
                             element_name);
	}
      else
	parse_error_element (context, error, "rdf:Description",
                                 FALSE, element_name);
      break;

    case STATE_INSIDE_TOPLEVEL_DESC:
      {
        XMLNameSpace *ns;

        ns = new_property_in_ns (context, element_name);
        if (ns != NULL)
          {
            context->state = STATE_INSIDE_PROPERTY;
            for (attr = 0; attribute_names[attr] != NULL; ++attr)
              {
                if (matches_rdf (attribute_names[attr], context, "resource"))
                  add_property_value (context, XMP_PTYPE_RESOURCE, NULL,
                                      g_strdup (attribute_values[attr]));
                else if (matches_rdf (attribute_names[attr], context,
                                      "parseType")
                         && ! strcmp (attribute_values[attr], "Resource"))
                  {
                    context->saved_state = STATE_INSIDE_TOPLEVEL_DESC;
                    context->state = STATE_INSIDE_STRUCT_ADD_NS;
                  }
                else
                  unknown_attribute (context, error, element_name,
                                     attribute_names[attr],
                                     attribute_values[attr]);
              }
          }
        else
          unknown_element (context, error, element_name);
      }
      break;

    case STATE_INSIDE_PROPERTY:
      if (matches_rdf (element_name, context, "Description"))
	{
          context->saved_state = context->state;
	  context->state = STATE_INSIDE_QDESC;
	  for (attr = 0; attribute_names[attr] != NULL; ++attr)
	    {
	      if (g_str_has_prefix (attribute_names[attr], "xmlns"))
		{
		  /* this desc. is a structure, not a property qualifier */
		  context->state = STATE_INSIDE_STRUCT_ADD_NS;
		}
	      else
                unknown_attribute (context, error, element_name,
                                   attribute_names[attr],
                                   attribute_values[attr]);
	    }
	}
      else if (matches_rdf (element_name, context, "Alt"))
	context->state = STATE_INSIDE_ALT;
      else if (matches_rdf (element_name, context, "Bag"))
	context->state = STATE_INSIDE_BAG;
      else if (matches_rdf (element_name, context, "Seq"))
	context->state = STATE_INSIDE_SEQ;
      else
        unknown_element (context, error, element_name);
      break;

    case STATE_INSIDE_QDESC:
      if (matches_rdf (element_name, context, "value"))
	context->state = STATE_INSIDE_QDESC_VALUE;
      else
	context->state = STATE_INSIDE_QDESC_QUAL;
      break;

    case STATE_INSIDE_STRUCT_ADD_NS:
    case STATE_INSIDE_STRUCT:
      {
        GSList       *ns_list;
        XMLNameSpace *ns;
        gboolean      found;

        /* compare with namespaces in scope of current rdf:Description */
        found = FALSE;
        ns_list = context->namespaces;
        while (ns_list != NULL)
          {
            ns = ns_list->data;
            if (ns->depth < context->depth - 2)
              break;
            if (has_ns_prefix (element_name, ns))
              {
                if (context->state == STATE_INSIDE_STRUCT_ADD_NS)
                  {
                    /* first element - save the namespace prefix and uri */
                    add_property_value (context, XMP_PTYPE_STRUCTURE,
                                        g_strdup (ns->prefix),
                                        g_strdup (ns->uri));
                  }
                context->state = STATE_INSIDE_STRUCT_ELEMENT;
                add_property_value (context, XMP_PTYPE_STRUCTURE,
                                    g_strdup (element_name
                                              + ns->prefix_len + 1),
                                    NULL);
                found = TRUE;
                break;
              }
            ns_list = ns_list->next;
          }
        if (found == FALSE)
          unknown_element (context, error, element_name);
      }
      break;

    case STATE_INSIDE_ALT:
      if (matches_rdf (element_name, context, "li"))
	{
	  context->state = STATE_INSIDE_ALT_LI;
	  for (attr = 0; attribute_names[attr] != NULL; ++attr)
	    {
	      if (matches_rdf (attribute_names[attr], context, "parseType")
                  && ! strcmp (attribute_values[attr], "Resource"))
                context->state = STATE_INSIDE_ALT_LI_RSC;
	      else if (! strcmp (attribute_names[attr], "xml:lang"))
                add_property_value (context, XMP_PTYPE_ALT_LANG,
                                    g_strdup (attribute_values[attr]),
                                    NULL);
	      else
                unknown_attribute (context, error, element_name,
                                   attribute_names[attr],
                                   attribute_values[attr]);
	    }
          /* rdf:Alt is not an ordered list, but some broken XMP files use */
          /* it instead of rdf:Seq.  Workaround: if we did not find some */
          /* attributes for the valid cases ALT_LANG or ALT_LI_RSC, then */
          /* we pretend that we are parsing a real list (bug #343315). */
          if ((context->property_type != XMP_PTYPE_ALT_LANG)
              && (context->state != STATE_INSIDE_ALT_LI_RSC))
            add_property_value (context, XMP_PTYPE_ORDERED_LIST,
                                NULL, NULL);
	}
      else
	parse_error_element (context, error, "rdf:li",
                                 FALSE, element_name);
      break;

    case STATE_INSIDE_BAG:
      if (matches_rdf (element_name, context, "li"))
	{
          context->state = STATE_INSIDE_BAG_LI;
	  for (attr = 0; attribute_names[attr] != NULL; ++attr)
	    {
	      if (matches_rdf (attribute_names[attr], context, "parseType")
                  && ! strcmp (attribute_values[attr], "Resource"))
                context->state = STATE_INSIDE_BAG_LI_RSC;
	      else
                unknown_attribute (context, error, element_name,
                                   attribute_names[attr],
                                   attribute_values[attr]);
	    }
          if (context->state != STATE_INSIDE_BAG_LI_RSC)
            add_property_value (context, XMP_PTYPE_UNORDERED_LIST,
                                NULL, NULL);
	}
      else
	parse_error_element (context, error, "rdf:li",
                                 FALSE, element_name);
      break;

    case STATE_INSIDE_SEQ:
      if (matches_rdf (element_name, context, "li"))
	{
          context->state = STATE_INSIDE_SEQ_LI;
	  for (attr = 0; attribute_names[attr] != NULL; ++attr)
	    {
	      if (matches_rdf (attribute_names[attr], context, "parseType")
                  && ! strcmp (attribute_values[attr], "Resource"))
                context->state = STATE_INSIDE_SEQ_LI_RSC;
	      else
                unknown_attribute (context, error, element_name,
                                   attribute_names[attr],
                                   attribute_values[attr]);
	    }
          if (context->state != STATE_INSIDE_SEQ_LI_RSC)
            add_property_value (context, XMP_PTYPE_ORDERED_LIST,
                                NULL, NULL);
	}
      else
	parse_error_element (context, error, "rdf:li",
                                 FALSE, element_name);
      break;

    case STATE_INSIDE_BAG_LI:
    case STATE_INSIDE_SEQ_LI:
      if (matches_rdf (element_name, context, "Description"))
        {
          context->saved_state = context->state;
          context->state = STATE_INSIDE_QDESC;
        }
      else
	parse_error_element (context, error, "rdf:Description",
                             TRUE, element_name);
      break;

    case STATE_INSIDE_ALT_LI_RSC:
      /* store the thumbnail image and ignore the other elements */
      if (! strcmp (element_name, "xapGImg:image")) /* FIXME */
        context->state = STATE_INSIDE_ALT_LI_RSC_IMG;
      else if (! strcmp (element_name, "xapGImg:format")
               || ! strcmp (element_name, "xapGImg:width")
               || ! strcmp (element_name, "xapGImg:height"))
        ignore_element (context);
      else
        unknown_element (context, error, element_name);
      break;

    case STATE_INSIDE_BAG_LI_RSC:
    case STATE_INSIDE_SEQ_LI_RSC:
      unknown_element (context, error, element_name);
      break;

    case STATE_SKIPPING_UNKNOWN_ELEMENTS:
    case STATE_SKIPPING_IGNORED_ELEMENTS:
      break;

    default:
      parse_error (context, error, XMP_ERROR_PARSE,
                   _("Nested elements (<%s>) are not allowed in this context"),
                   element_name);
      break;
    }
}
Пример #10
0
MarFS_Namespace* push_namespace(MarFS_Namespace* dummy, MarFS_Repo* repo) {
   if (! dummy) {
      LOG(LOG_ERR, "NULL namespace\n");
      exit(1);
   }
   if (!IS_ROOT_NS(dummy) && !repo) {
      LOG(LOG_ERR, "NULL repo\n");
      exit(1);
   }

   MarFS_Namespace* ns = (MarFS_Namespace*)malloc(sizeof(MarFS_Namespace));
   if (! ns) {
      LOG(LOG_ERR, "alloc failed for '%s'\n", dummy->name);
      exit(1);
   }
   if (_ns_count >= _ns_max) {
      LOG(LOG_ERR, "No room for namespqace '%s'\n", dummy->name);
      exit(1);
   }

   LOG(LOG_INFO, "namespace: %-16s (repo: %s)\n", dummy->name, repo->name);
   *ns = *dummy;

   // use <repo> for everything.
   RangeList* ranges = (RangeList*) malloc(sizeof(RangeList));
   *ranges = (RangeList) {
      .min  =  0,
      .max  = -1,
      .repo = repo
   };
   ns->range_list  = ranges;
   ns->iwrite_repo = repo;

   // these make it quicker to parse parts of the paths
   ns->name_len       = strlen(ns->name);
   ns->mnt_path_len   = strlen(ns->mnt_path);
   ns->md_path_len    = strlen(ns->md_path);

   _ns[_ns_count++] = ns;
   return ns;
}

int validate_config();          // fwd-decl

int read_config(const char* config_fname) {

   ///   // config_fname is ignored, for now, but will eventually hold everythying
   ///   if (! config_fname)
   ///      config_fname = CONFIG_DEFAULT;
   ///
   ///   MarFS_mnt_top       = "/marfs";
   ///   MarFS_mnt_top_len   = strlen(MarFS_mnt_top);

   _marfs_config.version_major = 0;
   _marfs_config.version_minor = 1;

   _marfs_config.mnt_top     = "/marfs";
   _marfs_config.mnt_top_len = strlen(_marfs_config.mnt_top);

   _marfs_config.name        = "static";
   _marfs_config.name_len    = strlen(_marfs_config.name);


   // ...........................................................................
   // hard-coded repositories
   //
   //     For sproxyd, repo.name must match an existing fast-cgi path
   //     For S3,      repo.name must match an existing bucket
   //
   // ...........................................................................

   _repo_max = 64;              /* the number we're about to allocate */
   _repo  = (MarFS_Repo**) malloc(_repo_max * sizeof(MarFS_Repo*));

   MarFS_Repo r_dummy;

   r_dummy = (MarFS_Repo) {
      .name          = "proxy",  // repo is sproxyd: this must match fastcgi-path
      .host          = "10.135.0.%d:81",
      .host_offset   = 30,
      .host_count    =  4,
      .access_method = ACCESSMETHOD_SPROXYD,
      .chunk_size    = (1024 * 1024 * 1028), /* max MarFS object (tune to match storage) */
      .is_online     = 1,
      .auth          = AUTH_S3_AWS_MASTER,
      .compression   = COMPRESS_NONE,
      .correction    = CORRECT_NONE,
      .encryption    = ENCRYPT_NONE,
      .latency_ms    = (10 * 1000) };
   push_repo(&r_dummy);

   // tiny, so detailed debugging (where we watch every char go over the line)
   //       won't be overwhelming at the scale needed for Multi.
   r_dummy = (MarFS_Repo) {
      .name          = "sproxyd_2k",  // repo is sproxyd: this must match fastcgi-path
      .host          = "10.135.0.21:81",
      .access_method = ACCESSMETHOD_SPROXYD,
      .chunk_size    = (2048), /* i.e. max MarFS object (small for debugging) */
      .is_online     = 1,
      .auth          = AUTH_S3_AWS_MASTER,
      .compression   = COMPRESS_NONE,
      .correction    = CORRECT_NONE,
      .encryption    = ENCRYPT_NONE,
      .latency_ms    = (10 * 1000),
   };
   push_repo(&r_dummy);

   // For Brett, unit-testing, small enough to make it easy to create MULTIs
   r_dummy = (MarFS_Repo) {
      .name          = "sproxyd_1M",  // repo is sproxyd: this must match fastcgi-path
      .host          = "10.135.0.22:81",
      .access_method = ACCESSMETHOD_SPROXYD,
      .chunk_size    = (1024 * 1024 * 1), /* max MarFS object (tune to match storage) */
      .is_online     = 1,
      .auth          = AUTH_S3_AWS_MASTER,
      .compression   = COMPRESS_NONE,
      .correction    = CORRECT_NONE,
      .encryption    = ENCRYPT_NONE,
      .latency_ms    = (10 * 1000)
   };
   push_repo(&r_dummy);

   // @@@-HTTPS: For Brett, unit-testing, small enough to make it easy to create MULTIs
   r_dummy = (MarFS_Repo) {
      .name          = "sproxyd_1M_https",  // repo is sproxyd: this must match fastcgi-path
      .host          = "10.135.0.22:444",
      .access_method = ACCESSMETHOD_SPROXYD,
      .chunk_size    = (1024 * 1024 * 1), /* max MarFS object (tune to match storage) */
      .is_online     = 1,
      .auth          = AUTH_S3_AWS_MASTER,
      .compression   = COMPRESS_NONE,
      .correction    = CORRECT_NONE,
      .encryption    = ENCRYPT_NONE,
      .latency_ms    = (10 * 1000)
   };
   push_repo(&r_dummy);


   // S3 on EMC ECS
   r_dummy = (MarFS_Repo) {
      .name          = "emc_s3",  // repo is s3: this must match existing bucket
      .host          = "10.140.0.15:9020", //"10.143.0.1:80",
      .access_method = ACCESSMETHOD_S3_EMC,
      .chunk_size    = (1024 * 1024 * 256), /* max MarFS object (tune to match storage) */
      .is_online     = 1,
      .auth          = AUTH_S3_AWS_MASTER,
      .compression   = COMPRESS_NONE,
      .correction    = CORRECT_NONE,
      .encryption    = ENCRYPT_NONE,
      .latency_ms    = (10 * 1000),
   };
   push_repo(&r_dummy);


#if TBD
   // semi-direct experiment
   r_dummy = (MarFS_Repo) {
      .name          = "semi",
      .host          = "/gpfs/marfs-gpfs/fuse/semi", //"10.143.0.1:443",
      .access_method = ACCESSMETHOD_SEMI_DIRECT,
      .chunk_size    = (1024 * 1024 * 1), /* max MarFS object (tune to match storage) */
      .is_online     = 1,
      .auth          = AUTH_NONE,
      .compression   = COMPRESS_NONE,
      .correction    = CORRECT_NONE,
      .encryption    = ENCRYPT_NONE,
      .latency_ms    = (10 * 1000),
   };
   push_repo(&r_dummy);
#endif



   // ...........................................................................
   // hard-coded namespaces
   //
   //     For sproxyd, namespace.name must match an existing sproxyd driver-alias
   //     For S3,      namespace.name is just part of the object-id
   //
   // NOTE: Two namespaces should not have the same mount-suffix, because
   //     Fuse will use this to look-up namespaces.  Two NSes also
   //     shouldn't have the same name, in case someone wants to lookup
   //     by-name.
   // ...........................................................................

   _ns_max = 64;              /* the number we're about to allocate */
   _ns  = (MarFS_Namespace**) malloc(_ns_max * sizeof(MarFS_Namespace*));

   MarFS_Namespace ns_dummy;


   // Brett, unit 
   ns_dummy = (MarFS_Namespace) {
      .name           = "brettk",
      .mnt_path       = "/brettk",  // "<mnt_top>/brettk" comes here

      .md_path        = "/gpfs/marfs-gpfs/brettk/mdfs",
      .fsinfo_path    = "/gpfs/marfs-gpfs/brettk/fsinfo", /* a file */
      .trash_md_path  = "/gpfs/marfs-gpfs/trash", // NOT NEC IN THE SAME FILESET!

      .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),
      .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),

      .dirty_pack_percent   =  0,
      .dirty_pack_threshold = 75,

      .quota_space = -1,          /* no limit */
      .quota_names = -1,             /* no limit */

      .shard_path  = NULL,
      .shard_count = 0,
   };
   push_namespace(&ns_dummy, find_repo_by_name("sproxyd_1M"));


   // @@@-HTTPS: Brett, unit 
   ns_dummy = (MarFS_Namespace) {
      .name           = "brettk_https",
      .mnt_path       = "/brettk_https",  // "<mnt_top>/brettk_https" comes here

      .md_path        = "/gpfs/marfs-gpfs/brettk_https/mdfs",
      .fsinfo_path    = "/gpfs/marfs-gpfs/brettk_https/fsinfo", /* a file */
      .trash_md_path  = "/gpfs/marfs-gpfs/trash", // NOT NEC IN THE SAME FILESET!

      .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),
      .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),

      .dirty_pack_percent   =  0,
      .dirty_pack_threshold = 75,

      .quota_space = -1,          /* no limit */
      .quota_names = -1,             /* no limit */

      .shard_path  = NULL,
      .shard_count = 0,
   };
   push_namespace(&ns_dummy, find_repo_by_name("sproxyd_1M_https"));

   // jti testing
   ns_dummy = (MarFS_Namespace) {
      .name           = "jti",
      .mnt_path       = "/jti",  // "<mnt_top>/jti" comes here

      .md_path        = "/gpfs/marfs-gpfs/jti/mdfs",
      .fsinfo_path    = "/gpfs/marfs-gpfs/jti/fsinfo", /* a file */
      .trash_md_path  = "/gpfs/marfs-gpfs/trash", // NOT NEC IN THE SAME FILESET!

      .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),
      .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),

      .dirty_pack_percent   =  0,
      .dirty_pack_threshold = 75,

      .quota_space = (1024L * 1024 * 1024),          /* 1 GB of data */
      .quota_names = 32,             /* 32 names */

      .shard_path  = NULL,
      .shard_count = 0,
   };
   push_namespace(&ns_dummy, find_repo_by_name("proxy"));


   // EMC ECS install (with S3)
   ns_dummy = (MarFS_Namespace) {
      .name           = "s3",
      .mnt_path       = "/s3",  // "<mnt_top>/s3" comes here

      .md_path        = "/gpfs/fs2/s3/mdfs",
      .fsinfo_path    = "/gpfs/fs2/s3/fsinfo", /* a file */
      .trash_md_path  = "/gpfs/fs2/trash", // NOT NEC IN THE SAME FILESET!

      .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),
      .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),

      .dirty_pack_percent   =  0,
      .dirty_pack_threshold = 75,

      .quota_space = (1024L * 1024 * 1024),          /* 1GB of data */
      .quota_names = 32,             /* 32 names */

      .shard_path  = NULL,
      .shard_count = 0,
   };
   push_namespace(&ns_dummy, find_repo_by_name("emc_s3"));


   // jti testing on machine without GPFS
   ns_dummy = (MarFS_Namespace) {
      .name           = "ext4",
      .mnt_path       = "/ext4",  // "<mnt_top>/ext4" comes here

      .md_path        = "/non_gpfs/mdfs",
      .trash_md_path  = "/non_gpfs/trash",
      .fsinfo_path    = "/non_gpfs/fsinfo",

      .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),
      .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),

      .dirty_pack_percent   =  0,
      .dirty_pack_threshold = 75,

      .quota_space = (1024L * 1024 * 1024),          /* 1 GB of data */
      .quota_names = 32,             /* 32 names */

      .shard_path  = NULL,
      .shard_count = 0,
   };
   push_namespace(&ns_dummy, find_repo_by_name("proxy"));


#ifdef TBD
   // jti testing semi-direct
   ns_dummy = (MarFS_Namespace) {
      .name           = "semi",
      .mnt_path       = "/semi",

      .md_path        = "/gpfs/marfs-gpfs/semi/mdfs",
      .trash_md_path  = "/gpfs/marfs-gpfs/semi/trash",
      .fsinfo_path    = "/gpfs/marfs-gpfs/semi/fsinfo",

      .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),
      .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ),

      .dirty_pack_percent   =  0,
      .dirty_pack_threshold = 75,

      .quota_space = (1024L * 1024 * 1024),          /* 1 GB of data */
      .quota_names = 32,             /* 32 names */

      .shard_path  = NULL,
      .shard_count = 0,
   };
   push_namespace(&ns_dummy, find_repo_by_name("semi"));
#endif



   // "root" is a special path
   //
   // NOTE: find_namespace_by_path() will only return this namespace if its
   //       <path> matches our <mnt_path> exactly.  That's because our
   //       mnt_path is (necessarily) a suffix of all paths.
   ns_dummy = (MarFS_Namespace) {
      .name           = "root",
      .mnt_path       = "/",
      .md_path        = "should_never_be_used",
      .trash_md_path  = "should_never_be_used",
      .fsinfo_path    = "should_never_be_used",

      .iperms = ( R_META ),     /* marfs_getattr() does manual stuff */
      .bperms = 0,

      .dirty_pack_percent   =  0,
      .dirty_pack_threshold = 75,

      .quota_space = -1,          /* no limit */
      .quota_names = -1,             /* no limit */

      .shard_path  = NULL,
      .shard_count = 0,
   };
   push_namespace(&ns_dummy, find_repo_by_name("sproxyd_1M"));


   return 0;                    /* success */
}







// ...........................................................................
// NAMESPACES
// ...........................................................................

// Find the namespace corresponding to the mnt_suffx in a Namespace struct,
// which corresponds with a "namespace" managed by fuse.  We might
// pontentially have many namespaces (should be cheap to have as many as
// you want), and this lookup is done for every fuse call (and in parallel
// from pftool).  Also done every time we parse an object-ID xattr!  Thus,
// this should eventually be made efficient.
//
// One way to make this fast would be to look through all the namespaces
// and identify the places where a path diverges for different namespaces.
// This becomes a series of hardcoded substring-ops, on the path.  Each one
// identifies the next suffix in a suffix tree.  (Attractive Chaos has an
// open source suffix-array impl).  The leaves would be pointers to
// Namespaces.
//
// NOTE: If the fuse mount-point is "/A/B", and you provide a path like
//       "/A/B/C", then the "path" seen by fuse callbacks is "/C".  In
//       otherwords, we should never see MarFS_mnt_top, as part of the
//       incoming path.
//
// For a quick first-cut, there's only one namespace.  Your path is either
// in it or fails.

MarFS_Namespace* find_namespace_by_name(const char* name) {
   int i;
   size_t name_len = strlen( name );

   for (i=0; i<_ns_count; ++i) {
      MarFS_Namespace* ns = _ns[i];
      // We want to compare the whole name to ns->name, not just the first
      // name length characters.  That will match names that are substrings
      // of name to name incorrectly.
      //
      //  if (! strncmp(ns->name, name, ns->name_len))
      if (( ns->name_len == name_len ) && ( ! strcmp( ns->name, name ))) {
         return ns;
      }
   }
   return NULL;
}


/*
 * @@@-HTTPS:
 * The path that is passed into this function always starts with the
 * "/" character. That character and any others up to the next "/"
 * character are the namespace's mnt_path. A namespace's mnt_path
 * must begin with the "/" character and not contain any other "/"
 * characters after the initial one by definition. It is the FUSE
 * mount point and we'll always use a one-level mount point.
 */
MarFS_Namespace* find_namespace_by_mnt_path(const char* path) {
   int i;
   char *path_dup;
   char *path_dup_token;
   size_t path_dup_len;


   path_dup = strdup( path );
   path_dup_token = strtok( path_dup, "/" );
   path_dup_len = strlen( path_dup );

/*
 * At this point path_dup will include the leading "/" and any other
 * characters up to, but not including, the next "/" character in
 * path. This includes path_dup being able to be "/" (the root
 * namespace.
 */

   for (i=0; i<_ns_count; ++i) {
      MarFS_Namespace* ns = _ns[i];

      if (( ns->mnt_path_len == path_dup_len )
          && ( !strcmp( ns->mnt_path, path_dup ))) {
         free( path_dup );
         return ns;
      }
   }

   free( path_dup );
   return NULL;
}

// Let others traverse namespaces, without knowing how they are stored
NSIterator        namespace_iterator() {
   return (NSIterator){ .pos = 0 };
}

MarFS_Namespace*  namespace_next(NSIterator* it) {
   if (it->pos >= _ns_count)
      return NULL;
   else
      return _ns[it->pos++];
}




// ...........................................................................
// REPOS
// ...........................................................................

MarFS_Repo* find_repo(MarFS_Namespace* ns,
                      size_t           file_size,
                      int              interactive_write) { // bool
   if (interactive_write)
      return ns->iwrite_repo;
   else
      return find_in_range(ns->range_list, file_size);
}


// later, _repo will be a B-tree, or something, associating repo-names with
// repos.
MarFS_Repo* find_repo_by_name(const char* repo_name) {
   int i;
   for (i=0; i<_repo_count; ++i) {
      MarFS_Repo* repo = _repo[i];
      if (!strcmp(repo_name, repo->name))
         return repo;
   }
   return NULL;
}

MarFS_Repo* find_repo_by_range (MarFS_Namespace*	ns,
                                size_t             file_size) {   
   RangeList* range_list;

   if (ns) {
      for (range_list=ns->range_list; range_list; range_list=range_list->next) {

         if ( (file_size >= range_list->min)
              && ((file_size <= range_list->max)
                  || (range_list->max == -1))) {

            return range_list->repo;
         }
      }
   }
   return NULL;
}

// Let others traverse repos, without knowing how they are stored
RepoIterator repo_iterator() {
   return (RepoIterator){ .pos = 0 };
}

MarFS_Repo*  repo_next(RepoIterator* it) {
   if (it->pos >= _repo_count)
      return NULL;
   else
      return _repo[it->pos++];
}




// Give us a pointer to your list-pointer.  Your list-pointer should start
// out having a value of NULL.  We maintain the list of repos ASCCENDING by
// min file-size handled.  Return false in case of conflicts.  Conflicts
// include overlapping ranges, or gaps in ranges.  Call with <max>==-1, to
// make range from <min> to infinity.
int insert_in_range(RangeList**  list,
                    size_t       min,
                    size_t       max,
                    MarFS_Repo*  repo) {

   RangeList** insert = list;   // ptr to place to store ptr to new element

   // leave <ptr> pointing to the inserted element
   RangeList*  this;
   for (this=*list; this; this=this->next) {

      if (min < this->min) {    // insert before <this>

         if (max == -1) {
            LOG(LOG_ERR, "range [%ld, -1] includes range [%ld, %ld]\n",
                    min, this->min, this->max);
            return -1;
         }
         if (max < this->min) {
            LOG(LOG_ERR, "gap between range [%ld, %ld] and [%ld, %ld]\n",
                    min, max, this->min, this->max);
            return -1;
         }
         if (max > this->min) {
            LOG(LOG_ERR, "overlap in range [%ld, %ld] and [%ld, %ld]\n",
                    min, max, this->min, this->max);
            return -1;
         }

         // do the insert
         break;
      }
      insert = &this->next;
   }


   RangeList* elt = (RangeList*)malloc(sizeof(RangeList));
   elt->min  = min;
   elt->max  = max;
   elt->repo = repo;
   elt->next = *insert;
   *insert = elt;
   return 0;                    /* success */
}

// given a file-size, find the corresponding element in a RangeList, and
// return the corresponding repo.  insert_range() maintains repos in
// descending order of the block-sizes they handle, to make this as quick
// as possible.
MarFS_Repo* find_in_range(RangeList* list,
                          size_t     block_size) {
   while (list) {
      if (block_size >= list->min)
         return list->repo;
      list = list->next;
   }
   return NULL;
}