patch: make *outfile extern
[platform/upstream/cdrkit.git] / genisoimage / rock.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)rock.c   1.43 05/05/01 joerg */
14 /*
15  * File rock.c - generate RRIP  records for iso9660 filesystems.
16  *
17  * Written by Eric Youngdale (1993).
18  *
19  * Copyright 1993 Yggdrasil Computing, Incorporated
20  * Copyright (c) 1999,2000-2003 J. Schilling
21  *
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)
25  * any later version.
26  *
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.
31  *
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.
35  */
36
37 #include <mconfig.h>
38 #include "genisoimage.h"
39 #include <device.h>
40 #include <schily.h>
41
42 #define SU_VERSION 1
43
44 #define SL_ROOT    8
45 #define SL_PARENT  4
46 #define SL_CURRENT 2
47 #define SL_CONTINUE 1
48
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             */
60 #ifdef APPLE_HYB
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                      */
65 #else
66 #define TF_SIZE (5 + 3 * 7)
67 #endif
68
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,
77                                                                                 struct stat *statbuf,
78                                                                                 struct stat *lstatbuf,
79                                                                                 int deep_opt);
80 char *generate_rr_extension_record(char *id, char *descriptor, char *source,
81                                                                                           int *size);
82 /*
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
86  */
87 #define RR_CUR_USE      (CE_SIZE + currlen + (ipnt - recstart))
88
89 #define MAYBE_ADD_CE_ENTRY(BYTES) \
90         (((int)(BYTES)) + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
91
92 /*
93  * Buffer to build RR attributes
94  */
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  */
102
103 /* if we are using converted filenames, we don't want the '/' character */
104 static void
105 rstrncpy(char *t, char *f, int c, struct unls_table *inls, 
106                         struct unls_table *onls)
107 {
108         while (c-- && *f) {
109                 *t = conv_charset(*f, inls, onls);
110                 if (*t == '/') {
111                         *t = '_';
112                 }
113                 t++;
114                 f++;
115         }
116 }
117
118 static void
119 add_CE_entry(char *field, int line)
120 {
121         if (MAYBE_ADD_CE_ENTRY(0)) {
122                 errmsgno(EX_BAD,
123                 "Panic: no space, cannot add RR CE entry (%d bytes mising) for %s line %d.\n",
124                 (CE_SIZE + currlen + (ipnt - recstart) - reclimit),
125                 field, line);
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");
130         }
131
132         if (recstart)
133                 set_733((char *) Rock + recstart - 8, ipnt + 28 - recstart);
134         Rock[ipnt++] = 'C';
135         Rock[ipnt++] = 'E';
136         Rock[ipnt++] = CE_SIZE;
137         Rock[ipnt++] = SU_VERSION;
138         set_733((char *) Rock + ipnt, 0);
139         ipnt += 8;
140         set_733((char *) Rock + ipnt, 0);
141         ipnt += 8;
142         set_733((char *) Rock + ipnt, 0);
143         ipnt += 8;
144         recstart = ipnt;
145         currlen = 0;
146         if (!mainrec)
147                 mainrec = ipnt;
148         reclimit = SECTOR_SIZE - 8;     /* Limit to one sector */
149 }
150
151 static int
152 gen_xa_attr(mode_t attr)
153 {
154         int     ret = 0;
155
156         if (attr & S_IRUSR)
157                 ret |= XA_O_READ;
158         if (attr & S_IXUSR)
159                 ret |= XA_O_EXEC;
160
161         if (attr & S_IRGRP)
162                 ret |= XA_G_READ;
163         if (attr & S_IXGRP)
164                 ret |= XA_G_EXEC;
165
166         if (attr & S_IROTH)
167                 ret |= XA_W_READ;
168         if (attr & S_IXOTH)
169                 ret |= XA_W_EXEC;
170
171         ret |= XA_FORM1;
172
173         if (S_ISDIR(attr))
174                 ret |= XA_DIR;
175
176         return (ret);
177 }
178
179 static void
180 gen_xa(struct stat *lstatbuf)
181 {
182                 /*
183                  * Group ID
184                  */
185                 set_722((char *) Rock + ipnt, lstatbuf->st_gid);
186                 ipnt += 2;
187                 /*
188                  * User ID
189                  */
190                 set_722((char *) Rock + ipnt, lstatbuf->st_uid);
191                 ipnt += 2;
192                 /*
193                  * Attributes
194                  */
195                 set_722((char *) Rock + ipnt, gen_xa_attr(lstatbuf->st_mode));
196                 ipnt += 2;
197
198                 Rock[ipnt++] = 'X';     /* XA Signature */
199                 Rock[ipnt++] = 'A';
200                 Rock[ipnt++] = 0;       /* File number (we always use '0' */
201
202                 Rock[ipnt++] = 0;       /* Reserved (5 Byte) */
203                 Rock[ipnt++] = 0;
204                 Rock[ipnt++] = 0;
205                 Rock[ipnt++] = 0;
206                 Rock[ipnt++] = 0;
207
208 }
209
210 int
211 generate_xa_rr_attributes(char *whole_name, char *name,
212                                                                   struct directory_entry *s_entry,
213                                                                   struct stat *statbuf,
214                                                                   struct stat *lstatbuf,
215                                                                   int deep_opt)
216 {
217         int             flagpos;
218         int             flagval;
219         int             need_ce;
220
221         statbuf = statbuf;      /* this shuts up unreferenced compiler */
222                                 /* warnings */
223         mainrec = recstart = ipnt = 0;
224
225         if (use_XA) {
226                 gen_xa(lstatbuf);
227         }
228
229 /*      reclimit = 0xf8; XXX we now use 254 == 0xfe */
230         reclimit = MAX_ISODIR;
231
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)
234                 return (0);
235
236         /*
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.
241          */
242         if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
243                 s_entry->isorec.name_len[0] = 1;
244         } else {
245                 s_entry->isorec.name_len[0] = strlen(s_entry->isorec.name);
246         }
247         currlen = s_entry->isorec.length[0] = s_entry->isorec.name_len[0] +
248                                 offsetof(struct iso_directory_record, name[0]);
249         if (currlen & 1)
250                 s_entry->isorec.length[0] = ++currlen;
251
252         if (currlen < 33+37) {
253                 /*
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.
258                  */
259                 currlen = 33+37;
260         }
261
262 #ifdef APPLE_HYB
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 */
268                 Rock[ipnt++] = 'A';
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;
281         }
282 #endif  /* APPLE_HYB */
283
284         if (!use_RockRidge)
285                 goto xa_only;
286
287         /* Identify that we are using the SUSP protocol */
288         if (deep_opt & NEED_SP) {
289                 /*
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.
293                  */
294                 Rock[ipnt++] = 'S';
295                 Rock[ipnt++] = 'P';
296                 Rock[ipnt++] = 7;
297                 Rock[ipnt++] = SU_VERSION;
298                 Rock[ipnt++] = 0xbe;
299                 Rock[ipnt++] = 0xef;
300                 if (use_XA)
301                         Rock[ipnt++] = sizeof (struct iso_xa_dir_record);
302                 else
303                         Rock[ipnt++] = 0;
304         }
305
306         /* First build the posix name field */
307         if (MAYBE_ADD_CE_ENTRY(RR_SIZE))
308                 add_CE_entry("RR", __LINE__);
309         Rock[ipnt++] = 'R';
310         Rock[ipnt++] = 'R';
311         Rock[ipnt++] = 5;
312         Rock[ipnt++] = SU_VERSION;
313         flagpos = ipnt;
314         flagval = 0;
315         Rock[ipnt++] = 0;       /* We go back and fix this later */
316
317         if (strcmp(name, ".") && strcmp(name, "..")) {
318                 char            *npnt;
319                 int             remain; /* Remaining name length  */
320                 int             use;    /* Current name part used */
321
322 #ifdef APPLE_HYB
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;
327                 } else {
328 #endif  /* APPLE_HYB */
329
330                         remain = strlen(name);
331                         npnt = name;
332 #ifdef APPLE_HYB
333                 }
334 #endif  /* APPLE_HYB */
335
336                 if (MAYBE_ADD_CE_ENTRY(NM_SIZE+1))
337                         add_CE_entry("NM", __LINE__);
338                 while (remain) {
339                         use = remain;
340                         need_ce = 0;
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;
344                                 need_ce++;
345                         }
346                         /* Only room for 256 per SUSP field */
347                         if (use > 0xf8) {
348                                 use = 0xf8;
349                                 need_ce++;
350                         }
351                         if (use < 0) {
352                                 comerrno(EX_BAD,
353                                 "Negative RR name length residual: %d\n",
354                                         use);
355                         }
356
357                         /* First build the posix name field */
358                         Rock[ipnt++] = 'N';
359                         Rock[ipnt++] = 'M';
360                         Rock[ipnt++] = NM_SIZE + use;
361                         Rock[ipnt++] = SU_VERSION;
362                         Rock[ipnt++] = (remain != use ? 1 : 0);
363                         flagval |= (1 << 3);
364
365                         /* convert charsets as required */
366 #ifdef APPLE_HYB
367                         if (USE_MAC_NAME(s_entry))
368                                 rstrncpy((char *) &Rock[ipnt], npnt, use,
369                                                         hfs_inls, out_nls);
370                         else
371 #endif  /* APPLE_HYB */
372                                 rstrncpy((char *) &Rock[ipnt], npnt, use,
373                                                         in_nls, out_nls);
374                         npnt += use;
375                         ipnt += use;
376                         remain -= use;
377                         if (remain && need_ce)
378                                 add_CE_entry("NM", __LINE__);
379                 }
380         }
381
382         /* Add the posix modes */
383         if (MAYBE_ADD_CE_ENTRY(PX_SIZE))
384                 add_CE_entry("PX", __LINE__);
385         Rock[ipnt++] = 'P';
386         Rock[ipnt++] = 'X';
387         Rock[ipnt++] = PX_SIZE;
388         Rock[ipnt++] = SU_VERSION;
389         flagval |= (1 << 0);
390         set_733((char *) Rock + ipnt, lstatbuf->st_mode);
391         ipnt += 8;
392         set_733((char *) Rock + ipnt, lstatbuf->st_nlink);
393         ipnt += 8;
394         set_733((char *) Rock + ipnt, lstatbuf->st_uid);
395         ipnt += 8;
396         set_733((char *) Rock + ipnt, lstatbuf->st_gid);
397         ipnt += 8;
398
399         /* Check for special devices */
400 #if     defined(S_IFCHR) || defined(S_IFBLK)
401         /*
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
405          * anymore.
406          */
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__);
410                 Rock[ipnt++] = 'P';
411                 Rock[ipnt++] = 'N';
412                 Rock[ipnt++] = PN_SIZE;
413                 Rock[ipnt++] = SU_VERSION;
414                 flagval |= (1 << 1);
415 #if 1
416                 /* This is the new and only code which uses <device.h> */
417                 set_733((char *) Rock + ipnt, major(lstatbuf->st_rdev));
418                 ipnt += 8;
419                 set_733((char *) Rock + ipnt, minor(lstatbuf->st_rdev));
420                 ipnt += 8;
421 #else
422                 /*
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
427                  * supports it.
428                  */
429                 if (sizeof (dev_t) <= 2) {
430                         set_733((char *)Rock + ipnt, (lstatbuf->st_rdev >> 8));
431                         ipnt += 8;
432                         set_733((char *)Rock + ipnt, lstatbuf->st_rdev & 0xff);
433                         ipnt += 8;
434                 } else if (sizeof (dev_t) <= 4) {
435                         set_733((char *)Rock + ipnt,
436                                                 (lstatbuf->st_rdev >> 8) >> 8);
437                         ipnt += 8;
438                         set_733((char *)Rock + ipnt,
439                                                 lstatbuf->st_rdev & 0xffff);
440                         ipnt += 8;
441                 } else {
442                         set_733((char *)Rock + ipnt,
443                                                 (lstatbuf->st_rdev >> 16)>>16);
444                         ipnt += 8;
445                         set_733((char *)Rock + ipnt, lstatbuf->st_rdev);
446                         ipnt += 8;
447                 }
448 #endif
449         }
450 #endif  /* defined(S_IFCHR) || defined(S_IFBLK) */
451
452         /* Check for and symbolic links.  VMS does not have these. */
453 #ifdef S_IFLNK
454         if (S_ISLNK(lstatbuf->st_mode)) {
455                 int             lenpos;
456                 int             lenval;
457                 int             j0;
458                 int             j1;
459                 int             nchar;
460                 Uchar           *cpnt;
461                 Uchar           *cpnt1;
462
463 #ifdef  HAVE_READLINK
464                 nchar = readlink(whole_name, (char *)symlink_buff,
465                                                 sizeof (symlink_buff)-1);
466 #else
467                 nchar = -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];
473                 flagval |= (1 << 2);
474
475                 if (!split_SL_field) {
476                         int             sl_bytes = 0;
477
478                         for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++) {
479                                 if (*cpnt1 == '/') {
480                                         sl_bytes += 4;
481                                 } else {
482                                         sl_bytes += 1;
483                                 }
484                         }
485                         if (sl_bytes > 250) {
486                                 /*
487                                  * the symbolic link won't fit into one
488                                  * SL System Use Field print an error message
489                                  * and continue with splited one
490                                  */
491                                 fprintf(stderr,
492                                 "symbolic link ``%s'' to long for one SL System Use Field, splitting",
493                                                                 cpnt);
494                         }
495                         if (MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes))
496                                 add_CE_entry("SL+", __LINE__);
497                 }
498                 while (nchar) {
499                         if (MAYBE_ADD_CE_ENTRY(SL_SIZE))
500                                 add_CE_entry("SL", __LINE__);
501                         Rock[ipnt++] = 'S';
502                         Rock[ipnt++] = 'L';
503                         lenpos = ipnt;
504                         Rock[ipnt++] = SL_SIZE;
505                         Rock[ipnt++] = SU_VERSION;
506                         Rock[ipnt++] = 0;       /* Flags */
507                         lenval = 5;
508                         while (*cpnt) {
509                                 cpnt1 = (Uchar *)
510                                                 strchr((char *)cpnt, '/');
511                                 if (cpnt1) {
512                                         nchar--;
513                                         *cpnt1 = 0;
514                                 }
515
516                                 /*
517                                  * We treat certain components in a special
518                                  * way.
519                                  */
520                                 if (cpnt[0] == '.' && cpnt[1] == '.' &&
521                                                                 cpnt[2] == 0) {
522                                         if (MAYBE_ADD_CE_ENTRY(2)) {
523                                                 add_CE_entry("SL-parent", __LINE__);
524                                                 if (cpnt1) {
525                                                         *cpnt1 = '/';
526                                                         nchar++;
527                                                         /*
528                                                          * A kluge so that we
529                                                          * can restart properly
530                                                          */
531                                                         cpnt1 = NULL;
532                                                 }
533                                                 break;
534                                         }
535                                         Rock[ipnt++] = SL_PARENT;
536                                         Rock[ipnt++] = 0; /* length is zero */
537                                         lenval += 2;
538                                         nchar -= 2;
539                                 } else if (cpnt[0] == '.' && cpnt[1] == 0) {
540                                         if (MAYBE_ADD_CE_ENTRY(2)) {
541                                                 add_CE_entry("SL-current", __LINE__);
542                                                 if (cpnt1) {
543                                                         *cpnt1 = '/';
544                                                         nchar++;
545                                                         /*
546                                                          * A kluge so that we
547                                                          * can restart properly
548                                                          */
549                                                         cpnt1 = NULL;
550                                                 }
551                                                 break;
552                                         }
553                                         Rock[ipnt++] = SL_CURRENT;
554                                         Rock[ipnt++] = 0; /* length is zero */
555                                         lenval += 2;
556                                         nchar -= 1;
557                                 } else if (cpnt[0] == 0) {
558                                         if (MAYBE_ADD_CE_ENTRY(2)) {
559                                                 add_CE_entry("SL-root", __LINE__);
560                                                 if (cpnt1) {
561                                                         *cpnt1 = '/';
562                                                         nchar++;
563                                                         /*
564                                                          * A kluge so that we
565                                                          * can restart properly
566                                                          */
567                                                         cpnt1 = NULL;
568                                                 }
569                                                 break;
570                                         }
571                                         Rock[ipnt++] = SL_ROOT;
572                                         Rock[ipnt++] = 0; /* length is zero */
573                                         lenval += 2;
574                                 } else {
575                                         /*
576                                          * If we do not have enough room for a
577                                          * component, start a new continuations
578                                          * segment now
579                                          */
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__);
584                                                 if (cpnt1) {
585                                                         *cpnt1 = '/';
586                                                         nchar++;
587                                                         /*
588                                                          * A kluge so that we
589                                                          * can restart properly
590                                                          */
591                                                         cpnt1 = NULL;
592                                                 }
593                                                 break;
594                                         }
595                                         j0 = strlen((char *) cpnt);
596                                         while (j0) {
597                                                 j1 = j0;
598                                                 if (j1 > 0xf8)
599                                                         j1 = 0xf8;
600                                                 need_ce = 0;
601                                                 if (j1 + currlen + 2 + CE_SIZE +
602                                                     (ipnt - recstart) >
603                                                                 reclimit) {
604
605                                                         j1 = reclimit -
606                                                             (currlen + 2) -
607                                                             CE_SIZE -
608                                                             (ipnt - recstart);
609                                                         need_ce++;
610                                                 }
611                                                 Rock[ipnt++] =
612                                                         (j1 != j0 ?
613                                                         SL_CONTINUE : 0);
614                                                 Rock[ipnt++] = j1;
615                                                 strncpy((char *)Rock + ipnt,
616                                                         (char *) cpnt, j1);
617                                                 ipnt += j1;
618                                                 lenval += j1 + 2;
619                                                 cpnt += j1;
620                                                 /*
621                                                  * Number we processed
622                                                  * this time
623                                                  */
624                                                 nchar -= j1;
625                                                 j0 -= j1;
626                                                 if (need_ce) {
627                                                         add_CE_entry(
628                                                             "SL-path-split",
629                                                             __LINE__);
630                                                         if (cpnt1) {
631                                                                 *cpnt1 = '/';
632                                                                 nchar++;
633                                                                 /*
634                                                                  * A kluge so
635                                                                  * that we can
636                                                                  * restart
637                                                                  * properly
638                                                                  */
639                                                                 cpnt1 = NULL;
640                                                         }
641                                                         break;
642                                                 }
643                                         }
644                                 }
645                                 if (cpnt1) {
646                                         cpnt = cpnt1 + 1;
647                                 } else
648                                         break;
649                         }
650                         Rock[lenpos] = lenval;
651                         if (nchar) {
652                                 /* We need another SL entry */
653                                 Rock[lenpos + 2] = SL_CONTINUE;
654                         }
655                 }       /* while nchar */
656         }       /* Is a symbolic link */
657 #endif  /* S_IFLNK */
658
659         /* Add in the Rock Ridge TF time field */
660         if (MAYBE_ADD_CE_ENTRY(TF_SIZE))
661                 add_CE_entry("TF", __LINE__);
662         Rock[ipnt++] = 'T';
663         Rock[ipnt++] = 'F';
664         Rock[ipnt++] = TF_SIZE;
665         Rock[ipnt++] = SU_VERSION;
666 #if defined(__QNX__) && !defined(__QNXNTO__)    /* Not on Neutrino! never OK? */
667         Rock[ipnt++] = 0x0f;
668 #else
669         Rock[ipnt++] = 0x0e;
670 #endif
671         flagval |= (1 << 7);
672
673 #if defined(__QNX__) && !defined(__QNXNTO__)    /* Not on Neutrino! never OK? */
674         iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
675         ipnt += 7;
676 #endif
677         iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
678         ipnt += 7;
679         iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
680         ipnt += 7;
681         iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
682         ipnt += 7;
683
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__);
688                 Rock[ipnt++] = 'R';
689                 Rock[ipnt++] = 'E';
690                 Rock[ipnt++] = RE_SIZE;
691                 Rock[ipnt++] = SU_VERSION;
692                 flagval |= (1 << 6);
693         }
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__);
698                 Rock[ipnt++] = 'P';
699                 Rock[ipnt++] = 'L';
700                 Rock[ipnt++] = PL_SIZE;
701                 Rock[ipnt++] = SU_VERSION;
702                 set_733((char *) Rock + ipnt, 0);
703                 ipnt += 8;
704                 flagval |= (1 << 5);
705         }
706
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__);
711                 Rock[ipnt++] = 'C';
712                 Rock[ipnt++] = 'L';
713                 Rock[ipnt++] = CL_SIZE;
714                 Rock[ipnt++] = SU_VERSION;
715                 set_733((char *) Rock + ipnt, 0);
716                 ipnt += 8;
717                 flagval |= (1 << 4);
718         }
719
720 #ifndef VMS
721         /*
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.
727          *
728          * In the future it would be nice if genisoimage actually did the
729          * compression.
730          */
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 };
734                 FILE            *zffile;
735                 unsigned int    file_size;
736                 Uchar           header[16];
737                 int             OK_flag;
738                 int             blocksize;
739                 int             headersize;
740
741                 /*
742                  * First open file and verify that the correct algorithm was
743                  * used
744                  */
745                 file_size = 0;
746                 OK_flag = 1;
747
748                 memset(header, 0, sizeof (header));
749
750                 zffile = fopen(whole_name, "rb");
751                 if (zffile != NULL) {
752                         if (fread(header, 1, sizeof (header), zffile) != sizeof (header))
753                                 OK_flag = 0;
754
755                         /* Check magic number */
756                         if (memcmp(header, zisofs_magic, sizeof (zisofs_magic)))
757                                 OK_flag = 0;
758
759                         /* Get the real size of the file */
760                         file_size = get_731((char *)header+8);
761
762                         /* Get the header size (>> 2) */
763                         headersize = header[12];
764
765                         /* Get the block size (log2) */
766                         blocksize = header[13];
767
768                         fclose(zffile);
769                 } else {
770                         OK_flag = 0;
771                         blocksize = headersize = 0; /* Make silly GCC quiet */
772                 }
773
774                 if (OK_flag) {
775                         if (MAYBE_ADD_CE_ENTRY(ZF_SIZE))
776                                 add_CE_entry("ZF", __LINE__);
777                         Rock[ipnt++] = 'Z';
778                         Rock[ipnt++] = 'F';
779                         Rock[ipnt++] = ZF_SIZE;
780                         Rock[ipnt++] = SU_VERSION;
781                         Rock[ipnt++] = 'p'; /* Algorithm: "paged zlib" */
782                         Rock[ipnt++] = 'z';
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 */
787                         ipnt += 8;
788                 }
789         }
790 #endif
791         /*
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.
794          */
795         if (deep_opt & NEED_CE)
796                 add_CE_entry("ER", __LINE__);
797
798         /*
799          * Done filling in all of the fields.  Now copy it back to a buffer
800          * for the file in question.
801          */
802         /* Now copy this back to the buffer for the file */
803         Rock[flagpos] = flagval;
804
805         /* If there was a CE, fill in the size field */
806         if (recstart)
807                 set_733((char *) Rock + recstart - 8, ipnt - recstart);
808
809 xa_only:
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);
814         return (ipnt);
815 }
816
817 /*
818  * Guaranteed to  return a single sector with the relevant info
819  */
820 char *
821 generate_rr_extension_record(char *id, char *descriptor, char *source, 
822                                                                           int *size)
823 {
824         int             lipnt = 0;
825         char            *pnt;
826         int             len_id;
827         int             len_des;
828         int             len_src;
829
830         len_id = strlen(id);
831         len_des = strlen(descriptor);
832         len_src = strlen(source);
833         Rock[lipnt++] = 'E';
834         Rock[lipnt++] = 'R';
835         Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src;
836         Rock[lipnt++] = 1;
837         Rock[lipnt++] = len_id;
838         Rock[lipnt++] = len_des;
839         Rock[lipnt++] = len_src;
840         Rock[lipnt++] = 1;
841
842         memcpy(Rock + lipnt, id, len_id);
843         lipnt += len_id;
844
845         memcpy(Rock + lipnt, descriptor, len_des);
846         lipnt += len_des;
847
848         memcpy(Rock + lipnt, source, len_src);
849         lipnt += len_src;
850
851         if (lipnt > SECTOR_SIZE) {
852 #ifdef  USE_LIBSCHILY
853                 comerrno(EX_BAD, "Extension record too long\n");
854 #else
855                 fprintf(stderr, "Extension record too long\n");
856                 exit(1);
857 #endif
858         }
859         pnt = (char *) e_malloc(SECTOR_SIZE);
860         memset(pnt, 0, SECTOR_SIZE);
861         memcpy(pnt, Rock, lipnt);
862         *size = lipnt;
863         return (pnt);
864 }