Subject: kern/8515: Acorn CD-ROMs
To: None <gnats-bugs@gnats.netbsd.org>
From: None <netbsd@precedence.co.uk>
List: netbsd-bugs
Date: 09/29/1999 10:36:37
>Number:         8515
>Category:       kern
>Synopsis:       Acorn CD-ROMs
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Sep 29 10:35:00 1999
>Last-Modified:
>Originator:     Stephen Borrill
>Organization:
Precedence Technologies Ltd
>Release:        22nd September 1999
>Environment:
	
NetBSD 1.4K arm32 -current snapshot

>Description:
Acorn RISC-OS machines take advantage of the system dependent extension
in the iso directory record to add certain capabilities to CDROMs. To
allow a NetBSD to serve an Acorn format CDROM to Acorn clients (as used
in many UK schools), the filename on the CDROM needs to be altered so that
the filetype is extracted and appended to the end. Also, there is a bit
that specifies whether an initial _ is to be replaced by a !

N.B. On a non-Acorn CDROM, the behaviour is entirely backward compatible;
the Acorn enhancments are ignored if the system dependent area is not
exactly 32 bytes long and doesn't begin with the 10 characters ARCHIMEDES
(non-terminated).

>How-To-Repeat:
mount an Acorn ISO-9660 CDROM. Filetypes will not be determined
>Fix:
The following patches will patch the kernel to add the Acorn compatibity
depending on a new mount option (ISOFSMNT_ACORN) specified by the -a
flag to mount_cd9660. 

There are two separate sections to the patches. One to the kernel and one
to the mount_cd9660 source (inc. man page update).

This may seem platform specific (to the arm32 port), but it isn't. I
am actively pushing various NetBSD ports into UK schools as an alternative
to NT and the ability to read Acorn CDROMs is useful across all ports.

--- cd9660_extern.h.orig	Mon Sep 27 22:46:08 1999
+++ cd9660_extern.h	Tue Sep 28 10:35:30 1999
@@ -108,6 +108,6 @@
 extern int (**cd9660_fifoop_p) __P((void *));
 
 int isochar __P((const u_char *, const u_char *, int, u_char *));
-int isofncmp __P((const u_char *, int, const u_char *, int, int));
-void isofntrans __P((u_char *, int, u_char *, u_short *, int, int, int));
+int isofncmp __P((const u_char *, int, const u_char *, int, int, int, struct iso_directory_record *));
+void isofntrans __P((u_char *, int, const u_char *, u_short *, int, int, int, int, struct iso_directory_record *));
 ino_t isodirino __P((struct iso_directory_record *, struct iso_mnt *));
--- cd9660_lookup.c.orig	Mon Sep 27 22:46:53 1999
+++ cd9660_lookup.c	Tue Sep 28 10:19:39 1999
@@ -55,6 +55,7 @@
 #include <isofs/cd9660/cd9660_node.h>
 #include <isofs/cd9660/iso_rrip.h>
 #include <isofs/cd9660/cd9660_rrip.h>
+#include <isofs/cd9660/cd9660_mount.h>
 
 struct	nchstats iso_nchstats;
 
@@ -267,7 +268,8 @@
 						goto notfound;
 				} else if (!(res = isofncmp(name,len,
 						   ep->name,namelen,
-						   imp->im_joliet_level))) {
+						   imp->im_joliet_level,
+						   (imp->im_flags&ISOFSMNT_ACORN),ep))) {
 					if (isonum_711(ep->flags)&2)
 						ino = isodirino(ep, imp);
 					else
--- cd9660_mount.h.orig	Mon Sep 27 22:46:16 1999
+++ cd9660_mount.h	Tue Sep 28 09:37:00 1999
@@ -51,3 +51,4 @@
 #define	ISOFSMNT_GENS	0x00000002	/* enable generation numbers */
 #define	ISOFSMNT_EXTATT	0x00000004	/* enable extended attributes */
 #define	ISOFSMNT_NOJOLIET 0x00000008	/* disable Joliet extensions */
+#define	ISOFSMNT_ACORN 0x00000010	/* enable Acorn extensions */
--- cd9660_vfsops.c.orig	Mon Sep 27 22:48:37 1999
+++ cd9660_vfsops.c	Tue Sep 28 09:37:59 1999
@@ -437,7 +437,8 @@
 		bp = NULL;
 	}
 	isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
-					 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
+					 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET |
+					 ISOFSMNT_ACORN);
 	switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
 	default:
 	    isomp->iso_ftype = ISO_FTYPE_DEFAULT;
