git: b9811d13572b - main - cd9660: merge level 1 and 2 filename conversion

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Thu, 24 Sep 2026 15:10:39 UTC
The branch main has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=b9811d13572b93adff2da16508eef18872b24c85

commit b9811d13572b93adff2da16508eef18872b24c85
Author:     Manuel Einfalt <einfalt1@proton.me>
AuthorDate: 2026-09-23 15:04:25 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2026-09-24 15:07:51 +0000

    cd9660: merge level 1 and 2 filename conversion
    
    Merge the nearly identical level 1 and level 2 filename conversion
    functions and add output buffer bounds checking.
    
    Always NUL-terminate the converted filename, allowing the redundant
    memset() in cd9660_translate_node_common() to be removed.
    
    Signed-off-by: Manuel Einfalt <einfalt1@proton.me>
    Reviewed by: emaste
    Pull request: https://github.com/freebsd/freebsd-src/pull/2443
---
 usr.sbin/makefs/cd9660.c | 129 +++++++++++++----------------------------------
 1 file changed, 35 insertions(+), 94 deletions(-)

diff --git a/usr.sbin/makefs/cd9660.c b/usr.sbin/makefs/cd9660.c
index 687bfe46ac27..cf004f22ecdd 100644
--- a/usr.sbin/makefs/cd9660.c
+++ b/usr.sbin/makefs/cd9660.c
@@ -139,10 +139,6 @@ static void cd9660_convert_structure(iso9660_disk *, fsnode *, cd9660node *, int
     int *, int *);
 static void cd9660_free_structure(cd9660node *);
 static int cd9660_generate_path_table(iso9660_disk *);
-static int cd9660_level1_convert_filename(iso9660_disk *, const char *, char *,
-    size_t, int);
-static int cd9660_level2_convert_filename(iso9660_disk *, const char *, char *,
-    size_t, int);
 static int cd9660_convert_filename(iso9660_disk *, const char *, char *, size_t,
     int);
 static void cd9660_populate_dot_records(iso9660_disk *, cd9660node *);
@@ -799,8 +795,6 @@ cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode)
 	char temp[ISO_FILENAME_MAXLENGTH];
 
 	/* Now populate the isoDirRecord structure */
-	memset(temp, 0, sizeof(temp));
-
 	(void)cd9660_convert_filename(diskStructure, newnode->node->name,
 	    temp, sizeof(temp), !(S_ISDIR(newnode->node->type)));
 
@@ -1564,13 +1558,15 @@ cd9660_compute_full_filename(cd9660node *node, char *buf)
 }
 
 /*
- * TODO: These two functions are almost identical.
- * Some code cleanup is possible here
- *
- * XXX bounds checking!
+ * Convert a file name to ISO compliant file name
+ * @param char * oldname The original filename
+ * @param char ** newname The new file name, in the appropriate character
+ *                        set and of appropriate length
+ * @param int 1 if file, 0 if directory
+ * @returns int The length of the new string
  */
 static int
-cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname,
+cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname,
     char *newname, size_t newnamelen, int is_file)
 {
 	/*
@@ -1578,58 +1574,7 @@ cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname,
 	 * File Name shall not contain more than 8 d or d1 characters
 	 * File Name Extension shall not contain more than 3 d or d1 characters
 	 * Directory Identifier shall not contain more than 8 d or d1 characters
-	 */
-	int namelen = 0;
-	int extlen = 0;
-	int found_ext = 0;
-	char *orignewname = newname;
-
-	while (*oldname != '\0' && extlen < 3) {
-		/* Handle period first, as it is special */
-		if (*oldname == '.') {
-			if (found_ext) {
-				*newname++ = '_';
-				extlen ++;
-			}
-			else {
-				*newname++ = '.';
-				found_ext = 1;
-			}
-		} else {
-			/* Enforce 12.3 / 8 */
-			if (namelen == 8 && !found_ext)
-				break;
-
-			if (islower((unsigned char)*oldname))
-				*newname++ = toupper((unsigned char)*oldname);
-			else if (isupper((unsigned char)*oldname)
-			    || isdigit((unsigned char)*oldname))
-				*newname++ = *oldname;
-			else
-				*newname++ = '_';
-
-			if (found_ext)
-				extlen++;
-			else
-				namelen++;
-		}
-		oldname++;
-	}
-	if (is_file) {
-		if (!found_ext && !diskStructure->omit_trailing_period)
-			*newname++ = '.';
-		/* Add version */
-		snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1);
-	}
-	return namelen + extlen + found_ext;
-}
-
-/* XXX bounds checking! */
-static int
-cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname,
-    char *newname, size_t newnamelen, int is_file)
-{
-	/*
+	 *
 	 * ISO 9660 : 7.5.1
 	 * File name : 0+ d or d1 characters
 	 * separator 1 (.)
@@ -1638,28 +1583,44 @@ cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname,
 	 * File version number (5 characters, 1-32767)
 	 * 1 <= Sum of File name and File name extension <= 30
 	 */
-	int maxlen = is_file ? 30 : 31;
 	int namelen = 0;
 	int extlen = 0;
 	int found_ext = 0;
 	char *orignewname = newname;
+	int level;
+	int maxlen = is_file ? 30 : 31;
+	size_t suffix_len = is_file ? 3 : 1;
+
+	assert(diskStructure->isoLevel == 1 || diskStructure->isoLevel == 2);
+	assert(newnamelen >= 4); /* at least enough memory for "[char];1\0" */
 
-	while (*oldname != '\0' && namelen + extlen < maxlen) {
+	level = diskStructure->isoLevel;
+	while ((newnamelen - (newname - orignewname) > suffix_len)
+		   && (*oldname != '\0' && ((level == 1 && extlen < 3)
+		   || (level == 2 && namelen + extlen < maxlen)))) {
 		/* Handle period first, as it is special */
-		if (*oldname == '.' && is_file) {
+		if (*oldname == '.' && (level == 1 || (level == 2 && is_file))) {
 			if (found_ext) {
-				if (diskStructure->allow_multidot) {
-					*newname++ = '.';
-				} else {
+				if (level == 1)
 					*newname++ = '_';
+				else if (level == 2) {
+					if (diskStructure->allow_multidot) {
+						*newname++ = '.';
+					} else {
+						*newname++ = '_';
+					}
 				}
-				extlen ++;
+				extlen++;
 			}
 			else {
 				*newname++ = '.';
 				found_ext = 1;
 			}
 		} else {
+			/* Enforce 12.3 / 8 */
+			if (level == 1 && namelen == 8 && !found_ext)
+				break;
+
 			if (islower((unsigned char)*oldname))
 				*newname++ = toupper((unsigned char)*oldname);
 			else if (isupper((unsigned char)*oldname) ||
@@ -1673,37 +1634,17 @@ cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname,
 			else
 				namelen++;
 		}
-		oldname ++;
+		oldname++;
 	}
 	if (is_file) {
 		if (!found_ext && !diskStructure->omit_trailing_period)
 			*newname++ = '.';
 		/* Add version */
 		snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1);
-	}
-	return namelen + extlen + found_ext;
-}
+	} else
+		*newname = '\0';
 
-/*
- * Convert a file name to ISO compliant file name
- * @param char * oldname The original filename
- * @param char ** newname The new file name, in the appropriate character
- *                        set and of appropriate length
- * @param int 1 if file, 0 if directory
- * @returns int The length of the new string
- */
-static int
-cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname,
-    char *newname, size_t newnamelen, int is_file)
-{
-	assert(1 <= diskStructure->isoLevel && diskStructure->isoLevel <= 2);
-	if (diskStructure->isoLevel == 1)
-		return(cd9660_level1_convert_filename(diskStructure,
-		    oldname, newname, newnamelen, is_file));
-	else if (diskStructure->isoLevel == 2)
-		return (cd9660_level2_convert_filename(diskStructure,
-		    oldname, newname, newnamelen, is_file));
-	abort();
+	return (namelen + extlen + found_ext);
 }
 
 int