aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/makefs/cd9660
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/makefs/cd9660')
-rw-r--r--usr.sbin/makefs/cd9660/Makefile.inc6
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_conversion.c200
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_debug.c454
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_eltorito.c751
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_eltorito.h166
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_strings.c120
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_write.c510
-rw-r--r--usr.sbin/makefs/cd9660/iso9660_rrip.c892
-rw-r--r--usr.sbin/makefs/cd9660/iso9660_rrip.h292
9 files changed, 3391 insertions, 0 deletions
diff --git a/usr.sbin/makefs/cd9660/Makefile.inc b/usr.sbin/makefs/cd9660/Makefile.inc
new file mode 100644
index 000000000000..ec949f1413dc
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/Makefile.inc
@@ -0,0 +1,6 @@
+.PATH: ${SRCDIR}/cd9660
+
+CFLAGS+=-I${SRCTOP}/sys/fs/cd9660/
+
+SRCS+= cd9660_strings.c cd9660_debug.c cd9660_eltorito.c \
+ cd9660_write.c cd9660_conversion.c iso9660_rrip.c
diff --git a/usr.sbin/makefs/cd9660/cd9660_conversion.c b/usr.sbin/makefs/cd9660/cd9660_conversion.c
new file mode 100644
index 000000000000..4ccc87e22661
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_conversion.c
@@ -0,0 +1,200 @@
+/* $NetBSD: cd9660_conversion.c,v 1.4 2007/03/14 14:11:17 christos Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+#include "cd9660.h"
+
+#include <sys/cdefs.h>
+static char cd9660_compute_gm_offset(time_t);
+
+#if 0
+static inline int
+cd9660_pad_even(length)
+int length;
+{
+ return length + (length & 0x01);
+}
+#endif
+
+/*
+* These can probably be implemented using a macro
+*/
+
+/* Little endian */
+void
+cd9660_721(uint16_t w, unsigned char *twochar)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+ w = bswap16(w);
+#endif
+ memcpy(twochar,&w,2);
+}
+
+void
+cd9660_731(uint32_t w, unsigned char *fourchar)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+ w = bswap32(w);
+#endif
+ memcpy(fourchar,&w,4);
+}
+
+/* Big endian */
+void
+cd9660_722(uint16_t w, unsigned char *twochar)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ w = bswap16(w);
+#endif
+ memcpy(twochar,&w,2);
+}
+
+void
+cd9660_732(uint32_t w, unsigned char *fourchar)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ w = bswap32(w);
+#endif
+ memcpy(fourchar,&w,4);
+}
+
+/**
+* Convert a dword into a double endian string of eight characters
+* @param int The double word to convert
+* @param char* The string to write the both endian double word to - It is assumed this is allocated and at least
+* eight characters long
+*/
+void
+cd9660_bothendian_dword(uint32_t dw, unsigned char *eightchar)
+{
+ uint32_t le, be;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ le = dw;
+ be = bswap32(dw);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ be = dw;
+ le = bswap32(dw);
+#endif
+ memcpy(eightchar, &le, 4);
+ memcpy((eightchar+4), &be, 4);
+}
+
+/**
+* Convert a word into a double endian string of four characters
+* @param int The word to convert
+* @param char* The string to write the both endian word to - It is assumed this is allocated and at least
+* four characters long
+*/
+void
+cd9660_bothendian_word(uint16_t dw, unsigned char *fourchar)
+{
+ uint16_t le, be;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ le = dw;
+ be = bswap16(dw);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ be = dw;
+ le = bswap16(dw);
+#endif
+ memcpy(fourchar, &le, 2);
+ memcpy((fourchar+2), &be, 2);
+}
+
+void
+cd9660_pad_string_spaces(char *str, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i ++) {
+ if (str[i] == '\0')
+ str[i] = 0x20;
+ }
+}
+
+static char
+cd9660_compute_gm_offset(time_t tim)
+{
+ struct tm t, gm;
+
+ (void)localtime_r(&tim, &t);
+ (void)gmtime_r(&tim, &gm);
+ gm.tm_year -= t.tm_year;
+ gm.tm_yday -= t.tm_yday;
+ gm.tm_hour -= t.tm_hour;
+ gm.tm_min -= t.tm_min;
+ if (gm.tm_year < 0)
+ gm.tm_yday = -1;
+ else if (gm.tm_year > 0)
+ gm.tm_yday = 1;
+
+ return (char)(-(gm.tm_min + 60* (24 * gm.tm_yday + gm.tm_hour)) / 15);
+}
+
+/* Long dates: 17 characters */
+void
+cd9660_time_8426(unsigned char *buf, time_t tim)
+{
+ struct tm t;
+ char temp[18];
+
+ (void)localtime_r(&tim, &t);
+ (void)snprintf(temp, sizeof(temp), "%04i%02i%02i%02i%02i%02i%02i",
+ 1900+(int)t.tm_year,
+ (int)t.tm_mon+1,
+ (int)t.tm_mday,
+ (int)t.tm_hour,
+ (int)t.tm_min,
+ (int)t.tm_sec,
+ 0);
+ (void)memcpy(buf, temp, 16);
+ buf[16] = cd9660_compute_gm_offset(tim);
+}
+
+/* Short dates: 7 characters */
+void
+cd9660_time_915(unsigned char *buf, time_t tim)
+{
+ struct tm t;
+
+ (void)localtime_r(&tim, &t);
+ buf[0] = t.tm_year;
+ buf[1] = t.tm_mon+1;
+ buf[2] = t.tm_mday;
+ buf[3] = t.tm_hour;
+ buf[4] = t.tm_min;
+ buf[5] = t.tm_sec;
+ buf[6] = cd9660_compute_gm_offset(tim);
+}
diff --git a/usr.sbin/makefs/cd9660/cd9660_debug.c b/usr.sbin/makefs/cd9660/cd9660_debug.c
new file mode 100644
index 000000000000..f49c5108f4c2
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_debug.c
@@ -0,0 +1,454 @@
+/* $NetBSD: cd9660_debug.c,v 1.11 2010/10/27 18:51:35 christos Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <sys/mount.h>
+
+#include "makefs.h"
+#include "cd9660.h"
+#include "iso9660_rrip.h"
+
+static void debug_print_susp_attrs(cd9660node *, int);
+static void debug_dump_to_xml_padded_hex_output(const char *, const char *,
+ int);
+
+static inline void
+print_n_tabs(int n)
+{
+ int i;
+
+ for (i = 1; i <= n; i ++)
+ printf("\t");
+}
+
+#if 0
+void
+debug_print_rrip_info(cd9660node *n)
+{
+ struct ISO_SUSP_ATTRIBUTES *t;
+ TAILQ_FOREACH(t, &node->head, rr_ll) {
+
+ }
+}
+#endif
+
+static void
+debug_print_susp_attrs(cd9660node *n, int indent)
+{
+ struct ISO_SUSP_ATTRIBUTES *t;
+
+ TAILQ_FOREACH(t, &n->head, rr_ll) {
+ print_n_tabs(indent);
+ printf("-");
+ printf("%c%c: L:%i",t->attr.su_entry.SP.h.type[0],
+ t->attr.su_entry.SP.h.type[1],
+ (int)t->attr.su_entry.SP.h.length[0]);
+ printf("\n");
+ }
+}
+
+void
+debug_print_tree(iso9660_disk *diskStructure, cd9660node *node, int level)
+{
+#if !HAVE_NBTOOL_CONFIG_H
+ cd9660node *cn;
+
+ print_n_tabs(level);
+ if (node->type & CD9660_TYPE_DOT) {
+ printf(". (%i)\n",
+ isonum_733(node->isoDirRecord->extent));
+ } else if (node->type & CD9660_TYPE_DOTDOT) {
+ printf("..(%i)\n",
+ isonum_733(node->isoDirRecord->extent));
+ } else if (node->isoDirRecord->name[0]=='\0') {
+ printf("(ROOT) (%" PRIu32 " to %" PRId64 ")\n",
+ node->fileDataSector,
+ node->fileDataSector +
+ node->fileSectorsUsed - 1);
+ } else {
+ printf("%s (%s) (%" PRIu32 " to %" PRId64 ")\n",
+ node->isoDirRecord->name,
+ (node->isoDirRecord->flags[0]
+ & ISO_FLAG_DIRECTORY) ? "DIR" : "FILE",
+ node->fileDataSector,
+ (node->fileSectorsUsed == 0) ?
+ node->fileDataSector :
+ node->fileDataSector
+ + node->fileSectorsUsed - 1);
+ }
+ if (diskStructure->rock_ridge_enabled)
+ debug_print_susp_attrs(node, level + 1);
+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
+ debug_print_tree(diskStructure, cn, level + 1);
+#else
+ printf("Sorry, debugging is not supported in host-tools mode.\n");
+#endif
+}
+
+void
+debug_print_path_tree(cd9660node *n)
+{
+ cd9660node *iterator = n;
+
+ /* Only display this message when called with the root node */
+ if (n->parent == NULL)
+ printf("debug_print_path_table: Dumping path table contents\n");
+
+ while (iterator != NULL) {
+ if (iterator->isoDirRecord->name[0] == '\0')
+ printf("0) (ROOT)\n");
+ else
+ printf("%i) %s\n", iterator->level,
+ iterator->isoDirRecord->name);
+
+ iterator = iterator->ptnext;
+ }
+}
+
+void
+debug_print_volume_descriptor_information(iso9660_disk *diskStructure)
+{
+ volume_descriptor *tmp = diskStructure->firstVolumeDescriptor;
+ char temp[CD9660_SECTOR_SIZE];
+
+ printf("==Listing Volume Descriptors==\n");
+
+ while (tmp != NULL) {
+ memset(temp, 0, CD9660_SECTOR_SIZE);
+ memcpy(temp, tmp->volumeDescriptorData + 1, 5);
+ printf("Volume descriptor in sector %" PRId64
+ ": type %i, ID %s\n",
+ tmp->sector, tmp->volumeDescriptorData[0], temp);
+ switch(tmp->volumeDescriptorData[0]) {
+ case 0:/*boot record*/
+ break;
+
+ case 1: /* PVD */
+ break;
+
+ case 2: /* SVD */
+ break;
+
+ case 3: /* Volume Partition Descriptor */
+ break;
+
+ case 255: /* terminator */
+ break;
+ }
+ tmp = tmp->next;
+ }
+
+ printf("==Done Listing Volume Descriptors==\n");
+}
+
+void
+debug_dump_to_xml_ptentry(path_table_entry *pttemp, int num, int mode)
+{
+ printf("<ptentry num=\"%i\">\n" ,num);
+ printf("<length>%i</length>\n", pttemp->length[0]);
+ printf("<extended_attribute_length>%i</extended_attribute_length>\n",
+ pttemp->extended_attribute_length[0]);
+ printf("<parent_number>%i</parent_number>\n",
+ debug_get_encoded_number(pttemp->parent_number,mode));
+ debug_dump_to_xml_padded_hex_output("name",
+ pttemp->name, pttemp->length[0]);
+ printf("</ptentry>\n");
+}
+
+void
+debug_dump_to_xml_path_table(FILE *fd, off_t sector, int size, int mode)
+{
+ path_table_entry pttemp;
+ int t = 0;
+ int n = 0;
+
+ if (fseeko(fd, CD9660_SECTOR_SIZE * sector, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ while (t < size) {
+ /* Read fixed data first */
+ fread(&pttemp, 1, 8, fd);
+ t += 8;
+ /* Read variable */
+ fread(((unsigned char*)&pttemp) + 8, 1, pttemp.length[0], fd);
+ t += pttemp.length[0];
+ debug_dump_to_xml_ptentry(&pttemp, n, mode);
+ n++;
+ }
+
+}
+
+/*
+ * XML Debug output functions
+ * Dump hierarchy of CD, as well as volume info, to XML
+ * Can be used later to diff against a standard,
+ * or just provide easy to read detailed debug output
+ */
+void
+debug_dump_to_xml(FILE *fd)
+{
+ unsigned char buf[CD9660_SECTOR_SIZE];
+ off_t sector;
+ int t, t2;
+ struct iso_primary_descriptor primaryVD;
+ struct _boot_volume_descriptor bootVD;
+
+ printf("<cd9660dump>\n");
+
+ /* Display Volume Descriptors */
+ sector = 16;
+ do {
+ if (fseeko(fd, CD9660_SECTOR_SIZE * sector, SEEK_SET) == -1)
+ err(1, "fseeko");
+ fread(buf, 1, CD9660_SECTOR_SIZE, fd);
+ t = (int)((unsigned char)buf[0]);
+ switch (t) {
+ case 0:
+ memcpy(&bootVD, buf, CD9660_SECTOR_SIZE);
+ break;
+ case 1:
+ memcpy(&primaryVD, buf, CD9660_SECTOR_SIZE);
+ break;
+ }
+ debug_dump_to_xml_volume_descriptor(buf, sector);
+ sector++;
+ } while (t != 255);
+
+ t = debug_get_encoded_number((u_char *)primaryVD.type_l_path_table,
+ 731);
+ t2 = debug_get_encoded_number((u_char *)primaryVD.path_table_size, 733);
+ printf("Path table 1 located at sector %i and is %i bytes long\n",
+ t,t2);
+ debug_dump_to_xml_path_table(fd, t, t2, 721);
+
+ t = debug_get_encoded_number((u_char *)primaryVD.type_m_path_table,
+ 731);
+ debug_dump_to_xml_path_table(fd, t, t2, 722);
+
+ printf("</cd9660dump>\n");
+}
+
+static void
+debug_dump_to_xml_padded_hex_output(const char *element, const char *buf,
+ int len)
+{
+ int i;
+ int t;
+
+ printf("<%s>",element);
+ for (i = 0; i < len; i++) {
+ t = (unsigned char)buf[i];
+ if (t >= 32 && t < 127)
+ printf("%c",t);
+ }
+ printf("</%s>\n",element);
+
+ printf("<%s:hex>",element);
+ for (i = 0; i < len; i++) {
+ t = (unsigned char)buf[i];
+ printf(" %x",t);
+ }
+ printf("</%s:hex>\n",element);
+}
+
+int
+debug_get_encoded_number(const unsigned char* buf, int mode)
+{
+#if !HAVE_NBTOOL_CONFIG_H
+ switch (mode) {
+ /* 711: Single bite */
+ case 711:
+ return isonum_711(buf);
+
+ /* 712: Single signed byte */
+ case 712:
+ return isonum_712(buf);
+
+ /* 721: 16 bit LE */
+ case 721:
+ return isonum_721(buf);
+
+ /* 731: 32 bit LE */
+ case 731:
+ return isonum_731(buf);
+
+ /* 722: 16 bit BE */
+ case 722:
+ return isonum_722(buf);
+
+ /* 732: 32 bit BE */
+ case 732:
+ return isonum_732(buf);
+
+ /* 723: 16 bit bothE */
+ case 723:
+ return isonum_723(buf);
+
+ /* 733: 32 bit bothE */
+ case 733:
+ return isonum_733(buf);
+ }
+#endif
+ return 0;
+}
+
+void
+debug_dump_integer(const char *element, const unsigned char* buf, int mode)
+{
+ printf("<%s>%i</%s>\n", element, debug_get_encoded_number(buf, mode),
+ element);
+}
+
+void
+debug_dump_string(const char *element __unused, const unsigned char *buf __unused, int len __unused)
+{
+
+}
+
+void
+debug_dump_directory_record_9_1(unsigned char* buf)
+{
+ struct iso_directory_record *rec = (struct iso_directory_record *)buf;
+ printf("<directoryrecord>\n");
+ debug_dump_integer("length", rec->length, 711);
+ debug_dump_integer("ext_attr_length", rec->ext_attr_length, 711);
+ debug_dump_integer("extent", rec->extent, 733);
+ debug_dump_integer("size", rec->size, 733);
+ debug_dump_integer("flags", rec->flags, 711);
+ debug_dump_integer("file_unit_size", rec->file_unit_size, 711);
+ debug_dump_integer("interleave", rec->interleave, 711);
+ debug_dump_integer("volume_sequence_number",
+ rec->volume_sequence_number, 723);
+ debug_dump_integer("name_len", rec->name_len, 711);
+ debug_dump_to_xml_padded_hex_output("name", rec->name,
+ debug_get_encoded_number(rec->length, 711));
+ printf("</directoryrecord>\n");
+}
+
+
+void
+debug_dump_to_xml_volume_descriptor(unsigned char* buf, int sector)
+{
+ struct iso_primary_descriptor *desc =
+ (struct iso_primary_descriptor *)buf;
+
+ printf("<volumedescriptor sector=\"%i\">\n", sector);
+ printf("<vdtype>");
+ switch(buf[0]) {
+ case 0:
+ printf("boot");
+ break;
+
+ case 1:
+ printf("primary");
+ break;
+
+ case 2:
+ printf("supplementary");
+ break;
+
+ case 3:
+ printf("volume partition descriptor");
+ break;
+
+ case 255:
+ printf("terminator");
+ break;
+ }
+
+ printf("</vdtype>\n");
+ switch(buf[0]) {
+ case 1:
+ debug_dump_integer("type", desc->type, 711);
+ debug_dump_to_xml_padded_hex_output("id", desc->id,
+ ISODCL(2, 6));
+ debug_dump_integer("version", (u_char *)desc->version, 711);
+ debug_dump_to_xml_padded_hex_output("system_id",
+ desc->system_id, ISODCL(9, 40));
+ debug_dump_to_xml_padded_hex_output("volume_id",
+ desc->volume_id, ISODCL(41, 72));
+ debug_dump_integer("volume_space_size",
+ (u_char *)desc->volume_space_size, 733);
+ debug_dump_integer("volume_set_size",
+ (u_char *)desc->volume_set_size, 733);
+ debug_dump_integer("volume_sequence_number",
+ (u_char *)desc->volume_sequence_number, 723);
+ debug_dump_integer("logical_block_size",
+ (u_char *)desc->logical_block_size, 723);
+ debug_dump_integer("path_table_size",
+ (u_char *)desc->path_table_size, 733);
+ debug_dump_integer("type_l_path_table",
+ (u_char *)desc->type_l_path_table, 731);
+ debug_dump_integer("opt_type_l_path_table",
+ (u_char *)desc->opt_type_l_path_table, 731);
+ debug_dump_integer("type_m_path_table",
+ (u_char *)desc->type_m_path_table, 732);
+ debug_dump_integer("opt_type_m_path_table",
+ (u_char *)desc->opt_type_m_path_table, 732);
+ debug_dump_directory_record_9_1(
+ (u_char *)desc->root_directory_record);
+ debug_dump_to_xml_padded_hex_output("volume_set_id",
+ desc->volume_set_id, ISODCL(191, 318));
+ debug_dump_to_xml_padded_hex_output("publisher_id",
+ desc->publisher_id, ISODCL(319, 446));
+ debug_dump_to_xml_padded_hex_output("preparer_id",
+ desc->preparer_id, ISODCL(447, 574));
+ debug_dump_to_xml_padded_hex_output("application_id",
+ desc->application_id, ISODCL(575, 702));
+ debug_dump_to_xml_padded_hex_output("copyright_file_id",
+ desc->copyright_file_id, ISODCL(703, 739));
+ debug_dump_to_xml_padded_hex_output("abstract_file_id",
+ desc->abstract_file_id, ISODCL(740, 776));
+ debug_dump_to_xml_padded_hex_output("bibliographic_file_id",
+ desc->bibliographic_file_id, ISODCL(777, 813));
+
+ debug_dump_to_xml_padded_hex_output("creation_date",
+ desc->creation_date, ISODCL(814, 830));
+ debug_dump_to_xml_padded_hex_output("modification_date",
+ desc->modification_date, ISODCL(831, 847));
+ debug_dump_to_xml_padded_hex_output("expiration_date",
+ desc->expiration_date, ISODCL(848, 864));
+ debug_dump_to_xml_padded_hex_output("effective_date",
+ desc->effective_date, ISODCL(865, 881));
+
+ debug_dump_to_xml_padded_hex_output("file_structure_version",
+ desc->file_structure_version, ISODCL(882, 882));
+ break;
+ }
+ printf("</volumedescriptor>\n");
+}
+
diff --git a/usr.sbin/makefs/cd9660/cd9660_eltorito.c b/usr.sbin/makefs/cd9660/cd9660_eltorito.c
new file mode 100644
index 000000000000..dd5bf67b2b09
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_eltorito.c
@@ -0,0 +1,751 @@
+/* $NetBSD: cd9660_eltorito.c,v 1.23 2018/03/28 06:48:55 nonaka Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "cd9660.h"
+#include "cd9660_eltorito.h"
+#include <util.h>
+
+#include <sys/cdefs.h>
+/*
+ * Partition Status Information from Apple Tech Note 1189
+ */
+#define APPLE_PS_VALID 0x00000001 /* Entry is valid */
+#define APPLE_PS_ALLOCATED 0x00000002 /* Entry is allocated */
+#define APPLE_PS_READABLE 0x00000010 /* Entry is readable */
+#define APPLE_PS_WRITABLE 0x00000020 /* Entry is writable */
+
+#ifdef DEBUG
+#define ELTORITO_DPRINTF(__x) printf __x
+#else
+#define ELTORITO_DPRINTF(__x)
+#endif
+
+#include <util.h>
+
+static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void);
+static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
+static struct boot_catalog_entry *cd9660_boot_setup_default_entry(
+ struct cd9660_boot_image *);
+static struct boot_catalog_entry *cd9660_boot_setup_section_head(char);
+#if 0
+static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *);
+#endif
+
+static struct cd9660_boot_image *default_boot_image;
+
+int
+cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info)
+{
+ struct stat stbuf;
+ const char *mode_msg;
+ char *temp;
+ char *sysname;
+ char *filename;
+ struct cd9660_boot_image *new_image, *tmp_image;
+
+ assert(boot_info != NULL);
+
+ if (*boot_info == '\0') {
+ warnx("Error: Boot disk information must be in the "
+ "format 'system;filename'");
+ return 0;
+ }
+
+ /* First decode the boot information */
+ temp = estrdup(boot_info);
+
+ sysname = temp;
+ filename = strchr(sysname, ';');
+ if (filename == NULL) {
+ warnx("supply boot disk information in the format "
+ "'system;filename'");
+ free(temp);
+ return 0;
+ }
+
+ *filename++ = '\0';
+
+ if (diskStructure->verbose_level > 0) {
+ printf("Found bootdisk with system %s, and filename %s\n",
+ sysname, filename);
+ }
+ new_image = ecalloc(1, sizeof(*new_image));
+ new_image->loadSegment = 0; /* default for now */
+
+ /* Decode System */
+ if (strcmp(sysname, "i386") == 0)
+ new_image->system = ET_SYS_X86;
+ else if (strcmp(sysname, "powerpc") == 0)
+ new_image->system = ET_SYS_PPC;
+ else if (strcmp(sysname, "macppc") == 0 ||
+ strcmp(sysname, "mac68k") == 0)
+ new_image->system = ET_SYS_MAC;
+ else if (strcmp(sysname, "efi") == 0)
+ new_image->system = ET_SYS_EFI;
+ else {
+ warnx("boot disk system must be "
+ "i386, powerpc, macppc, mac68k, or efi");
+ free(temp);
+ free(new_image);
+ return 0;
+ }
+
+
+ new_image->filename = estrdup(filename);
+
+ free(temp);
+
+ /* Get information about the file */
+ if (lstat(new_image->filename, &stbuf) == -1)
+ err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
+ new_image->filename);
+
+ switch (stbuf.st_size) {
+ case 1440 * 1024:
+ new_image->targetMode = ET_MEDIA_144FDD;
+ mode_msg = "Assigned boot image to 1.44 emulation mode";
+ break;
+ case 1200 * 1024:
+ new_image->targetMode = ET_MEDIA_12FDD;
+ mode_msg = "Assigned boot image to 1.2 emulation mode";
+ break;
+ case 2880 * 1024:
+ new_image->targetMode = ET_MEDIA_288FDD;
+ mode_msg = "Assigned boot image to 2.88 emulation mode";
+ break;
+ default:
+ new_image->targetMode = ET_MEDIA_NOEM;
+ mode_msg = "Assigned boot image to no emulation mode";
+ break;
+ }
+
+ if (diskStructure->verbose_level > 0)
+ printf("%s\n", mode_msg);
+
+ new_image->size = stbuf.st_size;
+ new_image->num_sectors =
+ howmany(new_image->size, diskStructure->sectorSize) *
+ howmany(diskStructure->sectorSize, 512);
+ if (diskStructure->verbose_level > 0) {
+ printf("New image has size %d, uses %d 512-byte sectors\n",
+ new_image->size, new_image->num_sectors);
+ }
+ new_image->sector = -1;
+ /* Bootable by default */
+ new_image->bootable = ET_BOOTABLE;
+ /* Add boot disk */
+
+ /* Group images for the same platform together. */
+ TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) {
+ if (tmp_image->system != new_image->system)
+ break;
+ }
+
+ if (tmp_image == NULL) {
+ TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image,
+ image_list);
+ } else
+ TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list);
+
+ new_image->serialno = diskStructure->image_serialno++;
+
+ new_image->platform_id = new_image->system;
+
+ /* TODO : Need to do anything about the boot image in the tree? */
+ diskStructure->is_bootable = 1;
+
+ /* First boot image is initial/default entry. */
+ if (default_boot_image == NULL)
+ default_boot_image = new_image;
+
+ return 1;
+}
+
+int
+cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure,
+ const char *option_string, const char *value)
+{
+ char *eptr;
+ struct cd9660_boot_image *image;
+
+ assert(option_string != NULL);
+
+ /* Find the last image added */
+ TAILQ_FOREACH(image, &diskStructure->boot_images, image_list) {
+ if (image->serialno + 1 == diskStructure->image_serialno)
+ break;
+ }
+ if (image == NULL)
+ errx(EXIT_FAILURE, "Attempted to add boot option, "
+ "but no boot images have been specified");
+
+ if (strcmp(option_string, "no-emul-boot") == 0) {
+ image->targetMode = ET_MEDIA_NOEM;
+ } else if (strcmp(option_string, "no-boot") == 0) {
+ image->bootable = ET_NOT_BOOTABLE;
+ } else if (strcmp(option_string, "hard-disk-boot") == 0) {
+ image->targetMode = ET_MEDIA_HDD;
+ } else if (strcmp(option_string, "boot-load-segment") == 0) {
+ image->loadSegment = strtoul(value, &eptr, 16);
+ if (eptr == value || *eptr != '\0' || errno != ERANGE) {
+ warn("%s: strtoul", __func__);
+ return 0;
+ }
+ } else if (strcmp(option_string, "platformid") == 0) {
+ if (strcmp(value, "efi") == 0)
+ image->platform_id = ET_SYS_EFI;
+ else {
+ warn("%s: unknown platform: %s", __func__, value);
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static struct boot_catalog_entry *
+cd9660_init_boot_catalog_entry(void)
+{
+ return ecalloc(1, sizeof(struct boot_catalog_entry));
+}
+
+static struct boot_catalog_entry *
+cd9660_boot_setup_validation_entry(char sys)
+{
+ struct boot_catalog_entry *entry;
+ boot_catalog_validation_entry *ve;
+ int16_t checksum;
+ unsigned char *csptr;
+ size_t i;
+ entry = cd9660_init_boot_catalog_entry();
+
+ entry->entry_type = ET_ENTRY_VE;
+ ve = &entry->entry_data.VE;
+
+ ve->header_id[0] = 1;
+ ve->platform_id[0] = sys;
+ ve->key[0] = 0x55;
+ ve->key[1] = 0xAA;
+
+ /* Calculate checksum */
+ checksum = 0;
+ cd9660_721(0, ve->checksum);
+ csptr = (unsigned char*)ve;
+ for (i = 0; i < sizeof(*ve); i += 2) {
+ checksum += (int16_t)csptr[i];
+ checksum += 256 * (int16_t)csptr[i + 1];
+ }
+ checksum = -checksum;
+ cd9660_721(checksum, ve->checksum);
+
+ ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, "
+ "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0],
+ ve->key[0], ve->key[1], checksum));
+ return entry;
+}
+
+static struct boot_catalog_entry *
+cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk)
+{
+ struct boot_catalog_entry *default_entry;
+ boot_catalog_initial_entry *ie;
+
+ default_entry = cd9660_init_boot_catalog_entry();
+ if (default_entry == NULL)
+ return NULL;
+
+ default_entry->entry_type = ET_ENTRY_IE;
+ ie = &default_entry->entry_data.IE;
+
+ ie->boot_indicator[0] = disk->bootable;
+ ie->media_type[0] = disk->targetMode;
+ cd9660_721(disk->loadSegment, ie->load_segment);
+ ie->system_type[0] = disk->system;
+ cd9660_721(disk->num_sectors, ie->sector_count);
+ cd9660_731(disk->sector, ie->load_rba);
+
+ ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, "
+ "load segment %04x, system type %d, sector count %d, "
+ "load rba %d\n", __func__, ie->boot_indicator[0],
+ ie->media_type[0], disk->loadSegment, ie->system_type[0],
+ disk->num_sectors, disk->sector));
+ return default_entry;
+}
+
+static struct boot_catalog_entry *
+cd9660_boot_setup_section_head(char platform)
+{
+ struct boot_catalog_entry *entry;
+ boot_catalog_section_header *sh;
+
+ entry = cd9660_init_boot_catalog_entry();
+ if (entry == NULL)
+ return NULL;
+
+ entry->entry_type = ET_ENTRY_SH;
+ sh = &entry->entry_data.SH;
+ /*
+ * More by default.
+ * The last one will manually be set to ET_SECTION_HEADER_LAST
+ */
+ sh->header_indicator[0] = ET_SECTION_HEADER_MORE;
+ sh->platform_id[0] = platform;
+ sh->num_section_entries[0] = 0;
+ return entry;
+}
+
+static struct boot_catalog_entry *
+cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk)
+{
+ struct boot_catalog_entry *entry;
+ boot_catalog_section_entry *se;
+ if ((entry = cd9660_init_boot_catalog_entry()) == NULL)
+ return NULL;
+
+ entry->entry_type = ET_ENTRY_SE;
+ se = &entry->entry_data.SE;
+
+ se->boot_indicator[0] = ET_BOOTABLE;
+ se->media_type[0] = disk->targetMode;
+ cd9660_721(disk->loadSegment, se->load_segment);
+ cd9660_721(disk->num_sectors, se->sector_count);
+ cd9660_731(disk->sector, se->load_rba);
+ return entry;
+}
+
+#if 0
+static u_char
+cd9660_boot_get_system_type(struct cd9660_boot_image *disk)
+{
+ /*
+ For hard drive booting, we need to examine the MBR to figure
+ out what the partition type is
+ */
+ return 0;
+}
+#endif
+
+/*
+ * Set up the BVD, Boot catalog, and the boot entries, but do no writing
+ */
+int
+cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector)
+{
+ int sector;
+ int used_sectors;
+ int num_entries = 0;
+ int catalog_sectors;
+ struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, *efi_head,
+ *valid_entry, *default_entry, *temp, *head, **headp, *next;
+ struct cd9660_boot_image *tmp_disk;
+ uint8_t system;
+
+ headp = NULL;
+ x86_head = mac_head = ppc_head = efi_head = NULL;
+
+ /* If there are no boot disks, don't bother building boot information */
+ if (TAILQ_EMPTY(&diskStructure->boot_images))
+ return 0;
+
+ /* Point to catalog: For now assume it consumes one sector */
+ ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector));
+ diskStructure->boot_catalog_sector = first_sector;
+ cd9660_731(first_sector,
+ diskStructure->boot_descriptor->boot_catalog_pointer);
+
+ /*
+ * Use system type of default image for validation entry. Fallback to
+ * X86 system type if not found.
+ */
+ system = default_boot_image != NULL ? default_boot_image->system :
+ ET_SYS_X86;
+
+ /* Step 1: Generate boot catalog */
+ /* Step 1a: Validation entry */
+ valid_entry = cd9660_boot_setup_validation_entry(system);
+ if (valid_entry == NULL)
+ return -1;
+
+ /*
+ * Count how many boot images there are,
+ * and how many sectors they consume.
+ */
+ num_entries = 1;
+ used_sectors = 0;
+
+ TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
+ used_sectors += tmp_disk->num_sectors;
+
+ /* One default entry per image */
+ num_entries++;
+ }
+ catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize);
+ used_sectors += catalog_sectors;
+
+ if (diskStructure->verbose_level > 0) {
+ printf("%s: there will be %i entries consuming %i sectors. "
+ "Catalog is %i sectors\n", __func__, num_entries,
+ used_sectors, catalog_sectors);
+ }
+
+ /* Populate sector numbers */
+ sector = first_sector + catalog_sectors;
+ TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
+ tmp_disk->sector = sector;
+ sector += tmp_disk->num_sectors /
+ (diskStructure->sectorSize / 512);
+ }
+
+ LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct);
+
+ /* Step 1b: Initial/default entry */
+ /* TODO : PARAM */
+ if (default_boot_image != NULL) {
+ struct cd9660_boot_image *tcbi;
+ TAILQ_FOREACH(tcbi, &diskStructure->boot_images, image_list) {
+ if (tcbi == default_boot_image) {
+ tmp_disk = tcbi;
+ break;
+ }
+ }
+ }
+ if (tmp_disk == NULL)
+ tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
+ default_entry = cd9660_boot_setup_default_entry(tmp_disk);
+ if (default_entry == NULL) {
+ warnx("Error: memory allocation failed in cd9660_setup_boot");
+ return -1;
+ }
+
+ LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct);
+
+ /* Todo: multiple default entries? */
+
+ tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
+
+ head = NULL;
+ temp = default_entry;
+
+ /* If multiple boot images are given : */
+ for (; tmp_disk != NULL; tmp_disk = TAILQ_NEXT(tmp_disk, image_list)) {
+ if (tmp_disk == default_boot_image)
+ continue;
+
+ /* Step 2: Section header */
+ switch (tmp_disk->platform_id) {
+ case ET_SYS_X86:
+ headp = &x86_head;
+ break;
+ case ET_SYS_PPC:
+ headp = &ppc_head;
+ break;
+ case ET_SYS_MAC:
+ headp = &mac_head;
+ break;
+ case ET_SYS_EFI:
+ headp = &efi_head;
+ break;
+ default:
+ warnx("%s: internal error: unknown system type",
+ __func__);
+ return -1;
+ }
+
+ if (*headp == NULL) {
+ head =
+ cd9660_boot_setup_section_head(tmp_disk->platform_id);
+ if (head == NULL) {
+ warnx("Error: memory allocation failed in "
+ "cd9660_setup_boot");
+ return -1;
+ }
+ LIST_INSERT_AFTER(default_entry, head, ll_struct);
+ *headp = head;
+ } else
+ head = *headp;
+
+ head->entry_data.SH.num_section_entries[0]++;
+
+ /* Step 2a: Section entry and extensions */
+ temp = cd9660_boot_setup_section_entry(tmp_disk);
+ if (temp == NULL) {
+ warn("%s: cd9660_boot_setup_section_entry", __func__);
+ return -1;
+ }
+
+ while ((next = LIST_NEXT(head, ll_struct)) != NULL &&
+ next->entry_type == ET_ENTRY_SE)
+ head = next;
+
+ LIST_INSERT_AFTER(head, temp, ll_struct);
+ }
+
+ /* Find the last Section Header entry and mark it as the last. */
+ head = NULL;
+ LIST_FOREACH(next, &diskStructure->boot_entries, ll_struct) {
+ if (next->entry_type == ET_ENTRY_SH)
+ head = next;
+ }
+ if (head != NULL)
+ head->entry_data.SH.header_indicator[0] = ET_SECTION_HEADER_LAST;
+
+ /* TODO: Remaining boot disks when implemented */
+
+ return first_sector + used_sectors;
+}
+
+int
+cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure,
+ volume_descriptor *bvd)
+{
+ boot_volume_descriptor *bvdData =
+ (boot_volume_descriptor*)bvd->volumeDescriptorData;
+
+ bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT;
+ memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
+ bvdData->version[0] = 1;
+ memcpy(bvdData->boot_system_identifier, ET_ID, 23);
+ memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
+ diskStructure->boot_descriptor =
+ (boot_volume_descriptor*) bvd->volumeDescriptorData;
+ return 1;
+}
+
+static int
+cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start,
+ off_t nsectors, int type)
+{
+ uint8_t val;
+ uint32_t lba;
+
+ if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ val = 0x80; /* Bootable */
+ fwrite(&val, sizeof(val), 1, fd);
+
+ val = 0xff; /* CHS begin */
+ fwrite(&val, sizeof(val), 1, fd);
+ fwrite(&val, sizeof(val), 1, fd);
+ fwrite(&val, sizeof(val), 1, fd);
+
+ val = type; /* Part type */
+ fwrite(&val, sizeof(val), 1, fd);
+
+ val = 0xff; /* CHS end */
+ fwrite(&val, sizeof(val), 1, fd);
+ fwrite(&val, sizeof(val), 1, fd);
+ fwrite(&val, sizeof(val), 1, fd);
+
+ /* LBA extent */
+ lba = htole32(sector_start);
+ fwrite(&lba, sizeof(lba), 1, fd);
+ lba = htole32(nsectors);
+ fwrite(&lba, sizeof(lba), 1, fd);
+
+ return 0;
+}
+
+static int
+cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions,
+ off_t sector_start, off_t nsectors, off_t sector_size,
+ const char *part_name, const char *part_type)
+{
+ uint32_t apm32, part_status;
+ uint16_t apm16;
+
+ part_status = APPLE_PS_VALID | APPLE_PS_ALLOCATED | APPLE_PS_READABLE |
+ APPLE_PS_WRITABLE;
+
+ if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ /* Signature */
+ apm16 = htobe16(0x504d);
+ fwrite(&apm16, sizeof(apm16), 1, fd);
+ apm16 = 0;
+ fwrite(&apm16, sizeof(apm16), 1, fd);
+
+ /* Total number of partitions */
+ apm32 = htobe32(total_partitions);
+ fwrite(&apm32, sizeof(apm32), 1, fd);
+ /* Bounds */
+ apm32 = htobe32(sector_start);
+ fwrite(&apm32, sizeof(apm32), 1, fd);
+ apm32 = htobe32(nsectors);
+ fwrite(&apm32, sizeof(apm32), 1, fd);
+
+ fwrite(part_name, strlen(part_name) + 1, 1, fd);
+ fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR);
+ fwrite(part_type, strlen(part_type) + 1, 1, fd);
+ fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR);
+
+ apm32 = 0;
+ /* pmLgDataStart */
+ fwrite(&apm32, sizeof(apm32), 1, fd);
+ /* pmDataCnt */
+ apm32 = htobe32(nsectors);
+ fwrite(&apm32, sizeof(apm32), 1, fd);
+ /* pmPartStatus */
+ apm32 = htobe32(part_status);
+ fwrite(&apm32, sizeof(apm32), 1, fd);
+
+ return 0;
+}
+
+int
+cd9660_write_boot(iso9660_disk *diskStructure, FILE *fd)
+{
+ struct boot_catalog_entry *e;
+ struct cd9660_boot_image *t;
+ int apm_partitions = 0;
+ int mbr_partitions = 0;
+
+ /* write boot catalog */
+ if (fseeko(fd, (off_t)diskStructure->boot_catalog_sector *
+ diskStructure->sectorSize, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ if (diskStructure->verbose_level > 0) {
+ printf("Writing boot catalog to sector %" PRId64 "\n",
+ diskStructure->boot_catalog_sector);
+ }
+ LIST_FOREACH(e, &diskStructure->boot_entries, ll_struct) {
+ if (diskStructure->verbose_level > 0) {
+ printf("Writing catalog entry of type %d\n",
+ e->entry_type);
+ }
+ /*
+ * It doesn't matter which one gets written
+ * since they are the same size
+ */
+ fwrite(&(e->entry_data.VE), 1, 32, fd);
+ }
+ if (diskStructure->verbose_level > 0)
+ printf("Finished writing boot catalog\n");
+
+ /* copy boot images */
+ TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
+ if (diskStructure->verbose_level > 0) {
+ printf("Writing boot image from %s to sectors %d\n",
+ t->filename, t->sector);
+ }
+ cd9660_copy_file(diskStructure, fd, t->sector, t->filename);
+
+ if (t->system == ET_SYS_MAC)
+ apm_partitions++;
+ if (t->system == ET_SYS_PPC)
+ mbr_partitions++;
+ }
+
+ /* some systems need partition tables as well */
+ if (mbr_partitions > 0 || diskStructure->chrp_boot) {
+ uint16_t sig;
+
+ fseek(fd, 0x1fe, SEEK_SET);
+ sig = htole16(0xaa55);
+ fwrite(&sig, sizeof(sig), 1, fd);
+
+ mbr_partitions = 0;
+
+ /* Write ISO9660 descriptor, enclosing the whole disk */
+ if (diskStructure->chrp_boot)
+ cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
+ 0, diskStructure->totalSectors *
+ (diskStructure->sectorSize / 512), 0x96);
+
+ /* Write all partition entries */
+ TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
+ if (t->system != ET_SYS_PPC)
+ continue;
+ cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
+ t->sector * (diskStructure->sectorSize / 512),
+ t->num_sectors * (diskStructure->sectorSize / 512),
+ 0x41 /* PReP Boot */);
+ }
+ }
+
+ if (apm_partitions > 0) {
+ /* Write DDR and global APM info */
+ uint32_t apm32;
+ uint16_t apm16;
+ int total_parts;
+
+ fseek(fd, 0, SEEK_SET);
+ apm16 = htobe16(0x4552);
+ fwrite(&apm16, sizeof(apm16), 1, fd);
+ /* Device block size */
+ apm16 = htobe16(512);
+ fwrite(&apm16, sizeof(apm16), 1, fd);
+ /* Device block count */
+ apm32 = htobe32(diskStructure->totalSectors *
+ (diskStructure->sectorSize / 512));
+ fwrite(&apm32, sizeof(apm32), 1, fd);
+ /* Device type/id */
+ apm16 = htobe16(1);
+ fwrite(&apm16, sizeof(apm16), 1, fd);
+ fwrite(&apm16, sizeof(apm16), 1, fd);
+
+ /* Count total needed entries */
+ total_parts = 2 + apm_partitions; /* Self + ISO9660 */
+
+ /* Write self-descriptor */
+ cd9660_write_apm_partition_entry(fd, 0, total_parts, 1,
+ total_parts, 512, "Apple", "Apple_partition_map");
+
+ /* Write all partition entries */
+ apm_partitions = 0;
+ TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
+ if (t->system != ET_SYS_MAC)
+ continue;
+
+ cd9660_write_apm_partition_entry(fd,
+ 1 + apm_partitions++, total_parts,
+ t->sector * (diskStructure->sectorSize / 512),
+ t->num_sectors * (diskStructure->sectorSize / 512),
+ 512, "CD Boot", "Apple_Bootstrap");
+ }
+
+ /* Write ISO9660 descriptor, enclosing the whole disk */
+ cd9660_write_apm_partition_entry(fd, 2 + apm_partitions,
+ total_parts, 0, diskStructure->totalSectors *
+ (diskStructure->sectorSize / 512), 512, "ISO9660",
+ "CD_ROM_Mode_1");
+ }
+
+ return 0;
+}
diff --git a/usr.sbin/makefs/cd9660/cd9660_eltorito.h b/usr.sbin/makefs/cd9660/cd9660_eltorito.h
new file mode 100644
index 000000000000..a9ad0901e1a7
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_eltorito.h
@@ -0,0 +1,166 @@
+/* $NetBSD: cd9660_eltorito.h,v 1.6 2017/01/24 11:22:43 nonaka Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#ifndef _CD9660_ELTORITO_H_
+#define _CD9660_ELTORITO_H_
+
+/* Boot defines */
+#define ET_ID "EL TORITO SPECIFICATION"
+#define ET_SYS_X86 0
+#define ET_SYS_PPC 1
+#define ET_SYS_MAC 2
+#define ET_SYS_EFI 0xef /* Platform ID at section header entry */
+
+#define ET_BOOT_ENTRY_SIZE 0x20
+
+#define ET_BOOTABLE 0x88
+#define ET_NOT_BOOTABLE 0
+
+#define ET_MEDIA_NOEM 0
+#define ET_MEDIA_12FDD 1
+#define ET_MEDIA_144FDD 2
+#define ET_MEDIA_288FDD 3
+#define ET_MEDIA_HDD 4
+
+#define ET_INDICATOR_HEADERMORE 0x90
+#define ET_INDICATOR_HEADERLAST 0x91
+#define ET_INDICATOR_EXTENSION 0x44
+
+/*** Boot Structures ***/
+
+typedef struct _boot_volume_descriptor {
+ u_char boot_record_indicator [ISODCL(0x00,0x00)];
+ u_char identifier [ISODCL(0x01,0x05)];
+ u_char version [ISODCL(0x06,0x06)];
+ u_char boot_system_identifier [ISODCL(0x07,0x26)];
+ u_char unused1 [ISODCL(0x27,0x46)];
+ u_char boot_catalog_pointer [ISODCL(0x47,0x4A)];
+ u_char unused2 [ISODCL(0x4B,0x7FF)];
+} boot_volume_descriptor;
+
+typedef struct _boot_catalog_validation_entry {
+ u_char header_id [ISODCL(0x00,0x00)];
+ u_char platform_id [ISODCL(0x01,0x01)];
+ u_char reserved1 [ISODCL(0x02,0x03)];
+ u_char manufacturer [ISODCL(0x04,0x1B)];
+ u_char checksum [ISODCL(0x1C,0x1D)];
+ u_char key [ISODCL(0x1E,0x1F)];
+} boot_catalog_validation_entry;
+
+typedef struct _boot_catalog_initial_entry {
+ u_char boot_indicator [ISODCL(0x00,0x00)];
+ u_char media_type [ISODCL(0x01,0x01)];
+ u_char load_segment [ISODCL(0x02,0x03)];
+ u_char system_type [ISODCL(0x04,0x04)];
+ u_char unused_1 [ISODCL(0x05,0x05)];
+ u_char sector_count [ISODCL(0x06,0x07)];
+ u_char load_rba [ISODCL(0x08,0x0B)];
+ u_char unused_2 [ISODCL(0x0C,0x1F)];
+} boot_catalog_initial_entry;
+
+#define ET_SECTION_HEADER_MORE 0x90
+#define ET_SECTION_HEADER_LAST 0x91
+
+typedef struct _boot_catalog_section_header {
+ u_char header_indicator [ISODCL(0x00,0x00)];
+ u_char platform_id [ISODCL(0x01,0x01)];
+ u_char num_section_entries [ISODCL(0x02,0x03)];
+ u_char id_string [ISODCL(0x04,0x1F)];
+} boot_catalog_section_header;
+
+typedef struct _boot_catalog_section_entry {
+ u_char boot_indicator [ISODCL(0x00,0x00)];
+ u_char media_type [ISODCL(0x01,0x01)];
+ u_char load_segment [ISODCL(0x02,0x03)];
+ u_char system_type [ISODCL(0x04,0x04)];
+ u_char unused_1 [ISODCL(0x05,0x05)];
+ u_char sector_count [ISODCL(0x06,0x07)];
+ u_char load_rba [ISODCL(0x08,0x0B)];
+ u_char selection_criteria [ISODCL(0x0C,0x0C)];
+ u_char vendor_criteria [ISODCL(0x0D,0x1F)];
+} boot_catalog_section_entry;
+
+typedef struct _boot_catalog_section_entry_extension {
+ u_char extension_indicator [ISODCL(0x00,0x00)];
+ u_char flags [ISODCL(0x01,0x01)];
+ u_char vendor_criteria [ISODCL(0x02,0x1F)];
+} boot_catalog_section_entry_extension;
+
+#define ET_ENTRY_VE 1
+#define ET_ENTRY_IE 2
+#define ET_ENTRY_SH 3
+#define ET_ENTRY_SE 4
+#define ET_ENTRY_EX 5
+
+struct boot_catalog_entry {
+ char entry_type;
+ union {
+ boot_catalog_validation_entry VE;
+ boot_catalog_initial_entry IE;
+ boot_catalog_section_header SH;
+ boot_catalog_section_entry SE;
+ boot_catalog_section_entry_extension EX;
+ } entry_data;
+
+ LIST_ENTRY(boot_catalog_entry) ll_struct;
+};
+
+/* Temporary structure */
+struct cd9660_boot_image {
+ char *filename;
+ int size;
+ int sector; /* copied to LoadRBA */
+ int num_sectors;
+ unsigned int loadSegment;
+ u_char targetMode;
+ u_char system;
+ u_char bootable;
+ u_char platform_id; /* for section header entry */
+ /*
+ * If the boot image exists in the filesystem
+ * already, this is a pointer to that node. For the sake
+ * of simplicity in future versions, this pointer is only
+ * to the node in the primary volume. This SHOULD be done
+ * via a hashtable lookup.
+ */
+ struct _cd9660node *boot_image_node;
+ TAILQ_ENTRY(cd9660_boot_image) image_list;
+ int serialno;
+};
+
+
+#endif /* _CD9660_ELTORITO_H_ */
+
diff --git a/usr.sbin/makefs/cd9660/cd9660_strings.c b/usr.sbin/makefs/cd9660/cd9660_strings.c
new file mode 100644
index 000000000000..b3111fca6cd1
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_strings.c
@@ -0,0 +1,120 @@
+/* $NetBSD: cd9660_strings.c,v 1.4 2007/01/16 17:32:05 hubertf Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <sys/mount.h>
+
+#include <sys/param.h>
+#include <ctype.h>
+
+#include "makefs.h"
+#include "cd9660.h"
+
+
+void
+cd9660_uppercase_characters(char *str, size_t len)
+{
+ size_t p;
+
+ for (p = 0; p < len; p++) {
+ if (islower((unsigned char)str[p]) )
+ str[p] -= 32;
+ }
+}
+
+static inline int
+cd9660_is_d_char(char c)
+{
+ return (isupper((unsigned char)c)
+ || c == '_'
+ || (c >= '0' && c <= '9'));
+}
+
+static inline int
+cd9660_is_a_char(char c)
+{
+ return (isupper((unsigned char)c)
+ || c == '_'
+ || (c >= '%' && c <= '?')
+ || (c >= ' ' && c <= '\"'));
+}
+
+/*
+ * Test a string to see if it is composed of valid a characters
+ * @param const char* The string to test
+ * @returns int 1 if valid, 2 if valid if characters are converted to
+ * upper case, 0 otherwise
+ */
+int
+cd9660_valid_a_chars(const char *str)
+{
+ const char *c = str;
+ int upperFound = 0;
+
+ while ((*c) != '\0') {
+ if (!(cd9660_is_a_char(*c))) {
+ if (islower((unsigned char)*c) )
+ upperFound = 1;
+ else
+ return 0;
+ }
+ c++;
+ }
+ return upperFound + 1;
+}
+
+/*
+ * Test a string to see if it is composed of valid d characters
+ * @param const char* The string to test
+ * @returns int 1 if valid, 2 if valid if characters are converted to
+ * upper case, 0 otherwise
+ */
+int
+cd9660_valid_d_chars(const char *str)
+{
+ const char *c=str;
+ int upperFound = 0;
+
+ while ((*c) != '\0') {
+ if (!(cd9660_is_d_char(*c))) {
+ if (islower((unsigned char)*c) )
+ upperFound = 1;
+ else
+ return 0;
+ }
+ c++;
+ }
+ return upperFound + 1;
+}
diff --git a/usr.sbin/makefs/cd9660/cd9660_write.c b/usr.sbin/makefs/cd9660/cd9660_write.c
new file mode 100644
index 000000000000..828af11669c1
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_write.c
@@ -0,0 +1,510 @@
+/* $NetBSD: cd9660_write.c,v 1.14 2011/01/04 09:48:21 wiz Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "cd9660.h"
+#include "iso9660_rrip.h"
+
+#include <sys/cdefs.h>
+#include <util.h>
+
+static int cd9660_write_volume_descriptors(iso9660_disk *, FILE *);
+static int cd9660_write_path_table(iso9660_disk *, FILE *, off_t, int);
+static int cd9660_write_path_tables(iso9660_disk *, FILE *);
+static int cd9660_write_file(iso9660_disk *, FILE *, cd9660node *);
+static int cd9660_write_filedata(iso9660_disk *, FILE *, off_t,
+ const unsigned char *, int);
+#if 0
+static int cd9660_write_buffered(FILE *, off_t, int, const unsigned char *);
+#endif
+static void cd9660_write_rr(iso9660_disk *, FILE *, cd9660node *, off_t, off_t);
+
+/*
+ * Write the image
+ * Writes the entire image
+ * @param const char* The filename for the image
+ * @returns int 1 on success, 0 on failure
+ */
+int
+cd9660_write_image(iso9660_disk *diskStructure, const char* image)
+{
+ FILE *fd;
+ int status;
+ unsigned char buf[CD9660_SECTOR_SIZE];
+
+ if ((fd = fopen(image, "w+")) == NULL) {
+ err(EXIT_FAILURE, "%s: Can't open `%s' for writing", __func__,
+ image);
+ }
+
+ if (diskStructure->verbose_level > 0)
+ printf("Writing image\n");
+
+ if (diskStructure->has_generic_bootimage) {
+ status = cd9660_copy_file(diskStructure, fd, 0,
+ diskStructure->generic_bootimage);
+ if (status == 0) {
+ warnx("%s: Error writing generic boot image",
+ __func__);
+ goto cleanup_bad_image;
+ }
+ }
+
+ /* Write the volume descriptors */
+ status = cd9660_write_volume_descriptors(diskStructure, fd);
+ if (status == 0) {
+ warnx("%s: Error writing volume descriptors to image",
+ __func__);
+ goto cleanup_bad_image;
+ }
+
+ if (diskStructure->verbose_level > 0)
+ printf("Volume descriptors written\n");
+
+ /*
+ * Write the path tables: there are actually four, but right
+ * now we are only concerned with two.
+ */
+ status = cd9660_write_path_tables(diskStructure, fd);
+ if (status == 0) {
+ warnx("%s: Error writing path tables to image", __func__);
+ goto cleanup_bad_image;
+ }
+
+ if (diskStructure->verbose_level > 0)
+ printf("Path tables written\n");
+
+ /* Write the directories and files */
+ status = cd9660_write_file(diskStructure, fd, diskStructure->rootNode);
+ if (status == 0) {
+ warnx("%s: Error writing files to image", __func__);
+ goto cleanup_bad_image;
+ }
+
+ if (diskStructure->is_bootable) {
+ cd9660_write_boot(diskStructure, fd);
+ }
+
+ /* Write padding bits. This is temporary */
+ memset(buf, 0, CD9660_SECTOR_SIZE);
+ cd9660_write_filedata(diskStructure, fd,
+ diskStructure->totalSectors - 1, buf, 1);
+
+ if (diskStructure->verbose_level > 0)
+ printf("Files written\n");
+ fclose(fd);
+
+ if (diskStructure->verbose_level > 0)
+ printf("Image closed\n");
+ return 1;
+
+cleanup_bad_image:
+ fclose(fd);
+ if (!diskStructure->keep_bad_images)
+ unlink(image);
+ if (diskStructure->verbose_level > 0)
+ printf("Bad image cleaned up\n");
+ return 0;
+}
+
+static int
+cd9660_write_volume_descriptors(iso9660_disk *diskStructure, FILE *fd)
+{
+ volume_descriptor *vd_temp = diskStructure->firstVolumeDescriptor;
+
+ while (vd_temp != NULL) {
+ cd9660_write_filedata(diskStructure, fd, vd_temp->sector,
+ vd_temp->volumeDescriptorData, 1);
+ vd_temp = vd_temp->next;
+ }
+ return 1;
+}
+
+/*
+ * Write out an individual path table
+ * Used just to keep redundant code to a minimum
+ * @param FILE *fd Valid file pointer
+ * @param int Sector to start writing path table to
+ * @param int Endian mode : BIG_ENDIAN or LITTLE_ENDIAN
+ * @returns int 1 on success, 0 on failure
+ */
+static int
+cd9660_write_path_table(iso9660_disk *diskStructure, FILE *fd, off_t sector,
+ int mode)
+{
+ int path_table_sectors = CD9660_BLOCKS(diskStructure->sectorSize,
+ diskStructure->pathTableLength);
+ unsigned char *buffer;
+ unsigned char *buffer_head;
+ int len, ret;
+ path_table_entry temp_entry;
+ cd9660node *ptcur;
+
+ buffer = ecalloc(path_table_sectors, diskStructure->sectorSize);
+ buffer_head = buffer;
+
+ ptcur = diskStructure->rootNode;
+
+ while (ptcur != NULL) {
+ memset(&temp_entry, 0, sizeof(path_table_entry));
+ temp_entry.length[0] = ptcur->isoDirRecord->name_len[0];
+ temp_entry.extended_attribute_length[0] =
+ ptcur->isoDirRecord->ext_attr_length[0];
+ memcpy(temp_entry.name, ptcur->isoDirRecord->name,
+ temp_entry.length[0] + 1);
+
+ /* round up */
+ len = temp_entry.length[0] + 8 + (temp_entry.length[0] & 0x01);
+
+ /* todo: function pointers instead */
+ if (mode == LITTLE_ENDIAN) {
+ cd9660_731(ptcur->fileDataSector,
+ temp_entry.first_sector);
+ cd9660_721((ptcur->parent == NULL ?
+ 1 : ptcur->parent->ptnumber),
+ temp_entry.parent_number);
+ } else {
+ cd9660_732(ptcur->fileDataSector,
+ temp_entry.first_sector);
+ cd9660_722((ptcur->parent == NULL ?
+ 1 : ptcur->parent->ptnumber),
+ temp_entry.parent_number);
+ }
+
+
+ memcpy(buffer, &temp_entry, len);
+ buffer += len;
+
+ ptcur = ptcur->ptnext;
+ }
+
+ ret = cd9660_write_filedata(diskStructure, fd, sector, buffer_head,
+ path_table_sectors);
+ free(buffer_head);
+ return ret;
+}
+
+
+/*
+ * Write out the path tables to disk
+ * Each file descriptor should be pointed to by the PVD, so we know which
+ * sector to copy them to. One thing to watch out for: the only path tables
+ * stored are in the endian mode that the application is compiled for. So,
+ * the first thing to do is write out that path table, then to write the one
+ * in the other endian mode requires to convert the endianness of each entry
+ * in the table. The best way to do this would be to create a temporary
+ * path_table_entry structure, then for each path table entry, copy it to
+ * the temporary entry, translate, then copy that to disk.
+ *
+ * @param FILE* Valid file descriptor
+ * @returns int 0 on failure, 1 on success
+ */
+static int
+cd9660_write_path_tables(iso9660_disk *diskStructure, FILE *fd)
+{
+ if (cd9660_write_path_table(diskStructure, fd,
+ diskStructure->primaryLittleEndianTableSector, LITTLE_ENDIAN) == 0)
+ return 0;
+
+ if (cd9660_write_path_table(diskStructure, fd,
+ diskStructure->primaryBigEndianTableSector, BIG_ENDIAN) == 0)
+ return 0;
+
+ /* @TODO: handle remaining two path tables */
+ return 1;
+}
+
+/*
+ * Write a file to disk
+ * Writes a file, its directory record, and its data to disk
+ * This file is designed to be called RECURSIVELY, so initially call it
+ * with the root node. All of the records should store what sector the
+ * file goes in, so no computation should be necessary.
+ *
+ * @param int fd Valid file descriptor
+ * @param struct cd9660node* writenode Pointer to the file to be written
+ * @returns int 0 on failure, 1 on success
+ */
+static int
+cd9660_write_file(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode)
+{
+ char *buf;
+ char *temp_file_name;
+ int ret;
+ off_t working_sector;
+ int cur_sector_offset;
+ iso_directory_record_cd9660 temp_record;
+ cd9660node *temp;
+ int rv = 0;
+
+ /* Todo : clean up variables */
+
+ temp_file_name = ecalloc(PATH_MAX, 1);
+ buf = emalloc(diskStructure->sectorSize);
+ if ((writenode->level != 0) &&
+ !(writenode->node->type & S_IFDIR)) {
+ fsinode *inode = writenode->node->inode;
+ /* Only attempt to write unwritten files that have length. */
+ if ((inode->flags & FI_WRITTEN) != 0) {
+ INODE_WARNX(("%s: skipping written inode %d", __func__,
+ (int)inode->st.st_ino));
+ } else if (writenode->fileDataLength > 0) {
+ INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32,
+ __func__, (int)inode->st.st_ino, inode->ino));
+ inode->flags |= FI_WRITTEN;
+ if (writenode->node->contents == NULL)
+ cd9660_compute_full_filename(writenode,
+ temp_file_name);
+ ret = cd9660_copy_file(diskStructure, fd,
+ writenode->fileDataSector,
+ (writenode->node->contents != NULL) ?
+ writenode->node->contents : temp_file_name);
+ if (ret == 0)
+ goto out;
+ }
+ } else {
+ /*
+ * Here is a new revelation that ECMA didn't explain
+ * (at least not well).
+ * ALL . and .. records store the name "\0" and "\1"
+ * respectively. So, for each directory, we have to
+ * make a new node.
+ *
+ * This is where it gets kinda messy, since we have to
+ * be careful of sector boundaries
+ */
+ cur_sector_offset = 0;
+ working_sector = writenode->fileDataSector;
+ if (fseeko(fd, working_sector * diskStructure->sectorSize,
+ SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ /*
+ * Now loop over children, writing out their directory
+ * records - beware of sector boundaries
+ */
+ TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
+ /*
+ * Copy the temporary record and adjust its size
+ * if necessary
+ */
+ memcpy(&temp_record, temp->isoDirRecord,
+ sizeof(iso_directory_record_cd9660));
+
+ temp_record.length[0] =
+ cd9660_compute_record_size(diskStructure, temp);
+
+ if (temp_record.length[0] + cur_sector_offset >=
+ diskStructure->sectorSize) {
+ cur_sector_offset = 0;
+ working_sector++;
+
+ /* Seek to the next sector. */
+ if (fseeko(fd, working_sector *
+ diskStructure->sectorSize, SEEK_SET) == -1)
+ err(1, "fseeko");
+ }
+ /* Write out the basic ISO directory record */
+ (void)fwrite(&temp_record, 1,
+ temp->isoDirRecord->length[0], fd);
+ if (diskStructure->rock_ridge_enabled) {
+ cd9660_write_rr(diskStructure, fd, temp,
+ cur_sector_offset, working_sector);
+ }
+ if (fseeko(fd, working_sector *
+ diskStructure->sectorSize + cur_sector_offset +
+ temp_record.length[0] - temp->su_tail_size,
+ SEEK_SET) == -1)
+ err(1, "fseeko");
+ if (temp->su_tail_size > 0)
+ fwrite(temp->su_tail_data, 1,
+ temp->su_tail_size, fd);
+ if (ferror(fd)) {
+ warnx("%s: write error", __func__);
+ goto out;
+ }
+ cur_sector_offset += temp_record.length[0];
+
+ }
+
+ /*
+ * Recurse on children.
+ */
+ TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
+ if ((ret = cd9660_write_file(diskStructure, fd, temp)) == 0)
+ goto out;
+ }
+ }
+ rv = 1;
+out:
+ free(temp_file_name);
+ free(buf);
+ return rv;
+}
+
+/*
+ * Wrapper function to write a buffer (one sector) to disk.
+ * Seeks and writes the buffer.
+ * NOTE: You dont NEED to use this function, but it might make your
+ * life easier if you have to write things that align to a sector
+ * (such as volume descriptors).
+ *
+ * @param int fd Valid file descriptor
+ * @param int sector Sector number to write to
+ * @param const unsigned char* Buffer to write. This should be the
+ * size of a sector, and if only a portion
+ * is written, the rest should be set to 0.
+ */
+static int
+cd9660_write_filedata(iso9660_disk *diskStructure, FILE *fd, off_t sector,
+ const unsigned char *buf, int numsecs)
+{
+ off_t curpos;
+ size_t success;
+
+ curpos = ftello(fd);
+
+ if (fseeko(fd, sector * diskStructure->sectorSize, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ success = fwrite(buf, diskStructure->sectorSize * numsecs, 1, fd);
+
+ if (fseeko(fd, curpos, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ if (success == 1)
+ success = diskStructure->sectorSize * numsecs;
+ return success;
+}
+
+#if 0
+static int
+cd9660_write_buffered(FILE *fd, off_t offset, int buff_len,
+ const unsigned char* buffer)
+{
+ static int working_sector = -1;
+ static char buf[CD9660_SECTOR_SIZE];
+
+ return 0;
+}
+#endif
+
+int
+cd9660_copy_file(iso9660_disk *diskStructure, FILE *fd, off_t start_sector,
+ const char *filename)
+{
+ FILE *rf;
+ int bytes_read;
+ int buf_size = diskStructure->sectorSize;
+ char *buf;
+
+ buf = emalloc(buf_size);
+ if ((rf = fopen(filename, "rb")) == NULL) {
+ warn("%s: cannot open %s", __func__, filename);
+ free(buf);
+ return 0;
+ }
+
+ if (diskStructure->verbose_level > 1)
+ printf("Writing file: %s\n",filename);
+
+ if (fseeko(fd, start_sector * diskStructure->sectorSize, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ while (!feof(rf)) {
+ bytes_read = fread(buf,1,buf_size,rf);
+ if (ferror(rf)) {
+ warn("%s: fread", __func__);
+ free(buf);
+ (void)fclose(rf);
+ return 0;
+ }
+
+ fwrite(buf,1,bytes_read,fd);
+ if (ferror(fd)) {
+ warn("%s: fwrite", __func__);
+ free(buf);
+ (void)fclose(rf);
+ return 0;
+ }
+ }
+
+ fclose(rf);
+ free(buf);
+ return 1;
+}
+
+static void
+cd9660_write_rr(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode,
+ off_t offset, off_t sector)
+{
+ int in_ca = 0;
+ struct ISO_SUSP_ATTRIBUTES *myattr;
+
+ offset += writenode->isoDirRecord->length[0];
+ if (fseeko(fd, sector * diskStructure->sectorSize + offset, SEEK_SET) ==
+ -1)
+ err(1, "fseeko");
+ /* Offset now points at the end of the record */
+ TAILQ_FOREACH(myattr, &writenode->head, rr_ll) {
+ fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd);
+
+ if (!in_ca) {
+ offset += CD9660_SUSP_ENTRY_SIZE(myattr);
+ if (myattr->last_in_suf) {
+ /*
+ * Point the offset to the start of this
+ * record's CE area
+ */
+ if (fseeko(fd, ((off_t)diskStructure->
+ susp_continuation_area_start_sector *
+ diskStructure->sectorSize)
+ + writenode->susp_entry_ce_start,
+ SEEK_SET) == -1)
+ err(1, "fseeko");
+ in_ca = 1;
+ }
+ }
+ }
+
+ /*
+ * If we had to go to the continuation area, head back to
+ * where we should be.
+ */
+ if (in_ca)
+ if (fseeko(fd, sector * diskStructure->sectorSize + offset,
+ SEEK_SET) == -1)
+ err(1, "fseeko");
+}
diff --git a/usr.sbin/makefs/cd9660/iso9660_rrip.c b/usr.sbin/makefs/cd9660/iso9660_rrip.c
new file mode 100644
index 000000000000..31c6e38a96fe
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/iso9660_rrip.c
@@ -0,0 +1,892 @@
+/* $NetBSD: iso9660_rrip.c,v 1.14 2014/05/30 13:14:47 martin Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+/* This will hold all the function definitions
+ * defined in iso9660_rrip.h
+ */
+
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <stdio.h>
+
+#include "makefs.h"
+#include "cd9660.h"
+#include "iso9660_rrip.h"
+#include <util.h>
+
+static void cd9660_rrip_initialize_inode(iso9660_disk *, cd9660node *);
+static int cd9660_susp_handle_continuation(iso9660_disk *, cd9660node *);
+static int cd9660_susp_handle_continuation_common(iso9660_disk *, cd9660node *,
+ int);
+
+int
+cd9660_susp_initialize(iso9660_disk *diskStructure, cd9660node *node,
+ cd9660node *parent, cd9660node *grandparent)
+{
+ cd9660node *cn;
+ int r;
+
+ /* Make sure the node is not NULL. If it is, there are major problems */
+ assert(node != NULL);
+
+ if (!(node->type & CD9660_TYPE_DOT) &&
+ !(node->type & CD9660_TYPE_DOTDOT))
+ TAILQ_INIT(&(node->head));
+ if (node->dot_record != 0)
+ TAILQ_INIT(&(node->dot_record->head));
+ if (node->dot_dot_record != 0)
+ TAILQ_INIT(&(node->dot_dot_record->head));
+
+ if (diskStructure->rr_inode_next == 0) {
+ RB_INIT(&diskStructure->rr_inode_map);
+ diskStructure->rr_inode_next = 1;
+ }
+
+ /* SUSP specific entries here */
+ if ((r = cd9660_susp_initialize_node(diskStructure, node)) < 0)
+ return r;
+
+ /* currently called cd9660node_rrip_init_links */
+ r = cd9660_rrip_initialize_node(diskStructure, node, parent, grandparent);
+ if (r < 0)
+ return r;
+
+ /*
+ * See if we need a CE record, and set all of the
+ * associated counters.
+ *
+ * This should be called after all extensions. After
+ * this is called, no new records should be added.
+ */
+ if ((r = cd9660_susp_handle_continuation(diskStructure, node)) < 0)
+ return r;
+
+ /* Recurse on children. */
+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
+ if ((r = cd9660_susp_initialize(diskStructure, cn, node, parent)) < 0)
+ return 0;
+ }
+ return 1;
+}
+
+int
+cd9660_susp_finalize(iso9660_disk *diskStructure, cd9660node *node)
+{
+ cd9660node *temp;
+ struct inode_map_node *mapnode, *mapnodetmp;
+ int r;
+
+ assert(node != NULL);
+
+ if (node == diskStructure->rootNode)
+ diskStructure->susp_continuation_area_current_free = 0;
+
+ if ((r = cd9660_susp_finalize_node(diskStructure, node)) < 0)
+ return r;
+ if ((r = cd9660_rrip_finalize_node(node)) < 0)
+ return r;
+
+ TAILQ_FOREACH(temp, &node->cn_children, cn_next_child) {
+ if ((r = cd9660_susp_finalize(diskStructure, temp)) < 0)
+ return r;
+ }
+
+ if (diskStructure->rr_inode_next != 0) {
+ RB_FOREACH_SAFE(mapnode, inode_map_tree,
+ &(diskStructure->rr_inode_map), mapnodetmp) {
+ RB_REMOVE(inode_map_tree,
+ &(diskStructure->rr_inode_map), mapnode);
+ free(mapnode);
+ }
+ diskStructure->rr_inode_next = 0;
+ }
+ return 1;
+}
+
+/*
+ * If we really wanted to speed things up, we could have some sort of
+ * lookup table on the SUSP entry type that calls a functor. Or, we could
+ * combine the functions. These functions are kept separate to allow
+ * easier addition of other extensions.
+
+ * For the sake of simplicity and clarity, we won't be doing that for now.
+ */
+
+/*
+ * SUSP needs to update the following types:
+ * CE (continuation area)
+ */
+int
+cd9660_susp_finalize_node(iso9660_disk *diskStructure, cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES *t;
+
+ /* Handle CE counters */
+ if (node->susp_entry_ce_length > 0) {
+ node->susp_entry_ce_start =
+ diskStructure->susp_continuation_area_current_free;
+ diskStructure->susp_continuation_area_current_free +=
+ node->susp_entry_ce_length;
+ }
+
+ TAILQ_FOREACH(t, &node->head, rr_ll) {
+ if (t->susp_type != SUSP_TYPE_SUSP ||
+ t->entry_type != SUSP_ENTRY_SUSP_CE)
+ continue;
+ cd9660_bothendian_dword(
+ diskStructure->
+ susp_continuation_area_start_sector,
+ t->attr.su_entry.CE.ca_sector);
+
+ cd9660_bothendian_dword(
+ diskStructure->
+ susp_continuation_area_start_sector,
+ t->attr.su_entry.CE.ca_sector);
+ cd9660_bothendian_dword(node->susp_entry_ce_start,
+ t->attr.su_entry.CE.offset);
+ cd9660_bothendian_dword(node->susp_entry_ce_length,
+ t->attr.su_entry.CE.length);
+ }
+ return 0;
+}
+
+int
+cd9660_rrip_finalize_node(cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES *t;
+
+ TAILQ_FOREACH(t, &node->head, rr_ll) {
+ if (t->susp_type != SUSP_TYPE_RRIP)
+ continue;
+ switch (t->entry_type) {
+ case SUSP_ENTRY_RRIP_CL:
+ /* Look at rr_relocated*/
+ if (node->rr_relocated == NULL)
+ return -1;
+ cd9660_bothendian_dword(
+ node->rr_relocated->fileDataSector,
+ (unsigned char *)
+ t->attr.rr_entry.CL.dir_loc);
+ break;
+ case SUSP_ENTRY_RRIP_PL:
+ /* Look at rr_real_parent */
+ if (node->parent == NULL ||
+ node->parent->rr_real_parent == NULL)
+ return -1;
+ cd9660_bothendian_dword(
+ node->parent->rr_real_parent->fileDataSector,
+ (unsigned char *)
+ t->attr.rr_entry.PL.dir_loc);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int
+cd9660_susp_handle_continuation_common(iso9660_disk *diskStructure,
+ cd9660node *node, int space)
+{
+ int ca_used, susp_used, susp_used_pre_ce, working;
+ struct ISO_SUSP_ATTRIBUTES *temp, *pre_ce, *last, *CE, *ST;
+
+ pre_ce = last = NULL;
+ working = 254 - space;
+ if (node->su_tail_size > 0)
+ /* Allow 4 bytes for "ST" record. */
+ working -= node->su_tail_size + 4;
+ /* printf("There are %i bytes to work with\n",working); */
+
+ susp_used_pre_ce = susp_used = 0;
+ ca_used = 0;
+ TAILQ_FOREACH(temp, &node->head, rr_ll) {
+ if (working < 0)
+ break;
+ /*
+ * printf("SUSP Entry found, length is %i\n",
+ * CD9660_SUSP_ENTRY_SIZE(temp));
+ */
+ working -= CD9660_SUSP_ENTRY_SIZE(temp);
+ if (working >= 0) {
+ last = temp;
+ susp_used += CD9660_SUSP_ENTRY_SIZE(temp);
+ }
+ if (working >= 28) {
+ /*
+ * Remember the last entry after which we
+ * could insert a "CE" entry.
+ */
+ pre_ce = last;
+ susp_used_pre_ce = susp_used;
+ }
+ }
+
+ /* A CE entry is needed */
+ if (working <= 0) {
+ CE = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
+ SUSP_ENTRY_SUSP_CE, "CE", SUSP_LOC_ENTRY);
+ cd9660_susp_ce(CE, node);
+ /* This will automatically insert at the appropriate location */
+ if (pre_ce != NULL)
+ TAILQ_INSERT_AFTER(&node->head, pre_ce, CE, rr_ll);
+ else
+ TAILQ_INSERT_HEAD(&node->head, CE, rr_ll);
+ last = CE;
+ susp_used = susp_used_pre_ce + 28;
+ /* Count how much CA data is necessary */
+ for (temp = TAILQ_NEXT(last, rr_ll); temp != NULL;
+ temp = TAILQ_NEXT(temp, rr_ll)) {
+ ca_used += CD9660_SUSP_ENTRY_SIZE(temp);
+ }
+ }
+
+ /* An ST entry is needed */
+ if (node->su_tail_size > 0) {
+ ST = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
+ SUSP_ENTRY_SUSP_ST, "ST", SUSP_LOC_ENTRY);
+ cd9660_susp_st(ST, node);
+ if (last != NULL)
+ TAILQ_INSERT_AFTER(&node->head, last, ST, rr_ll);
+ else
+ TAILQ_INSERT_HEAD(&node->head, ST, rr_ll);
+ last = ST;
+ susp_used += 4;
+ }
+ if (last != NULL)
+ last->last_in_suf = 1;
+
+ node->susp_entry_size = susp_used;
+ node->susp_entry_ce_length = ca_used;
+
+ diskStructure->susp_continuation_area_size += ca_used;
+ return 1;
+}
+
+/* See if a continuation entry is needed for each of the different types */
+static int
+cd9660_susp_handle_continuation(iso9660_disk *diskStructure, cd9660node *node)
+{
+ assert (node != NULL);
+
+ /* Entry */
+ if (cd9660_susp_handle_continuation_common(diskStructure,
+ node,(int)(node->isoDirRecord->length[0])) < 0)
+ return 0;
+
+ return 1;
+}
+
+int
+cd9660_susp_initialize_node(iso9660_disk *diskStructure, cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES *temp;
+
+ /*
+ * Requirements/notes:
+ * CE: is added for us where needed
+ * ST: not sure if it is even required, but if so, should be
+ * handled by the CE code
+ * PD: isn't needed (though might be added for testing)
+ * SP: is stored ONLY on the . record of the root directory
+ * ES: not sure
+ */
+
+ /* Check for root directory, add SP and ER if needed. */
+ if (node->type & CD9660_TYPE_DOT) {
+ if (node->parent == diskStructure->rootNode) {
+ temp = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
+ SUSP_ENTRY_SUSP_SP, "SP", SUSP_LOC_DOT);
+ cd9660_susp_sp(temp, node);
+
+ /* Should be first entry. */
+ TAILQ_INSERT_HEAD(&node->head, temp, rr_ll);
+ }
+ }
+ return 1;
+}
+
+static void
+cd9660_rrip_initialize_inode(iso9660_disk *diskStructure, cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES *attr;
+
+ /*
+ * Inode dependent values - this may change,
+ * but for now virtual files and directories do
+ * not have an inode structure
+ */
+
+ if ((node->node != NULL) && (node->node->inode != NULL)) {
+ /* PX - POSIX attributes */
+ attr = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
+ cd9660node_rrip_px(diskStructure, attr, node->node);
+
+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
+
+ /* TF - timestamp */
+ attr = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_TF, "TF", SUSP_LOC_ENTRY);
+ cd9660node_rrip_tf(attr, node->node);
+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
+
+ /* SL - Symbolic link */
+ /* ?????????? Dan - why is this here? */
+ if (TAILQ_EMPTY(&node->cn_children) &&
+ node->node->inode != NULL &&
+ S_ISLNK(node->node->inode->st.st_mode))
+ cd9660_createSL(node);
+
+ /* PN - device number */
+ if (node->node->inode != NULL &&
+ ((S_ISCHR(node->node->inode->st.st_mode) ||
+ S_ISBLK(node->node->inode->st.st_mode)))) {
+ attr =
+ cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PN, "PN",
+ SUSP_LOC_ENTRY);
+ cd9660node_rrip_pn(attr, node->node);
+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
+ }
+ }
+}
+
+int
+cd9660_rrip_initialize_node(iso9660_disk *diskStructure, cd9660node *node,
+ cd9660node *parent, cd9660node *grandparent)
+{
+ struct ISO_SUSP_ATTRIBUTES *current = NULL;
+
+ assert(node != NULL);
+
+ if (node->type & CD9660_TYPE_DOT) {
+ /*
+ * Handle ER - should be the only entry to appear on
+ * a "." record
+ */
+ if (node->parent == diskStructure->rootNode) {
+ cd9660_susp_ER(node, 1, SUSP_RRIP_ER_EXT_ID,
+ SUSP_RRIP_ER_EXT_DES, SUSP_RRIP_ER_EXT_SRC);
+ }
+ if (parent != NULL && parent->node != NULL &&
+ parent->node->inode != NULL) {
+ /* PX - POSIX attributes */
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
+ cd9660node_rrip_px(diskStructure, current,
+ parent->node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+
+ /* TF - timestamp */
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_TF, "TF", SUSP_LOC_ENTRY);
+ cd9660node_rrip_tf(current, parent->node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+ } else if (node->type & CD9660_TYPE_DOTDOT) {
+ if (grandparent != NULL && grandparent->node != NULL &&
+ grandparent->node->inode != NULL) {
+ /* PX - POSIX attributes */
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
+ cd9660node_rrip_px(diskStructure, current,
+ grandparent->node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+
+ /* TF - timestamp */
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_TF, "TF", SUSP_LOC_ENTRY);
+ cd9660node_rrip_tf(current, grandparent->node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+ /* Handle PL */
+ if (parent != NULL && parent->rr_real_parent != NULL) {
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PL, "PL", SUSP_LOC_DOTDOT);
+ cd9660_rrip_PL(current,node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+ } else {
+ cd9660_rrip_initialize_inode(diskStructure, node);
+
+ if (node == diskStructure->rr_moved_dir) {
+ cd9660_rrip_add_NM(node, RRIP_DEFAULT_MOVE_DIR_NAME);
+ } else if (node->node != NULL) {
+ cd9660_rrip_NM(node);
+ }
+
+ /* Rock ridge directory relocation code here. */
+
+ /* First handle the CL for the placeholder file. */
+ if (node->rr_relocated != NULL) {
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_CL, "CL", SUSP_LOC_ENTRY);
+ cd9660_rrip_CL(current, node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+
+ /* Handle RE*/
+ if (node->rr_real_parent != NULL) {
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_RE, "RE", SUSP_LOC_ENTRY);
+ cd9660_rrip_RE(current,node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+ }
+ return 1;
+}
+
+struct ISO_SUSP_ATTRIBUTES*
+cd9660node_susp_create_node(int susp_type, int entry_type, const char *type_id,
+ int write_loc)
+{
+ struct ISO_SUSP_ATTRIBUTES* temp;
+
+ temp = emalloc(sizeof(*temp));
+ temp->susp_type = susp_type;
+ temp->entry_type = entry_type;
+ temp->last_in_suf = 0;
+ /* Phase this out */
+ temp->type_of[0] = type_id[0];
+ temp->type_of[1] = type_id[1];
+ temp->write_location = write_loc;
+
+ /*
+ * Since the first four bytes is common, lets go ahead and
+ * set the type identifier, since we are passing that to this
+ * function anyhow.
+ */
+ temp->attr.su_entry.SP.h.type[0] = type_id[0];
+ temp->attr.su_entry.SP.h.type[1] = type_id[1];
+ return temp;
+}
+
+int
+cd9660_rrip_PL(struct ISO_SUSP_ATTRIBUTES* p, cd9660node *node __unused)
+{
+ p->attr.rr_entry.PL.h.length[0] = 12;
+ p->attr.rr_entry.PL.h.version[0] = 1;
+ return 1;
+}
+
+int
+cd9660_rrip_CL(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *node __unused)
+{
+ p->attr.rr_entry.CL.h.length[0] = 12;
+ p->attr.rr_entry.CL.h.version[0] = 1;
+ return 1;
+}
+
+int
+cd9660_rrip_RE(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *node __unused)
+{
+ p->attr.rr_entry.RE.h.length[0] = 4;
+ p->attr.rr_entry.RE.h.version[0] = 1;
+ return 1;
+}
+
+void
+cd9660_createSL(cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES* current;
+ int path_count, dir_count, done, i, j, dir_copied;
+ char temp_cr[255];
+ char temp_sl[255]; /* used in copying continuation entry*/
+ char* sl_ptr;
+
+ sl_ptr = node->node->symlink;
+
+ done = 0;
+ path_count = 0;
+ dir_count = 0;
+ dir_copied = 0;
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_SL, "SL", SUSP_LOC_ENTRY);
+
+ current->attr.rr_entry.SL.h.version[0] = 1;
+ current->attr.rr_entry.SL.flags[0] = SL_FLAGS_NONE;
+
+ if (*sl_ptr == '/') {
+ temp_cr[0] = SL_FLAGS_ROOT;
+ temp_cr[1] = 0;
+ memcpy(current->attr.rr_entry.SL.component + path_count,
+ temp_cr, 2);
+ path_count += 2;
+ sl_ptr++;
+ }
+
+ for (i = 0; i < (dir_count + 2); i++)
+ temp_cr[i] = '\0';
+
+ while (!done) {
+ while ((*sl_ptr != '/') && (*sl_ptr != '\0')) {
+ dir_copied = 1;
+ if (*sl_ptr == '.') {
+ if ((*(sl_ptr + 1) == '/') || (*(sl_ptr + 1)
+ == '\0')) {
+ temp_cr[0] = SL_FLAGS_CURRENT;
+ sl_ptr++;
+ } else if(*(sl_ptr + 1) == '.') {
+ if ((*(sl_ptr + 2) == '/') ||
+ (*(sl_ptr + 2) == '\0')) {
+ temp_cr[0] = SL_FLAGS_PARENT;
+ sl_ptr += 2;
+ }
+ } else {
+ temp_cr[dir_count+2] = *sl_ptr;
+ sl_ptr++;
+ dir_count++;
+ }
+ } else {
+ temp_cr[dir_count + 2] = *sl_ptr;
+ sl_ptr++;
+ dir_count++;
+ }
+ }
+
+ if ((path_count + dir_count) >= 249) {
+ current->attr.rr_entry.SL.flags[0] |= SL_FLAGS_CONTINUE;
+
+ j = 0;
+
+ if (path_count <= 249) {
+ while(j != (249 - path_count)) {
+ temp_sl[j] = temp_cr[j];
+ j++;
+ }
+ temp_sl[0] = SL_FLAGS_CONTINUE;
+ temp_sl[1] = j - 2;
+ memcpy(
+ current->attr.rr_entry.SL.component +
+ path_count,
+ temp_sl, j);
+ }
+
+ path_count += j;
+ current->attr.rr_entry.SL.h.length[0] = path_count + 5;
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ current= cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_SL, "SL", SUSP_LOC_ENTRY);
+ current->attr.rr_entry.SL.h.version[0] = 1;
+ current->attr.rr_entry.SL.flags[0] = SL_FLAGS_NONE;
+
+ path_count = 0;
+
+ if (dir_count > 2) {
+ while (j != dir_count + 2) {
+ current->attr.rr_entry.SL.component[
+ path_count + 2] = temp_cr[j];
+ j++;
+ path_count++;
+ }
+ current->attr.rr_entry.SL.component[1]
+ = path_count;
+ path_count+= 2;
+ } else {
+ while(j != dir_count) {
+ current->attr.rr_entry.SL.component[
+ path_count+2] = temp_cr[j];
+ j++;
+ path_count++;
+ }
+ }
+ } else {
+ if (dir_copied == 1) {
+ temp_cr[1] = dir_count;
+ memcpy(current->attr.rr_entry.SL.component +
+ path_count,
+ temp_cr, dir_count + 2);
+ path_count += dir_count + 2;
+ }
+ }
+
+ if (*sl_ptr == '\0') {
+ done = 1;
+ current->attr.rr_entry.SL.h.length[0] = path_count + 5;
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ } else {
+ sl_ptr++;
+ dir_count = 0;
+ dir_copied = 0;
+ for(i = 0; i < 255; i++) {
+ temp_cr[i] = '\0';
+ }
+ }
+ }
+}
+
+static int
+inode_map_node_cmp(struct inode_map_node *a, struct inode_map_node *b)
+{
+ if (a->key < b->key)
+ return (-1);
+ if (a->key > b->key)
+ return (1);
+ return (0);
+}
+
+RB_GENERATE(inode_map_tree, inode_map_node, entry, inode_map_node_cmp);
+
+static uint64_t
+inode_map(iso9660_disk *diskStructure, uint64_t in)
+{
+ struct inode_map_node lookup = { .key = in };
+ struct inode_map_node *node;
+
+ /*
+ * Always assign an inode number if src inode unset. mtree mode leaves
+ * src inode unset for files with st_nlink == 1.
+ */
+ if (in != 0) {
+ node = RB_FIND(inode_map_tree, &(diskStructure->rr_inode_map),
+ &lookup);
+ if (node != NULL)
+ return (node->value);
+ }
+
+ node = emalloc(sizeof(struct inode_map_node));
+ node->key = in;
+ node->value = diskStructure->rr_inode_next++;
+ RB_INSERT(inode_map_tree, &(diskStructure->rr_inode_map), node);
+ return (node->value);
+}
+
+int
+cd9660node_rrip_px(iso9660_disk *diskStructure, struct ISO_SUSP_ATTRIBUTES *v,
+ fsnode *pxinfo)
+{
+ v->attr.rr_entry.PX.h.length[0] = 44;
+ v->attr.rr_entry.PX.h.version[0] = 1;
+ cd9660_bothendian_dword(pxinfo->inode->st.st_mode,
+ v->attr.rr_entry.PX.mode);
+ cd9660_bothendian_dword(pxinfo->inode->st.st_nlink,
+ v->attr.rr_entry.PX.links);
+ cd9660_bothendian_dword(pxinfo->inode->st.st_uid,
+ v->attr.rr_entry.PX.uid);
+ cd9660_bothendian_dword(pxinfo->inode->st.st_gid,
+ v->attr.rr_entry.PX.gid);
+ cd9660_bothendian_dword(inode_map(diskStructure,
+ pxinfo->inode->st.st_ino), v->attr.rr_entry.PX.serial);
+
+ return 1;
+}
+
+int
+cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *pn_field, fsnode *fnode)
+{
+ pn_field->attr.rr_entry.PN.h.length[0] = 20;
+ pn_field->attr.rr_entry.PN.h.version[0] = 1;
+
+ if (sizeof (fnode->inode->st.st_rdev) > 4)
+ cd9660_bothendian_dword(
+ (uint64_t)fnode->inode->st.st_rdev >> 32,
+ pn_field->attr.rr_entry.PN.high);
+ else
+ cd9660_bothendian_dword(0, pn_field->attr.rr_entry.PN.high);
+
+ cd9660_bothendian_dword(fnode->inode->st.st_rdev & 0xffffffff,
+ pn_field->attr.rr_entry.PN.low);
+ return 1;
+}
+
+#if 0
+int
+cd9660node_rrip_nm(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *file_node)
+{
+ int nm_length = strlen(file_node->isoDirRecord->name) + 5;
+ p->attr.rr_entry.NM.h.type[0] = 'N';
+ p->attr.rr_entry.NM.h.type[1] = 'M';
+ sprintf(p->attr.rr_entry.NM.altname, "%s", file_node->isoDirRecord->name);
+ p->attr.rr_entry.NM.h.length[0] = (unsigned char)nm_length;
+ p->attr.rr_entry.NM.h.version[0] = (unsigned char)1;
+ p->attr.rr_entry.NM.flags[0] = (unsigned char) NM_PARENT;
+ return 1;
+}
+#endif
+
+int
+cd9660node_rrip_tf(struct ISO_SUSP_ATTRIBUTES *p, fsnode *_node)
+{
+ p->attr.rr_entry.TF.flags[0] = TF_MODIFY | TF_ACCESS | TF_ATTRIBUTES;
+ p->attr.rr_entry.TF.h.length[0] = 5;
+ p->attr.rr_entry.TF.h.version[0] = 1;
+
+ /*
+ * Need to add creation time, backup time,
+ * expiration time, and effective time.
+ */
+
+ cd9660_time_915(p->attr.rr_entry.TF.timestamp,
+ _node->inode->st.st_mtime);
+ p->attr.rr_entry.TF.h.length[0] += 7;
+
+ cd9660_time_915(p->attr.rr_entry.TF.timestamp + 7,
+ _node->inode->st.st_atime);
+ p->attr.rr_entry.TF.h.length[0] += 7;
+
+ cd9660_time_915(p->attr.rr_entry.TF.timestamp + 14,
+ _node->inode->st.st_ctime);
+ p->attr.rr_entry.TF.h.length[0] += 7;
+ return 1;
+}
+
+int
+cd9660_susp_sp(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *spinfo __unused)
+{
+ p->attr.su_entry.SP.h.length[0] = 7;
+ p->attr.su_entry.SP.h.version[0] = 1;
+ p->attr.su_entry.SP.check[0] = 0xBE;
+ p->attr.su_entry.SP.check[1] = 0xEF;
+ p->attr.su_entry.SP.len_skp[0] = 0;
+ return 1;
+}
+
+int
+cd9660_susp_st(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *stinfo __unused)
+{
+ p->attr.su_entry.ST.h.type[0] = 'S';
+ p->attr.su_entry.ST.h.type[1] = 'T';
+ p->attr.su_entry.ST.h.length[0] = 4;
+ p->attr.su_entry.ST.h.version[0] = 1;
+ return 1;
+}
+
+int
+cd9660_susp_ce(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *spinfo __unused)
+{
+ p->attr.su_entry.CE.h.length[0] = 28;
+ p->attr.su_entry.CE.h.version[0] = 1;
+ /* Other attributes dont matter right now, will be updated later */
+ return 1;
+}
+
+int
+cd9660_susp_pd(struct ISO_SUSP_ATTRIBUTES *p __unused, int length __unused)
+{
+ return 1;
+}
+
+void
+cd9660_rrip_add_NM(cd9660node *node, const char *name)
+{
+ int working,len;
+ const char *p;
+ struct ISO_SUSP_ATTRIBUTES *r;
+
+ /*
+ * Each NM record has 254 bytes to work with. This means that
+ * the name data itself only has 249 bytes to work with. So, a
+ * name with 251 characters would require two nm records.
+ */
+ p = name;
+ working = 1;
+ while (working) {
+ r = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_NM, "NM", SUSP_LOC_ENTRY);
+ r->attr.rr_entry.NM.h.version[0] = 1;
+ r->attr.rr_entry.NM.flags[0] = RRIP_NM_FLAGS_NONE;
+ len = strlen(p);
+
+ if (len > 249) {
+ len = 249;
+ r->attr.rr_entry.NM.flags[0] = RRIP_NM_FLAGS_CONTINUE;
+ } else {
+ working = 0;
+ }
+ memcpy(r->attr.rr_entry.NM.altname, p, len);
+ r->attr.rr_entry.NM.h.length[0] = 5 + len;
+
+ TAILQ_INSERT_TAIL(&node->head, r, rr_ll);
+
+ p += len;
+ }
+}
+
+void
+cd9660_rrip_NM(cd9660node *node)
+{
+ cd9660_rrip_add_NM(node, node->node->name);
+}
+
+struct ISO_SUSP_ATTRIBUTES*
+cd9660_susp_ER(cd9660node *node,
+ u_char ext_version, const char* ext_id, const char* ext_des,
+ const char* ext_src)
+{
+ int l;
+ struct ISO_SUSP_ATTRIBUTES *r;
+
+ r = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
+ SUSP_ENTRY_SUSP_ER, "ER", SUSP_LOC_DOT);
+
+ /* Fixed data is 8 bytes */
+ r->attr.su_entry.ER.h.length[0] = 8;
+ r->attr.su_entry.ER.h.version[0] = 1;
+
+ r->attr.su_entry.ER.len_id[0] = (u_char)strlen(ext_id);
+ r->attr.su_entry.ER.len_des[0] = (u_char)strlen(ext_des);
+ r->attr.su_entry.ER.len_src[0] = (u_char)strlen(ext_src);
+
+ l = r->attr.su_entry.ER.len_id[0] +
+ r->attr.su_entry.ER.len_src[0] +
+ r->attr.su_entry.ER.len_des[0];
+
+ /* Everything must fit. */
+ assert(l + r->attr.su_entry.ER.h.length[0] <= 254);
+
+ r->attr.su_entry.ER.h.length[0] += (u_char)l;
+
+
+ r->attr.su_entry.ER.ext_ver[0] = ext_version;
+ memcpy(r->attr.su_entry.ER.ext_data, ext_id,
+ (int)r->attr.su_entry.ER.len_id[0]);
+ l = (int) r->attr.su_entry.ER.len_id[0];
+ memcpy(r->attr.su_entry.ER.ext_data + l,ext_des,
+ (int)r->attr.su_entry.ER.len_des[0]);
+
+ l += (int)r->attr.su_entry.ER.len_des[0];
+ memcpy(r->attr.su_entry.ER.ext_data + l,ext_src,
+ (int)r->attr.su_entry.ER.len_src[0]);
+
+ TAILQ_INSERT_TAIL(&node->head, r, rr_ll);
+ return r;
+}
+
+struct ISO_SUSP_ATTRIBUTES*
+cd9660_susp_ES(struct ISO_SUSP_ATTRIBUTES *last __unused, cd9660node *node __unused)
+{
+ return NULL;
+}
diff --git a/usr.sbin/makefs/cd9660/iso9660_rrip.h b/usr.sbin/makefs/cd9660/iso9660_rrip.h
new file mode 100644
index 000000000000..4c738d27ba45
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/iso9660_rrip.h
@@ -0,0 +1,292 @@
+/* $NetBSD: iso9660_rrip.h,v 1.5 2009/01/10 22:06:29 bjh21 Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+#ifndef __ISO9660_RRIP_H__
+#define __ISO9660_RRIP_H__
+
+/*
+ * This will hold all the functions needed to
+ * write an ISO 9660 image with Rock Ridge Extensions
+ */
+
+/* For writing must use ISO_RRIP_EXTREF structure */
+
+#include "makefs.h"
+#include <cd9660_rrip.h>
+#include "cd9660.h"
+#include <sys/queue.h>
+
+#define PX_LENGTH 0x2C
+#define PN_LENGTH 0x14
+#define TF_CREATION 0x01
+#define TF_MODIFY 0x02
+#define TF_ACCESS 0x04
+#define TF_ATTRIBUTES 0x08
+#define TF_BACKUP 0x10
+#define TF_EXPIRATION 0x20
+#define TF_EFFECTIVE 0x40
+#define TF_LONG_FORM 0x80
+#define NM_CONTINUE 0x01
+#define NM_CURRENT 0x02
+#define NM_PARENT 0x04
+
+
+#define SUSP_LOC_ENTRY 0x01
+#define SUSP_LOC_DOT 0x02
+#define SUSP_LOC_DOTDOT 0x04
+
+#define SUSP_TYPE_SUSP 1
+#define SUSP_TYPE_RRIP 2
+
+#define SUSP_ENTRY_SUSP_CE 1
+#define SUSP_ENTRY_SUSP_PD 2
+#define SUSP_ENTRY_SUSP_SP 3
+#define SUSP_ENTRY_SUSP_ST 4
+#define SUSP_ENTRY_SUSP_ER 5
+#define SUSP_ENTRY_SUSP_ES 6
+
+#define SUSP_ENTRY_RRIP_PX 1
+#define SUSP_ENTRY_RRIP_PN 2
+#define SUSP_ENTRY_RRIP_SL 3
+#define SUSP_ENTRY_RRIP_NM 4
+#define SUSP_ENTRY_RRIP_CL 5
+#define SUSP_ENTRY_RRIP_PL 6
+#define SUSP_ENTRY_RRIP_RE 7
+#define SUSP_ENTRY_RRIP_TF 8
+#define SUSP_ENTRY_RRIP_SF 9
+
+#define SUSP_RRIP_ER_EXT_ID "IEEE_P1282"
+#define SUSP_RRIP_ER_EXT_DES "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS."
+#define SUSP_RRIP_ER_EXT_SRC "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION."
+
+#define SL_FLAGS_NONE 0
+#define SL_FLAGS_CONTINUE 1
+#define SL_FLAGS_CURRENT 2
+#define SL_FLAGS_PARENT 4
+#define SL_FLAGS_ROOT 8
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char mode [ISODCL(5,12)];
+ u_char links [ISODCL(13,20)];
+ u_char uid [ISODCL(21,28)];
+ u_char gid [ISODCL(29,36)];
+ u_char serial [ISODCL(37,44)];
+} ISO_RRIP_PX;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char high [ISODCL(5,12)];
+ u_char low [ISODCL(13,20)];
+} ISO_RRIP_PN;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char flags [ISODCL ( 4, 4)];
+ u_char component [ISODCL ( 4, 256)];
+ u_int nBytes;
+} ISO_RRIP_SL;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char flags [ISODCL ( 4, 4)];
+ u_char timestamp [ISODCL ( 5, 256)];
+} ISO_RRIP_TF;
+
+#define RRIP_NM_FLAGS_NONE 0x00
+#define RRIP_NM_FLAGS_CONTINUE 0x01
+#define RRIP_NM_FLAGS_CURRENT 0x02
+#define RRIP_NM_FLAGS_PARENT 0x04
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char flags [ISODCL ( 4, 4)];
+ u_char altname [ISODCL ( 4, 256)];
+} ISO_RRIP_NM;
+
+/* Note that this is the same structure as cd9660_rrip.h : ISO_RRIP_CONT */
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char ca_sector [ISODCL ( 5, 12)];
+ u_char offset [ISODCL ( 13, 20)];
+ u_char length [ISODCL ( 21, 28)];
+} ISO_SUSP_CE;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char padding_area [ISODCL ( 4, 256)];
+} ISO_SUSP_PD;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char check [ISODCL ( 4, 5)];
+ u_char len_skp [ISODCL ( 6, 6)];
+} ISO_SUSP_SP;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+} ISO_SUSP_ST;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char len_id [ISODCL ( 4, 4)];
+ u_char len_des [ISODCL ( 5, 5)];
+ u_char len_src [ISODCL ( 6, 6)];
+ u_char ext_ver [ISODCL ( 7, 7)];
+ u_char ext_data [ISODCL (8,256)];
+/* u_char ext_id [ISODCL ( 8, 256)];
+ u_char ext_des [ISODCL ( 257, 513)];
+ u_char ext_src [ISODCL ( 514, 770)];*/
+} ISO_SUSP_ER;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char ext_seq [ISODCL ( 4, 4)];
+} ISO_SUSP_ES;
+
+typedef union {
+ ISO_RRIP_PX PX;
+ ISO_RRIP_PN PN;
+ ISO_RRIP_SL SL;
+ ISO_RRIP_NM NM;
+ ISO_RRIP_CLINK CL;
+ ISO_RRIP_PLINK PL;
+ ISO_RRIP_RELDIR RE;
+ ISO_RRIP_TF TF;
+} rrip_entry;
+
+typedef union {
+ ISO_SUSP_CE CE;
+ ISO_SUSP_PD PD;
+ ISO_SUSP_SP SP;
+ ISO_SUSP_ST ST;
+ ISO_SUSP_ER ER;
+ ISO_SUSP_ES ES;
+} susp_entry;
+
+typedef union {
+ susp_entry su_entry;
+ rrip_entry rr_entry;
+} SUSP_ENTRIES;
+
+struct ISO_SUSP_ATTRIBUTES {
+ SUSP_ENTRIES attr;
+ int type;
+ char type_of[2];
+ char last_in_suf; /* last entry in the System Use Field? */
+ /* Dan's addons - will merge later. This allows use of a switch */
+ char susp_type; /* SUSP or RRIP */
+ char entry_type; /* Record type */
+ char write_location;
+ TAILQ_ENTRY(ISO_SUSP_ATTRIBUTES) rr_ll;
+};
+
+#define CD9660_SUSP_ENTRY_SIZE(entry)\
+ ((int) ((entry)->attr.su_entry.SP.h.length[0]))
+
+/* Recursive function - move later to func pointer code*/
+int cd9660_susp_finalize(iso9660_disk *, cd9660node *);
+
+/* These two operate on single nodes */
+int cd9660_susp_finalize_node(iso9660_disk *, cd9660node *);
+int cd9660_rrip_finalize_node(cd9660node *);
+
+/* POSIX File attribute */
+int cd9660node_rrip_px(iso9660_disk *, struct ISO_SUSP_ATTRIBUTES *, fsnode *);
+
+/* Device number */
+int cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
+
+/* Symbolic link */
+int cd9660node_rrip_SL(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
+
+/* Alternate Name function */
+void cd9660_rrip_NM(cd9660node *);
+void cd9660_rrip_add_NM(cd9660node *,const char *);
+
+/* Parent and child link function */
+int cd9660_rrip_PL(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+int cd9660_rrip_CL(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+int cd9660_rrip_RE(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+
+int cd9660node_rrip_tf(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
+
+
+
+/*
+ * Relocation directory function. I'm not quite sure what
+ * sort of parameters are needed, but personally I don't think
+ * any parameters are needed except for the memory address where
+ * the information needs to be put in
+ */
+int cd9660node_rrip_re(void *, fsnode *);
+
+/*
+ * Don't know if this function is needed because it apparently is an
+ * optional feature that does not really need to be implemented but I
+ * thought I should add it anyway.
+ */
+int cd9660_susp_ce (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+int cd9660_susp_pd (struct ISO_SUSP_ATTRIBUTES *, int);
+int cd9660_susp_sp (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+int cd9660_susp_st (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+
+struct ISO_SUSP_ATTRIBUTES *cd9660_susp_ER(cd9660node *, u_char, const char *,
+ const char *, const char *);
+struct ISO_SUSP_ATTRIBUTES *cd9660_susp_ES(struct ISO_SUSP_ATTRIBUTES*,
+ cd9660node *);
+
+
+/* Helper functions */
+
+/* Common SUSP/RRIP functions */
+int cd9660_susp_initialize(iso9660_disk *, cd9660node *, cd9660node *,
+ cd9660node *);
+int cd9660_susp_initialize_node(iso9660_disk *, cd9660node *);
+struct ISO_SUSP_ATTRIBUTES *cd9660node_susp_create_node(int, int, const char *,
+ int);
+struct ISO_SUSP_ATTRIBUTES *cd9660node_susp_add_entry(cd9660node *,
+ struct ISO_SUSP_ATTRIBUTES *, struct ISO_SUSP_ATTRIBUTES *, int);
+
+/* RRIP specific functions */
+int cd9660_rrip_initialize_node(iso9660_disk *, cd9660node *, cd9660node *,
+ cd9660node *);
+void cd9660_createSL(cd9660node *);
+
+/* Functions that probably can be removed */
+/* int cd9660node_initialize_node(int, char *); */
+
+
+#endif