--- cd9660_vnops.c.orig	Mon Sep 27 22:47:14 1999
+++ cd9660_vnops.c	Tue Sep 28 10:53:53 1999
@@ -63,6 +63,7 @@
 #include <isofs/cd9660/cd9660_extern.h>
 #include <isofs/cd9660/cd9660_node.h>
 #include <isofs/cd9660/iso_rrip.h>
+#include <isofs/cd9660/cd9660_mount.h>
 
 /*
  * Structure for reading directories
@@ -554,7 +555,10 @@
 				   idp->current.d_name, &namelen,
 				   imp->iso_ftype == ISO_FTYPE_9660,
 				   isonum_711(ep->flags)&4,
-				   imp->im_joliet_level);
+				   imp->im_joliet_level,
+				   (imp->im_flags&ISOFSMNT_ACORN),ep);
+
+
 			switch (idp->current.d_name[0]) {
 			case 0:
 				idp->current.d_name[0] = '.';
--- cd9660_util.c.orig	Mon Sep 27 22:47:06 1999
+++ cd9660_util.c	Tue Sep 28 15:01:50 1999
@@ -59,6 +59,75 @@
 #include <isofs/cd9660/cd9660_extern.h>
 
 /*
+ * Convert Acorn filename if directory is Acorn-format
+ */
+
+#define CD9660_NOACORNFILETYPE         -1
+#define CD9660_NOTACORN                -2
+
+#define DONT_ADD_ACORN_UNIXEX
+
+int get_acorn_filetype(rec, name)
+        struct iso_directory_record *rec;
+        char *name;
+{
+        int offset,filetype;
+        unsigned char *data;
+
+        offset = (isonum_711(rec->name_len)+ISO_DIRECTORY_RECORD_SIZE);
+        offset += offset%2; /* Round up to next even */
+        data = ((unsigned char *) rec) + offset;
+
+        if (isonum_711(rec->length)-offset != 32) return CD9660_NOTACORN;
+        if (strncmp(data,"ARCHIMEDES",10)) return CD9660_NOTACORN;
+        /* Directory record has 32 byte system use area
+
+          0-9 "ARCHIMEDES"
+                                 13121110
+        10-13 Load address      &FFFtttdd
+                                 17161514
+        14-17 Execution address &dddddddd
+                                 21201918
+        18-21 Attributes        &ffffffaa
+        22-31 Reserved          0
+
+        ttt = filetype
+        dd  = date stamp (ignored - use directory record date)
+        ffffff = filesystem specific attributes (bit 0 of offset 19 is
+                 set if initial underscore should be replaced by !)
+        aa  = RISCOS access permissions (ignore - read access is forced)
+
+        */
+
+        if (((data[19] & 1) == 1) && (name[0] == '_'))  name[0] = '!';
+
+        /* Don't read a filetype if a directory */
+        if ((isonum_711(rec->flags) & 2) != 0) return CD9660_NOACORNFILETYPE;
+
+        /* Return if not filetyped */
+        if( data[13] != 0xff || (data[12]&0xf0) != 0xf0) return CD9660_NOACORNFILETYPE;
+
+        filetype = ((data[12] & 0xf)<<8) | data[11];
+
+        switch(filetype) {
+#ifdef DONT_ADD_ACORN_TEXT
+        case 0xfff:
+             return CD9660_NOACORNFILETYPE;
+             break;
+#endif
+#ifdef DONT_ADD_ACORN_UNIXEX
+        case 0xfe6:
+             return CD9660_NOACORNFILETYPE;
+             break;
+#endif
+        default:
+             return filetype;
+             break;
+        }
+        return CD9660_NOACORNFILETYPE;
+}
+
+/*
  * Get one character out of an iso filename
  * Return number of bytes consumed
  */
@@ -91,18 +160,25 @@
  * Note: Version number plus ';' may be omitted.
  */
 int
