Module Name:    src
Committed By:   reinoud
Date:           Wed Jan 27 00:06:49 UTC 2016

Modified Files:
        src/sys/fs/udf: udf_subr.c

Log Message:
Fix filename creation and deleting with illegal file names. UDF has a
machanism for it but it allowed to create a file with a name it considered
illegal that then couldn't be deleted with the same name.

Fixes PR kern/50608. When confirmed, it can be closed.


To generate a diff of this commit:
cvs rdiff -u -r1.135 -r1.136 src/sys/fs/udf/udf_subr.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/fs/udf/udf_subr.c
diff -u src/sys/fs/udf/udf_subr.c:1.135 src/sys/fs/udf/udf_subr.c:1.136
--- src/sys/fs/udf/udf_subr.c:1.135	Sat Dec 19 03:16:09 2015
+++ src/sys/fs/udf/udf_subr.c	Wed Jan 27 00:06:49 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_subr.c,v 1.135 2015/12/19 03:16:09 dholland Exp $ */
+/* $NetBSD: udf_subr.c,v 1.136 2016/01/27 00:06:49 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -29,7 +29,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.135 2015/12/19 03:16:09 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.136 2016/01/27 00:06:49 reinoud Exp $");
 #endif /* not lint */
 
 
@@ -4486,7 +4486,8 @@ udf_lookup_name_in_dir(struct vnode *vp,
 	struct dirhash       *dirh;
 	struct dirhash_entry *dirh_ep;
 	struct fileid_desc *fid;
-	struct dirent *dirent;
+	struct dirent *dirent, *s_dirent;
+	struct charspec osta_charspec;
 	uint64_t diroffset;
 	uint32_t lb_size;
 	int hit, error;
@@ -4504,18 +4505,28 @@ udf_lookup_name_in_dir(struct vnode *vp,
 	dirh = dir_node->dir_hash;
 
 	/* allocate temporary space for fid */
-	lb_size = udf_rw32(dir_node->ump->logical_vol->lb_size);
-	fid     = malloc(lb_size, M_UDFTEMP, M_WAITOK);
-	dirent  = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
+	lb_size  = udf_rw32(dir_node->ump->logical_vol->lb_size);
+	fid      = malloc(lb_size, M_UDFTEMP, M_WAITOK);
+	dirent   = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
+	s_dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
 
 	DPRINTF(DIRHASH, ("dirhash_lookup looking for `%*.*s`\n",
 		namelen, namelen, name));
 
+	/* convert given unix name to canonical unix name */
+	udf_osta_charset(&osta_charspec);
+	unix_to_udf_name((char *) fid->data, &fid->l_fi,
+		name, namelen, &osta_charspec);
+	udf_to_unix_name(s_dirent->d_name, NAME_MAX,
+		(char *) fid->data, fid->l_fi,
+		&osta_charspec);
+	s_dirent->d_namlen = strlen(s_dirent->d_name);
+
 	/* search our dirhash hits */
 	memset(icb_loc, 0, sizeof(*icb_loc));
 	dirh_ep = NULL;
 	for (;;) {
-		hit = dirhash_lookup(dirh, name, namelen, &dirh_ep);
+		hit = dirhash_lookup(dirh, s_dirent->d_name, s_dirent->d_namlen, &dirh_ep);
 		/* if no hit, abort the search */
 		if (!hit)
 			break;
@@ -4532,16 +4543,7 @@ udf_lookup_name_in_dir(struct vnode *vp,
 			dirent->d_namlen, dirent->d_namlen, dirent->d_name));
 
 		/* see if its our entry */
-#ifdef DIAGNOSTIC
-		if (dirent->d_namlen != namelen) {
-			printf("WARNING: dirhash_lookup() returned wrong "
-				"d_namelen: %d and ought to be %d\n",
-				dirent->d_namlen, namelen);
-			printf("\tlooked for `%s' and got `%s'\n",
-				name, dirent->d_name);
-		}
-#endif
-		if (strncmp(dirent->d_name, name, namelen) == 0) {
+		if (strncmp(dirent->d_name, s_dirent->d_name, s_dirent->d_namlen) == 0) {
 			*found = 1;
 			*icb_loc = fid->icb;
 			break;
@@ -4549,6 +4551,7 @@ udf_lookup_name_in_dir(struct vnode *vp,
 	}
 	free(fid, M_UDFTEMP);
 	free(dirent, M_UDFTEMP);
+	free(s_dirent, M_UDFTEMP);
 
 	dirhash_put(dir_node->dir_hash);
 
@@ -4718,12 +4721,11 @@ udf_dir_detach(struct udf_mount *ump, st
 	struct dirhash_entry *dirh_ep;
 	struct file_entry    *fe  = dir_node->fe;
 	struct fileid_desc *fid;
-	struct dirent *dirent;
+	struct dirent *dirent, *s_dirent;
+	struct charspec osta_charspec;
 	uint64_t diroffset;
 	uint32_t lb_size, fidsize;
 	int found, error;
-	char const *name  = cnp->cn_nameptr;
-	int namelen = cnp->cn_namelen;
 	int hit, refcnt;
 
 	/* get our dirhash and make sure its read in */
@@ -4740,16 +4742,26 @@ udf_dir_detach(struct udf_mount *ump, st
 		assert(dir_node->efe);
 	}
 
-	/* allocate temporary space for fid */
-	lb_size = udf_rw32(dir_node->ump->logical_vol->lb_size);
-	fid     = malloc(lb_size, M_UDFTEMP, M_WAITOK);
-	dirent  = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
+	/* allocate temporary space for fid and dirents */
+	lb_size  = udf_rw32(dir_node->ump->logical_vol->lb_size);
+	fid      = malloc(lb_size, M_UDFTEMP, M_WAITOK);
+	dirent   = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
+	s_dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK);
+
+	/* convert given unix name to canonical unix name */
+	udf_osta_charset(&osta_charspec);
+	unix_to_udf_name((char *) fid->data, &fid->l_fi,
+		cnp->cn_nameptr, cnp->cn_namelen, &osta_charspec);
+	udf_to_unix_name(s_dirent->d_name, NAME_MAX,
+		(char *) fid->data, fid->l_fi,
+		&osta_charspec);
+	s_dirent->d_namlen = strlen(s_dirent->d_name);
 
 	/* search our dirhash hits */
 	found = 0;
 	dirh_ep = NULL;
 	for (;;) {
-		hit = dirhash_lookup(dirh, name, namelen, &dirh_ep);
+		hit = dirhash_lookup(dirh, s_dirent->d_name, s_dirent->d_namlen, &dirh_ep);
 		/* if no hit, abort the search */
 		if (!hit)
 			break;
@@ -4763,8 +4775,8 @@ udf_dir_detach(struct udf_mount *ump, st
 			break;
 
 		/* see if its our entry */
-		KASSERT(dirent->d_namlen == namelen);
-		if (strncmp(dirent->d_name, name, namelen) == 0) {
+		KASSERT(dirent->d_namlen == s_dirent->d_namlen);
+		if (strncmp(dirent->d_name, s_dirent->d_name, s_dirent->d_namlen) == 0) {
 			found = 1;
 			break;
 		}
@@ -4845,6 +4857,7 @@ udf_dir_detach(struct udf_mount *ump, st
 error_out:
 	free(fid, M_UDFTEMP);
 	free(dirent, M_UDFTEMP);
+	free(s_dirent, M_UDFTEMP);
 
 	dirhash_put(dir_node->dir_hash);
 

Reply via email to