diff options
Diffstat (limited to 'genisoimage/rock.c')
-rw-r--r-- | genisoimage/rock.c | 864 |
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); +} |