-isofncmp(fn, fnlen, isofn, isolen, joliet_level)
-	const u_char *fn, *isofn;
-	int fnlen, isolen, joliet_level;
+isofncmp(fn, fnlen, isofnin, isolen, joliet_level, acorn, ep)
+	const u_char *fn, *isofnin;
+	int fnlen, isolen, joliet_level, acorn;
+	struct iso_directory_record *ep;
 {
 	int i, j;
 	char c;
-	const u_char *isoend = isofn + isolen;
+	u_char convname[NAME_MAX];
+	u_char *isofn = convname;
+	u_char *isoend;
+	u_short convlen;
+
+	isofntrans((u_char *)isofnin, isolen, convname, &convlen, 0, 0, joliet_level, acorn, ep);
+	isoend = (u_char *)isofn + convlen;
 
 	while (--fnlen >= 0) {
 		if (isofn == isoend)
 			return *fn;
-		isofn += isochar(isofn, isoend, joliet_level, &c);
+		c = (char) *isofn++;
 		if (c == ';') {
 			switch (*fn++) {
 			default:
@@ -118,8 +194,7 @@
 				}
 			}
 			for (j = 0; isofn != isoend; j = j * 10 + c - '0')
-				isofn += isochar(isofn, isoend,
-						 joliet_level, &c);
+				c = (char) *isofn++;
 			return i - j;
 		}
 		if (((u_char) c) != *fn) {
@@ -136,14 +211,13 @@
 		fn++;
 	}
 	if (isofn != isoend) {
-		isofn += isochar(isofn, isoend, joliet_level, &c);
+		c = (char) *isofn++;
 		switch (c) {
 		default:
 			return -1;
 		case '.':
 			if (isofn != isoend) {
-				isochar(isofn, isoend, joliet_level, &c);
-				if (c == ';')
+				if ((char)*isofn == ';')
 					return 0;
 			}
 			return -1;
@@ -158,34 +232,50 @@
  * translate a filename
  */
 void
-isofntrans(infn, infnlen, outfn, outfnlen, original, assoc, joliet_level)
-	u_char *infn, *outfn;
+isofntrans(infn, infnlen, outfnin, outfnlen, original, assoc, joliet_level, acorn, ep)
+	u_char *infn;
+	const u_char *outfnin;
 	int infnlen;
 	u_short *outfnlen;
 	int original;
 	int assoc;
 	int joliet_level;
+	int acorn;
+	struct iso_directory_record *ep;
 {
-	int fnidx = 0;
+	int fnidx = 0, filetype = CD9660_NOTACORN;
 	u_char *infnend = infn + infnlen;
+	u_char *outfn = (u_char *)outfnin;
+
+        if(acorn && infnlen > 0) filetype = get_acorn_filetype(ep, infn);
 	
 	if (assoc) {
 		*outfn++ = ASSOCCHAR;
 		fnidx++;
 	}
+
 	for (; infn != infnend; fnidx++) {
 		char c;
 
 		infn += isochar(infn, infnend, joliet_level, &c);
 
-		if (!original && joliet_level == 0 && c >= 'A' && c <= 'Z')
+		if (!original && filetype == CD9660_NOTACORN &&
+		        joliet_level == 0 && c >= 'A' && c <= 'Z')
 			*outfn++ = c + ('a' - 'A');
 		else if (!original && c == ';') {
-			if (fnidx > 0 && outfn[-1] == '.')
+			if (fnidx > 0 && outfn[-1] == '.') {
 				fnidx--;
+				outfn--;
+			}
 			break;
 		} else
 			*outfn++ = c;
 	}
+	if (filetype >= 0) {
+	        *outfn++=',';
+       		sprintf (outfn ,"%3.3x", filetype);
+       		fnidx += 4;
+	}
+
 	*outfnlen = fnidx;
 }

--- mount_cd9660.8.orig	Mon Sep 27 22:41:33 1999
+++ mount_cd9660.8	Mon Sep 27 22:44:38 1999
@@ -44,7 +44,7 @@
 .Nd mount an ISO-9660 filesystem
 .Sh SYNOPSIS
 .Nm ""
-.Op Fl egr
+.Op Fl aegr
 .Op Fl o Ar options
 .Ar special node
 .Sh DESCRIPTION
@@ -60,6 +60,10 @@
 .Pp
 The options are as follows:
 .Bl -tag -width indent
+.It Fl a
+Enable the interpretation of Acorn CDFS extensions (initial
+underscores are converted to exclamation marks, the filetype
+is appended to the file name as ,xxx and filename case is preserved).
 .It Fl e
 Enable the use of extended attributes.
 .It Fl g
--- mount_cd9660.c.orig	Mon Sep 27 22:41:28 1999
+++ mount_cd9660.c	Tue Sep 28 11:42:40 1999
@@ -86,8 +86,11 @@
 	char *dev, *dir;
 
 	mntflags = opts = 0;
-	while ((ch = getopt(argc, argv, "egjo:r")) != -1)
+	while ((ch = getopt(argc, argv, "egjo:ra")) != -1)
 		switch (ch) {
+		case 'a':
+			opts |= ISOFSMNT_ACORN;
+			break;
 		case 'e':
 			opts |= ISOFSMNT_EXTATT;
 			break;
@@ -135,6 +138,6 @@
 usage()
 {
 	(void)fprintf(stderr,
-		"usage: mount_cd9660 [-egr] [-o options] special node\n");
+		"usage: mount_cd9660 [-aegr] [-o options] special node\n");
 	exit(1);
 }
>Audit-Trail:
>Unformatted: