2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)rock.c 1.43 05/05/01 joerg */
15 * File rock.c - generate RRIP records for iso9660 filesystems.
17 * Written by Eric Youngdale (1993).
19 * Copyright 1993 Yggdrasil Computing, Incorporated
20 * Copyright (c) 1999,2000-2003 J. Schilling
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2, or (at your option)
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38 #include "genisoimage.h"
49 #define CE_SIZE 28 /* SUSP Continuation aerea */
50 #define CL_SIZE 12 /* RR Child Link for deep dir relocation */
51 #define ER_SIZE 8 /* RR Extension record for RR signature */
52 #define NM_SIZE 5 /* RR Real name */
53 #define PL_SIZE 12 /* RR Paren Link for deep dir relocation */
54 #define PN_SIZE 20 /* RR POSIX device modes (Major/Minor) */
55 #define PX_SIZE 36 /* RR POSIX Extensions (mode/nlink(uid/gid) */
56 #define RE_SIZE 4 /* RR Relocated directory */
57 #define RR_SIZE 5 /* RR RR Signature in every file */
58 #define SL_SIZE 20 /* RR Symlink */
59 #define ZF_SIZE 16 /* RR* Linux compression extension */
61 #define AA_SIZE 14 /* size of Apple extension */
62 #endif /* APPLE_HYB */
63 #if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */
64 #define TF_SIZE (5 + 4 * 7) /* RR Time field */
66 #define TF_SIZE (5 + 3 * 7)
69 static void rstrncpy(char *t, char *f, int c,
70 struct unls_table *inls,
71 struct unls_table *onls);
72 static void add_CE_entry(char *field, int line);
73 static int gen_xa_attr(mode_t attr);
74 static void gen_xa(struct stat *lstatbuf);
75 int generate_xa_rr_attributes(char *whole_name, char *name,
76 struct directory_entry *s_entry,
78 struct stat *lstatbuf,
80 char *generate_rr_extension_record(char *id, char *descriptor, char *source,
83 * If we need to store this number of bytes, make sure we
84 * do not box ourselves in so that we do not have room for
85 * a CE entry for the continuation record
87 #define RR_CUR_USE (CE_SIZE + currlen + (ipnt - recstart))
89 #define MAYBE_ADD_CE_ENTRY(BYTES) \
90 (((int)(BYTES)) + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
93 * Buffer to build RR attributes
95 static Uchar Rock[16384];
96 static Uchar symlink_buff[PATH_MAX+1];
97 static int ipnt = 0; /* Current "write" offset in Rock[] */
98 static int recstart = 0; /* Start offset in Rock[] for this area */
99 static int currlen = 0; /* # of non RR bytes used in this area */
100 static int mainrec = 0; /* # of RR bytes use in main dir area */
101 static int reclimit; /* Max. # of bytes usable in this area */
103 /* if we are using converted filenames, we don't want the '/' character */
105 rstrncpy(char *t, char *f, int c, struct unls_table *inls,
106 struct unls_table *onls)
109 *t = conv_charset(*f, inls, onls);
119 add_CE_entry(char *field, int line)
121 if (MAYBE_ADD_CE_ENTRY(0)) {
123 "Panic: no space, cannot add RR CE entry (%d bytes mising) for %s line %d.\n",
124 (CE_SIZE + currlen + (ipnt - recstart) - reclimit),
126 errmsgno(EX_BAD, "currlen: %d ipnt: %d, recstart: %d\n",
127 currlen, ipnt, recstart);
128 errmsgno(EX_BAD, "Send bug report to the maintainer.\n");
129 comerrno(EX_BAD, "Aborting.\n");
133 set_733((char *) Rock + recstart - 8, ipnt + 28 - recstart);
136 Rock[ipnt++] = CE_SIZE;
137 Rock[ipnt++] = SU_VERSION;
138 set_733((char *) Rock + ipnt, 0);
140 set_733((char *) Rock + ipnt, 0);
142 set_733((char *) Rock + ipnt, 0);
148 reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
152 gen_xa_attr(mode_t attr)
180 gen_xa(struct stat *lstatbuf)
185 set_722((char *) Rock + ipnt, lstatbuf->st_gid);
190 set_722((char *) Rock + ipnt, lstatbuf->st_uid);
195 set_722((char *) Rock + ipnt, gen_xa_attr(lstatbuf->st_mode));
198 Rock[ipnt++] = 'X'; /* XA Signature */
200 Rock[ipnt++] = 0; /* File number (we always use '0' */
202 Rock[ipnt++] = 0; /* Reserved (5 Byte) */
211 generate_xa_rr_attributes(char *whole_name, char *name,
212 struct directory_entry *s_entry,
213 struct stat *statbuf,
214 struct stat *lstatbuf,
221 statbuf = statbuf; /* this shuts up unreferenced compiler */
223 mainrec = recstart = ipnt = 0;
229 /* reclimit = 0xf8; XXX we now use 254 == 0xfe */
230 reclimit = MAX_ISODIR;
232 /* no need to fill in the RR stuff if we won't see the file */
233 if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
237 * Obtain the amount of space that is currently used for the directory
238 * record. We may safely use the current name length; because if name
239 * confilcts force us to change the ISO-9660 name later, the name will
240 * never become longer than now.
242 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
243 s_entry->isorec.name_len[0] = 1;
245 s_entry->isorec.name_len[0] = strlen(s_entry->isorec.name);
247 currlen = s_entry->isorec.length[0] = s_entry->isorec.name_len[0] +
248 offsetof(struct iso_directory_record, name[0]);
250 s_entry->isorec.length[0] = ++currlen;
252 if (currlen < 33+37) {
254 * If the ISO-9660 name length is less than 37, we may use
255 * ISO-9660:1988 name rules and for this reason, the name len
256 * may later increase from adding e.g. ".;1"; in this case
257 * just use the upper limit.
263 /* if we have regular file, then add Apple extensions */
264 if (S_ISREG(lstatbuf->st_mode) && apple_ext && s_entry->hfs_ent) {
265 if (MAYBE_ADD_CE_ENTRY(AA_SIZE))
266 add_CE_entry("AA", __LINE__);
267 Rock[ipnt++] = 'A'; /* AppleSignature */
269 Rock[ipnt++] = AA_SIZE; /* includes AppleSignature bytes */
270 Rock[ipnt++] = 0x02; /* SystemUseID */
271 Rock[ipnt++] = s_entry->hfs_ent->u.file.type[0];
272 Rock[ipnt++] = s_entry->hfs_ent->u.file.type[1];
273 Rock[ipnt++] = s_entry->hfs_ent->u.file.type[2];
274 Rock[ipnt++] = s_entry->hfs_ent->u.file.type[3];
275 Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[0];
276 Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[1];
277 Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[2];
278 Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[3];
279 Rock[ipnt++] = (s_entry->hfs_ent->fdflags >> 8) & 0xff;
280 Rock[ipnt++] = s_entry->hfs_ent->fdflags & 0xff;
282 #endif /* APPLE_HYB */
287 /* Identify that we are using the SUSP protocol */
288 if (deep_opt & NEED_SP) {
290 * We may not use a CE record here but we never will need to
291 * do so, as this SP record is only used for the "." entry
292 * of the root directory.
297 Rock[ipnt++] = SU_VERSION;
301 Rock[ipnt++] = sizeof (struct iso_xa_dir_record);
306 /* First build the posix name field */
307 if (MAYBE_ADD_CE_ENTRY(RR_SIZE))
308 add_CE_entry("RR", __LINE__);
312 Rock[ipnt++] = SU_VERSION;
315 Rock[ipnt++] = 0; /* We go back and fix this later */
317 if (strcmp(name, ".") && strcmp(name, "..")) {
319 int remain; /* Remaining name length */
320 int use; /* Current name part used */
323 /* use the HFS name if it exists */
324 if (USE_MAC_NAME(s_entry)) {
325 remain = strlen(s_entry->hfs_ent->name);
326 npnt = s_entry->hfs_ent->name;
328 #endif /* APPLE_HYB */
330 remain = strlen(name);
334 #endif /* APPLE_HYB */
336 if (MAYBE_ADD_CE_ENTRY(NM_SIZE+1))
337 add_CE_entry("NM", __LINE__);
341 /* Can we fit this SUSP and a CE entry? */
342 if (MAYBE_ADD_CE_ENTRY(NM_SIZE+use)) {
343 use = reclimit - NM_SIZE - RR_CUR_USE;
346 /* Only room for 256 per SUSP field */
353 "Negative RR name length residual: %d\n",
357 /* First build the posix name field */
360 Rock[ipnt++] = NM_SIZE + use;
361 Rock[ipnt++] = SU_VERSION;
362 Rock[ipnt++] = (remain != use ? 1 : 0);
365 /* convert charsets as required */
367 if (USE_MAC_NAME(s_entry))
368 rstrncpy((char *) &Rock[ipnt], npnt, use,
371 #endif /* APPLE_HYB */
372 rstrncpy((char *) &Rock[ipnt], npnt, use,
377 if (remain && need_ce)
378 add_CE_entry("NM", __LINE__);
382 /* Add the posix modes */
383 if (MAYBE_ADD_CE_ENTRY(PX_SIZE))
384 add_CE_entry("PX", __LINE__);
387 Rock[ipnt++] = PX_SIZE;
388 Rock[ipnt++] = SU_VERSION;
390 set_733((char *) Rock + ipnt, lstatbuf->st_mode);
392 set_733((char *) Rock + ipnt, lstatbuf->st_nlink);
394 set_733((char *) Rock + ipnt, lstatbuf->st_uid);
396 set_733((char *) Rock + ipnt, lstatbuf->st_gid);
399 /* Check for special devices */
400 #if defined(S_IFCHR) || defined(S_IFBLK)
402 * The code in this if statement used to be #ifdef'd with NON_UNIXFS.
403 * But as statdefs.h always provides the macros S_ISCHR() & S_ISBLK()
404 * and device.h always provides major()/minor() it is not needed
407 if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
408 if (MAYBE_ADD_CE_ENTRY(PN_SIZE))
409 add_CE_entry("PN", __LINE__);
412 Rock[ipnt++] = PN_SIZE;
413 Rock[ipnt++] = SU_VERSION;
416 /* This is the new and only code which uses <device.h> */
417 set_733((char *) Rock + ipnt, major(lstatbuf->st_rdev));
419 set_733((char *) Rock + ipnt, minor(lstatbuf->st_rdev));
423 * If we don't have sysmacros.h, then we have to guess as to
424 * how best to pick apart the device number for major/minor.
425 * Note: this may very well be wrong for many systems, so it
426 * is always best to use the major/minor macros if the system
429 if (sizeof (dev_t) <= 2) {
430 set_733((char *)Rock + ipnt, (lstatbuf->st_rdev >> 8));
432 set_733((char *)Rock + ipnt, lstatbuf->st_rdev & 0xff);
434 } else if (sizeof (dev_t) <= 4) {
435 set_733((char *)Rock + ipnt,
436 (lstatbuf->st_rdev >> 8) >> 8);
438 set_733((char *)Rock + ipnt,
439 lstatbuf->st_rdev & 0xffff);
442 set_733((char *)Rock + ipnt,
443 (lstatbuf->st_rdev >> 16)>>16);
445 set_733((char *)Rock + ipnt, lstatbuf->st_rdev);
450 #endif /* defined(S_IFCHR) || defined(S_IFBLK) */
452 /* Check for and symbolic links. VMS does not have these. */
454 if (S_ISLNK(lstatbuf->st_mode)) {
464 nchar = readlink(whole_name, (char *)symlink_buff,
465 sizeof (symlink_buff)-1);
468 #endif /* HAVE_READLINK */
469 symlink_buff[nchar < 0 ? 0 : nchar] = 0;
470 nchar = strlen((char *) symlink_buff);
471 set_733(s_entry->isorec.size, 0);
472 cpnt = &symlink_buff[0];
475 if (!split_SL_field) {
478 for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++) {
485 if (sl_bytes > 250) {
487 * the symbolic link won't fit into one
488 * SL System Use Field print an error message
489 * and continue with splited one
492 "symbolic link ``%s'' to long for one SL System Use Field, splitting",
495 if (MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes))
496 add_CE_entry("SL+", __LINE__);
499 if (MAYBE_ADD_CE_ENTRY(SL_SIZE))
500 add_CE_entry("SL", __LINE__);
504 Rock[ipnt++] = SL_SIZE;
505 Rock[ipnt++] = SU_VERSION;
506 Rock[ipnt++] = 0; /* Flags */
510 strchr((char *)cpnt, '/');
517 * We treat certain components in a special
520 if (cpnt[0] == '.' && cpnt[1] == '.' &&
522 if (MAYBE_ADD_CE_ENTRY(2)) {
523 add_CE_entry("SL-parent", __LINE__);
529 * can restart properly
535 Rock[ipnt++] = SL_PARENT;
536 Rock[ipnt++] = 0; /* length is zero */
539 } else if (cpnt[0] == '.' && cpnt[1] == 0) {
540 if (MAYBE_ADD_CE_ENTRY(2)) {
541 add_CE_entry("SL-current", __LINE__);
547 * can restart properly
553 Rock[ipnt++] = SL_CURRENT;
554 Rock[ipnt++] = 0; /* length is zero */
557 } else if (cpnt[0] == 0) {
558 if (MAYBE_ADD_CE_ENTRY(2)) {
559 add_CE_entry("SL-root", __LINE__);
565 * can restart properly
571 Rock[ipnt++] = SL_ROOT;
572 Rock[ipnt++] = 0; /* length is zero */
576 * If we do not have enough room for a
577 * component, start a new continuations
580 if (split_SL_component ?
581 MAYBE_ADD_CE_ENTRY(6) :
582 MAYBE_ADD_CE_ENTRY(6 + strlen((char *) cpnt))) {
583 add_CE_entry("SL++", __LINE__);
589 * can restart properly
595 j0 = strlen((char *) cpnt);
601 if (j1 + currlen + 2 + CE_SIZE +
615 strncpy((char *)Rock + ipnt,
621 * Number we processed
650 Rock[lenpos] = lenval;
652 /* We need another SL entry */
653 Rock[lenpos + 2] = SL_CONTINUE;
656 } /* Is a symbolic link */
659 /* Add in the Rock Ridge TF time field */
660 if (MAYBE_ADD_CE_ENTRY(TF_SIZE))
661 add_CE_entry("TF", __LINE__);
664 Rock[ipnt++] = TF_SIZE;
665 Rock[ipnt++] = SU_VERSION;
666 #if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */
673 #if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */
674 iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
677 iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
679 iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
681 iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
684 /* Add in the Rock Ridge RE (relocated dir) field */
685 if (deep_opt & NEED_RE) {
686 if (MAYBE_ADD_CE_ENTRY(RE_SIZE))
687 add_CE_entry("RE", __LINE__);
690 Rock[ipnt++] = RE_SIZE;
691 Rock[ipnt++] = SU_VERSION;
694 /* Add in the Rock Ridge PL record, if required. */
695 if (deep_opt & NEED_PL) {
696 if (MAYBE_ADD_CE_ENTRY(PL_SIZE))
697 add_CE_entry("PL", __LINE__);
700 Rock[ipnt++] = PL_SIZE;
701 Rock[ipnt++] = SU_VERSION;
702 set_733((char *) Rock + ipnt, 0);
707 /* Add in the Rock Ridge CL field, if required. */
708 if (deep_opt & NEED_CL) {
709 if (MAYBE_ADD_CE_ENTRY(CL_SIZE))
710 add_CE_entry("CL", __LINE__);
713 Rock[ipnt++] = CL_SIZE;
714 Rock[ipnt++] = SU_VERSION;
715 set_733((char *) Rock + ipnt, 0);
722 * If transparent compression was requested, fill in the correct field
723 * for this file, if (and only if) it is actually a compressed file!
724 * This relies only on magic number, but it should in general not
725 * be an issue since if you're using -z odds are most of your
726 * files are already compressed.
728 * In the future it would be nice if genisoimage actually did the
731 if (transparent_compression && S_ISREG(lstatbuf->st_mode)) {
732 static const Uchar zisofs_magic[8] =
733 { 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07 };
735 unsigned int file_size;
742 * First open file and verify that the correct algorithm was
748 memset(header, 0, sizeof (header));
750 zffile = fopen(whole_name, "rb");
751 if (zffile != NULL) {
752 if (fread(header, 1, sizeof (header), zffile) != sizeof (header))
755 /* Check magic number */
756 if (memcmp(header, zisofs_magic, sizeof (zisofs_magic)))
759 /* Get the real size of the file */
760 file_size = get_731((char *)header+8);
762 /* Get the header size (>> 2) */
763 headersize = header[12];
765 /* Get the block size (log2) */
766 blocksize = header[13];
771 blocksize = headersize = 0; /* Make silly GCC quiet */
775 if (MAYBE_ADD_CE_ENTRY(ZF_SIZE))
776 add_CE_entry("ZF", __LINE__);
779 Rock[ipnt++] = ZF_SIZE;
780 Rock[ipnt++] = SU_VERSION;
781 Rock[ipnt++] = 'p'; /* Algorithm: "paged zlib" */
783 /* 2 bytes for algorithm-specific information */
784 Rock[ipnt++] = headersize;
785 Rock[ipnt++] = blocksize;
786 set_733((char *) Rock + ipnt, file_size); /* Real file size */
792 * Add in the Rock Ridge CE field, if required. We use this for the
793 * extension record that is stored in the root directory.
795 if (deep_opt & NEED_CE)
796 add_CE_entry("ER", __LINE__);
799 * Done filling in all of the fields. Now copy it back to a buffer
800 * for the file in question.
802 /* Now copy this back to the buffer for the file */
803 Rock[flagpos] = flagval;
805 /* If there was a CE, fill in the size field */
807 set_733((char *) Rock + recstart - 8, ipnt - recstart);
810 s_entry->rr_attributes = (Uchar *) e_malloc(ipnt);
811 s_entry->total_rr_attr_size = ipnt;
812 s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
813 memcpy(s_entry->rr_attributes, Rock, ipnt);
818 * Guaranteed to return a single sector with the relevant info
821 generate_rr_extension_record(char *id, char *descriptor, char *source,
831 len_des = strlen(descriptor);
832 len_src = strlen(source);
835 Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src;
837 Rock[lipnt++] = len_id;
838 Rock[lipnt++] = len_des;
839 Rock[lipnt++] = len_src;
842 memcpy(Rock + lipnt, id, len_id);
845 memcpy(Rock + lipnt, descriptor, len_des);
848 memcpy(Rock + lipnt, source, len_src);
851 if (lipnt > SECTOR_SIZE) {
853 comerrno(EX_BAD, "Extension record too long\n");
855 fprintf(stderr, "Extension record too long\n");
859 pnt = (char *) e_malloc(SECTOR_SIZE);
860 memset(pnt, 0, SECTOR_SIZE);
861 memcpy(pnt, Rock, lipnt);