diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index 8b56a29..8647889 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -3220,11 +3220,12 @@ int define_filename_trans(void)
 	ebitmap_t e_tclasses;
 	ebitmap_node_t *snode, *tnode, *cnode;
 	filename_trans_t *ft;
+	filename_trans_datum_t *ftdatum;
 	filename_trans_rule_t *ftr;
 	type_datum_t *typdatum;
 	uint32_t otype;
 	unsigned int c, s, t;
-	int add;
+	int add, rc;
 
 	if (pass == 1) {
 		/* stype */
@@ -3308,40 +3309,44 @@ int define_filename_trans(void)
 			ebitmap_for_each_bit(&e_ttypes, tnode, t) {
 				if (!ebitmap_node_get_bit(tnode, t))
 					continue;
-	
-				for (ft = policydbp->filename_trans; ft; ft = ft->next) {
-					if (ft->stype == (s + 1) &&
-					    ft->ttype == (t + 1) &&
-					    ft->tclass == (c + 1) &&
-					    !strcmp(ft->name, name)) {
-						yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s",
-							 name, 
-							 policydbp->p_type_val_to_name[s],
-							 policydbp->p_type_val_to_name[t],
-							 policydbp->p_class_val_to_name[c]);
-						goto bad;
-					}
-				}
-	
-				ft = malloc(sizeof(*ft));
+
+				ft = calloc(1, sizeof(*ft));
 				if (!ft) {
 					yyerror("out of memory");
 					goto bad;
 				}
-				memset(ft, 0, sizeof(*ft));
-	
-				ft->next = policydbp->filename_trans;
-				policydbp->filename_trans = ft;
-	
+				ft->stype = s+1;
+				ft->ttype = t+1;
+				ft->tclass = c+1;
 				ft->name = strdup(name);
 				if (!ft->name) {
 					yyerror("out of memory");
 					goto bad;
 				}
-				ft->stype = s + 1;
-				ft->ttype = t + 1;
-				ft->tclass = c + 1;
-				ft->otype = otype;
+
+				ftdatum = hashtab_search(policydbp->filename_trans,
+							 (hashtab_key_t)ft);
+				if (ftdatum) {
+					yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s",
+						 name,
+						 policydbp->p_type_val_to_name[s],
+						 policydbp->p_type_val_to_name[t],
+						 policydbp->p_class_val_to_name[c]);
+					goto bad;
+				}
+
+				ftdatum = calloc(1, sizeof(*ftdatum));
+				if (!ftdatum) {
+					yyerror("out of memory");
+					goto bad;
+				}
+				rc = hashtab_insert(policydbp->filename_trans,
+						    (hashtab_key_t)ft,
+						    ftdatum);
+				if (rc) {
+					yyerror("out of memory");
+					goto bad;
+				}
 			}
 		}
 	
diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c
index a78ce81..d91fafd 100644
--- a/checkpolicy/test/dispol.c
+++ b/checkpolicy/test/dispol.c
@@ -330,18 +330,38 @@ static void display_role_trans(policydb_t *p, FILE *fp)
 	}
 }
 
+struct filenametr_display_args {
+	policydb_t *p;
+	FILE *fp;
+};
+
+static int filenametr_display(hashtab_key_t key,
+			      hashtab_datum_t datum,
+			      void *ptr)
+{
+	struct filename_trans *ft = (struct filename_trans *)key;
+	struct filename_trans_datum *ftdatum = datum;
+	struct filenametr_display_args *args = ptr;
+	policydb_t *p = args->p;
+	FILE *fp = args->fp;
+
+	display_id(p, fp, SYM_TYPES, ft->stype - 1, "");
+	display_id(p, fp, SYM_TYPES, ft->ttype - 1, "");
+	display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":");
+	display_id(p, fp, SYM_TYPES, ftdatum->otype - 1, "");
+	fprintf(fp, " %s\n", ft->name);
+	return 0;
+}
+
+
 static void display_filename_trans(policydb_t *p, FILE *fp)
 {
-	filename_trans_t *ft;
+	struct filenametr_display_args args;
 
 	fprintf(fp, "filename_trans rules:\n");
-	for (ft = p->filename_trans; ft; ft = ft->next) {
-		display_id(p, fp, SYM_TYPES, ft->stype - 1, "");
-		display_id(p, fp, SYM_TYPES, ft->ttype - 1, "");
-		display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":");
-		display_id(p, fp, SYM_TYPES, ft->otype - 1, "");
-		fprintf(fp, " %s\n", ft->name);
-	}
+	args.p = p;
+	args.fp = fp;
+	hashtab_map(p->filename_trans, filenametr_display, &args);
 }
 
 int menu(void)
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
index a813201..d33981b 100644
--- a/libsepol/cil/src/cil_binary.c
+++ b/libsepol/cil/src/cil_binary.c
@@ -1131,13 +1131,13 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru
 	class_datum_t *sepol_obj = NULL;
 	struct cil_list *class_list;
 	type_datum_t *sepol_result = NULL;
-	filename_trans_t *new = NULL;
+	filename_trans_t *newkey = NULL;
+	filename_trans_datum_t *newdatum = NULL, *otype = NULL;
 	ebitmap_t src_bitmap, tgt_bitmap;
 	ebitmap_node_t *node1, *node2;
 	unsigned int i, j;
 	struct cil_list_item *c;
 	char *name = DATUM(typetrans->name)->name;
-	uint32_t *otype = NULL;
 
 	if (name == CIL_KEY_STAR) {
 		struct cil_type_rule trans;
@@ -1177,20 +1177,20 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru
 				rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj);
 				if (rc != SEPOL_OK) goto exit;
 
