945 lines
24 KiB
C
945 lines
24 KiB
C
/* @(#)rock.c 1.66 12/12/02 joerg */
|
|
#include <schily/mconfig.h>
|
|
#ifndef lint
|
|
static UConst char sccsid[] =
|
|
"@(#)rock.c 1.66 12/12/02 joerg";
|
|
#endif
|
|
/*
|
|
* File rock.c - generate RRIP records for iso9660 filesystems.
|
|
*
|
|
* Written by Eric Youngdale (1993).
|
|
*
|
|
* Copyright 1993 Yggdrasil Computing, Incorporated
|
|
* Copyright (c) 1999,2000-2012 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 "mkisofs.h"
|
|
#include "rock.h"
|
|
#include <schily/device.h>
|
|
#include <schily/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_OLD_SIZE 36 /* RR POSIX Extensions (mode/nlink/uid/gid) */
|
|
#define PX_SIZE 44 /* RR POSIX Extensions (mode/nlink/uid/gid/ino) */
|
|
#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 */
|
|
#define TF_SIZE_LONG (5 + 4 * 17) /* RR Time field */
|
|
#else
|
|
#define TF_SIZE (5 + 3 * 7)
|
|
#define TF_SIZE_LONG (5 + 3 * 17)
|
|
#endif
|
|
|
|
LOCAL void rstrncpy __PR((char *t, char *f, size_t tlen,
|
|
siconvt_t *inls,
|
|
siconvt_t *onls));
|
|
LOCAL void add_CE_entry __PR((char *field, int line));
|
|
LOCAL int gen_xa_attr __PR((mode_t attr));
|
|
LOCAL void gen_xa __PR((struct stat *lstatbuf));
|
|
EXPORT int generate_xa_rr_attributes __PR((char *whole_name,
|
|
char *name,
|
|
struct directory_entry *s_entry,
|
|
struct stat *statbuf,
|
|
struct stat *lstatbuf,
|
|
int deep_opt));
|
|
char *generate_rr_extension_record __PR((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
|
|
*/
|
|
LOCAL Uchar Rock[16384];
|
|
LOCAL Uchar symlink_buff[PATH_MAX+1];
|
|
LOCAL int ipnt = 0; /* Current "write" offset in Rock[] */
|
|
LOCAL int recstart = 0; /* Start offset in Rock[] for this area */
|
|
LOCAL int currlen = 0; /* # of non RR bytes used in this area */
|
|
LOCAL int mainrec = 0; /* # of RR bytes use in main dir area */
|
|
LOCAL int reclimit; /* Max. # of bytes usable in this area */
|
|
|
|
/* if we are using converted filenames, we don't want the '/' character */
|
|
LOCAL void
|
|
rstrncpy(t, f, tlen, inls, onls)
|
|
char *t;
|
|
char *f;
|
|
size_t tlen; /* The to-length */
|
|
siconvt_t *inls;
|
|
siconvt_t *onls;
|
|
{
|
|
size_t flen = strlen(f);
|
|
|
|
while (tlen > 0 && *f) {
|
|
size_t ofl = flen;
|
|
size_t otl = tlen;
|
|
|
|
conv_charset((Uchar *)t, &tlen, (Uchar *)f, &flen, inls, onls);
|
|
if (*t == '/') {
|
|
*t = '_';
|
|
}
|
|
t += otl - tlen;
|
|
f += ofl - flen;
|
|
}
|
|
}
|
|
|
|
LOCAL void
|
|
add_CE_entry(field, line)
|
|
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 */
|
|
}
|
|
|
|
#ifdef PROTOTYPES
|
|
LOCAL int
|
|
gen_xa_attr(mode_t attr)
|
|
#else
|
|
LOCAL int
|
|
gen_xa_attr(attr)
|
|
mode_t attr;
|
|
#endif
|
|
{
|
|
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);
|
|
}
|
|
|
|
LOCAL void
|
|
gen_xa(lstatbuf)
|
|
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;
|
|
|
|
}
|
|
|
|
#ifdef PROTOTYPES
|
|
EXPORT int
|
|
generate_xa_rr_attributes(char *whole_name, char *name,
|
|
struct directory_entry *s_entry,
|
|
struct stat *statbuf,
|
|
struct stat *lstatbuf,
|
|
int deep_opt)
|
|
#else
|
|
EXPORT int
|
|
generate_xa_rr_attributes(whole_name, name,
|
|
s_entry,
|
|
statbuf,
|
|
lstatbuf,
|
|
deep_opt)
|
|
char *whole_name;
|
|
char *name;
|
|
struct directory_entry *s_entry;
|
|
struct stat *statbuf,
|
|
*lstatbuf;
|
|
int deep_opt;
|
|
#endif
|
|
{
|
|
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, ".") != 0 && strcmp(name, "..") != 0) {
|
|
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
|
|
* XXX If we are using iconv() based locales and in/out
|
|
* XXX locale differ, then strlen(&Rock[ipnt]) may
|
|
* XXX increase. We would need to compute the length
|
|
* XXX early enough.
|
|
*/
|
|
#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';
|
|
if (rrip112) {
|
|
Rock[ipnt++] = PX_SIZE;
|
|
} else {
|
|
Rock[ipnt++] = PX_OLD_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;
|
|
if (rrip112) {
|
|
/*
|
|
* We will set up correct inode numbers later
|
|
* after we did assign them.
|
|
*/
|
|
set_733((char *)Rock + ipnt, 0);
|
|
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 schily/stat.h always provides the macros S_ISCHR() & S_ISBLK()
|
|
* and schily/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 <schily/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;
|
|
BOOL last_sl = FALSE; /* Don't suppress last '/' */
|
|
|
|
#ifdef HAVE_READLINK
|
|
nchar = readlink(deep_opt&DID_CHDIR?name:whole_name,
|
|
(char *)symlink_buff,
|
|
sizeof (symlink_buff)-1);
|
|
if (nchar < 0)
|
|
errmsg(_("Cannot read link '%s'.\n"), whole_name);
|
|
#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 || last_sl) {
|
|
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;
|
|
}
|
|
if (cpnt == &symlink_buff[0])
|
|
Rock[ipnt++] = SL_ROOT;
|
|
else
|
|
Rock[ipnt++] = 0;
|
|
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) {
|
|
*cpnt1 = '/';
|
|
if (cpnt1 > symlink_buff && !last_sl &&
|
|
cpnt1[1] == '\0') {
|
|
last_sl = TRUE;
|
|
}
|
|
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(long_rr_time ? TF_SIZE_LONG:TF_SIZE))
|
|
add_CE_entry("TF", __LINE__);
|
|
Rock[ipnt++] = 'T';
|
|
Rock[ipnt++] = 'F';
|
|
Rock[ipnt++] = long_rr_time ? TF_SIZE_LONG:TF_SIZE;
|
|
Rock[ipnt++] = SU_VERSION;
|
|
#if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */
|
|
Rock[ipnt++] = long_rr_time ? 0x8f:0x0f;
|
|
#else
|
|
Rock[ipnt++] = long_rr_time ? 0x8e:0x0e;
|
|
#endif
|
|
flagval |= (1 << 7);
|
|
|
|
#if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */
|
|
if (long_rr_time) {
|
|
iso9660_date((char *)&Rock[ipnt], lstatbuf->st_ftime);
|
|
ipnt += 7;
|
|
} else {
|
|
/*
|
|
* XXX Do we have nanoseconds on QNX?
|
|
*/
|
|
iso9660_ldate((char *)&Rock[ipnt], lstatbuf->st_ftime, 0, -100);
|
|
ipnt += 17;
|
|
}
|
|
#endif
|
|
if (long_rr_time) {
|
|
iso9660_ldate((char *)&Rock[ipnt],
|
|
lstatbuf->st_mtime, stat_mnsecs(lstatbuf), -100);
|
|
ipnt += 17;
|
|
iso9660_ldate((char *)&Rock[ipnt],
|
|
lstatbuf->st_atime, stat_ansecs(lstatbuf), -100);
|
|
ipnt += 17;
|
|
iso9660_ldate((char *)&Rock[ipnt],
|
|
lstatbuf->st_ctime, stat_cnsecs(lstatbuf), -100);
|
|
ipnt += 17;
|
|
} else {
|
|
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 mkisofs 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
|
|
*/
|
|
EXPORT char *
|
|
generate_rr_extension_record(id, descriptor, source, size)
|
|
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) {
|
|
comerrno(EX_BAD, _("Extension record too long\n"));
|
|
}
|
|
pnt = (char *)e_malloc(SECTOR_SIZE);
|
|
memset(pnt, 0, SECTOR_SIZE);
|
|
memcpy(pnt, Rock, lipnt);
|
|
*size = lipnt;
|
|
return (pnt);
|
|
}
|