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;
}
int main( int argc, char *argv[] ) {

  char sectype_code = '_';
  MarFS_SecType marfs_sectype;
  char compType_code = '_';
  MarFS_CompType marfs_comptype;
  char comptype_code = '_';
  MarFS_CorrectType marfs_correcttype;
  char code;
  int ret_val;
  MarFS_Namespace_Ptr namespacePtr;
  MarFS_Repo_Ptr repoPtr;


  INIT_LOG();
  fprintf( stdout, "\n" );

  if (read_configuration()) {
    fprintf( stderr, "ERROR: Reading MarFS configuration failed.\n" );
    return 1;
  }
  fprintf( stdout, "CORRECT: The members of the MarFS config structure are:\n" );
  fprintf( stdout, "\tconfig name            : %s\n", marfs_config->name );
  fprintf( stdout, "\tconfig version         : %d.%d\n", marfs_config->version_major, marfs_config->version_minor );
  fprintf( stdout, "\tconfig mnt-top          : %s\n", marfs_config->mnt_top );
  // fprintf( stdout, "\tconfig namespace count : %lu\n", marfs_config->namespace_count );
  fprintf( stdout, "\n" );

  ret_val = free_configuration();
  if ( ! ret_val ) {
     fprintf( stdout, "CORRECT: free_configuration returned %d\n", ret_val );
     if ( marfs_config == NULL ) {
        fprintf( stdout, "CORRECT: We freed the MarFS configuration and it is now NULL.\n" );
     } else {
        fprintf( stderr, "ERROR: free_configuration did not set the MarFS configuration to NULL.\n" );
     }
  } else {
    fprintf( stderr, "ERROR: free_configuration returned %d\n", ret_val );
  }
  fprintf( stdout, "\n" );


  fprintf( stdout, "Re-reading the configuration to continue testing...\n" );
  read_configuration(); 
  if ( marfs_config == NULL ) {
    fprintf( stderr, "ERROR: Reading MarFS configuration failed.\n" );
    return 1;
  }
  fprintf( stdout, "\n" );


  if ( lookup_sectype( "none", &marfs_sectype )) {
    fprintf( stderr, "ERROR: Invalid sectype value of \"%s\".\n", "none" );
  } else {
    fprintf( stdout, "CORRECT: SecType value of \"%s\" translates to %d.\n", "none", marfs_sectype );
  }

  if ( encode_sectype( SECTYPE_NONE, &code )) {
    fprintf( stderr, "ERROR: Invalid enumeration value of %d.\n", SECTYPE_NONE );
  } else {
    fprintf( stdout, "CORRECT: Encode value of %d is \"%c\".\n", SECTYPE_NONE, code );
  }

  if ( decode_sectype( '_', &marfs_sectype )) {
    fprintf( stderr, "ERROR: Invalid code of \"%c\".\n", '_' );
  } else {
    fprintf( stdout, "CORRECT: Decode code of \"%c\" is %d.\n", '_',marfs_sectype ); 
  }

  fprintf( stdout, "\n" );

  if ( lookup_comptype( "none", &marfs_comptype )) {
    fprintf( stderr, "ERROR: Invalid comptype value of \"%s\".\n", "none" );
  } else {
    fprintf( stdout, "CORRECT: CompType value of \"%s\" translates to %d.\n", "none", marfs_comptype );
  }

  if ( encode_comptype( COMPTYPE_NONE, &code )) {
    fprintf( stderr, "ERROR: Invalid enumeration value of %d.\n", COMPTYPE_NONE );
  } else {
    fprintf( stdout, "CORRECT: Encode value of %d is \"%c\".\n", COMPTYPE_NONE, code );
  }

  if ( decode_comptype( '_', &marfs_comptype )) {
    fprintf( stderr, "ERROR: Invalid code of \"%c\".\n", '_' );
  } else {
    fprintf( stdout, "CORRECT: Decode code of \"%c\" is %d.\n", '_',marfs_comptype ); 
  }

  fprintf( stdout, "\n" );

  if ( lookup_correcttype( "none", &marfs_correcttype )) {
    fprintf( stderr, "ERROR: Invalid correcttype value of \"%s\".\n", "none" );
  } else {
    fprintf( stdout, "CORRECT: CorrectType value of \"%s\" translates to %d.\n", "none", marfs_correcttype );
  }

  if ( encode_correcttype( CORRECTTYPE_NONE, &code )) {
    fprintf( stderr, "ERROR: Invalid enumeration value of %d.\n", CORRECTTYPE_NONE );
  } else {
    fprintf( stdout, "CORRECT: Encode value of %d is \"%c\".\n", CORRECTTYPE_NONE, code );
  }

  if ( decode_correcttype( '_', &marfs_correcttype )) {
    fprintf( stderr, "ERROR: Invalid code of \"%c\".\n", '_' );
  } else {
    fprintf( stdout, "CORRECT: Decode code of \"%c\" is %d.\n", '_',marfs_correcttype ); 
  }
  fprintf( stdout, "\n" );


  namespacePtr = find_namespace_by_name( "BoGuS" );
  if ( namespacePtr == NULL ) {
    fprintf( stdout, "CORRECT: Namespace \"BoGuS\" does not exist.\n" );
  } else {
    fprintf( stderr, "ERROR: Namespace \"BoGuS\" does not exist and was found.\n" );
  }
  fprintf( stdout, "\n" );

  namespacePtr = find_namespace_by_name( "s3" );
  if ( namespacePtr != NULL ) {
    fprintf( stdout, "CORRECT: Namespace \"s3\" does exist and has mnt_path \"%s\".\n", namespacePtr->mnt_path );
  } else {
    fprintf( stderr, "ERROR: Namespace \"s3\" does exist and was not found.\n" );
  }
  fprintf( stdout, "\n" );


  namespacePtr = find_namespace_by_mnt_path( "/BoGuS" );
  if ( namespacePtr == NULL ) {
    fprintf( stdout, "CORRECT: Mntpath \"/BoGuS\" does not exist.\n" );
  } else {
    fprintf( stderr, "ERROR: Mntpath \"/BoGuS\" does not exist and was found.\n" );
  }
  fprintf( stdout, "\n" );


  namespacePtr = find_namespace_by_mnt_path( "/s3" );
  if ( namespacePtr != NULL ) {
    fprintf( stdout, "CORRECT: Mntpath \"/s3\" does exist and has name \"%s\".\n", namespacePtr->name );
  } else {
    fprintf( stderr, "ERROR: Mntpath \"/s3\" does exist and was not found.\n" );
  }

  repoPtr = find_repo_by_range( namespacePtr, 38 );
  if ( repoPtr != NULL ) {
    fprintf( stdout, "CORRECT: Namespace \"%s\" has a repo \"%s\" for files of size 38.\n",
			namespacePtr->name,
			repoPtr->name );
  } else {
    fprintf( stderr, "ERROR: Namespace \"%s\" should have a repo for files of size 38.\n",
			namespacePtr->name );
  }
  fprintf( stdout, "\n" );

  namespacePtr = find_namespace_by_mnt_path( "/" );
  if ( namespacePtr != NULL ) {
    fprintf( stdout, "CORRECT: Mntpath \"/\" does exist and has name \"%s\".\n", namespacePtr->name );
  } else {
    fprintf( stderr, "ERROR: Mntpath \"/\" does exist and was not found.\n" );
  }
  fprintf( stdout, "\n" );



/*
 * Since the file_size argument is size_t, that is unsigned and negative numbers
 * are not allowed.
 *
  fprintf( stdout, "\n" );

  repoPtr = find_repo_by_range( namespacePtr, -2 );
  if ( repoPtr == NULL ) {
    fprintf( stdout, "CORRECT: Namespace \"%s\" should not have a repo for files of size -2.\n",
			namespacePtr->name );
  } else {
    fprintf( stderr, "ERROR: Namespace \"%s\" incorrectly has a repo \"%s\" for files of size -2.\n",
			namespacePtr->name,
                        repoPtr->repo_name );
  }
 */

  fprintf( stdout, "\n" );

  repoPtr = find_repo_by_range( NULL, 38 );
  if ( repoPtr == NULL ) {
    fprintf( stdout, "CORRECT: A NULL namespace should not have a repo for files of size 38.\n" );
  } else {
    fprintf( stderr, "ERROR: A NULL namespace incorrectly has a repo \"%s\" for files of size 38.\n",
			repoPtr->name );
  }

  fprintf( stdout, "\n" );

  repoPtr = find_repo_by_name( "BoGuS" );
  if ( repoPtr == NULL ) {
    fprintf( stdout, "CORRECT: Repo name \"BoGuS\" does not exist.\n" );
  } else {
    fprintf( stderr, "ERROR: Repo name \"BoGuS\" does not exist and was found.\n" );
  }

  fprintf( stdout, "\n" );

  repoPtr = find_repo_by_name( "emcS3_00" );
  if ( repoPtr != NULL ) {
    fprintf( stdout, "CORRECT: Repo name \"emcS3_00\" does exist and has host \"%s\".\n", repoPtr->host );
  } else {
    fprintf( stderr, "ERROR: Repo name \"emcS3_00\" does exist and was not found.\n" );
  }
  fprintf( stdout, "\n" );

  // --- show contents of all repos
  RepoIterator rit = repo_iterator();
  while (( repoPtr = repo_next( &rit )) != NULL ) {
     debug_repo(repoPtr);
     fprintf(stdout, "\n");
  }
  fprintf(stdout, "\n");

  // --- show contents of all namespaces
  NSIterator nit = namespace_iterator();
  while (( namespacePtr = namespace_next( &nit )) != NULL ) {
     debug_namespace(namespacePtr);
     fprintf(stdout, "\n");
  }
  fprintf( stdout, "\n" );


  return 0;
}