summaryrefslogtreecommitdiff
path: root/genisoimage/rock.c
diff options
context:
space:
mode:
Diffstat (limited to 'genisoimage/rock.c')
-rw-r--r--genisoimage/rock.c864
1 files changed, 864 insertions, 0 deletions
diff --git a/genisoimage/rock.c b/genisoimage/rock.c
new file mode 100644
index 0000000..7565bae
--- /dev/null
+++ b/genisoimage/rock.c
@@ -0,0 +1,864 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)rock.c 1.43 05/05/01 joerg */
+/*
+ * File rock.c - generate RRIP records for iso9660 filesystems.
+ *
+ * Written by Eric Youngdale (1993).
+ *
+ * Copyright 1993 Yggdrasil Computing, Incorporated
+ * Copyright (c) 1999,2000-2003 J. Schilling
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include "genisoimage.h"
+#include <device.h>
+#include <schily.h>
+
+#define SU_VERSION 1
+
+#define SL_ROOT 8
+#define SL_PARENT 4
+#define SL_CURRENT 2
+#define SL_CONTINUE 1
+
+#define CE_SIZE 28 /* SUSP Continuation aerea */
+#define CL_SIZE 12 /* RR Child Link for deep dir relocation */
+#define ER_SIZE 8 /* RR Extension record for RR signature */
+#define NM_SIZE 5 /* RR Real name */
+#define PL_SIZE 12 /* RR Paren Link for deep dir relocation */
+#define PN_SIZE 20 /* RR POSIX device modes (Major/Minor) */
+#define PX_SIZE 36 /* RR POSIX Extensions (mode/nlink(uid/gid) */
+#define RE_SIZE 4 /* RR Relocated directory */
+#define RR_SIZE 5 /* RR RR Signature in every file */
+#define SL_SIZE 20 /* RR Symlink */
+#define ZF_SIZE 16 /* RR* Linux compression extension */
+#ifdef APPLE_HYB
+#define AA_SIZE 14 /* size of Apple extension */
+#endif /* APPLE_HYB */
+#if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */
+#define TF_SIZE (5 + 4 * 7) /* RR Time field */
+#else
+#define TF_SIZE (5 + 3 * 7)
+#endif
+
+static void rstrncpy(char *t, char *f, int c,
+ struct unls_table *inls,
+ struct unls_table *onls);
+static void add_CE_entry(char *field, int line);
+static int gen_xa_attr(mode_t attr);
+static void gen_xa(struct stat *lstatbuf);
+int generate_xa_rr_attributes(char *whole_name, char *name,
+ struct directory_entry *s_entry,
+ struct stat *statbuf,
+ struct stat *lstatbuf,
+ int deep_opt);
+char *generate_rr_extension_record(char *id, char *descriptor, char *source,
+ int *size);
+/*
+ * If we need to store this number of bytes, make sure we
+ * do not box ourselves in so that we do not have room for
+ * a CE entry for the continuation record
+ */
+#define RR_CUR_USE (CE_SIZE + currlen + (ipnt - recstart))
+
+#define MAYBE_ADD_CE_ENTRY(BYTES) \
+ (((int)(BYTES)) + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
+
+/*
+ * Buffer to build RR attributes
+ */
+static Uchar Rock[16384];
+static Uchar symlink_buff[PATH_MAX+1];
+static int ipnt = 0; /* Current "write" offset in Rock[] */
+static int recstart = 0; /* Start offset in Rock[] for this area */
+static int currlen = 0; /* # of non RR bytes used in this area */
+static int mainrec = 0; /* # of RR bytes use in main dir area */
+static int reclimit; /* Max. # of bytes usable in this area */
+
+/* if we are using converted filenames, we don't want the '/' character */
+static void
+rstrncpy(char *t, char *f, int c, struct unls_table *inls,
+ struct unls_table *onls)
+{
+ while (c-- && *f) {
+ *t = conv_charset(*f, inls, onls);
+ if (*t == '/') {
+ *t = '_';
+ }
+ t++;
+ f++;
+ }
+}
+
+static void
+add_CE_entry(char *field, int line)
+{
+ if (MAYBE_ADD_CE_ENTRY(0)) {
+ errmsgno(EX_BAD,
+ "Panic: no space, cannot add RR CE entry (%d bytes mising) for %s line %d.\n",
+ (CE_SIZE + currlen + (ipnt - recstart) - reclimit),
+ field, line);
+ errmsgno(EX_BAD, "currlen: %d ipnt: %d, recstart: %d\n",
+ currlen, ipnt, recstart);
+ errmsgno(EX_BAD, "Send bug report to the maintainer.\n");
+ comerrno(EX_BAD, "Aborting.\n");
+ }
+
+ if (recstart)
+ set_733((char *) Rock + recstart - 8, ipnt + 28 - recstart);
+ Rock[ipnt++] = 'C';
+ Rock[ipnt++] = 'E';
+ Rock[ipnt++] = CE_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char *) Rock + ipnt, 0);
+ ipnt += 8;
+ set_733((char *) Rock + ipnt, 0);
+ ipnt += 8;
+ set_733((char *) Rock + ipnt, 0);
+ ipnt += 8;
+ recstart = ipnt;
+ currlen = 0;
+ if (!mainrec)
+ mainrec = ipnt;
+ reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
+}
+
+static int
+gen_xa_attr(mode_t attr)
+{
+ int ret = 0;
+
+ if (attr & S_IRUSR)
+ ret |= XA_O_READ;
+ if (attr & S_IXUSR)
+ ret |= XA_O_EXEC;
+
+ if (attr & S_IRGRP)
+ ret |= XA_G_READ;
+ if (attr & S_IXGRP)
+ ret |= XA_G_EXEC;
+
+ if (attr & S_IROTH)
+ ret |= XA_W_READ;
+ if (attr & S_IXOTH)
+ ret |= XA_W_EXEC;
+
+ ret |= XA_FORM1;
+
+ if (S_ISDIR(attr))
+ ret |= XA_DIR;
+
+ return (ret);
+}
+
+static void
+gen_xa(struct stat *lstatbuf)
+{
+ /*
+ * Group ID
+ */
+ set_722((char *) Rock + ipnt, lstatbuf->st_gid);
+ ipnt += 2;
+ /*
+ * User ID
+ */
+ set_722((char *) Rock + ipnt, lstatbuf->st_uid);
+ ipnt += 2;
+ /*
+ * Attributes
+ */
+ set_722((char *) Rock + ipnt, gen_xa_attr(lstatbuf->st_mode));
+ ipnt += 2;
+
+ Rock[ipnt++] = 'X'; /* XA Signature */
+ Rock[ipnt++] = 'A';
+ Rock[ipnt++] = 0; /* File number (we always use '0' */
+
+ Rock[ipnt++] = 0; /* Reserved (5 Byte) */
+ Rock[ipnt++] = 0;
+ Rock[ipnt++] = 0;
+ Rock[ipnt++] = 0;
+ Rock[ipnt++] = 0;
+
+}
+
+int
+generate_xa_rr_attributes(char *whole_name, char *name,
+ struct directory_entry *s_entry,
+ struct stat *statbuf,
+ struct stat *lstatbuf,
+ int deep_opt)
+{
+ int flagpos;
+ int flagval;
+ int need_ce;
+
+ statbuf = statbuf; /* this shuts up unreferenced compiler */
+ /* warnings */
+ mainrec = recstart = ipnt = 0;
+
+ if (use_XA) {
+ gen_xa(lstatbuf);
+ }
+
+/* reclimit = 0xf8; XXX we now use 254 == 0xfe */
+ reclimit = MAX_ISODIR;
+
+ /* no need to fill in the RR stuff if we won't see the file */
+ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
+ return (0);
+
+ /*
+ * Obtain the amount of space that is currently used for the directory
+ * record. We may safely use the current name length; because if name
+ * confilcts force us to change the ISO-9660 name later, the name will
+ * never become longer than now.
+ */
+ if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+ s_entry->isorec.name_len[0] = 1;
+ } else {
+ s_entry->isorec.name_len[0] = strlen(s_entry->isorec.name);
+ }
+ currlen = s_entry->isorec.length[0] = s_entry->isorec.name_len[0] +
+ offsetof(struct iso_directory_record, name[0]);
+ if (currlen & 1)
+ s_entry->isorec.length[0] = ++currlen;
+
+ if (currlen < 33+37) {
+ /*
+ * If the ISO-9660 name length is less than 37, we may use
+ * ISO-9660:1988 name rules and for this reason, the name len
+ * may later increase from adding e.g. ".;1"; in this case
+ * just use the upper limit.
+ */
+ currlen = 33+37;
+ }
+
+#ifdef APPLE_HYB
+ /* if we have regular file, then add Apple extensions */
+ if (S_ISREG(lstatbuf->st_mode) && apple_ext && s_entry->hfs_ent) {
+ if (MAYBE_ADD_CE_ENTRY(AA_SIZE))
+ add_CE_entry("AA", __LINE__);
+ Rock[ipnt++] = 'A'; /* AppleSignature */
+ Rock[ipnt++] = 'A';
+ Rock[ipnt++] = AA_SIZE; /* includes AppleSignature bytes */
+ Rock[ipnt++] = 0x02; /* SystemUseID */
+ Rock[ipnt++] = s_entry->hfs_ent->u.file.type[0];
+ Rock[ipnt++] = s_entry->hfs_ent->u.file.type[1];
+ Rock[ipnt++] = s_entry->hfs_ent->u.file.type[2];
+ Rock[ipnt++] = s_entry->hfs_ent->u.file.type[3];
+ Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[0];
+ Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[1];
+ Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[2];
+ Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[3];
+ Rock[ipnt++] = (s_entry->hfs_ent->fdflags >> 8) & 0xff;
+ Rock[ipnt++] = s_entry->hfs_ent->fdflags & 0xff;
+ }
+#endif /* APPLE_HYB */
+
+ if (!use_RockRidge)
+ goto xa_only;
+
+ /* Identify that we are using the SUSP protocol */
+ if (deep_opt & NEED_SP) {
+ /*
+ * We may not use a CE record here but we never will need to
+ * do so, as this SP record is only used for the "." entry
+ * of the root directory.
+ */
+ Rock[ipnt++] = 'S';
+ Rock[ipnt++] = 'P';
+ Rock[ipnt++] = 7;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 0xbe;
+ Rock[ipnt++] = 0xef;
+ if (use_XA)
+ Rock[ipnt++] = sizeof (struct iso_xa_dir_record);
+ else
+ Rock[ipnt++] = 0;
+ }
+
+ /* First build the posix name field */
+ if (MAYBE_ADD_CE_ENTRY(RR_SIZE))
+ add_CE_entry("RR", __LINE__);
+ Rock[ipnt++] = 'R';
+ Rock[ipnt++] = 'R';
+ Rock[ipnt++] = 5;
+ Rock[ipnt++] = SU_VERSION;
+ flagpos = ipnt;
+ flagval = 0;
+ Rock[ipnt++] = 0; /* We go back and fix this later */
+
+ if (strcmp(name, ".") && strcmp(name, "..")) {
+ char *npnt;
+ int remain; /* Remaining name length */
+ int use; /* Current name part used */
+
+#ifdef APPLE_HYB
+ /* use the HFS name if it exists */
+ if (USE_MAC_NAME(s_entry)) {
+ remain = strlen(s_entry->hfs_ent->name);
+ npnt = s_entry->hfs_ent->name;
+ } else {
+#endif /* APPLE_HYB */
+
+ remain = strlen(name);
+ npnt = name;
+#ifdef APPLE_HYB
+ }
+#endif /* APPLE_HYB */
+
+ if (MAYBE_ADD_CE_ENTRY(NM_SIZE+1))
+ add_CE_entry("NM", __LINE__);
+ while (remain) {
+ use = remain;
+ need_ce = 0;
+ /* Can we fit this SUSP and a CE entry? */
+ if (MAYBE_ADD_CE_ENTRY(NM_SIZE+use)) {
+ use = reclimit - NM_SIZE - RR_CUR_USE;
+ need_ce++;
+ }
+ /* Only room for 256 per SUSP field */
+ if (use > 0xf8) {
+ use = 0xf8;
+ need_ce++;
+ }
+ if (use < 0) {
+ comerrno(EX_BAD,
+ "Negative RR name length residual: %d\n",
+ use);
+ }
+
+ /* First build the posix name field */
+ Rock[ipnt++] = 'N';
+ Rock[ipnt++] = 'M';
+ Rock[ipnt++] = NM_SIZE + use;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = (remain != use ? 1 : 0);
+ flagval |= (1 << 3);
+
+ /* convert charsets as required */
+#ifdef APPLE_HYB
+ if (USE_MAC_NAME(s_entry))
+ rstrncpy((char *) &Rock[ipnt], npnt, use,
+ hfs_inls, out_nls);
+ else
+#endif /* APPLE_HYB */
+ rstrncpy((char *) &Rock[ipnt], npnt, use,
+ in_nls, out_nls);
+ npnt += use;
+ ipnt += use;
+ remain -= use;
+ if (remain && need_ce)
+ add_CE_entry("NM", __LINE__);
+ }
+ }
+
+ /* Add the posix modes */
+ if (MAYBE_ADD_CE_ENTRY(PX_SIZE))
+ add_CE_entry("PX", __LINE__);
+ Rock[ipnt++] = 'P';
+ Rock[ipnt++] = 'X';
+ Rock[ipnt++] = PX_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1 << 0);
+ set_733((char *) Rock + ipnt, lstatbuf->st_mode);
+ ipnt += 8;
+ set_733((char *) Rock + ipnt, lstatbuf->st_nlink);
+ ipnt += 8;
+ set_733((char *) Rock + ipnt, lstatbuf->st_uid);
+ ipnt += 8;
+ set_733((char *) Rock + ipnt, lstatbuf->st_gid);
+ ipnt += 8;
+
+ /* Check for special devices */
+#if defined(S_IFCHR) || defined(S_IFBLK)
+ /*
+ * The code in this if statement used to be #ifdef'd with NON_UNIXFS.
+ * But as statdefs.h always provides the macros S_ISCHR() & S_ISBLK()
+ * and device.h always provides major()/minor() it is not needed
+ * anymore.
+ */
+ if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
+ if (MAYBE_ADD_CE_ENTRY(PN_SIZE))
+ add_CE_entry("PN", __LINE__);
+ Rock[ipnt++] = 'P';
+ Rock[ipnt++] = 'N';
+ Rock[ipnt++] = PN_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1 << 1);
+#if 1
+ /* This is the new and only code which uses <device.h> */
+ set_733((char *) Rock + ipnt, major(lstatbuf->st_rdev));
+ ipnt += 8;
+ set_733((char *) Rock + ipnt, minor(lstatbuf->st_rdev));
+ ipnt += 8;
+#else
+ /*
+ * If we don't have sysmacros.h, then we have to guess as to
+ * how best to pick apart the device number for major/minor.
+ * Note: this may very well be wrong for many systems, so it
+ * is always best to use the major/minor macros if the system
+ * supports it.
+ */
+ if (sizeof (dev_t) <= 2) {
+ set_733((char *)Rock + ipnt, (lstatbuf->st_rdev >> 8));
+ ipnt += 8;
+ set_733((char *)Rock + ipnt, lstatbuf->st_rdev & 0xff);
+ ipnt += 8;
+ } else if (sizeof (dev_t) <= 4) {
+ set_733((char *)Rock + ipnt,
+ (lstatbuf->st_rdev >> 8) >> 8);
+ ipnt += 8;
+ set_733((char *)Rock + ipnt,
+ lstatbuf->st_rdev & 0xffff);
+ ipnt += 8;
+ } else {
+ set_733((char *)Rock + ipnt,
+ (lstatbuf->st_rdev >> 16)>>16);
+ ipnt += 8;
+ set_733((char *)Rock + ipnt, lstatbuf->st_rdev);
+ ipnt += 8;
+ }
+#endif
+ }
+#endif /* defined(S_IFCHR) || defined(S_IFBLK) */
+
+ /* Check for and symbolic links. VMS does not have these. */
+#ifdef S_IFLNK
+ if (S_ISLNK(lstatbuf->st_mode)) {
+ int lenpos;
+ int lenval;
+ int j0;
+ int j1;
+ int nchar;
+ Uchar *cpnt;
+ Uchar *cpnt1;
+
+#ifdef HAVE_READLINK
+ nchar = readlink(whole_name, (char *)symlink_buff,
+ sizeof (symlink_buff)-1);
+#else
+ nchar = -1;
+#endif /* HAVE_READLINK */
+ symlink_buff[nchar < 0 ? 0 : nchar] = 0;
+ nchar = strlen((char *) symlink_buff);
+ set_733(s_entry->isorec.size, 0);
+ cpnt = &symlink_buff[0];
+ flagval |= (1 << 2);
+
+ if (!split_SL_field) {
+ int sl_bytes = 0;
+
+ for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++) {
+ if (*cpnt1 == '/') {
+ sl_bytes += 4;
+ } else {
+ sl_bytes += 1;
+ }
+ }
+ if (sl_bytes > 250) {
+ /*
+ * the symbolic link won't fit into one
+ * SL System Use Field print an error message
+ * and continue with splited one
+ */
+ fprintf(stderr,
+ "symbolic link ``%s'' to long for one SL System Use Field, splitting",
+ cpnt);
+ }
+ if (MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes))
+ add_CE_entry("SL+", __LINE__);
+ }
+ while (nchar) {
+ if (MAYBE_ADD_CE_ENTRY(SL_SIZE))
+ add_CE_entry("SL", __LINE__);
+ Rock[ipnt++] = 'S';
+ Rock[ipnt++] = 'L';
+ lenpos = ipnt;
+ Rock[ipnt++] = SL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 0; /* Flags */
+ lenval = 5;
+ while (*cpnt) {
+ cpnt1 = (Uchar *)
+ strchr((char *)cpnt, '/');
+ if (cpnt1) {
+ nchar--;
+ *cpnt1 = 0;
+ }
+
+ /*
+ * We treat certain components in a special
+ * way.
+ */
+ if (cpnt[0] == '.' && cpnt[1] == '.' &&
+ cpnt[2] == 0) {
+ if (MAYBE_ADD_CE_ENTRY(2)) {
+ add_CE_entry("SL-parent", __LINE__);
+ if (cpnt1) {
+ *cpnt1 = '/';
+ nchar++;
+ /*
+ * A kluge so that we
+ * can restart properly
+ */
+ cpnt1 = NULL;
+ }
+ break;
+ }
+ Rock[ipnt++] = SL_PARENT;
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ nchar -= 2;
+ } else if (cpnt[0] == '.' && cpnt[1] == 0) {
+ if (MAYBE_ADD_CE_ENTRY(2)) {
+ add_CE_entry("SL-current", __LINE__);
+ if (cpnt1) {
+ *cpnt1 = '/';
+ nchar++;
+ /*
+ * A kluge so that we
+ * can restart properly
+ */
+ cpnt1 = NULL;
+ }
+ break;
+ }
+ Rock[ipnt++] = SL_CURRENT;
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ nchar -= 1;
+ } else if (cpnt[0] == 0) {
+ if (MAYBE_ADD_CE_ENTRY(2)) {
+ add_CE_entry("SL-root", __LINE__);
+ if (cpnt1) {
+ *cpnt1 = '/';
+ nchar++;
+ /*
+ * A kluge so that we
+ * can restart properly
+ */
+ cpnt1 = NULL;
+ }
+ break;
+ }
+ Rock[ipnt++] = SL_ROOT;
+ Rock[ipnt++] = 0; /* length is zero */
+ lenval += 2;
+ } else {
+ /*
+ * If we do not have enough room for a
+ * component, start a new continuations
+ * segment now
+ */
+ if (split_SL_component ?
+ MAYBE_ADD_CE_ENTRY(6) :
+ MAYBE_ADD_CE_ENTRY(6 + strlen((char *) cpnt))) {
+ add_CE_entry("SL++", __LINE__);
+ if (cpnt1) {
+ *cpnt1 = '/';
+ nchar++;
+ /*
+ * A kluge so that we
+ * can restart properly
+ */
+ cpnt1 = NULL;
+ }
+ break;
+ }
+ j0 = strlen((char *) cpnt);
+ while (j0) {
+ j1 = j0;
+ if (j1 > 0xf8)
+ j1 = 0xf8;
+ need_ce = 0;
+ if (j1 + currlen + 2 + CE_SIZE +
+ (ipnt - recstart) >
+ reclimit) {
+
+ j1 = reclimit -
+ (currlen + 2) -
+ CE_SIZE -
+ (ipnt - recstart);
+ need_ce++;
+ }
+ Rock[ipnt++] =
+ (j1 != j0 ?
+ SL_CONTINUE : 0);
+ Rock[ipnt++] = j1;
+ strncpy((char *)Rock + ipnt,
+ (char *) cpnt, j1);
+ ipnt += j1;
+ lenval += j1 + 2;
+ cpnt += j1;
+ /*
+ * Number we processed
+ * this time
+ */
+ nchar -= j1;
+ j0 -= j1;
+ if (need_ce) {
+ add_CE_entry(
+ "SL-path-split",
+ __LINE__);
+ if (cpnt1) {
+ *cpnt1 = '/';
+ nchar++;
+ /*
+ * A kluge so
+ * that we can
+ * restart
+ * properly
+ */
+ cpnt1 = NULL;
+ }
+ break;
+ }
+ }
+ }
+ if (cpnt1) {
+ cpnt = cpnt1 + 1;
+ } else
+ break;
+ }
+ Rock[lenpos] = lenval;
+ if (nchar) {
+ /* We need another SL entry */
+ Rock[lenpos + 2] = SL_CONTINUE;
+ }
+ } /* while nchar */
+ } /* Is a symbolic link */
+#endif /* S_IFLNK */
+
+ /* Add in the Rock Ridge TF time field */
+ if (MAYBE_ADD_CE_ENTRY(TF_SIZE))
+ add_CE_entry("TF", __LINE__);
+ Rock[ipnt++] = 'T';
+ Rock[ipnt++] = 'F';
+ Rock[ipnt++] = TF_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+#if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */
+ Rock[ipnt++] = 0x0f;
+#else
+ Rock[ipnt++] = 0x0e;
+#endif
+ flagval |= (1 << 7);
+
+#if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
+ ipnt += 7;
+#endif
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
+ ipnt += 7;
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
+ ipnt += 7;
+ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
+ ipnt += 7;
+
+ /* Add in the Rock Ridge RE (relocated dir) field */
+ if (deep_opt & NEED_RE) {
+ if (MAYBE_ADD_CE_ENTRY(RE_SIZE))
+ add_CE_entry("RE", __LINE__);
+ Rock[ipnt++] = 'R';
+ Rock[ipnt++] = 'E';
+ Rock[ipnt++] = RE_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ flagval |= (1 << 6);
+ }
+ /* Add in the Rock Ridge PL record, if required. */
+ if (deep_opt & NEED_PL) {
+ if (MAYBE_ADD_CE_ENTRY(PL_SIZE))
+ add_CE_entry("PL", __LINE__);
+ Rock[ipnt++] = 'P';
+ Rock[ipnt++] = 'L';
+ Rock[ipnt++] = PL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char *) Rock + ipnt, 0);
+ ipnt += 8;
+ flagval |= (1 << 5);
+ }
+
+ /* Add in the Rock Ridge CL field, if required. */
+ if (deep_opt & NEED_CL) {
+ if (MAYBE_ADD_CE_ENTRY(CL_SIZE))
+ add_CE_entry("CL", __LINE__);
+ Rock[ipnt++] = 'C';
+ Rock[ipnt++] = 'L';
+ Rock[ipnt++] = CL_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ set_733((char *) Rock + ipnt, 0);
+ ipnt += 8;
+ flagval |= (1 << 4);
+ }
+
+#ifndef VMS
+ /*
+ * If transparent compression was requested, fill in the correct field
+ * for this file, if (and only if) it is actually a compressed file!
+ * This relies only on magic number, but it should in general not
+ * be an issue since if you're using -z odds are most of your
+ * files are already compressed.
+ *
+ * In the future it would be nice if genisoimage actually did the
+ * compression.
+ */
+ if (transparent_compression && S_ISREG(lstatbuf->st_mode)) {
+ static const Uchar zisofs_magic[8] =
+ { 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07 };
+ FILE *zffile;
+ unsigned int file_size;
+ Uchar header[16];
+ int OK_flag;
+ int blocksize;
+ int headersize;
+
+ /*
+ * First open file and verify that the correct algorithm was
+ * used
+ */
+ file_size = 0;
+ OK_flag = 1;
+
+ memset(header, 0, sizeof (header));
+
+ zffile = fopen(whole_name, "rb");
+ if (zffile != NULL) {
+ if (fread(header, 1, sizeof (header), zffile) != sizeof (header))
+ OK_flag = 0;
+
+ /* Check magic number */
+ if (memcmp(header, zisofs_magic, sizeof (zisofs_magic)))
+ OK_flag = 0;
+
+ /* Get the real size of the file */
+ file_size = get_731((char *)header+8);
+
+ /* Get the header size (>> 2) */
+ headersize = header[12];
+
+ /* Get the block size (log2) */
+ blocksize = header[13];
+
+ fclose(zffile);
+ } else {
+ OK_flag = 0;
+ blocksize = headersize = 0; /* Make silly GCC quiet */
+ }
+
+ if (OK_flag) {
+ if (MAYBE_ADD_CE_ENTRY(ZF_SIZE))
+ add_CE_entry("ZF", __LINE__);
+ Rock[ipnt++] = 'Z';
+ Rock[ipnt++] = 'F';
+ Rock[ipnt++] = ZF_SIZE;
+ Rock[ipnt++] = SU_VERSION;
+ Rock[ipnt++] = 'p'; /* Algorithm: "paged zlib" */
+ Rock[ipnt++] = 'z';
+ /* 2 bytes for algorithm-specific information */
+ Rock[ipnt++] = headersize;
+ Rock[ipnt++] = blocksize;
+ set_733((char *) Rock + ipnt, file_size); /* Real file size */
+ ipnt += 8;
+ }
+ }
+#endif
+ /*
+ * Add in the Rock Ridge CE field, if required. We use this for the
+ * extension record that is stored in the root directory.
+ */
+ if (deep_opt & NEED_CE)
+ add_CE_entry("ER", __LINE__);
+
+ /*
+ * Done filling in all of the fields. Now copy it back to a buffer
+ * for the file in question.
+ */
+ /* Now copy this back to the buffer for the file */
+ Rock[flagpos] = flagval;
+
+ /* If there was a CE, fill in the size field */
+ if (recstart)
+ set_733((char *) Rock + recstart - 8, ipnt - recstart);
+
+xa_only:
+ s_entry->rr_attributes = (Uchar *) e_malloc(ipnt);
+ s_entry->total_rr_attr_size = ipnt;
+ s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
+ memcpy(s_entry->rr_attributes, Rock, ipnt);
+ return (ipnt);
+}
+
+/*
+ * Guaranteed to return a single sector with the relevant info
+ */
+char *
+generate_rr_extension_record(char *id, char *descriptor, char *source,
+ int *size)
+{
+ int lipnt = 0;
+ char *pnt;
+ int len_id;
+ int len_des;
+ int len_src;
+
+ len_id = strlen(id);
+ len_des = strlen(descriptor);
+ len_src = strlen(source);
+ Rock[lipnt++] = 'E';
+ Rock[lipnt++] = 'R';
+ Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src;
+ Rock[lipnt++] = 1;
+ Rock[lipnt++] = len_id;
+ Rock[lipnt++] = len_des;
+ Rock[lipnt++] = len_src;
+ Rock[lipnt++] = 1;
+
+ memcpy(Rock + lipnt, id, len_id);
+ lipnt += len_id;
+
+ memcpy(Rock + lipnt, descriptor, len_des);
+ lipnt += len_des;
+
+ memcpy(Rock + lipnt, source, len_src);
+ lipnt += len_src;
+
+ if (lipnt > SECTOR_SIZE) {
+#ifdef USE_LIBSCHILY
+ comerrno(EX_BAD, "Extension record too long\n");
+#else
+ fprintf(stderr, "Extension record too long\n");
+ exit(1);
+#endif
+ }
+ pnt = (char *) e_malloc(SECTOR_SIZE);
+ memset(pnt, 0, SECTOR_SIZE);
+ memcpy(pnt, Rock, lipnt);
+ *size = lipnt;
+ return (pnt);
+}