~ubuntu-branches/ubuntu/utopic/cdrkit/utopic

1.1.1 by Eduard Bloch
Import upstream version 1.1.0
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
}