-				new = cil_malloc(sizeof(*new));
-				memset(new, 0, sizeof(*new));
-				new->stype = sepol_src->s.value;
-				new->ttype = sepol_tgt->s.value;
-				new->tclass = sepol_obj->s.value;
-				new->otype = sepol_result->s.value;
-				new->name = cil_strdup(name);
+				newkey = cil_calloc(1, sizeof(*newkey));
+				newdatum = cil_calloc(1, sizeof(*newdatum));
+				newkey->stype = sepol_src->s.value;
+				newkey->ttype = sepol_tgt->s.value;
+				newkey->tclass = sepol_obj->s.value;
+				newkey->name = cil_strdup(name);
+				newdatum->otype = sepol_result->s.value;
 
-				rc = hashtab_insert(filename_trans_table, (hashtab_key_t)new, &(new->otype));
+				rc = hashtab_insert(filename_trans_table, (hashtab_key_t)newkey, newdatum);
 				if (rc != SEPOL_OK) {
 					if (rc == SEPOL_EEXIST) {
 						add = CIL_FALSE;
-						otype = hashtab_search(filename_trans_table, (hashtab_key_t)new);
-						if (new->otype != *otype) {
+						otype = hashtab_search(filename_trans_table, (hashtab_key_t)newkey);
+						if (newdatum->otype != otype->otype) {
 							cil_log(CIL_ERR, "Conflicting name type transition rules\n");
 						} else {
 							rc = SEPOL_OK;
@@ -1201,11 +1201,17 @@ int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *db, stru
 				}
 
 				if (add == CIL_TRUE) {
-					new->next = pdb->filename_trans;
-					pdb->filename_trans = new;
+					rc = hashtab_insert(pdb->filename_trans,
+							    (hashtab_key_t)newkey,
+							    newdatum);
+					if (rc != SEPOL_OK) {
+						cil_log(CIL_ERR, "Out of memory\n");
+						goto exit;
+					}
 				} else {
-					free(new->name);
-					free(new);
+					free(newkey->name);
+					free(newkey);
+					free(newdatum);
 					if (rc != SEPOL_OK) {
 						goto exit;
 					}
@@ -2943,7 +2949,8 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st
 	type_datum_t *sepol_tgt = NULL;
 	class_datum_t *sepol_class = NULL;
 	struct cil_list *class_list;
-	range_trans_t *new;
+	range_trans_t *newkey = NULL;
+	struct mls_range *newdatum = NULL;
 	ebitmap_t src_bitmap, tgt_bitmap;
 	ebitmap_node_t *node1, *node2;
 	unsigned int i, j;
@@ -2975,24 +2982,25 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st
 				rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_class);
 				if (rc != SEPOL_OK) goto exit;
 
-				new = cil_malloc(sizeof(*new));
-				memset(new, 0, sizeof(range_trans_t));
-				new->source_type = sepol_src->s.value;
-				new->target_type = sepol_tgt->s.value;
-				new->target_class = sepol_class->s.value;
-				rc = __cil_levelrange_to_mls_range(pdb, rangetrans->range, &new->target_range);
+				newkey = cil_calloc(1, sizeof(*newkey));
+				newdatum = cil_calloc(1, sizeof(*newdatum));
+				newkey->source_type = sepol_src->s.value;
+				newkey->target_type = sepol_tgt->s.value;
+				newkey->target_class = sepol_class->s.value;
+				rc = __cil_levelrange_to_mls_range(pdb, rangetrans->range, newdatum);
 				if (rc != SEPOL_OK) {
-					free(new);
+					free(newkey);
+					free(newdatum);
 					goto exit;
 				}
 
 				rc = SEPOL_OK;
-				rc = hashtab_insert(range_trans_table, (hashtab_key_t)new, &(new->target_range));
+				rc = hashtab_insert(range_trans_table, (hashtab_key_t)newkey, newdatum);
 				if (rc != SEPOL_OK) {
 					if (rc == SEPOL_EEXIST) {
 						add = CIL_FALSE;
-						o_range = hashtab_search(range_trans_table, (hashtab_key_t)new);
-						if (!mls_range_eq(&new->target_range, o_range)) {
+						o_range = hashtab_search(range_trans_table, (hashtab_key_t)newkey);
+						if (!mls_range_eq(newdatum, o_range)) {
 							cil_log(CIL_ERR, "Conflicting Range transition rules\n");
 						} else {
 							rc = SEPOL_OK;
@@ -3003,11 +3011,20 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st
 				}
 
 				if (add == CIL_TRUE) {
-					new->next = pdb->range_tr;
-					pdb->range_tr = new;
+					rc = hashtab_insert(pdb->range_tr,
+							    (hashtab_key_t)newkey,
+							    newdatum);
+					if (rc != SEPOL_OK) {
+						mls_range_destroy(newdatum);
+						free(newdatum);
+						free(newkey);
+						cil_log(CIL_ERR, "Out of memory\n");
+						goto exit;
+					}
 				} else {
-					mls_range_destroy(&new->target_range);
-					free(new);
+					mls_range_destroy(newdatum);
+					free(newdatum);
+					free(newkey);
 					if (rc != SEPOL_OK) {
 						goto exit;
 					}
diff --git a/libsepol/include/sepol/policydb/context.h b/libsepol/include/sepol/policydb/context.h
index dbb7c3e..c844c37 100644
--- a/libsepol/include/sepol/policydb/context.h
+++ b/libsepol/include/sepol/policydb/context.h
@@ -50,6 +50,46 @@ static inline int mls_context_cpy(context_struct_t * dst,
 	return 0;
 }
 
+/*
+ * Sets both levels in the MLS range of 'dst' to the low level of 'src'.
+ */
+static inline int mls_context_cpy_low(context_struct_t *dst, context_struct_t *src)
+{
+	int rc;
+
+	dst->range.level[0].sens = src->range.level[0].sens;
+	rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
+	if (rc)
+		goto out;
+
+	dst->range.level[1].sens = src->range.level[0].sens;
+	rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[0].cat);
+	if (rc)
+		ebitmap_destroy(&dst->range.level[0].cat);
+out:
+	return rc;
+}
+
+/*
+ * Sets both levels in the MLS range of 'dst' to the high level of 'src'.
+ */
+static inline int mls_context_cpy_high(context_struct_t *dst, context_struct_t *src)
+{
+	int rc;
+
+	dst->range.level[0].sens = src->range.level[1].sens;
+	rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[1].cat);
+	if (rc)
+		goto out;
+
+	dst->range.level[1].sens = src->range.level[1].sens;
+	rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
+	if (rc)
+		ebitmap_destroy(&dst->range.level[0].cat);
+out:
+	return rc;
+}
+
 static inline int mls_context_cmp(context_struct_t * c1, context_struct_t * c2)
 {
 	return (mls_level_eq(&c1->range.level[0], &c2->range.level[0]) &&
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index 77e46fb..31cdd76 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -162,10 +162,12 @@ typedef struct filename_trans {
 	uint32_t ttype;
 	uint32_t tclass;
 	char *name;
-	uint32_t otype;
-	struct filename_trans *next;
 } filename_trans_t;
 
+typedef struct filename_trans_datum {
+	uint32_t otype;		/* expected of new object */
+} filename_trans_datum_t;
+
 /* Type attributes */
 typedef struct type_datum {
 	symtab_datum_t s;
@@ -218,8 +220,6 @@ typedef struct range_trans {
 	uint32_t source_type;
 	uint32_t target_type;
 	uint32_t target_class;
-	mls_range_t target_range;
-	struct range_trans *next;
 } range_trans_t;
 
 /* Boolean data type */
@@ -555,9 +555,6 @@ typedef struct policydb {
 	/* role transitions */
 	role_trans_t *role_tr;
 
-	/* type transition rules with a 'name' component */
-	filename_trans_t *filename_trans;
-
 	/* role allows */
 	role_allow_t *role_allow;
 
@@ -570,8 +567,11 @@ typedef struct policydb {
 	   fixed labeling behavior. */
 	genfs_t *genfs;
 
-	/* range transitions */
-	range_trans_t *range_tr;
+	/* range transitions table (range_trans_key -> mls_range) */
+	hashtab_t range_tr;
+
+	/* file transitions with the last path component */
+	hashtab_t filename_trans;
 
 	ebitmap_t *type_attr_map;
 
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index 32df6f8..c5e0f3c 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -1385,10 +1385,12 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules)
 static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules)
 {
 	unsigned int i, j;
-	filename_trans_t *new_trans, *cur_trans;
+	filename_trans_t key, *new_trans;
+	filename_trans_datum_t *otype;
 	filename_trans_rule_t *cur_rule;
 	ebitmap_t stypes, ttypes;
 	ebitmap_node_t *snode, *tnode;
+	int rc;
 
 	cur_rule = rules;
 	while (cur_rule) {
@@ -1418,40 +1420,32 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r
 				if (!ebitmap_node_get_bit(tnode, j))
 					continue;
 
-				cur_trans = state->out->filename_trans;
-				while (cur_trans) {
-					if ((cur_trans->stype == i + 1) &&
-					    (cur_trans->ttype == j + 1) &&
-					    (cur_trans->tclass == cur_rule->tclass) &&
-					    (!strcmp(cur_trans->name, cur_rule->name))) {
-						/* duplicate rule, who cares */
-						if (cur_trans->otype == mapped_otype)
-							break;
-
-						ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\":  %s vs %s",
-						    state->out->p_type_val_to_name[i],
-						    state->out->p_type_val_to_name[j],
-						    state->out->p_class_val_to_name[cur_trans->tclass - 1],
-						    cur_trans->name,
-						    state->out->p_type_val_to_name[cur_trans->otype - 1],
-						    state->out->p_type_val_to_name[mapped_otype - 1]);
+				key.stype = i + 1;
+				key.ttype = j + 1;
+				key.tclass = cur_rule->tclass;
+				key.name = cur_rule->name;
+				otype = hashtab_search(state->out->filename_trans,
+						       (hashtab_key_t) &key);
+				if (otype) {
+					/* duplicate rule, ignore */
+					if (otype->otype == mapped_otype)
+						continue;
 
-						return -1;
-					}
-					cur_trans = cur_trans->next;
+					ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\":  %s vs %s",
+					    state->out->p_type_val_to_name[i],
+					    state->out->p_type_val_to_name[j],
+					    state->out->p_class_val_to_name[cur_rule->tclass - 1],
+					    cur_rule->name,
+					    state->out->p_type_val_to_name[otype->otype - 1],
+					    state->out->p_type_val_to_name[mapped_otype - 1]);
+					return -1;
 				}
-				/* duplicate rule, who cares */
-				if (cur_trans)
-					continue;
 
-				new_trans = malloc(sizeof(*new_trans));
+				new_trans = calloc(1, sizeof(*new_trans));
 				if (!new_trans) {
 					ERR(state->handle, "Out of memory!");
 					return -1;
 				}
-				memset(new_trans, 0, sizeof(*new_trans));
-				new_trans->next = state->out->filename_trans;
-				state->out->filename_trans = new_trans;
 
 				new_trans->name = strdup(cur_rule->name);
 				if (!new_trans->name) {
@@ -1461,7 +1455,21 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r
 				new_trans->stype = i + 1;
 				new_trans->ttype = j + 1;
 				new_trans->tclass = cur_rule->tclass;
-				new_trans->otype = mapped_otype;
+
+				otype = calloc(1, sizeof(*otype));
+				if (!otype) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				otype->otype = mapped_otype;
+
+				rc = hashtab_insert(state->out->filename_trans,
+						    (hashtab_key_t)new_trans,
+						    otype);
+				if (rc) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
 			}
 		}
 
@@ -1477,63 +1485,67 @@ static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t tclass,
 			      mls_semantic_range_t * trange,
 			      expand_state_t * state)
 {
-	range_trans_t *rt, *check_rt = state->out->range_tr;
-	mls_range_t exp_range;
+	range_trans_t *rt = NULL, key;
+	mls_range_t *r, *exp_range = NULL;
 	int rc = -1;
 
-	if (mls_semantic_range_expand(trange, &exp_range, state->out,
+	exp_range = calloc(1, sizeof(*exp_range));
+	if (!exp_range) {
+		ERR(state->handle, "Out of memory!");
+		return -1;
+	}
+
+	if (mls_semantic_range_expand(trange, exp_range, state->out,
 				      state->handle))
-		goto out;
+		goto err;
 
 	/* check for duplicates/conflicts */
-	while (check_rt) {
-		if ((check_rt->source_type == stype) &&
-		    (check_rt->target_type == ttype) &&
-		    (check_rt->target_class == tclass)) {
-			if (mls_range_eq(&check_rt->target_range, &exp_range)) {
-				/* duplicate */
-				break;
-			} else {
-				/* conflict */
-				ERR(state->handle,
-				    "Conflicting range trans rule %s %s : %s",
-				    state->out->p_type_val_to_name[stype - 1],
-				    state->out->p_type_val_to_name[ttype - 1],
-				    state->out->p_class_val_to_name[tclass -
-								    1]);
-				goto out;
-			}
-		}
-		check_rt = check_rt->next;
-	}
-	if (check_rt) {
-		/* this is a dup - skip */
-		rc = 0;
-		goto out;
+	key.source_type = stype;
+	key.target_type = ttype;
+	key.target_class = tclass;
+	r = hashtab_search(state->out->range_tr, (hashtab_key_t) &key);
+	if (r) {
+		if (mls_range_eq(r, exp_range)) {
+			/* duplicate, ignore */
+			mls_range_destroy(exp_range);
+			free(exp_range);
+			return 0;
+		}
+
+		/* conflict */
+		ERR(state->handle,
+		    "Conflicting range trans rule %s %s : %s",
+		    state->out->p_type_val_to_name[stype - 1],
+		    state->out->p_type_val_to_name[ttype - 1],
+		    state->out->p_class_val_to_name[tclass - 1]);
+		goto err;
 	}
 
-	rt = (range_trans_t *) calloc(1, sizeof(range_trans_t));
+	rt = calloc(1, sizeof(*rt));
 	if (!rt) {
 		ERR(state->handle, "Out of memory!");
-		goto out;
+		goto err;
 	}
-
-	rt->next = state->out->range_tr;
-	state->out->range_tr = rt;
-
 	rt->source_type = stype;
 	rt->target_type = ttype;
 	rt->target_class = tclass;
-	if (mls_range_cpy(&rt->target_range, &exp_range)) {
+
+	rc = hashtab_insert(state->out->range_tr, (hashtab_key_t) rt,
+			    exp_range);
+	if (rc) {
 		ERR(state->handle, "Out of memory!");
-		goto out;
-	}
+		goto err;
 
-	rc = 0;
+	}
 
-      out:
-	mls_range_destroy(&exp_range);
-	return rc;
+	return 0;
+err:
+	free(rt);
+	if (exp_range) {
+		mls_range_destroy(exp_range);
+		free(exp_range);
+	}
+	return -1;
 }
 
 static int expand_range_trans(expand_state_t * state,
diff --git a/libsepol/src/mls.c b/libsepol/src/mls.c
index 8047d91..be85475 100644
--- a/libsepol/src/mls.c
+++ b/libsepol/src/mls.c
@@ -610,22 +610,45 @@ int mls_compute_sid(policydb_t * policydb,
 		    sepol_security_class_t tclass,
 		    uint32_t specified, context_struct_t * newcontext)
 {
-	range_trans_t *rtr;
+	range_trans_t rtr;
+	struct mls_range *r;
+	struct class_datum *cladatum;
+	int default_range = 0;
+
 	if (!policydb->mls)
 		return 0;
 
 	switch (specified) {
 	case AVTAB_TRANSITION:
 		/* Look for a range transition rule. */
-		for (rtr = policydb->range_tr; rtr; rtr = rtr->next) {
-			if (rtr->source_type == scontext->type &&
-			    rtr->target_type == tcontext->type &&
-			    rtr->target_class == tclass) {
-				/* Set the range from the rule */
-				return mls_range_set(newcontext,
-						     &rtr->target_range);
-			}
+		rtr.source_type = scontext->type;
+		rtr.target_type = tcontext->type;
+		rtr.target_class = tclass;
+		r = hashtab_search(policydb->range_tr, (hashtab_key_t) &rtr);
+		if (r)
+			return mls_range_set(newcontext, r);
+
+		if (tclass && tclass <= policydb->p_classes.nprim) {
+			cladatum = policydb->class_val_to_struct[tclass - 1];
+			if (cladatum)
+				default_range = cladatum->default_range;
+		}
+
+		switch (default_range) {
+		case DEFAULT_SOURCE_LOW:
+			return mls_context_cpy_low(newcontext, scontext);
+		case DEFAULT_SOURCE_HIGH:
+			return mls_context_cpy_high(newcontext, scontext);
+		case DEFAULT_SOURCE_LOW_HIGH:
+			return mls_context_cpy(newcontext, scontext);
+		case DEFAULT_TARGET_LOW:
+			return mls_context_cpy_low(newcontext, tcontext);
+		case DEFAULT_TARGET_HIGH:
+			return mls_context_cpy_high(newcontext, tcontext);
+		case DEFAULT_TARGET_LOW_HIGH:
+			return mls_context_cpy(newcontext, tcontext);
 		}
+
 		/* Fallthrough */
 	case AVTAB_CHANGE:
 		if (tclass == SECCLASS_PROCESS)
@@ -635,15 +658,8 @@ int mls_compute_sid(policydb_t * policydb,
 			/* Use the process effective MLS attributes. */
 			return mls_scopy_context(newcontext, scontext);
 	case AVTAB_MEMBER:
-		/* Only polyinstantiate the MLS attributes if
-		   the type is being polyinstantiated */
-		if (newcontext->type != tcontext->type) {
-			/* Use the process effective MLS attributes. */
-			return mls_scopy_context(newcontext, scontext);
-		} else {
-			/* Use the related object MLS attributes. */
-			return mls_copy_context(newcontext, tcontext);
-		}
+		/* Use the process effective MLS attributes. */
+		return mls_context_cpy_low(newcontext, scontext);
 	default:
 		return -EINVAL;
 	}
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index d1019e4..9d15fd1 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -721,6 +721,77 @@ static int roles_init(policydb_t * p)
 	goto out;
 }
 
+static inline unsigned long
+partial_name_hash(unsigned long c, unsigned long prevhash)
+{
+	return (prevhash + (c << 4) + (c >> 4)) * 11;
+}
+
+static unsigned int filenametr_hash(hashtab_t h, hashtab_key_t k)
+{
+	const struct filename_trans *ft = (const struct filename_trans *)k;
+	unsigned long hash;
+	unsigned int byte_num;
+	unsigned char focus;
+
+	hash = ft->stype ^ ft->ttype ^ ft->tclass;
+
+	byte_num = 0;
+	while ((focus = ft->name[byte_num++]))
+		hash = partial_name_hash(focus, hash);
+	return hash & (h->size - 1);
+}
+
+static int filenametr_cmp(hashtab_t h __attribute__ ((unused)),
+			  hashtab_key_t k1, hashtab_key_t k2)
+{
+	const struct filename_trans *ft1 = (const struct filename_trans *)k1;
+	const struct filename_trans *ft2 = (const struct filename_trans *)k2;
+	int v;
+
+	v = ft1->stype - ft2->stype;
+	if (v)
+		return v;
+
+	v = ft1->ttype - ft2->ttype;
+	if (v)
+		return v;
+
+	v = ft1->tclass - ft2->tclass;
+	if (v)
+		return v;
+
+	return strcmp(ft1->name, ft2->name);
+
+}
+
+static unsigned int rangetr_hash(hashtab_t h, hashtab_key_t k)
+{
+	const struct range_trans *key = (const struct range_trans *)k;
+	return (key->source_type + (key->target_type << 3) +
+		(key->target_class << 5)) & (h->size - 1);
+}
+
+static int rangetr_cmp(hashtab_t h __attribute__ ((unused)),
+		       hashtab_key_t k1, hashtab_key_t k2)
+{
+	const struct range_trans *key1 = (const struct range_trans *)k1;
+	const struct range_trans *key2 = (const struct range_trans *)k2;
+	int v;
+
+	v = key1->source_type - key2->source_type;
+	if (v)
+		return v;
+
+	v = key1->target_type - key2->target_type;
+	if (v)
+		return v;
+
+	v = key1->target_class - key2->target_class;
+
+	return v;
+}
+
 /*
  * Initialize a policy database structure.
  */
@@ -730,50 +801,63 @@ int policydb_init(policydb_t * p)
 
 	memset(p, 0, sizeof(policydb_t));
 
-	ebitmap_init(&p->policycaps);
-
-	ebitmap_init(&p->permissive_map);
-
 	for (i = 0; i < SYM_NUM; i++) {
 		p->sym_val_to_name[i] = NULL;
 		rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
 		if (rc)
-			goto out_free_symtab;
+			goto out;
 	}
 
 	/* initialize the module stuff */
 	for (i = 0; i < SYM_NUM; i++) {
 		if (symtab_init(&p->scope[i], symtab_sizes[i])) {
-			goto out_free_symtab;
+			goto out;
 		}
 	}
 	if ((p->global = avrule_block_create()) == NULL ||
 	    (p->global->branch_list = avrule_decl_create(1)) == NULL) {
-		goto out_free_symtab;
+		goto out;
 	}
 	p->decl_val_to_struct = NULL;
 
 	rc = avtab_init(&p->te_avtab);
 	if (rc)
-		goto out_free_symtab;
+		goto out;
 
 	rc = roles_init(p);
 	if (rc)
-		goto out_free_symtab;
+		goto out;
+
+	p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
+	if (!p->filename_trans) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
+	if (!p->range_tr) {
+		rc = -ENOMEM;
+		goto out;
+	}
 
 	rc = cond_policydb_init(p);
 	if (rc)
-		goto out_free_symtab;
-      out:
-	return rc;
+		goto out;
+
+	ebitmap_init(&p->policycaps);
+	ebitmap_init(&p->permissive_map);
 
-      out_free_symtab:
+	return 0;
+
+out:
+	hashtab_destroy(p->filename_trans);
+	hashtab_destroy(p->range_tr);
 	for (i = 0; i < SYM_NUM; i++) {
 		hashtab_destroy(p->symtab[i].table);
 		hashtab_destroy(p->scope[i].table);
 	}
 	avrule_block_list_destroy(p->global);
-	goto out;
+	return 0;
 }
 
 int policydb_role_cache(hashtab_key_t key
@@ -1242,6 +1326,27 @@ static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
 common_destroy, class_destroy, role_destroy, type_destroy, user_destroy,
 	    cond_destroy_bool, sens_destroy, cat_destroy,};
 
+static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
+			      void *p __attribute__ ((unused)))
+{
+	struct filename_trans *ft = (struct filename_trans *)key;
+	free(ft->name);
+	free(key);
+	free(datum);
+	return 0;
+}
+
+static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum,
+			    void *p __attribute__ ((unused)))
+{
+	struct mls_range *rt = (struct mls_range *)datum;
+	free(key);
+	ebitmap_destroy(&rt->level[0].cat);
+	ebitmap_destroy(&rt->level[1].cat);
+	free(datum);
+	return 0;
+}
+
 void ocontext_selinux_free(ocontext_t **ocontexts)
 {
 	ocontext_t *c, *ctmp;
@@ -1291,8 +1396,6 @@ void policydb_destroy(policydb_t * p)
 	unsigned int i;
 	role_allow_t *ra, *lra = NULL;
 	role_trans_t *tr, *ltr = NULL;
-	range_trans_t *rt, *lrt = NULL;
-	filename_trans_t *ft, *nft;
 
 	if (!p)
 		return;
@@ -1358,14 +1461,6 @@ void policydb_destroy(policydb_t * p)
 	if (ltr)
 		free(ltr);
 
-	ft = p->filename_trans;
-	while (ft) {
-		nft = ft->next;
-		free(ft->name);
-		free(ft);
-		ft = nft;
-	}
-
 	for (ra = p->role_allow; ra; ra = ra->next) {
 		if (lra)
 			free(lra);
@@ -1374,19 +1469,11 @@ void policydb_destroy(policydb_t * p)
 	if (lra)
 		free(lra);
 
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		if (lrt) {
-			ebitmap_destroy(&lrt->target_range.level[0].cat);
-			ebitmap_destroy(&lrt->target_range.level[1].cat);
-			free(lrt);
-		}
-		lrt = rt;
-	}
-	if (lrt) {
-		ebitmap_destroy(&lrt->target_range.level[0].cat);
-		ebitmap_destroy(&lrt->target_range.level[1].cat);
-		free(lrt);
-	}
+	hashtab_map(p->filename_trans, filenametr_destroy, NULL);
+	hashtab_destroy(p->filename_trans);
+
+	hashtab_map(p->range_tr, range_tr_destroy, NULL);
+	hashtab_destroy(p->range_tr);
 
 	if (p->type_attr_map) {
 		for (i = 0; i < p->p_types.nprim; i++) {
@@ -2428,11 +2515,12 @@ int role_allow_read(role_allow_t ** r, struct policy_file *fp)
 	return 0;
 }
 
-int filename_trans_read(filename_trans_t **t, struct policy_file *fp)
+int filename_trans_read(policydb_t *p, struct policy_file *fp)
 {
 	unsigned int i;
 	uint32_t buf[4], nel, len;
-	filename_trans_t *ft, *lft;
+	filename_trans_t *ft;
+	filename_trans_datum_t *otype;
 	int rc;
 	char *name;
 
@@ -2441,43 +2529,54 @@ int filename_trans_read(filename_trans_t **t, struct policy_file *fp)
 		return -1;
 	nel = le32_to_cpu(buf[0]);
 
-	lft = NULL;
 	for (i = 0; i < nel; i++) {
-		ft = calloc(1, sizeof(struct filename_trans));
+		ft = NULL;
+		otype = NULL;
+		name = NULL;
+
+		ft = calloc(1, sizeof(*ft));
 		if (!ft)
-			return -1;
-		if (lft)
-			lft->next = ft;
-		else
-			*t = ft;
-		lft = ft;
+			goto err;
+		otype = calloc(1, sizeof(*otype));
+		if (!ft)
+			goto err;
 		rc = next_entry(buf, fp, sizeof(uint32_t));
 		if (rc < 0)
-			return -1;
+			goto err;
 		len = le32_to_cpu(buf[0]);
 		if (zero_or_saturated(len))
-			return -1;
+			goto err;
 
 		name = calloc(len + 1, sizeof(*name));
 		if (!name)
-			return -1;
+			goto err;
 
 		ft->name = name;
 
 		rc = next_entry(name, fp, len);
 		if (rc < 0)
-			return -1;
+			goto err;
 
 		rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
 		if (rc < 0)
-			return -1;
+			goto err;
 
 		ft->stype = le32_to_cpu(buf[0]);
 		ft->ttype = le32_to_cpu(buf[1]);
 		ft->tclass = le32_to_cpu(buf[2]);
-		ft->otype = le32_to_cpu(buf[3]);
+		otype->otype = le32_to_cpu(buf[3]);
+
+		rc = hashtab_insert(p->filename_trans, (hashtab_key_t) ft,
+				    otype);
+		if (rc)
+			goto err;
 	}
 	return 0;
+err:
+	free(ft);
+	free(otype);
+	free(name);
+	return -1;
 }
 
 static int ocontext_read_xen(struct policydb_compat_info *info,
@@ -3129,8 +3228,9 @@ static avrule_t *avrule_read(policydb_t * p
 static int range_read(policydb_t * p, struct policy_file *fp)
 {
 	uint32_t buf[2], nel;
-	range_trans_t *rt, *lrt;
-	range_trans_rule_t *rtr, *lrtr = NULL;
+	range_trans_t *rt = NULL;
+	struct mls_range *r = NULL;
+	range_trans_rule_t *rtr = NULL, *lrtr = NULL;
 	unsigned int i;
 	int new_rangetr = (p->policy_type == POLICY_KERN &&
 			   p->policyvers >= POLICYDB_VERSION_RANGETRANS);
@@ -3140,44 +3240,41 @@ static int range_read(policydb_t * p, struct policy_file *fp)
 	if (rc < 0)
 		return -1;
 	nel = le32_to_cpu(buf[0]);
-	lrt = NULL;
 	for (i = 0; i < nel; i++) {
 		rt = calloc(1, sizeof(range_trans_t));
 		if (!rt)
 			return -1;
-		if (lrt)
-			lrt->next = rt;
-		else
-			p->range_tr = rt;
 		rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
 		if (rc < 0)
-			return -1;
+			goto err;
 		rt->source_type = le32_to_cpu(buf[0]);
 		rt->target_type = le32_to_cpu(buf[1]);
 		if (new_rangetr) {
 			rc = next_entry(buf, fp, (sizeof(uint32_t)));
 			if (rc < 0)
-				return -1;
+				goto err;
 			rt->target_class = le32_to_cpu(buf[0]);
 		} else
 			rt->target_class = SECCLASS_PROCESS;
-		if (mls_read_range_helper(&rt->target_range, fp))
-			return -1;
-		lrt = rt;
-	}
-
-	/* if this is a kernel policy, we are done - otherwise we need to
-	 * convert these structs to range_trans_rule_ts */
-	if (p->policy_type == POLICY_KERN)
-		return 0;
+		r = calloc(1, sizeof(*r));
+		if (!r)
+			goto err;
+		if (mls_read_range_helper(r, fp))
+			goto err;
+
+		if (p->policy_type == POLICY_KERN) {
+			rc = hashtab_insert(p->range_tr, (hashtab_key_t)rt, r);
+			if (rc)
+				goto err;
+			rt = NULL;
+			r = NULL;
+			continue;
+		}
 
-	/* create range_trans_rules_ts that correspond to the range_trans_ts
-	 * that were just read in from an older policy */
-	for (rt = p->range_tr; rt; rt = rt->next) {
+		/* Module policy: convert to range_trans_rule and discard. */
 		rtr = malloc(sizeof(range_trans_rule_t));
-		if (!rtr) {
-			return -1;
-		}
+		if (!rtr)
+			goto err;
 		range_trans_rule_init(rtr);
 
 		if (lrtr)
@@ -3186,38 +3283,36 @@ static int range_read(policydb_t * p, struct policy_file *fp)
 			p->global->enabled->range_tr_rules = rtr;
 
 		if (ebitmap_set_bit(&rtr->stypes.types, rt->source_type - 1, 1))
-			return -1;
+			goto err;
 
 		if (ebitmap_set_bit(&rtr->ttypes.types, rt->target_type - 1, 1))
-			return -1;
+			goto err;
 
 		if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1))
-			return -1;
+			goto err;
 
-		if (mls_range_to_semantic(&rt->target_range, &rtr->trange))
-			return -1;
+		if (mls_range_to_semantic(r, &rtr->trange))
+			goto err;
 
+		free(rt);
+		rt = NULL;
+		free(r);
+		r = NULL;
 		lrtr = rtr;
 	}
 
-	/* now destroy the range_trans_ts */
-	lrt = NULL;
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		if (lrt) {
-			ebitmap_destroy(&lrt->target_range.level[0].cat);
-			ebitmap_destroy(&lrt->target_range.level[1].cat);
-			free(lrt);
-		}
-		lrt = rt;
+	return 0;
+err:
+	free(rt);
+	if (r) {
+		mls_range_destroy(r);
+		free(r);
 	}
-	if (lrt) {
-		ebitmap_destroy(&lrt->target_range.level[0].cat);
-		ebitmap_destroy(&lrt->target_range.level[1].cat);
-		free(lrt);
+	if (rtr) {
+		range_trans_rule_destroy(rtr);
+		free(rtr);
 	}
-	p->range_tr = NULL;
-
-	return 0;
+	return -1;
 }
 
 int avrule_read_list(policydb_t * p, avrule_t ** avrules,
@@ -3908,7 +4003,7 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
 		if (role_allow_read(&p->role_allow, fp))
 			goto bad;
 		if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS &&
-		    filename_trans_read(&p->filename_trans, fp))
+		    filename_trans_read(p, fp))
 			goto bad;
 	} else {
 		/* first read the AV rule blocks, then the scope tables */
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index fbc6dad..190424f 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -563,40 +563,55 @@ static int role_allow_write(role_allow_t * r, struct policy_file *fp)
 	return POLICYDB_SUCCESS;
 }
 
-static int filename_trans_write(filename_trans_t * r, struct policy_file *fp)
+static int filename_write_helper(hashtab_key_t key, void *data, void *ptr)
 {
-	filename_trans_t *ft;
 	uint32_t buf[4];
-	size_t nel, items, len;
+	size_t items, len;
+	struct filename_trans *ft = (struct filename_trans *)key;
+	struct filename_trans_datum *otype = data;
+	void *fp = ptr;
 
-	nel = 0;
-	for (ft = r; ft; ft = ft->next)
-		nel++;
-	buf[0] = cpu_to_le32(nel);
+	len = strlen(ft->name);
+	buf[0] = cpu_to_le32(len);
 	items = put_entry(buf, sizeof(uint32_t), 1, fp);
 	if (items != 1)
 		return POLICYDB_ERROR;
-	for (ft = r; ft; ft = ft->next) {
-		len = strlen(ft->name);
-		buf[0] = cpu_to_le32(len);
-		items = put_entry(buf, sizeof(uint32_t), 1, fp);
-		if (items != 1)
-			return POLICYDB_ERROR;
 
-		items = put_entry(ft->name, sizeof(char), len, fp);
-		if (items != len)
-			return POLICYDB_ERROR;
+	items = put_entry(ft->name, sizeof(char), len, fp);
+	if (items != len)
+		return POLICYDB_ERROR;
 
-		buf[0] = cpu_to_le32(ft->stype);
-		buf[1] = cpu_to_le32(ft->ttype);
-		buf[2] = cpu_to_le32(ft->tclass);
-		buf[3] = cpu_to_le32(ft->otype);
-		items = put_entry(buf, sizeof(uint32_t), 4, fp);
-		if (items != 4)
-			return POLICYDB_ERROR;
-	}
+	buf[0] = cpu_to_le32(ft->stype);
+	buf[1] = cpu_to_le32(ft->ttype);
+	buf[2] = cpu_to_le32(ft->tclass);
+	buf[3] = cpu_to_le32(otype->otype);
+	items = put_entry(buf, sizeof(uint32_t), 4, fp);
+	if (items != 4)
+		return POLICYDB_ERROR;
 
-	return POLICYDB_SUCCESS;
+	return 0;
+}
+
+static int filename_trans_write(struct policydb *p, void *fp)
+{
+	size_t nel, items;
+	uint32_t buf[1];
+	int rc;
+
+	if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
+		return 0;
+
+	nel =  p->filename_trans->nel;
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+
+	rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
+	if (rc)
+		return rc;
+
+	return 0;
 }
 
 static int role_set_write(role_set_t * x, struct policy_file *fp)
@@ -1512,51 +1527,96 @@ static int genfs_write(policydb_t * p, struct policy_file *fp)
 	return POLICYDB_SUCCESS;
 }
 
+
+struct rangetrans_count_args {
+	size_t nel;
+	int new_rangetr;
+};
+
+static int rangetrans_count(hashtab_key_t key,
+			    void *data __attribute__ ((unused)),
+			    void *ptr)
+{
+	struct range_trans *rt = (struct range_trans *)key;
+	struct rangetrans_count_args *count = ptr;
+
+	/* all range_transitions are written for the new format, only
+	   process related range_transitions are written for the old
+	   format, so count accordingly */
+	if (count->new_rangetr || rt->target_class == SECCLASS_PROCESS)
+		count->nel++;
+	return 0;
+}
+
+struct rangetrans_write_args {
+	struct policy_data pd;
+	int new_rangetr;
+};
+
+static int range_write_helper(hashtab_key_t key, void *data, void *ptr)
+{
+	uint32_t buf[2];
+	struct range_trans *rt = (struct range_trans *)key;
+	struct mls_range *r = data;
+	struct rangetrans_write_args *args = ptr;
+	struct policy_file *fp = args->pd.fp;
+	int new_rangetr = args->new_rangetr;
+	size_t items;
+	static int warning_issued = 0;
+	int rc;
+
+	if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) {
+		if (!warning_issued)
+			WARN(fp->handle, "Discarding range_transition "
+			     "rules for security classes other than "
+			     "\"process\"");
+		warning_issued = 1;
+		return 0;
+	}
+
+	buf[0] = cpu_to_le32(rt->source_type);
+	buf[1] = cpu_to_le32(rt->target_type);
+	items = put_entry(buf, sizeof(uint32_t), 2, fp);
+	if (items != 2)
+		return POLICYDB_ERROR;
+	if (new_rangetr) {
+		buf[0] = cpu_to_le32(rt->target_class);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+	}
+	rc = mls_write_range_helper(r, fp);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
 static int range_write(policydb_t * p, struct policy_file *fp)
 {
-	size_t nel, items;
-	struct range_trans *rt;
+	size_t items;
 	uint32_t buf[2];
 	int new_rangetr = (p->policy_type == POLICY_KERN &&
 			   p->policyvers >= POLICYDB_VERSION_RANGETRANS);
-	int warning_issued = 0;
+	struct rangetrans_count_args cargs;
+	struct rangetrans_write_args wargs;
+	int rc;
 
-	nel = 0;
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		/* all range_transitions are written for the new format, only
-		   process related range_transitions are written for the old
-		   format, so count accordingly */
-		if (new_rangetr || rt->target_class == SECCLASS_PROCESS)
-			nel++;
-	}
-	buf[0] = cpu_to_le32(nel);
+	cargs.nel = 0;
+	cargs.new_rangetr = new_rangetr;
+	rc = hashtab_map(p->range_tr, rangetrans_count, &cargs);
+	if (rc)
+		return rc;
+
+	buf[0] = cpu_to_le32(cargs.nel);
 	items = put_entry(buf, sizeof(uint32_t), 1, fp);
 	if (items != 1)
 		return POLICYDB_ERROR;
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) {
-			if (!warning_issued)
-				WARN(fp->handle, "Discarding range_transition "
-				     "rules for security classes other than "
-				     "\"process\"");
-			warning_issued = 1;
-			continue;
-		}
-		buf[0] = cpu_to_le32(rt->source_type);
-		buf[1] = cpu_to_le32(rt->target_type);
-		items = put_entry(buf, sizeof(uint32_t), 2, fp);
-		if (items != 2)
-			return POLICYDB_ERROR;
-		if (new_rangetr) {
-			buf[0] = cpu_to_le32(rt->target_class);
-			items = put_entry(buf, sizeof(uint32_t), 1, fp);
-			if (items != 1)
-				return POLICYDB_ERROR;
-		}
-		if (mls_write_range_helper(&rt->target_range, fp))
-			return POLICYDB_ERROR;
-	}
-	return POLICYDB_SUCCESS;
+
+	wargs.pd.p = p;
+	wargs.pd.fp = fp;
+	wargs.new_rangetr = new_rangetr;
+	return hashtab_map(p->range_tr, range_write_helper, &wargs);
 }
 
 /************** module writing functions below **************/
@@ -2136,7 +2196,7 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
 		if (role_allow_write(p->role_allow, fp))
 			return POLICYDB_ERROR;
 		if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
-			if (filename_trans_write(p->filename_trans, fp))
+			if (filename_trans_write(p, fp))
 				return POLICYDB_ERROR;
 		} else {
 			if (p->filename_trans)
