1 /* @(#)rock.c	1.66 12/12/02 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)rock.c	1.66 12/12/02 joerg";
6 #endif
7 /*
8  * File rock.c - generate RRIP  records for iso9660 filesystems.
9  *
10  * Written by Eric Youngdale (1993).
11  *
12  * Copyright 1993 Yggdrasil Computing, Incorporated
13  * Copyright (c) 1999,2000-2012 J. Schilling
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2, or (at your option)
18  * any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28  */
29 
30 #include "mkisofs.h"
31 #include "rock.h"
32 #include <schily/device.h>
33 #include <schily/schily.h>
34 
35 #define	SU_VERSION 1
36 
37 #define	SL_ROOT    8
38 #define	SL_PARENT  4
39 #define	SL_CURRENT 2
40 #define	SL_CONTINUE 1
41 
42 #define	CE_SIZE 28	/* SUSP	Continuation aerea			*/
43 #define	CL_SIZE 12	/* RR	Child Link for deep dir relocation	*/
44 #define	ER_SIZE 8	/* RR	Extension record for RR signature	*/
45 #define	NM_SIZE 5	/* RR	Real name				*/
46 #define	PL_SIZE 12	/* RR	Paren Link for deep dir relocation	*/
47 #define	PN_SIZE 20	/* RR	POSIX device modes (Major/Minor)	*/
48 #define	PX_OLD_SIZE 36	/* RR	POSIX Extensions (mode/nlink/uid/gid)	*/
49 #define	PX_SIZE 44	/* RR	POSIX Extensions (mode/nlink/uid/gid/ino) */
50 #define	RE_SIZE 4	/* RR	Relocated directory			*/
51 #define	RR_SIZE 5	/* RR	RR Signature in every file		*/
52 #define	SL_SIZE 20	/* RR	Symlink					*/
53 #define	ZF_SIZE 16	/* RR*	Linux compression extension		*/
54 #ifdef APPLE_HYB
55 #define	AA_SIZE 14	/* size of Apple extension */
56 #endif	/* APPLE_HYB */
57 #if defined(__QNX__) && !defined(__QNXNTO__)	/* Not on Neutrino! never OK? */
58 #define	TF_SIZE (5 + 4 * 7)	/* RR	Time field			*/
59 #define	TF_SIZE_LONG (5 + 4 * 17) /* RR	Time field			*/
60 #else
61 #define	TF_SIZE (5 + 3 * 7)
62 #define	TF_SIZE_LONG (5 + 3 * 17)
63 #endif
64 
65 LOCAL	void	rstrncpy			__PR((char *t, char *f, size_t tlen,
66 							siconvt_t *inls,
67 							siconvt_t *onls));
68 LOCAL	void	add_CE_entry			__PR((char *field, int line));
69 LOCAL	int	gen_xa_attr			__PR((mode_t attr));
70 LOCAL	void	gen_xa				__PR((struct stat *lstatbuf));
71 EXPORT	int	generate_xa_rr_attributes	__PR((char *whole_name,
72 							char *name,
73 							struct directory_entry *s_entry,
74 							struct stat *statbuf,
75 							struct stat *lstatbuf,
76 							int deep_opt));
77 	char	*generate_rr_extension_record	__PR((char *id,
78 							char *descriptor,
79 							char *source,
80 							int *size));
81 /*
82  * If we need to store this number of bytes, make sure we
83  * do not box ourselves in so that we do not have room for
84  * a CE entry for the continuation record
85  */
86 #define	RR_CUR_USE	(CE_SIZE + currlen + (ipnt - recstart))
87 
88 #define	MAYBE_ADD_CE_ENTRY(BYTES) \
89 	(((int)(BYTES)) + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
90 
91 /*
92  * Buffer to build RR attributes
93  */
94 LOCAL	Uchar	Rock[16384];
95 LOCAL	Uchar	symlink_buff[PATH_MAX+1];
96 LOCAL	int	ipnt = 0;	/* Current "write" offset in Rock[]	*/
97 LOCAL	int	recstart = 0;	/* Start offset in Rock[] for this area	*/
98 LOCAL	int	currlen = 0;	/* # of non RR bytes used in this area	*/
99 LOCAL	int	mainrec = 0;	/* # of RR bytes use in main dir area	*/
100 LOCAL	int	reclimit;	/* Max. # of bytes usable in this area	*/
101 
102 /* if we are using converted filenames, we don't want the '/' character */
103 LOCAL void
rstrncpy(t,f,tlen,inls,onls)104 rstrncpy(t, f, tlen, inls, onls)
105 	char	*t;
106 	char	*f;
107 	size_t	tlen;		/* The to-length */
108 	siconvt_t *inls;
109 	siconvt_t *onls;
110 {
111 	size_t	flen = strlen(f);
112 
113 	while (tlen > 0 && *f) {
114 		size_t	ofl = flen;
115 		size_t	otl = tlen;
116 
117 		conv_charset((Uchar *)t, &tlen, (Uchar *)f, &flen, inls, onls);
118 		if (*t == '/') {
119 			*t = '_';
120 		}
121 		t += otl - tlen;
122 		f += ofl - flen;
123 	}
124 }
125 
126 LOCAL void
add_CE_entry(field,line)127 add_CE_entry(field, line)
128 	char	*field;
129 	int	line;
130 {
131 	if (MAYBE_ADD_CE_ENTRY(0)) {
132 		errmsgno(EX_BAD,
133 		_("Panic: no space, cannot add RR CE entry (%d bytes mising) for %s line %d.\n"),
134 		(CE_SIZE + currlen + (ipnt - recstart) - reclimit),
135 		field, line);
136 		errmsgno(EX_BAD, _("currlen: %d ipnt: %d, recstart: %d\n"),
137 				currlen, ipnt, recstart);
138 		errmsgno(EX_BAD, _("Send  bug report to the maintainer.\n"));
139 		comerrno(EX_BAD, _("Aborting.\n"));
140 	}
141 
142 	if (recstart)
143 		set_733((char *)Rock + recstart - 8, ipnt + 28 - recstart);
144 	Rock[ipnt++] = 'C';
145 	Rock[ipnt++] = 'E';
146 	Rock[ipnt++] = CE_SIZE;
147 	Rock[ipnt++] = SU_VERSION;
148 	set_733((char *)Rock + ipnt, 0);
149 	ipnt += 8;
150 	set_733((char *)Rock + ipnt, 0);
151 	ipnt += 8;
152 	set_733((char *)Rock + ipnt, 0);
153 	ipnt += 8;
154 	recstart = ipnt;
155 	currlen = 0;
156 	if (!mainrec)
157 		mainrec = ipnt;
158 	reclimit = SECTOR_SIZE - 8;	/* Limit to one sector */
159 }
160 
161 #ifdef	PROTOTYPES
162 LOCAL int
gen_xa_attr(mode_t attr)163 gen_xa_attr(mode_t attr)
164 #else
165 LOCAL int
166 gen_xa_attr(attr)
167 	mode_t	attr;
168 #endif
169 {
170 	int	ret = 0;
171 
172 	if (attr & S_IRUSR)
173 		ret |= XA_O_READ;
174 	if (attr & S_IXUSR)
175 		ret |= XA_O_EXEC;
176 
177 	if (attr & S_IRGRP)
178 		ret |= XA_G_READ;
179 	if (attr & S_IXGRP)
180 		ret |= XA_G_EXEC;
181 
182 	if (attr & S_IROTH)
183 		ret |= XA_W_READ;
184 	if (attr & S_IXOTH)
185 		ret |= XA_W_EXEC;
186 
187 	ret |= XA_FORM1;
188 
189 	if (S_ISDIR(attr))
190 		ret |= XA_DIR;
191 
192 	return (ret);
193 }
194 
195 LOCAL void
gen_xa(lstatbuf)196 gen_xa(lstatbuf)
197 	struct stat	*lstatbuf;
198 {
199 		/*
200 		 * Group ID
201 		 */
202 		set_722((char *)Rock + ipnt, lstatbuf->st_gid);
203 		ipnt += 2;
204 		/*
205 		 * User ID
206 		 */
207 		set_722((char *)Rock + ipnt, lstatbuf->st_uid);
208 		ipnt += 2;
209 		/*
210 		 * Attributes
211 		 */
212 		set_722((char *)Rock + ipnt, gen_xa_attr(lstatbuf->st_mode));
213 		ipnt += 2;
214 
215 		Rock[ipnt++] = 'X';	/* XA Signature */
216 		Rock[ipnt++] = 'A';
217 		Rock[ipnt++] = 0;	/* File number (we always use '0' */
218 
219 		Rock[ipnt++] = 0;	/* Reserved (5 Byte) */
220 		Rock[ipnt++] = 0;
221 		Rock[ipnt++] = 0;
222 		Rock[ipnt++] = 0;
223 		Rock[ipnt++] = 0;
224 
225 }
226 
227 #ifdef PROTOTYPES
228 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)229 generate_xa_rr_attributes(char *whole_name, char *name,
230 			struct directory_entry *s_entry,
231 			struct stat *statbuf,
232 			struct stat *lstatbuf,
233 			int deep_opt)
234 #else
235 EXPORT int
236 generate_xa_rr_attributes(whole_name, name,
237 			s_entry,
238 			statbuf,
239 			lstatbuf,
240 			deep_opt)
241 	char		*whole_name;
242 	char		*name;
243 	struct directory_entry *s_entry;
244 	struct stat	*statbuf,
245 			*lstatbuf;
246 	int		deep_opt;
247 #endif
248 {
249 	int		flagpos;
250 	int		flagval;
251 	int		need_ce;
252 
253 	statbuf = statbuf;	/* this shuts up unreferenced compiler */
254 				/* warnings */
255 	mainrec = recstart = ipnt = 0;
256 
257 	if (use_XA) {
258 		gen_xa(lstatbuf);
259 	}
260 
261 /*	reclimit = 0xf8; XXX we now use 254 == 0xfe */
262 	reclimit = MAX_ISODIR;
263 
264 	/* no need to fill in the RR stuff if we won't see the file */
265 	if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
266 		return (0);
267 
268 	/*
269 	 * Obtain the amount of space that is currently used for the directory
270 	 * record.  We may safely use the current name length; because if name
271 	 * confilcts force us to change the ISO-9660 name later, the name will
272 	 * never become longer than now.
273 	 */
274 	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
275 		s_entry->isorec.name_len[0] = 1;
276 	} else {
277 		s_entry->isorec.name_len[0] = strlen(s_entry->isorec.name);
278 	}
279 	currlen = s_entry->isorec.length[0] = s_entry->isorec.name_len[0] +
280 				offsetof(struct iso_directory_record, name[0]);
281 	if (currlen & 1)
282 		s_entry->isorec.length[0] = ++currlen;
283 
284 	if (currlen < 33+37) {
285 		/*
286 		 * If the ISO-9660 name length is less than 37, we may use
287 		 * ISO-9660:1988 name rules and for this reason, the name len
288 		 * may later increase from adding e.g. ".;1"; in this case
289 		 * just use the upper limit.
290 		 */
291 		currlen = 33+37;
292 	}
293 
294 #ifdef APPLE_HYB
295 	/* if we have regular file, then add Apple extensions */
296 	if (S_ISREG(lstatbuf->st_mode) && apple_ext && s_entry->hfs_ent) {
297 		if (MAYBE_ADD_CE_ENTRY(AA_SIZE))
298 			add_CE_entry("AA", __LINE__);
299 		Rock[ipnt++] = 'A';	/* AppleSignature */
300 		Rock[ipnt++] = 'A';
301 		Rock[ipnt++] = AA_SIZE;	/* includes AppleSignature bytes */
302 		Rock[ipnt++] = 0x02;	/* SystemUseID */
303 		Rock[ipnt++] = s_entry->hfs_ent->u.file.type[0];
304 		Rock[ipnt++] = s_entry->hfs_ent->u.file.type[1];
305 		Rock[ipnt++] = s_entry->hfs_ent->u.file.type[2];
306 		Rock[ipnt++] = s_entry->hfs_ent->u.file.type[3];
307 		Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[0];
308 		Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[1];
309 		Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[2];
310 		Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[3];
311 		Rock[ipnt++] = (s_entry->hfs_ent->fdflags >> 8) & 0xff;
312 		Rock[ipnt++] = s_entry->hfs_ent->fdflags & 0xff;
313 	}
314 #endif	/* APPLE_HYB */
315 
316 	if (!use_RockRidge)
317 		goto xa_only;
318 
319 	/* Identify that we are using the SUSP protocol */
320 	if (deep_opt & NEED_SP) {
321 		/*
322 		 * We may not use a CE record here but we never will need to
323 		 * do so, as this SP record is only used for the "." entry
324 		 * of the root directory.
325 		 */
326 		Rock[ipnt++] = 'S';
327 		Rock[ipnt++] = 'P';
328 		Rock[ipnt++] = 7;
329 		Rock[ipnt++] = SU_VERSION;
330 		Rock[ipnt++] = 0xbe;
331 		Rock[ipnt++] = 0xef;
332 		if (use_XA)
333 			Rock[ipnt++] = sizeof (struct iso_xa_dir_record);
334 		else
335 			Rock[ipnt++] = 0;
336 	}
337 
338 	/* First build the posix name field */
339 	if (MAYBE_ADD_CE_ENTRY(RR_SIZE))
340 		add_CE_entry("RR", __LINE__);
341 	Rock[ipnt++] = 'R';
342 	Rock[ipnt++] = 'R';
343 	Rock[ipnt++] = 5;
344 	Rock[ipnt++] = SU_VERSION;
345 	flagpos = ipnt;
346 	flagval = 0;
347 	Rock[ipnt++] = 0;	/* We go back and fix this later */
348 
349 	if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0) {
350 		char		*npnt;
351 		int		remain;	/* Remaining name length  */
352 		int		use;	/* Current name part used */
353 
354 #ifdef APPLE_HYB
355 		/* use the HFS name if it exists */
356 		if (USE_MAC_NAME(s_entry)) {
357 			remain = strlen(s_entry->hfs_ent->name);
358 			npnt = s_entry->hfs_ent->name;
359 		} else {
360 #endif	/* APPLE_HYB */
361 
362 			remain = strlen(name);
363 			npnt = name;
364 #ifdef APPLE_HYB
365 		}
366 #endif	/* APPLE_HYB */
367 
368 		if (MAYBE_ADD_CE_ENTRY(NM_SIZE+1))
369 			add_CE_entry("NM", __LINE__);
370 		while (remain) {
371 			use = remain;
372 			need_ce = 0;
373 			/* Can we fit this SUSP and a CE entry? */
374 			if (MAYBE_ADD_CE_ENTRY(NM_SIZE+use)) {
375 				use = reclimit - NM_SIZE - RR_CUR_USE;
376 				need_ce++;
377 			}
378 			/* Only room for 256 per SUSP field */
379 			if (use > 0xf8) {
380 				use = 0xf8;
381 				need_ce++;
382 			}
383 			if (use < 0) {
384 				comerrno(EX_BAD,
385 				_("Negative RR name length residual: %d\n"),
386 					use);
387 			}
388 
389 			/* First build the posix name field */
390 			Rock[ipnt++] = 'N';
391 			Rock[ipnt++] = 'M';
392 			Rock[ipnt++] = NM_SIZE + use;
393 			Rock[ipnt++] = SU_VERSION;
394 			Rock[ipnt++] = (remain != use ? 1 : 0);
395 			flagval |= (1 << 3);
396 
397 			/*
398 			 * Convert charsets as required
399 			 * XXX If we are using iconv() based locales and in/out
400 			 * XXX locale differ, then strlen(&Rock[ipnt]) may
401 			 * XXX increase. We would need to compute the length
402 			 * XXX early enough.
403 			 */
404 #ifdef APPLE_HYB
405 			if (USE_MAC_NAME(s_entry))
406 				rstrncpy((char *)&Rock[ipnt], npnt, use,
407 							hfs_inls, out_nls);
408 			else
409 #endif	/* APPLE_HYB */
410 				rstrncpy((char *)&Rock[ipnt], npnt, use,
411 							in_nls, out_nls);
412 			npnt += use;
413 			ipnt += use;
414 			remain -= use;
415 			if (remain && need_ce)
416 				add_CE_entry("NM", __LINE__);
417 		}
418 	}
419 
420 	/* Add the posix modes */
421 	if (MAYBE_ADD_CE_ENTRY(PX_SIZE))
422 		add_CE_entry("PX", __LINE__);
423 	Rock[ipnt++] = 'P';
424 	Rock[ipnt++] = 'X';
425 	if (rrip112) {
426 		Rock[ipnt++] = PX_SIZE;
427 	} else {
428 		Rock[ipnt++] = PX_OLD_SIZE;
429 	}
430 	Rock[ipnt++] = SU_VERSION;
431 	flagval |= (1 << 0);
432 	set_733((char *)Rock + ipnt, lstatbuf->st_mode);
433 	ipnt += 8;
434 	set_733((char *)Rock + ipnt, lstatbuf->st_nlink);
435 	ipnt += 8;
436 	set_733((char *)Rock + ipnt, lstatbuf->st_uid);
437 	ipnt += 8;
438 	set_733((char *)Rock + ipnt, lstatbuf->st_gid);
439 	ipnt += 8;
440 	if (rrip112) {
441 		/*
442 		 * We will set up correct inode numbers later
443 		 * after we did assign them.
444 		 */
445 		set_733((char *)Rock + ipnt, 0);
446 		ipnt += 8;
447 	}
448 
449 	/* Check for special devices */
450 #if	defined(S_IFCHR) || defined(S_IFBLK)
451 	/*
452 	 * The code in this if statement used to be #ifdef'd with NON_UNIXFS.
453 	 * But as schily/stat.h always provides the macros S_ISCHR() & S_ISBLK()
454 	 * and schily/device.h always provides major()/minor() it is not needed
455 	 * anymore.
456 	 */
457 	if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
458 		if (MAYBE_ADD_CE_ENTRY(PN_SIZE))
459 			add_CE_entry("PN", __LINE__);
460 		Rock[ipnt++] = 'P';
461 		Rock[ipnt++] = 'N';
462 		Rock[ipnt++] = PN_SIZE;
463 		Rock[ipnt++] = SU_VERSION;
464 		flagval |= (1 << 1);
465 #if 1
466 		/* This is the new and only code which uses <schily/device.h> */
467 		set_733((char *)Rock + ipnt, major(lstatbuf->st_rdev));
468 		ipnt += 8;
469 		set_733((char *)Rock + ipnt, minor(lstatbuf->st_rdev));
470 		ipnt += 8;
471 #else
472 		/*
473 		 * If we don't have sysmacros.h, then we have to guess as to
474 		 * how best to pick apart the device number for major/minor.
475 		 * Note: this may very well be wrong for many systems, so it
476 		 * is always best to use the major/minor macros if the system
477 		 * supports it.
478 		 */
479 		if (sizeof (dev_t) <= 2) {
480 			set_733((char *)Rock + ipnt, (lstatbuf->st_rdev >> 8));
481 			ipnt += 8;
482 			set_733((char *)Rock + ipnt, lstatbuf->st_rdev & 0xff);
483 			ipnt += 8;
484 		} else if (sizeof (dev_t) <= 4) {
485 			set_733((char *)Rock + ipnt,
486 						(lstatbuf->st_rdev >> 8) >> 8);
487 			ipnt += 8;
488 			set_733((char *)Rock + ipnt,
489 						lstatbuf->st_rdev & 0xffff);
490 			ipnt += 8;
491 		} else {
492 			set_733((char *)Rock + ipnt,
493 						(lstatbuf->st_rdev >> 16)>>16);
494 			ipnt += 8;
495 			set_733((char *)Rock + ipnt, lstatbuf->st_rdev);
496 			ipnt += 8;
497 		}
498 #endif
499 	}
500 #endif	/* defined(S_IFCHR) || defined(S_IFBLK) */
501 
502 	/* Check for and symbolic links.  VMS does not have these. */
503 #ifdef S_IFLNK
504 	if (S_ISLNK(lstatbuf->st_mode)) {
505 		int		lenpos;
506 		int		lenval;
507 		int		j0;
508 		int		j1;
509 		int		nchar;
510 		Uchar		*cpnt;
511 		Uchar		*cpnt1;
512 		BOOL		last_sl = FALSE; /* Don't suppress last '/' */
513 
514 #ifdef	HAVE_READLINK
515 		nchar = readlink(deep_opt&DID_CHDIR?name:whole_name,
516 						(char *)symlink_buff,
517 						sizeof (symlink_buff)-1);
518 		if (nchar < 0)
519 			errmsg(_("Cannot read link '%s'.\n"), whole_name);
520 #else
521 		nchar = -1;
522 #endif	/* HAVE_READLINK */
523 		symlink_buff[nchar < 0 ? 0 : nchar] = 0;
524 		nchar = strlen((char *)symlink_buff);
525 		set_733(s_entry->isorec.size, 0);
526 		cpnt = &symlink_buff[0];
527 		flagval |= (1 << 2);
528 
529 		if (!split_SL_field) {
530 			int		sl_bytes = 0;
531 
532 			for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++) {
533 				if (*cpnt1 == '/') {
534 					sl_bytes += 4;
535 				} else {
536 					sl_bytes += 1;
537 				}
538 			}
539 			if (sl_bytes > 250) {
540 				/*
541 				 * the symbolic link won't fit into one
542 				 * SL System Use Field print an error message
543 				 * and continue with splited one
544 				 */
545 				fprintf(stderr,
546 				_("symbolic link ``%s'' to long for one SL System Use Field, splitting"),
547 								cpnt);
548 			}
549 			if (MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes))
550 				add_CE_entry("SL+", __LINE__);
551 		}
552 		while (nchar) {
553 			if (MAYBE_ADD_CE_ENTRY(SL_SIZE))
554 				add_CE_entry("SL", __LINE__);
555 			Rock[ipnt++] = 'S';
556 			Rock[ipnt++] = 'L';
557 			lenpos = ipnt;
558 			Rock[ipnt++] = SL_SIZE;
559 			Rock[ipnt++] = SU_VERSION;
560 			Rock[ipnt++] = 0;	/* Flags */
561 			lenval = 5;
562 			while (*cpnt || last_sl) {
563 				cpnt1 = (Uchar *)
564 						strchr((char *)cpnt, '/');
565 				if (cpnt1) {
566 					nchar--;
567 					*cpnt1 = 0;
568 				}
569 
570 				/*
571 				 * We treat certain components in a special
572 				 * way.
573 				 */
574 				if (cpnt[0] == '.' && cpnt[1] == '.' &&
575 								cpnt[2] == 0) {
576 					if (MAYBE_ADD_CE_ENTRY(2)) {
577 						add_CE_entry("SL-parent", __LINE__);
578 						if (cpnt1) {
579 							*cpnt1 = '/';
580 							nchar++;
581 							/*
582 							 * A kluge so that we
583 							 * can restart properly
584 							 */
585 							cpnt1 = NULL;
586 						}
587 						break;
588 					}
589 					Rock[ipnt++] = SL_PARENT;
590 					Rock[ipnt++] = 0; /* length is zero */
591 					lenval += 2;
592 					nchar -= 2;
593 				} else if (cpnt[0] == '.' && cpnt[1] == 0) {
594 					if (MAYBE_ADD_CE_ENTRY(2)) {
595 						add_CE_entry("SL-current", __LINE__);
596 						if (cpnt1) {
597 							*cpnt1 = '/';
598 							nchar++;
599 							/*
600 							 * A kluge so that we
601 							 * can restart properly
602 							 */
603 							cpnt1 = NULL;
604 						}
605 						break;
606 					}
607 					Rock[ipnt++] = SL_CURRENT;
608 					Rock[ipnt++] = 0; /* length is zero */
609 					lenval += 2;
610 					nchar -= 1;
611 				} else if (cpnt[0] == 0) {
612 					if (MAYBE_ADD_CE_ENTRY(2)) {
613 						add_CE_entry("SL-root", __LINE__);
614 						if (cpnt1) {
615 							*cpnt1 = '/';
616 							nchar++;
617 							/*
618 							 * A kluge so that we
619 							 * can restart properly
620 							 */
621 							cpnt1 = NULL;
622 						}
623 						break;
624 					}
625 					if (cpnt == &symlink_buff[0])
626 						Rock[ipnt++] = SL_ROOT;
627 					else
628 						Rock[ipnt++] = 0;
629 					Rock[ipnt++] = 0; /* length is zero */
630 					lenval += 2;
631 				} else {
632 					/*
633 					 * If we do not have enough room for a
634 					 * component, start a new continuations
635 					 * segment now
636 					 */
637 					if (split_SL_component ?
638 						MAYBE_ADD_CE_ENTRY(6) :
639 						MAYBE_ADD_CE_ENTRY(6 + strlen((char *)cpnt))) {
640 						add_CE_entry("SL++", __LINE__);
641 						if (cpnt1) {
642 							*cpnt1 = '/';
643 							nchar++;
644 							/*
645 							 * A kluge so that we
646 							 * can restart properly
647 							 */
648 							cpnt1 = NULL;
649 						}
650 						break;
651 					}
652 					j0 = strlen((char *)cpnt);
653 					while (j0) {
654 						j1 = j0;
655 						if (j1 > 0xf8)
656 							j1 = 0xf8;
657 						need_ce = 0;
658 						if (j1 + currlen + 2 + CE_SIZE +
659 						    (ipnt - recstart) >
660 								reclimit) {
661 
662 							j1 = reclimit -
663 							    (currlen + 2) -
664 							    CE_SIZE -
665 							    (ipnt - recstart);
666 							need_ce++;
667 						}
668 						Rock[ipnt++] =
669 							(j1 != j0 ?
670 							SL_CONTINUE : 0);
671 						Rock[ipnt++] = j1;
672 						strncpy((char *)Rock + ipnt,
673 							(char *)cpnt, j1);
674 						ipnt += j1;
675 						lenval += j1 + 2;
676 						cpnt += j1;
677 						/*
678 						 * Number we processed
679 						 * this time
680 						 */
681 						nchar -= j1;
682 						j0 -= j1;
683 						if (need_ce) {
684 							add_CE_entry(
685 							    "SL-path-split",
686 							    __LINE__);
687 							if (cpnt1) {
688 								*cpnt1 = '/';
689 								nchar++;
690 								/*
691 								 * A kluge so
692 								 * that we can
693 								 * restart
694 								 * properly
695 								 */
696 								cpnt1 = NULL;
697 							}
698 							break;
699 						}
700 					}
701 				}
702 				if (cpnt1) {
703 					*cpnt1 = '/';
704 					if (cpnt1 > symlink_buff && !last_sl &&
705 					    cpnt1[1] == '\0') {
706 						last_sl = TRUE;
707 					}
708 					cpnt = cpnt1 + 1;
709 				} else
710 					break;
711 			}
712 			Rock[lenpos] = lenval;
713 			if (nchar) {
714 				/* We need another SL entry */
715 				Rock[lenpos + 2] = SL_CONTINUE;
716 			}
717 		}	/* while nchar */
718 	}	/* Is a symbolic link */
719 #endif	/* S_IFLNK */
720 
721 	/* Add in the Rock Ridge TF time field */
722 	if (MAYBE_ADD_CE_ENTRY(long_rr_time ? TF_SIZE_LONG:TF_SIZE))
723 		add_CE_entry("TF", __LINE__);
724 	Rock[ipnt++] = 'T';
725 	Rock[ipnt++] = 'F';
726 	Rock[ipnt++] = long_rr_time ? TF_SIZE_LONG:TF_SIZE;
727 	Rock[ipnt++] = SU_VERSION;
728 #if defined(__QNX__) && !defined(__QNXNTO__)	/* Not on Neutrino! never OK? */
729 	Rock[ipnt++] = long_rr_time ? 0x8f:0x0f;
730 #else
731 	Rock[ipnt++] = long_rr_time ? 0x8e:0x0e;
732 #endif
733 	flagval |= (1 << 7);
734 
735 #if defined(__QNX__) && !defined(__QNXNTO__)	/* Not on Neutrino! never OK? */
736 	if (long_rr_time) {
737 		iso9660_date((char *)&Rock[ipnt], lstatbuf->st_ftime);
738 		ipnt += 7;
739 	} else {
740 		/*
741 		 * XXX Do we have nanoseconds on QNX?
742 		 */
743 		iso9660_ldate((char *)&Rock[ipnt], lstatbuf->st_ftime, 0, -100);
744 		ipnt += 17;
745 	}
746 #endif
747 	if (long_rr_time) {
748 		iso9660_ldate((char *)&Rock[ipnt],
749 				lstatbuf->st_mtime, stat_mnsecs(lstatbuf), -100);
750 		ipnt += 17;
751 		iso9660_ldate((char *)&Rock[ipnt],
752 				lstatbuf->st_atime, stat_ansecs(lstatbuf), -100);
753 		ipnt += 17;
754 		iso9660_ldate((char *)&Rock[ipnt],
755 				lstatbuf->st_ctime, stat_cnsecs(lstatbuf), -100);
756 		ipnt += 17;
757 	} else {
758 		iso9660_date((char *)&Rock[ipnt], lstatbuf->st_mtime);
759 		ipnt += 7;
760 		iso9660_date((char *)&Rock[ipnt], lstatbuf->st_atime);
761 		ipnt += 7;
762 		iso9660_date((char *)&Rock[ipnt], lstatbuf->st_ctime);
763 		ipnt += 7;
764 	}
765 
766 	/* Add in the Rock Ridge RE (relocated dir) field */
767 	if (deep_opt & NEED_RE) {
768 		if (MAYBE_ADD_CE_ENTRY(RE_SIZE))
769 			add_CE_entry("RE", __LINE__);
770 		Rock[ipnt++] = 'R';
771 		Rock[ipnt++] = 'E';
772 		Rock[ipnt++] = RE_SIZE;
773 		Rock[ipnt++] = SU_VERSION;
774 		flagval |= (1 << 6);
775 	}
776 	/* Add in the Rock Ridge PL record, if required. */
777 	if (deep_opt & NEED_PL) {
778 		if (MAYBE_ADD_CE_ENTRY(PL_SIZE))
779 			add_CE_entry("PL", __LINE__);
780 		Rock[ipnt++] = 'P';
781 		Rock[ipnt++] = 'L';
782 		Rock[ipnt++] = PL_SIZE;
783 		Rock[ipnt++] = SU_VERSION;
784 		set_733((char *)Rock + ipnt, 0);
785 		ipnt += 8;
786 		flagval |= (1 << 5);
787 	}
788 
789 	/* Add in the Rock Ridge CL field, if required. */
790 	if (deep_opt & NEED_CL) {
791 		if (MAYBE_ADD_CE_ENTRY(CL_SIZE))
792 			add_CE_entry("CL", __LINE__);
793 		Rock[ipnt++] = 'C';
794 		Rock[ipnt++] = 'L';
795 		Rock[ipnt++] = CL_SIZE;
796 		Rock[ipnt++] = SU_VERSION;
797 		set_733((char *)Rock + ipnt, 0);
798 		ipnt += 8;
799 		flagval |= (1 << 4);
800 	}
801 
802 #ifndef VMS
803 	/*
804 	 * If transparent compression was requested, fill in the correct field
805 	 * for this file, if (and only if) it is actually a compressed file!
806 	 * This relies only on magic number, but it should in general not
807 	 * be an issue since if you're using -z odds are most of your
808 	 * files are already compressed.
809 	 *
810 	 * In the future it would be nice if mkisofs actually did the
811 	 * compression.
812 	 */
813 	if (transparent_compression && S_ISREG(lstatbuf->st_mode)) {
814 		static const Uchar zisofs_magic[8] =
815 			{ 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07 };
816 		FILE		*zffile;
817 		unsigned int	file_size;
818 		Uchar		header[16];
819 		int		OK_flag;
820 		int		blocksize;
821 		int		headersize;
822 
823 		/*
824 		 * First open file and verify that the correct algorithm was
825 		 * used
826 		 */
827 		file_size = 0;
828 		OK_flag = 1;
829 
830 		memset(header, 0, sizeof (header));
831 
832 		zffile = fopen(whole_name, "rb");
833 		if (zffile != NULL) {
834 			if (fread(header, 1, sizeof (header), zffile) != sizeof (header))
835 				OK_flag = 0;
836 
837 			/* Check magic number */
838 			if (memcmp(header, zisofs_magic, sizeof (zisofs_magic)))
839 				OK_flag = 0;
840 
841 			/* Get the real size of the file */
842 			file_size = get_731((char *)header+8);
843 
844 			/* Get the header size (>> 2) */
845 			headersize = header[12];
846 
847 			/* Get the block size (log2) */
848 			blocksize = header[13];
849 
850 			fclose(zffile);
851 		} else {
852 			OK_flag = 0;
853 			blocksize = headersize = 0; /* Make silly GCC quiet */
854 		}
855 
856 		if (OK_flag) {
857 			if (MAYBE_ADD_CE_ENTRY(ZF_SIZE))
858 				add_CE_entry("ZF", __LINE__);
859 			Rock[ipnt++] = 'Z';
860 			Rock[ipnt++] = 'F';
861 			Rock[ipnt++] = ZF_SIZE;
862 			Rock[ipnt++] = SU_VERSION;
863 			Rock[ipnt++] = 'p'; /* Algorithm: "paged zlib" */
864 			Rock[ipnt++] = 'z';
865 			/* 2 bytes for algorithm-specific information */
866 			Rock[ipnt++] = headersize;
867 			Rock[ipnt++] = blocksize;
868 			set_733((char *)Rock + ipnt, file_size); /* Real file size */
869 			ipnt += 8;
870 		}
871 	}
872 #endif
873 	/*
874 	 * Add in the Rock Ridge CE field, if required.  We use  this for the
875 	 * extension record that is stored in the root directory.
876 	 */
877 	if (deep_opt & NEED_CE)
878 		add_CE_entry("ER", __LINE__);
879 
880 	/*
881 	 * Done filling in all of the fields.  Now copy it back to a buffer
882 	 * for the file in question.
883 	 */
884 	/* Now copy this back to the buffer for the file */
885 	Rock[flagpos] = flagval;
886 
887 	/* If there was a CE, fill in the size field */
888 	if (recstart)
889 		set_733((char *)Rock + recstart - 8, ipnt - recstart);
890 
891 xa_only:
892 	s_entry->rr_attributes = (Uchar *) e_malloc(ipnt);
893 	s_entry->total_rr_attr_size = ipnt;
894 	s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
895 	memcpy(s_entry->rr_attributes, Rock, ipnt);
896 	return (ipnt);
897 }
898 
899 /*
900  * Guaranteed to  return a single sector with the relevant info
901  */
902 EXPORT char *
generate_rr_extension_record(id,descriptor,source,size)903 generate_rr_extension_record(id, descriptor, source, size)
904 	char	*id;
905 	char	*descriptor;
906 	char	*source;
907 	int	*size;
908 {
909 	int		lipnt = 0;
910 	char		*pnt;
911 	int		len_id;
912 	int		len_des;
913 	int		len_src;
914 
915 	len_id = strlen(id);
916 	len_des = strlen(descriptor);
917 	len_src = strlen(source);
918 	Rock[lipnt++] = 'E';
919 	Rock[lipnt++] = 'R';
920 	Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src;
921 	Rock[lipnt++] = 1;
922 	Rock[lipnt++] = len_id;
923 	Rock[lipnt++] = len_des;
924 	Rock[lipnt++] = len_src;
925 	Rock[lipnt++] = 1;
926 
927 	memcpy(Rock + lipnt, id, len_id);
928 	lipnt += len_id;
929 
930 	memcpy(Rock + lipnt, descriptor, len_des);
931 	lipnt += len_des;
932 
933 	memcpy(Rock + lipnt, source, len_src);
934 	lipnt += len_src;
935 
936 	if (lipnt > SECTOR_SIZE) {
937 		comerrno(EX_BAD, _("Extension record too long\n"));
938 	}
939 	pnt = (char *)e_malloc(SECTOR_SIZE);
940 	memset(pnt, 0, SECTOR_SIZE);
941 	memcpy(pnt, Rock, lipnt);
942 	*size = lipnt;
943 	return (pnt);
944 }
945