xref: /freebsd/usr.sbin/makefs/cd9660.c (revision 1f31d437428014e864bcce1223cf7017180e2608)
1  /*	$NetBSD: cd9660.c,v 1.56 2019/10/18 04:09:02 msaitoh Exp $	*/
2  
3  /*-
4   * SPDX-License-Identifier: BSD-2-Clause AND BSD-4-Clause
5   *
6   * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
7   * Perez-Rathke and Ram Vedam.  All rights reserved.
8   *
9   * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
10   * Alan Perez-Rathke and Ram Vedam.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   * 1. Redistributions of source code must retain the above copyright
16   *    notice, this list of conditions and the following disclaimer.
17   * 2. Redistributions in binary form must reproduce the above
18   *    copyright notice, this list of conditions and the following
19   *    disclaimer in the documentation and/or other materials provided
20   *    with the distribution.
21   *
22   * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
23   * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
24   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26   * DISCLAIMED.  IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
27   * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
28   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30   * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34   * OF SUCH DAMAGE.
35   */
36  /*
37   * Copyright (c) 2001 Wasabi Systems, Inc.
38   * All rights reserved.
39   *
40   * Written by Luke Mewburn for Wasabi Systems, Inc.
41   *
42   * Redistribution and use in source and binary forms, with or without
43   * modification, are permitted provided that the following conditions
44   * are met:
45   * 1. Redistributions of source code must retain the above copyright
46   *    notice, this list of conditions and the following disclaimer.
47   * 2. Redistributions in binary form must reproduce the above copyright
48   *    notice, this list of conditions and the following disclaimer in the
49   *    documentation and/or other materials provided with the distribution.
50   * 3. All advertising materials mentioning features or use of this software
51   *    must display the following acknowledgement:
52   *      This product includes software developed for the NetBSD Project by
53   *      Wasabi Systems, Inc.
54   * 4. The name of Wasabi Systems, Inc. may not be used to endorse
55   *    or promote products derived from this software without specific prior
56   *    written permission.
57   *
58   * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
59   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
60   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
61   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
62   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
63   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
64   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
65   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
66   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
67   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
68   * POSSIBILITY OF SUCH DAMAGE.
69   */
70  /*
71   * Copyright (c) 1982, 1986, 1989, 1993
72   *	The Regents of the University of California.  All rights reserved.
73   *
74   * Redistribution and use in source and binary forms, with or without
75   * modification, are permitted provided that the following conditions
76   * are met:
77   * 1. Redistributions of source code must retain the above copyright
78   *    notice, this list of conditions and the following disclaimer.
79   * 2. Redistributions in binary form must reproduce the above copyright
80   *    notice, this list of conditions and the following disclaimer in the
81   *    documentation and/or other materials provided with the distribution.
82   * 3. Neither the name of the University nor the names of its contributors
83   *    may be used to endorse or promote products derived from this software
84   *    without specific prior written permission.
85   *
86   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
87   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
88   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
89   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
90   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
91   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
92   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
93   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
94   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
95   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
96   * SUCH DAMAGE.
97   *
98    */
99  
100  #include <sys/param.h>
101  #include <sys/queue.h>
102  #include <ctype.h>
103  #include <stdlib.h>
104  #include <string.h>
105  #include <util.h>
106  
107  #include "makefs.h"
108  #include "cd9660.h"
109  #include "cd9660/iso9660_rrip.h"
110  
111  static void cd9660_finalize_PVD(iso9660_disk *);
112  static cd9660node *cd9660_allocate_cd9660node(void);
113  static void cd9660_set_defaults(iso9660_disk *);
114  static int cd9660_arguments_set_string(const char *, const char *, size_t,
115      char, char *);
116  static void cd9660_populate_iso_dir_record(
117      struct _iso_directory_record_cd9660 *, u_char, u_char, u_char,
118      const char *);
119  static void cd9660_setup_root_node(iso9660_disk *);
120  static int cd9660_setup_volume_descriptors(iso9660_disk *);
121  #if 0
122  static int cd9660_fill_extended_attribute_record(cd9660node *);
123  #endif
124  static void cd9660_sort_nodes(cd9660node *);
125  static int cd9660_translate_node_common(iso9660_disk *, cd9660node *);
126  static int cd9660_translate_node(iso9660_disk *, fsnode *, cd9660node *);
127  static int cd9660_compare_filename(const char *, const char *);
128  static void cd9660_sorted_child_insert(cd9660node *, cd9660node *);
129  static int cd9660_handle_collisions(iso9660_disk *, cd9660node *, int);
130  static cd9660node *cd9660_rename_filename(iso9660_disk *, cd9660node *, int,
131      int);
132  static void cd9660_copy_filenames(iso9660_disk *, cd9660node *);
133  static void cd9660_sorting_nodes(cd9660node *);
134  static int cd9660_count_collisions(cd9660node *);
135  static cd9660node *cd9660_rrip_move_directory(iso9660_disk *, cd9660node *);
136  static int cd9660_add_dot_records(iso9660_disk *, cd9660node *);
137  
138  static void cd9660_convert_structure(iso9660_disk *, fsnode *, cd9660node *, int,
139      int *, int *);
140  static void cd9660_free_structure(cd9660node *);
141  static int cd9660_generate_path_table(iso9660_disk *);
142  static int cd9660_level1_convert_filename(iso9660_disk *, const char *, char *,
143      size_t, int);
144  static int cd9660_level2_convert_filename(iso9660_disk *, const char *, char *,
145      size_t, int);
146  static int cd9660_convert_filename(iso9660_disk *, const char *, char *, size_t,
147      int);
148  static void cd9660_populate_dot_records(iso9660_disk *, cd9660node *);
149  static int64_t cd9660_compute_offsets(iso9660_disk *, cd9660node *, int64_t);
150  #if 0
151  static int cd9660_copy_stat_info(cd9660node *, cd9660node *, int);
152  #endif
153  static cd9660node *cd9660_create_virtual_entry(iso9660_disk *, const char *,
154      cd9660node *, int, int);
155  static cd9660node *cd9660_create_file(iso9660_disk *, const char *,
156      cd9660node *, cd9660node *);
157  static cd9660node *cd9660_create_directory(iso9660_disk *, const char *,
158      cd9660node *, cd9660node *);
159  static cd9660node *cd9660_create_special_directory(iso9660_disk *, u_char,
160      cd9660node *);
161  static int  cd9660_add_generic_bootimage(iso9660_disk *, const char *);
162  
163  
164  /*
165   * Allocate and initialize a cd9660node
166   * @returns struct cd9660node * Pointer to new node, or NULL on error
167   */
168  static cd9660node *
cd9660_allocate_cd9660node(void)169  cd9660_allocate_cd9660node(void)
170  {
171  	cd9660node *temp = ecalloc(1, sizeof(*temp));
172  
173  	TAILQ_INIT(&temp->cn_children);
174  	temp->parent = temp->dot_record = temp->dot_dot_record = NULL;
175  	temp->ptnext = temp->ptprev = temp->ptlast = NULL;
176  	temp->node = NULL;
177  	temp->isoDirRecord = NULL;
178  	temp->isoExtAttributes = NULL;
179  	temp->rr_real_parent = temp->rr_relocated = NULL;
180  	temp->su_tail_data = NULL;
181  	return temp;
182  }
183  
184  /**
185  * Set default values for cd9660 extension to makefs
186  */
187  static void
cd9660_set_defaults(iso9660_disk * diskStructure)188  cd9660_set_defaults(iso9660_disk *diskStructure)
189  {
190  	/*Fix the sector size for now, though the spec allows for other sizes*/
191  	diskStructure->sectorSize = 2048;
192  
193  	/* Set up defaults in our own structure */
194  	diskStructure->verbose_level = 0;
195  	diskStructure->keep_bad_images = 0;
196  	diskStructure->isoLevel = 2;
197  
198  	diskStructure->rock_ridge_enabled = 0;
199  	diskStructure->rock_ridge_renamed_dir_name = 0;
200  	diskStructure->rock_ridge_move_count = 0;
201  	diskStructure->rr_moved_dir = 0;
202  
203  	diskStructure->chrp_boot = 0;
204  
205  	diskStructure->include_padding_areas = 1;
206  
207  	/* Spec breaking functionality */
208  	diskStructure->allow_deep_trees =
209  	    diskStructure->allow_start_dot =
210  	    diskStructure->allow_max_name =
211  	    diskStructure->allow_illegal_chars =
212  	    diskStructure->allow_lowercase =
213  	    diskStructure->allow_multidot =
214  	    diskStructure->omit_trailing_period = 0;
215  
216  	/* Make sure the PVD is clear */
217  	memset(&diskStructure->primaryDescriptor, 0, 2048);
218  
219  	memset(diskStructure->primaryDescriptor.publisher_id,	0x20,128);
220  	memset(diskStructure->primaryDescriptor.preparer_id,	0x20,128);
221  	memset(diskStructure->primaryDescriptor.application_id,	0x20,128);
222  	memset(diskStructure->primaryDescriptor.copyright_file_id, 0x20,37);
223  	memset(diskStructure->primaryDescriptor.abstract_file_id, 0x20,37);
224  	memset(diskStructure->primaryDescriptor.bibliographic_file_id, 0x20,37);
225  
226  	strlcpy(diskStructure->primaryDescriptor.system_id, "FreeBSD",
227  	    sizeof(diskStructure->primaryDescriptor.system_id));
228  
229  	/* Boot support: Initially disabled */
230  	diskStructure->has_generic_bootimage = 0;
231  	diskStructure->generic_bootimage = NULL;
232  
233  	diskStructure->boot_image_directory = 0;
234  	/*memset(diskStructure->boot_descriptor, 0, 2048);*/
235  
236  	diskStructure->is_bootable = 0;
237  	TAILQ_INIT(&diskStructure->boot_images);
238  	LIST_INIT(&diskStructure->boot_entries);
239  }
240  
241  void
cd9660_prep_opts(fsinfo_t * fsopts)242  cd9660_prep_opts(fsinfo_t *fsopts)
243  {
244  	iso9660_disk *diskStructure = ecalloc(1, sizeof(*diskStructure));
245  
246  #define OPT_STR(letter, name, desc) \
247  	{ letter, name, NULL, OPT_STRBUF, 0, 0, desc }
248  
249  #define OPT_NUM(letter, name, field, min, max, desc) \
250  	{ letter, name, &diskStructure->field, \
251  	  sizeof(diskStructure->field) == 8 ? OPT_INT64 : \
252  	  (sizeof(diskStructure->field) == 4 ? OPT_INT32 : \
253  	  (sizeof(diskStructure->field) == 2 ? OPT_INT16 : OPT_INT8)), \
254  	  min, max, desc }
255  
256  #define OPT_BOOL(letter, name, field, desc) \
257  	OPT_NUM(letter, name, field, 0, 1, desc)
258  
259  	const option_t cd9660_options[] = {
260  		OPT_NUM('l', "isolevel", isoLevel,
261  		    1, 2, "ISO Level"),
262  		OPT_NUM('v', "verbose", verbose_level,
263  		    0, 2, "Turns on verbose output"),
264  
265  		OPT_BOOL('R', "rockridge", rock_ridge_enabled,
266  		    "Enable Rock-Ridge extensions"),
267  		OPT_BOOL('C', "chrp-boot", chrp_boot,
268  		    "Enable CHRP boot"),
269  		OPT_BOOL('K', "keep-bad-images", keep_bad_images,
270  		    "Keep bad images"),
271  		OPT_BOOL('D', "allow-deep-trees", allow_deep_trees,
272  		    "Allow trees more than 8 levels"),
273  		OPT_BOOL('a', "allow-max-name", allow_max_name,
274  		    "Allow 37 char filenames (unimplemented)"),
275  		OPT_BOOL('i', "allow-illegal-chars", allow_illegal_chars,
276  		    "Allow illegal characters in filenames"),
277  		OPT_BOOL('m', "allow-multidot", allow_multidot,
278  		    "Allow multiple periods in filenames"),
279  		OPT_BOOL('o', "omit-trailing-period", omit_trailing_period,
280  		    "Omit trailing periods in filenames"),
281  		OPT_BOOL('\0', "allow-lowercase", allow_lowercase,
282  		    "Allow lowercase characters in filenames"),
283  		OPT_BOOL('\0', "no-trailing-padding", include_padding_areas,
284  		    "Include padding areas"),
285  
286  		OPT_STR('A', "applicationid", "Application Identifier"),
287  		OPT_STR('P', "publisher", "Publisher Identifier"),
288  		OPT_STR('p', "preparer", "Preparer Identifier"),
289  		OPT_STR('L', "label", "Disk Label"),
290  		OPT_STR('V', "volumeid", "Volume Set Identifier"),
291  		OPT_STR('B', "bootimage", "Boot image parameter"),
292  		OPT_STR('G', "generic-bootimage", "Generic boot image param"),
293  		OPT_STR('\0', "bootimagedir", "Boot image directory"),
294  		OPT_STR('\0', "no-emul-boot", "No boot emulation"),
295  		OPT_STR('\0', "no-boot", "No boot support"),
296  		OPT_STR('\0', "hard-disk-boot", "Boot from hard disk"),
297  		OPT_STR('\0', "boot-load-segment", "Boot load segment"),
298  		OPT_STR('\0', "platformid", "Section Header Platform ID"),
299  
300  		{ .name = NULL }
301  	};
302  
303  	fsopts->fs_specific = diskStructure;
304  	fsopts->fs_options = copy_opts(cd9660_options);
305  
306  	cd9660_set_defaults(diskStructure);
307  }
308  
309  void
cd9660_cleanup_opts(fsinfo_t * fsopts)310  cd9660_cleanup_opts(fsinfo_t *fsopts)
311  {
312  	free(fsopts->fs_specific);
313  	free(fsopts->fs_options);
314  }
315  
316  static int
cd9660_arguments_set_string(const char * val,const char * fieldtitle,size_t length,char testmode,char * dest)317  cd9660_arguments_set_string(const char *val, const char *fieldtitle,
318      size_t length, char testmode, char *dest)
319  {
320  	size_t len;
321  	int test;
322  
323  	if (val == NULL)
324  		warnx("error: '%s' requires a string argument", fieldtitle);
325  	else if ((len = strlen(val)) <= length) {
326  		if (testmode == 'd')
327  			test = cd9660_valid_d_chars(val);
328  		else
329  			test = cd9660_valid_a_chars(val);
330  		if (test) {
331  			memcpy(dest, val, len);
332  			if (test == 2)
333  				cd9660_uppercase_characters(dest, len);
334  			return 1;
335  		} else
336  			warnx("error: '%s' must be composed of %c-characters",
337  			    fieldtitle, testmode);
338  	} else
339  		warnx("error: '%s' must be at most 32 characters long",
340  		    fieldtitle);
341  	return 0;
342  }
343  
344  /*
345   * Command-line parsing function
346   */
347  
348  int
cd9660_parse_opts(const char * option,fsinfo_t * fsopts)349  cd9660_parse_opts(const char *option, fsinfo_t *fsopts)
350  {
351  	int	rv, i;
352  	iso9660_disk *diskStructure = fsopts->fs_specific;
353  	option_t *cd9660_options = fsopts->fs_options;
354  	char buf[1024];
355  	const char *name, *desc;
356  
357  	assert(option != NULL);
358  
359  	if (debug & DEBUG_FS_PARSE_OPTS)
360  		printf("%s: got `%s'\n", __func__, option);
361  
362  	i = set_option(cd9660_options, option, buf, sizeof(buf));
363  	if (i == -1)
364  		return 0;
365  
366  	if (cd9660_options[i].name == NULL)
367  		abort();
368  
369  	name = cd9660_options[i].name;
370  	desc = cd9660_options[i].desc;
371  	switch (cd9660_options[i].letter) {
372  	case 'h':
373  	case 'S':
374  		rv = 0; /* this is not handled yet */
375  		break;
376  	case 'L':
377  		rv = cd9660_arguments_set_string(buf, desc, 32, 'd',
378  		    diskStructure->primaryDescriptor.volume_id);
379  		break;
380  	case 'A':
381  		rv = cd9660_arguments_set_string(buf, desc, 128, 'a',
382  		    diskStructure->primaryDescriptor.application_id);
383  		break;
384  	case 'P':
385  		rv = cd9660_arguments_set_string(buf, desc, 128, 'a',
386  		    diskStructure->primaryDescriptor.publisher_id);
387  		break;
388  	case 'p':
389  		rv = cd9660_arguments_set_string(buf, desc, 128, 'a',
390  		    diskStructure->primaryDescriptor.preparer_id);
391  		break;
392  	case 'V':
393  		rv = cd9660_arguments_set_string(buf, desc, 128, 'a',
394  		    diskStructure->primaryDescriptor.volume_set_id);
395  		break;
396  	/* Boot options */
397  	case 'B':
398  		if (buf[0] == '\0') {
399  			warnx("The Boot Image parameter requires a valid boot"
400  			    "information string");
401  			rv = 0;
402  		} else
403  			rv = cd9660_add_boot_disk(diskStructure, buf);
404  		break;
405  	case 'G':
406  		if (buf[0] == '\0') {
407  			warnx("The Generic Boot Image parameter requires a"
408  			    " valid boot information string");
409  			rv = 0;
410  		} else
411  			rv = cd9660_add_generic_bootimage(diskStructure, buf);
412  		break;
413  	default:
414  		if (strcmp(name, "bootimagedir") == 0) {
415  			/*
416  			 * XXXfvdl this is unused.
417  			 */
418  			if (buf[0] == '\0') {
419  				warnx("The Boot Image Directory parameter"
420  				    " requires a directory name");
421  				rv = 0;
422  			} else {
423  				diskStructure->boot_image_directory =
424  				    emalloc(strlen(buf) + 1);
425  				/* BIG TODO: Add the max length function here */
426  				rv = cd9660_arguments_set_string(buf, desc, 12,
427  				    'd', diskStructure->boot_image_directory);
428  			}
429  		} else if (strcmp(name, "no-emul-boot") == 0 ||
430  		    strcmp(name, "no-boot") == 0 ||
431  		    strcmp(name, "hard-disk-boot") == 0) {
432  			/* RRIP */
433  			cd9660_eltorito_add_boot_option(diskStructure, name, 0);
434  			rv = 1;
435  		} else if (strcmp(name, "boot-load-segment") == 0 ||
436  		    strcmp(name, "platformid") == 0) {
437  			if (buf[0] == '\0') {
438  				warnx("Option `%s' doesn't contain a value",
439  				    name);
440  				rv = 0;
441  			} else {
442  				cd9660_eltorito_add_boot_option(diskStructure,
443  				    name, buf);
444  				rv = 1;
445  			}
446  		} else
447  			rv = 1;
448  	}
449  	return rv;
450  }
451  
452  /*
453   * Main function for cd9660_makefs
454   * Builds the ISO image file
455   * @param const char *image The image filename to create
456   * @param const char *dir The directory that is being read
457   * @param struct fsnode *root The root node of the filesystem tree
458   * @param struct fsinfo_t *fsopts Any options
459   */
460  void
cd9660_makefs(const char * image,const char * dir,fsnode * root,fsinfo_t * fsopts)461  cd9660_makefs(const char *image, const char *dir, fsnode *root,
462      fsinfo_t *fsopts)
463  {
464  	int64_t startoffset;
465  	int ret, numDirectories;
466  	uint64_t pathTableSectors;
467  	int64_t firstAvailableSector;
468  	int64_t totalSpace;
469  	int error;
470  	cd9660node *real_root;
471  	iso9660_disk *diskStructure = fsopts->fs_specific;
472  
473  	if (diskStructure->verbose_level > 0)
474  		printf("%s: ISO level is %i\n", __func__,
475  		    diskStructure->isoLevel);
476  	if (diskStructure->isoLevel < 2 &&
477  	    diskStructure->allow_multidot)
478  		errx(EXIT_FAILURE, "allow-multidot requires iso level of 2");
479  
480  	assert(image != NULL);
481  	assert(dir != NULL);
482  	assert(root != NULL);
483  
484  	if (diskStructure->verbose_level > 0)
485  		printf("%s: image %s directory %s root %p\n", __func__,
486  		    image, dir, root);
487  
488  	/* Set up some constants. Later, these will be defined with options */
489  
490  	/* Counter needed for path tables */
491  	numDirectories = 0;
492  
493  	/* Convert tree to our own format */
494  	/* Actually, we now need to add the REAL root node, at level 0 */
495  
496  	real_root = cd9660_allocate_cd9660node();
497  	real_root->isoDirRecord = emalloc(sizeof(*real_root->isoDirRecord));
498  	/* Leave filename blank for root */
499  	memset(real_root->isoDirRecord->name, 0,
500  	    sizeof(real_root->isoDirRecord->name));
501  
502  	real_root->level = 0;
503  	diskStructure->rootNode = real_root;
504  	real_root->type = CD9660_TYPE_DIR;
505  	error = 0;
506  	real_root->node = root;
507  	cd9660_convert_structure(diskStructure, root, real_root, 1,
508  	    &numDirectories, &error);
509  
510  	if (TAILQ_EMPTY(&real_root->cn_children)) {
511  		errx(EXIT_FAILURE, "%s: converted directory is empty. "
512  		    "Tree conversion failed", __func__);
513  	} else if (error != 0) {
514  		errx(EXIT_FAILURE, "%s: tree conversion failed", __func__);
515  	} else {
516  		if (diskStructure->verbose_level > 0)
517  			printf("%s: tree converted\n", __func__);
518  	}
519  
520  	/* Add the dot and dot dot records */
521  	cd9660_add_dot_records(diskStructure, real_root);
522  
523  	cd9660_setup_root_node(diskStructure);
524  
525  	if (diskStructure->verbose_level > 0)
526  		printf("%s: done converting tree\n", __func__);
527  
528  	/* Rock ridge / SUSP init pass */
529  	if (diskStructure->rock_ridge_enabled) {
530  		cd9660_susp_initialize(diskStructure, diskStructure->rootNode,
531  		    diskStructure->rootNode, NULL);
532  	}
533  
534  	/* Build path table structure */
535  	diskStructure->pathTableLength = cd9660_generate_path_table(
536  	    diskStructure);
537  
538  	pathTableSectors = CD9660_BLOCKS(diskStructure->sectorSize,
539  		diskStructure->pathTableLength);
540  
541  	firstAvailableSector = cd9660_setup_volume_descriptors(diskStructure);
542  	if (diskStructure->is_bootable) {
543  		firstAvailableSector = cd9660_setup_boot(diskStructure,
544  		    firstAvailableSector);
545  		if (firstAvailableSector < 0)
546  			errx(EXIT_FAILURE, "setup_boot failed");
547  	}
548  	/* LE first, then BE */
549  	diskStructure->primaryLittleEndianTableSector = firstAvailableSector;
550  	diskStructure->primaryBigEndianTableSector =
551  		diskStructure->primaryLittleEndianTableSector + pathTableSectors;
552  
553  	/* Set the secondary ones to -1, not going to use them for now */
554  	diskStructure->secondaryBigEndianTableSector = -1;
555  	diskStructure->secondaryLittleEndianTableSector = -1;
556  
557  	diskStructure->dataFirstSector =
558  	    diskStructure->primaryBigEndianTableSector + pathTableSectors;
559  	if (diskStructure->verbose_level > 0)
560  		printf("%s: Path table conversion complete. "
561  		    "Each table is %i bytes, or %" PRIu64 " sectors.\n",
562  		    __func__,
563  		    diskStructure->pathTableLength, pathTableSectors);
564  
565  	startoffset = diskStructure->sectorSize*diskStructure->dataFirstSector;
566  
567  	totalSpace = cd9660_compute_offsets(diskStructure, real_root, startoffset);
568  
569  	diskStructure->totalSectors = diskStructure->dataFirstSector +
570  		CD9660_BLOCKS(diskStructure->sectorSize, totalSpace);
571  
572  	/* Disabled until pass 1 is done */
573  	if (diskStructure->rock_ridge_enabled) {
574  		diskStructure->susp_continuation_area_start_sector =
575  		    diskStructure->totalSectors;
576  		diskStructure->totalSectors +=
577  		    CD9660_BLOCKS(diskStructure->sectorSize,
578  			diskStructure->susp_continuation_area_size);
579  		cd9660_susp_finalize(diskStructure, diskStructure->rootNode);
580  	}
581  
582  
583  	cd9660_finalize_PVD(diskStructure);
584  
585  	/* Add padding sectors, just for testing purposes right now */
586  	/* diskStructure->totalSectors+=150; */
587  
588  	/* Debugging output */
589  	if (diskStructure->verbose_level > 0) {
590  		printf("%s: Sectors 0-15 reserved\n", __func__);
591  		printf("%s: Primary path tables starts in sector %"
592  		    PRId64 "\n", __func__,
593  		    diskStructure->primaryLittleEndianTableSector);
594  		printf("%s: File data starts in sector %"
595  		    PRId64 "\n", __func__, diskStructure->dataFirstSector);
596  		printf("%s: Total sectors: %"
597  		    PRId64 "\n", __func__, diskStructure->totalSectors);
598  	}
599  
600  	/*
601  	 * Add padding sectors at the end
602  	 * TODO: Clean this up and separate padding
603  	 */
604  	if (diskStructure->include_padding_areas)
605  		diskStructure->totalSectors += 150;
606  
607  	ret = cd9660_write_image(diskStructure, image);
608  
609  	if (diskStructure->verbose_level > 1) {
610  		debug_print_volume_descriptor_information(diskStructure);
611  		debug_print_tree(diskStructure, real_root, 0);
612  		debug_print_path_tree(real_root);
613  	}
614  
615  	/* Clean up data structures */
616  	cd9660_free_structure(real_root);
617  
618  	if (diskStructure->verbose_level > 0)
619  		printf("%s: done ret = %d\n", __func__, ret);
620  
621  	if (ret == 0)	/* cd9660_write_image() failed */
622  		exit(1);
623  }
624  
625  /* Generic function pointer - implement later */
626  typedef int (*cd9660node_func)(cd9660node *);
627  
628  static void
cd9660_finalize_PVD(iso9660_disk * diskStructure)629  cd9660_finalize_PVD(iso9660_disk *diskStructure)
630  {
631  	time_t tstamp = stampst.st_ino ? stampst.st_mtime : time(NULL);
632  
633  	/* root should be a fixed size of 34 bytes since it has no name */
634  	memcpy(diskStructure->primaryDescriptor.root_directory_record,
635  		diskStructure->rootNode->dot_record->isoDirRecord, 34);
636  
637  	/* In RRIP, this might be longer than 34 */
638  	diskStructure->primaryDescriptor.root_directory_record[0] = 34;
639  
640  	/* Set up all the important numbers in the PVD */
641  	cd9660_bothendian_dword(diskStructure->totalSectors,
642  	    (unsigned char *)diskStructure->primaryDescriptor.volume_space_size);
643  	cd9660_bothendian_word(1,
644  	    (unsigned char *)diskStructure->primaryDescriptor.volume_set_size);
645  	cd9660_bothendian_word(1,
646  	    (unsigned char *)
647  		diskStructure->primaryDescriptor.volume_sequence_number);
648  	cd9660_bothendian_word(diskStructure->sectorSize,
649  	    (unsigned char *)
650  		diskStructure->primaryDescriptor.logical_block_size);
651  	cd9660_bothendian_dword(diskStructure->pathTableLength,
652  	    (unsigned char *)diskStructure->primaryDescriptor.path_table_size);
653  
654  	cd9660_731(diskStructure->primaryLittleEndianTableSector,
655  		(u_char *)diskStructure->primaryDescriptor.type_l_path_table);
656  	cd9660_732(diskStructure->primaryBigEndianTableSector,
657  		(u_char *)diskStructure->primaryDescriptor.type_m_path_table);
658  
659  	diskStructure->primaryDescriptor.file_structure_version[0] = 1;
660  
661  	/* Pad all strings with spaces instead of nulls */
662  	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_id, 32);
663  	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.system_id, 32);
664  	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_set_id,
665  	    128);
666  	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.publisher_id,
667  	    128);
668  	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.preparer_id,
669  	    128);
670  	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.application_id,
671  	    128);
672  	cd9660_pad_string_spaces(
673  	    diskStructure->primaryDescriptor.copyright_file_id, 37);
674  	cd9660_pad_string_spaces(
675  		diskStructure->primaryDescriptor.abstract_file_id, 37);
676  	cd9660_pad_string_spaces(
677  		diskStructure->primaryDescriptor.bibliographic_file_id, 37);
678  
679  	/* Setup dates */
680  	cd9660_time_8426(
681  	    (unsigned char *)diskStructure->primaryDescriptor.creation_date,
682  	    tstamp);
683  	cd9660_time_8426(
684  	    (unsigned char *)diskStructure->primaryDescriptor.modification_date,
685  	    tstamp);
686  
687  #if 0
688  	cd9660_set_date(diskStructure->primaryDescriptor.expiration_date,
689  	    tstamp);
690  #endif
691  
692  	memset(diskStructure->primaryDescriptor.expiration_date, '0', 16);
693  	diskStructure->primaryDescriptor.expiration_date[16] = 0;
694  
695  	cd9660_time_8426(
696  	    (unsigned char *)diskStructure->primaryDescriptor.effective_date,
697  	    tstamp);
698  	/* make this sane */
699  	cd9660_time_915(diskStructure->rootNode->dot_record->isoDirRecord->date,
700  	    tstamp);
701  }
702  
703  static void
cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 * record,u_char ext_attr_length,u_char flags,u_char name_len,const char * name)704  cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 *record,
705  			       u_char ext_attr_length, u_char flags,
706  			       u_char name_len, const char * name)
707  {
708  	time_t tstamp = stampst.st_ino ? stampst.st_mtime : time(NULL);
709  
710  	record->ext_attr_length[0] = ext_attr_length;
711  	cd9660_time_915(record->date, tstamp);
712  	record->flags[0] = ISO_FLAG_CLEAR | flags;
713  	record->file_unit_size[0] = 0;
714  	record->interleave[0] = 0;
715  	cd9660_bothendian_word(1, record->volume_sequence_number);
716  	record->name_len[0] = name_len;
717  	memset(record->name, '\0', sizeof (record->name));
718  	memcpy(record->name, name, name_len);
719  	record->length[0] = 33 + name_len;
720  
721  	/* Todo : better rounding */
722  	record->length[0] += (record->length[0] & 1) ? 1 : 0;
723  }
724  
725  static void
cd9660_setup_root_node(iso9660_disk * diskStructure)726  cd9660_setup_root_node(iso9660_disk *diskStructure)
727  {
728  	cd9660_populate_iso_dir_record(diskStructure->rootNode->isoDirRecord,
729  	    0, ISO_FLAG_DIRECTORY, 1, "\0");
730  
731  }
732  
733  /*********** SUPPORT FUNCTIONS ***********/
734  static int
cd9660_setup_volume_descriptors(iso9660_disk * diskStructure)735  cd9660_setup_volume_descriptors(iso9660_disk *diskStructure)
736  {
737  	/* Boot volume descriptor should come second */
738  	int sector = 16;
739  	/* For now, a fixed 2 : PVD and terminator */
740  	volume_descriptor *temp, *t;
741  
742  	/* Set up the PVD */
743  	temp = emalloc(sizeof(*temp));
744  	temp->volumeDescriptorData =
745  	   (unsigned char *)&diskStructure->primaryDescriptor;
746  	temp->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_PVD;
747  	temp->volumeDescriptorData[6] = 1;
748  	temp->sector = sector;
749  	memcpy(temp->volumeDescriptorData + 1,
750  	    ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
751  	diskStructure->firstVolumeDescriptor = temp;
752  
753  	sector++;
754  	/* Set up boot support if enabled. BVD must reside in sector 17 */
755  	if (diskStructure->is_bootable) {
756  		t = emalloc(sizeof(*t));
757  		t->volumeDescriptorData = ecalloc(1, 2048);
758  		temp->next = t;
759  		temp = t;
760  		t->sector = 17;
761  		if (diskStructure->verbose_level > 0)
762  			printf("Setting up boot volume descriptor\n");
763  		cd9660_setup_boot_volume_descriptor(diskStructure, t);
764  		sector++;
765  	}
766  
767  	/* Set up the terminator */
768  	t = emalloc(sizeof(*t));
769  	t->volumeDescriptorData = ecalloc(1, 2048);
770  	temp->next = t;
771  	t->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_TERMINATOR;
772  	t->next = NULL;
773  	t->volumeDescriptorData[6] = 1;
774  	t->sector = sector;
775  	memcpy(t->volumeDescriptorData + 1,
776  	    ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
777  
778  	sector++;
779  	return sector;
780  }
781  
782  #if 0
783  /*
784   * Populate EAR at some point. Not required, but is used by NetBSD's
785   * cd9660 support
786   */
787  static int
788  cd9660_fill_extended_attribute_record(cd9660node *node)
789  {
790  	node->isoExtAttributes = emalloc(sizeof(*node->isoExtAttributes));
791  	return 1;
792  }
793  #endif
794  
795  static int
cd9660_translate_node_common(iso9660_disk * diskStructure,cd9660node * newnode)796  cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode)
797  {
798  	u_char flag;
799  	char temp[ISO_FILENAME_MAXLENGTH];
800  
801  	/* Now populate the isoDirRecord structure */
802  	memset(temp, 0, sizeof(temp));
803  
804  	(void)cd9660_convert_filename(diskStructure, newnode->node->name,
805  	    temp, sizeof(temp), !(S_ISDIR(newnode->node->type)));
806  
807  	flag = ISO_FLAG_CLEAR;
808  	if (S_ISDIR(newnode->node->type))
809  		flag |= ISO_FLAG_DIRECTORY;
810  
811  	cd9660_populate_iso_dir_record(newnode->isoDirRecord, 0,
812  	    flag, strlen(temp), temp);
813  
814  	cd9660_bothendian_dword(newnode->fileDataLength,
815  	    newnode->isoDirRecord->size);
816  	/* If the file is a link, we want to set the size to 0 */
817  	if (S_ISLNK(newnode->node->type))
818  		newnode->fileDataLength = 0;
819  
820  	return 1;
821  }
822  
823  /*
824   * Translate fsnode to cd9660node
825   * Translate filenames and other metadata, including dates, sizes,
826   * permissions, etc
827   * @param struct fsnode * The node generated by makefs
828   * @param struct cd9660node * The intermediate node to be written to
829   * @returns int 0 on failure, 1 on success
830   */
831  static int
cd9660_translate_node(iso9660_disk * diskStructure,fsnode * node,cd9660node * newnode)832  cd9660_translate_node(iso9660_disk *diskStructure, fsnode *node,
833      cd9660node *newnode)
834  {
835  	if (node == NULL) {
836  		if (diskStructure->verbose_level > 0)
837  			printf("%s: NULL node passed, returning\n", __func__);
838  		return 0;
839  	}
840  	newnode->isoDirRecord = emalloc(sizeof(*newnode->isoDirRecord));
841  	/* Set the node pointer */
842  	newnode->node = node;
843  
844  	/* Set the size */
845  	if (!(S_ISDIR(node->type)))
846  		newnode->fileDataLength = node->inode->st.st_size;
847  
848  	if (cd9660_translate_node_common(diskStructure, newnode) == 0)
849  		return 0;
850  
851  	/* Finally, overwrite some of the values that are set by default */
852  	cd9660_time_915(newnode->isoDirRecord->date,
853  	    stampst.st_ino ? stampst.st_mtime : node->inode->st.st_mtime);
854  
855  	return 1;
856  }
857  
858  /*
859   * Compares two ISO filenames
860   * @param const char * The first file name
861   * @param const char * The second file name
862   * @returns : -1 if first is less than second, 0 if they are the same, 1 if
863   *	the second is greater than the first
864   */
865  static int
cd9660_compare_filename(const char * first,const char * second)866  cd9660_compare_filename(const char *first, const char *second)
867  {
868  	/*
869  	 * This can be made more optimal once it has been tested
870  	 * (the extra character, for example, is for testing)
871  	 */
872  
873  	int p1 = 0;
874  	int p2 = 0;
875  	char c1, c2;
876  	/* First, on the filename */
877  
878  	while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1
879  		&& p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1) {
880  		c1 = first[p1];
881  		c2 = second[p2];
882  		if (c1 == '.' && c2 =='.')
883  			break;
884  		else if (c1 == '.') {
885  			p2++;
886  			c1 = ' ';
887  		} else if (c2 == '.') {
888  			p1++;
889  			c2 = ' ';
890  		} else {
891  			p1++;
892  			p2++;
893  		}
894  
895  		if (c1 < c2)
896  			return -1;
897  		else if (c1 > c2) {
898  			return 1;
899  		}
900  	}
901  
902  	if (first[p1] == '.' && second[p2] == '.') {
903  		p1++;
904  		p2++;
905  		while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1
906  			&& p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1) {
907  			c1 = first[p1];
908  			c2 = second[p2];
909  			if (c1 == ';' && c2 == ';')
910  				break;
911  			else if (c1 == ';') {
912  				p2++;
913  				c1 = ' ';
914  			} else if (c2 == ';') {
915  				p1++;
916  				c2 = ' ';
917  			} else {
918  				p1++;
919  				p2++;
920  			}
921  
922  			if (c1 < c2)
923  				return -1;
924  			else if (c1 > c2)
925  				return 1;
926  		}
927  	}
928  	return 0;
929  }
930  
931  /*
932   * Insert a node into list with ISO sorting rules
933   * @param cd9660node * The head node of the list
934   * @param cd9660node * The node to be inserted
935   */
936  static void
cd9660_sorted_child_insert(cd9660node * parent,cd9660node * cn_new)937  cd9660_sorted_child_insert(cd9660node *parent, cd9660node *cn_new)
938  {
939  	int compare;
940  	cd9660node *cn;
941  	struct cd9660_children_head *head = &parent->cn_children;
942  
943  	/* TODO: Optimize? */
944  	cn_new->parent = parent;
945  
946  	/*
947  	 * first will either be 0, the . or the ..
948  	 * if . or .., this means no other entry may be written before first
949  	 * if 0, the new node may be inserted at the head
950  	 */
951  
952  	TAILQ_FOREACH(cn, head, cn_next_child) {
953  		/*
954  		 * Dont insert a node twice -
955  		 * that would cause an infinite loop
956  		 */
957  		if (cn_new == cn)
958  			return;
959  
960  		compare = cd9660_compare_filename(cn_new->isoDirRecord->name,
961  			cn->isoDirRecord->name);
962  
963  		if (compare == 0)
964  			compare = cd9660_compare_filename(cn_new->node->name,
965  				cn->node->name);
966  
967  		if (compare < 0)
968  			break;
969  	}
970  	if (cn == NULL)
971  		TAILQ_INSERT_TAIL(head, cn_new, cn_next_child);
972  	else
973  		TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child);
974  }
975  
976  /*
977   * Called After cd9660_sorted_child_insert
978   * handles file collisions by suffixing each filename with ~n
979   * where n represents the files respective place in the ordering
980   */
981  static int
cd9660_handle_collisions(iso9660_disk * diskStructure,cd9660node * colliding,int past)982  cd9660_handle_collisions(iso9660_disk *diskStructure, cd9660node *colliding,
983      int past)
984  {
985  	cd9660node *iter, *next, *prev;
986  	int skip;
987  	int delete_chars = 0;
988  	int temp_past = past;
989  	int temp_skip;
990  	int flag = 0;
991  	cd9660node *end_of_range;
992  
993  	for (iter = TAILQ_FIRST(&colliding->cn_children);
994  	     iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) {
995  		if (strcmp(iter->isoDirRecord->name,
996  		           next->isoDirRecord->name) != 0) {
997  			iter = TAILQ_NEXT(iter, cn_next_child);
998  			continue;
999  		}
1000  		flag = 1;
1001  		temp_skip = skip = cd9660_count_collisions(iter);
1002  		end_of_range = iter;
1003  		while (temp_skip > 0) {
1004  			temp_skip--;
1005  			end_of_range = TAILQ_NEXT(end_of_range, cn_next_child);
1006  		}
1007  		temp_past = past;
1008  		while (temp_past > 0) {
1009  			if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL)
1010  				end_of_range = next;
1011  			else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL)
1012  				iter = prev;
1013  			else
1014  				delete_chars++;
1015  			temp_past--;
1016  		}
1017  		skip += past;
1018  		iter = cd9660_rename_filename(diskStructure, iter, skip,
1019  		    delete_chars);
1020  	}
1021  	return flag;
1022  }
1023  
1024  
1025  static cd9660node *
cd9660_rename_filename(iso9660_disk * diskStructure,cd9660node * iter,int num,int delete_chars)1026  cd9660_rename_filename(iso9660_disk *diskStructure, cd9660node *iter, int num,
1027      int delete_chars)
1028  {
1029  	int i = 0;
1030  	int numbts, digit, digits, temp, powers, count;
1031  	char *naming;
1032  	int maxlength;
1033          char *tmp;
1034  
1035  	if (diskStructure->verbose_level > 0)
1036  		printf("Rename_filename called\n");
1037  
1038  	assert(1 <= diskStructure->isoLevel && diskStructure->isoLevel <= 2);
1039  	/* TODO : A LOT of chanes regarding 8.3 filenames */
1040  	if (diskStructure->isoLevel == 1)
1041  		maxlength = 8;
1042  	else if (diskStructure->isoLevel == 2)
1043  		maxlength = 31;
1044  	else
1045  		maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION;
1046  
1047  	tmp = emalloc(ISO_FILENAME_MAXLENGTH);
1048  
1049  	while (i < num && iter) {
1050  		powers = 1;
1051  		count = 0;
1052  		digits = 1;
1053  		while (((int)(i / powers) ) >= 10) {
1054  			digits++;
1055  			powers = powers * 10;
1056  		}
1057  
1058  		naming = iter->o_name;
1059  
1060  		/*
1061  		while ((*naming != '.') && (*naming != ';')) {
1062  			naming++;
1063  			count++;
1064  		}
1065  		*/
1066  
1067  		while (count < maxlength) {
1068  			if (*naming == ';')
1069  				break;
1070  			naming++;
1071  			count++;
1072  		}
1073  
1074  		if ((count + digits) < maxlength)
1075  			numbts = count;
1076  		else
1077  			numbts = maxlength - (digits);
1078  		numbts -= delete_chars;
1079  
1080  		/* 8.3 rules - keep the extension, add before the dot */
1081  
1082  		/*
1083  		 * This code makes a bunch of assumptions.
1084  		 * See if you can spot them all :)
1085  		 */
1086  
1087  #if 0
1088  		if (diskStructure->isoLevel == 1) {
1089  			numbts = 8 - digits - delete_chars;
1090  			if (dot < 0) {
1091  
1092  			} else {
1093  				if (dot < 8) {
1094  					memmove(&tmp[numbts],&tmp[dot],4);
1095  				}
1096  			}
1097  		}
1098  #endif
1099  
1100  		/* (copying just the filename before the '.' */
1101  		memcpy(tmp, (iter->o_name), numbts);
1102  
1103  		/* adding the appropriate number following the name */
1104  		temp = i;
1105  		while (digits > 0) {
1106  			digit = (int)(temp / powers);
1107  			temp = temp - digit * powers;
1108  			snprintf(&tmp[numbts], ISO_FILENAME_MAXLENGTH - numbts,
1109  			    "%d", digit);
1110  			digits--;
1111  			numbts++;
1112  			powers = powers / 10;
1113  		}
1114  
1115  		while ((*naming != ';')  && (numbts < maxlength)) {
1116  			tmp[numbts] = (*naming);
1117  			naming++;
1118  			numbts++;
1119  		}
1120  
1121  		tmp[numbts] = ';';
1122  		tmp[numbts+1] = '1';
1123  		tmp[numbts+2] = '\0';
1124  
1125  		/*
1126  		 * now tmp has exactly the identifier
1127  		 * we want so we'll copy it back to record
1128  		 */
1129  		memcpy((iter->isoDirRecord->name), tmp, numbts + 3);
1130  
1131  		iter = TAILQ_NEXT(iter, cn_next_child);
1132  		i++;
1133  	}
1134  
1135  	free(tmp);
1136  	return iter;
1137  }
1138  
1139  /* Todo: Figure out why these functions are nec. */
1140  static void
cd9660_copy_filenames(iso9660_disk * diskStructure,cd9660node * node)1141  cd9660_copy_filenames(iso9660_disk *diskStructure, cd9660node *node)
1142  {
1143  	cd9660node *cn;
1144  
1145  	if (TAILQ_EMPTY(&node->cn_children))
1146  		return;
1147  
1148  	if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) {
1149  		debug_print_tree(diskStructure, diskStructure->rootNode, 0);
1150  		exit(1);
1151  	}
1152  
1153  	TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
1154  		cd9660_copy_filenames(diskStructure, cn);
1155  		memcpy(cn->o_name, cn->isoDirRecord->name, sizeof(cn->o_name));
1156  	}
1157  }
1158  
1159  static void
cd9660_sorting_nodes(cd9660node * node)1160  cd9660_sorting_nodes(cd9660node *node)
1161  {
1162  	cd9660node *cn;
1163  
1164  	TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
1165  		cd9660_sorting_nodes(cn);
1166  	cd9660_sort_nodes(node);
1167  }
1168  
1169  /* XXX Bubble sort. */
1170  static void
cd9660_sort_nodes(cd9660node * node)1171  cd9660_sort_nodes(cd9660node *node)
1172  {
1173  	cd9660node *cn, *next;
1174  
1175  	do {
1176  		TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
1177  			if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL)
1178  				return;
1179  			else if (strcmp(next->isoDirRecord->name,
1180  				        cn->isoDirRecord->name) >= 0)
1181  				continue;
1182  			TAILQ_REMOVE(&node->cn_children, next, cn_next_child);
1183  			TAILQ_INSERT_BEFORE(cn, next, cn_next_child);
1184  			break;
1185  		}
1186  	} while (cn != NULL);
1187  }
1188  
1189  static int
cd9660_count_collisions(cd9660node * copy)1190  cd9660_count_collisions(cd9660node *copy)
1191  {
1192  	int count = 0;
1193  	cd9660node *iter, *next;
1194  
1195  	for (iter = copy;
1196  	     (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;
1197  	     iter = next) {
1198  		if (cd9660_compare_filename(iter->isoDirRecord->name,
1199  			next->isoDirRecord->name) == 0)
1200  			count++;
1201  		else
1202  			return count;
1203  	}
1204  #if 0
1205  	if ((next = TAILQ_NEXT(iter, cn_next_child)) != NULL) {
1206  		printf("%s: count is %i\n", __func__, count);
1207  		compare = cd9660_compare_filename(iter->isoDirRecord->name,
1208  			next->isoDirRecord->name);
1209  		if (compare == 0) {
1210  			count++;
1211  			return cd9660_recurse_on_collision(next, count);
1212  		} else
1213  			return count;
1214  	}
1215  #endif
1216  	return count;
1217  }
1218  
1219  static cd9660node *
cd9660_rrip_move_directory(iso9660_disk * diskStructure,cd9660node * dir)1220  cd9660_rrip_move_directory(iso9660_disk *diskStructure, cd9660node *dir)
1221  {
1222  	char newname[9];
1223  	cd9660node *tfile;
1224  
1225  	/*
1226  	 * This function needs to:
1227  	 * 1) Create an empty virtual file in place of the old directory
1228  	 * 2) Point the virtual file to the new directory
1229  	 * 3) Point the relocated directory to its old parent
1230  	 * 4) Move the directory specified by dir into rr_moved_dir,
1231  	 * and rename it to "diskStructure->rock_ridge_move_count" (as a string)
1232  	 */
1233  
1234  	/* First see if the moved directory even exists */
1235  	if (diskStructure->rr_moved_dir == NULL) {
1236  		diskStructure->rr_moved_dir = cd9660_create_directory(
1237  		    diskStructure, ISO_RRIP_DEFAULT_MOVE_DIR_NAME,
1238  		    diskStructure->rootNode, dir);
1239  		if (diskStructure->rr_moved_dir == NULL)
1240  			return 0;
1241  		cd9660_time_915(diskStructure->rr_moved_dir->isoDirRecord->date,
1242  		    stampst.st_ino ? stampst.st_mtime : start_time.tv_sec);
1243  	}
1244  
1245  	/* Create a file with the same ORIGINAL name */
1246  	tfile = cd9660_create_file(diskStructure, dir->node->name, dir->parent,
1247  	    dir);
1248  	if (tfile == NULL)
1249  		return NULL;
1250  
1251  	diskStructure->rock_ridge_move_count++;
1252  	snprintf(newname, sizeof(newname), "%08u",
1253  	    diskStructure->rock_ridge_move_count);
1254  
1255  	/* Point to old parent */
1256  	dir->rr_real_parent = dir->parent;
1257  
1258  	/* Place the placeholder file */
1259  	if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)) {
1260  		TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile,
1261  		    cn_next_child);
1262  	} else {
1263  		cd9660_sorted_child_insert(dir->rr_real_parent, tfile);
1264  	}
1265  
1266  	/* Point to new parent */
1267  	dir->parent = diskStructure->rr_moved_dir;
1268  
1269  	/* Point the file to the moved directory */
1270  	tfile->rr_relocated = dir;
1271  
1272  	/* Actually move the directory */
1273  	cd9660_sorted_child_insert(diskStructure->rr_moved_dir, dir);
1274  
1275  	/* TODO: Inherit permissions / ownership (basically the entire inode) */
1276  
1277  	/* Set the new name */
1278  	memset(dir->isoDirRecord->name, 0, sizeof(dir->isoDirRecord->name));
1279  	strncpy(dir->isoDirRecord->name, newname, 8);
1280  	dir->isoDirRecord->length[0] = 34 + 8;
1281  	dir->isoDirRecord->name_len[0] = 8;
1282  
1283  	return dir;
1284  }
1285  
1286  static int
cd9660_add_dot_records(iso9660_disk * diskStructure,cd9660node * root)1287  cd9660_add_dot_records(iso9660_disk *diskStructure, cd9660node *root)
1288  {
1289  	struct cd9660_children_head *head = &root->cn_children;
1290  	cd9660node *cn;
1291  
1292  	TAILQ_FOREACH(cn, head, cn_next_child) {
1293  		if ((cn->type & CD9660_TYPE_DIR) == 0)
1294  			continue;
1295  		/* Recursion first */
1296  		cd9660_add_dot_records(diskStructure, cn);
1297  	}
1298  	cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOT, root);
1299  	cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOTDOT,
1300  	    root);
1301  	return 1;
1302  }
1303  
1304  /*
1305   * Convert node to cd9660 structure
1306   * This function is designed to be called recursively on the root node of
1307   * the filesystem
1308   * Lots of recursion going on here, want to make sure it is efficient
1309   * @param struct fsnode * The root node to be converted
1310   * @param struct cd9660* The parent node (should not be NULL)
1311   * @param int Current directory depth
1312   * @param int* Running count of the number of directories that are being created
1313   */
1314  static void
cd9660_convert_structure(iso9660_disk * diskStructure,fsnode * root,cd9660node * parent_node,int level,int * numDirectories,int * error)1315  cd9660_convert_structure(iso9660_disk *diskStructure, fsnode *root,
1316      cd9660node *parent_node, int level, int *numDirectories, int *error)
1317  {
1318  	fsnode *iterator = root;
1319  	cd9660node *this_node;
1320  	int working_level;
1321  	int add;
1322  	int flag = 0;
1323  	int counter = 0;
1324  
1325  	/*
1326  	 * Newer, more efficient method, reduces recursion depth
1327  	 */
1328  	if (root == NULL) {
1329  		warnx("%s: root is null", __func__);
1330  		return;
1331  	}
1332  
1333  	/* Test for an empty directory - makefs still gives us the . record */
1334  	if ((S_ISDIR(root->type)) && (root->name[0] == '.')
1335  		&& (root->name[1] == '\0')) {
1336  		root = root->next;
1337  		if (root == NULL)
1338  			return;
1339  	}
1340  	if ((this_node = cd9660_allocate_cd9660node()) == NULL) {
1341  		CD9660_MEM_ALLOC_ERROR(__func__);
1342  	}
1343  
1344  	/*
1345  	 * To reduce the number of recursive calls, we will iterate over
1346  	 * the next pointers to the right.
1347  	 */
1348  	while (iterator != NULL) {
1349  		add = 1;
1350  		/*
1351  		 * Increment the directory count if this is a directory
1352  		 * Ignore "." entries. We will generate them later
1353  		 */
1354  		if (!S_ISDIR(iterator->type) ||
1355  		    strcmp(iterator->name, ".") != 0) {
1356  
1357  			/* Translate the node, including its filename */
1358  			this_node->parent = parent_node;
1359  			cd9660_translate_node(diskStructure, iterator,
1360  			    this_node);
1361  			this_node->level = level;
1362  
1363  			if (S_ISDIR(iterator->type)) {
1364  				(*numDirectories)++;
1365  				this_node->type = CD9660_TYPE_DIR;
1366  				working_level = level + 1;
1367  
1368  				/*
1369  				 * If at level 8, directory would be at 8
1370  				 * and have children at 9 which is not
1371  				 * allowed as per ISO spec
1372  				 */
1373  				if (level == 8) {
1374  					if ((!diskStructure->allow_deep_trees) &&
1375  					  (!diskStructure->rock_ridge_enabled)) {
1376  						warnx("error: found entry "
1377  						     "with depth greater "
1378  						     "than 8.");
1379  						(*error) = 1;
1380  						return;
1381  					} else if (diskStructure->
1382  						   rock_ridge_enabled) {
1383  						working_level = 3;
1384  						/*
1385  						 * Moved directory is actually
1386  						 * at level 2.
1387  						 */
1388  						this_node->level =
1389  						    working_level - 1;
1390  						if (cd9660_rrip_move_directory(
1391  							diskStructure,
1392  							this_node) == NULL) {
1393  							warnx("Failure in "
1394  							      "cd9660_rrip_"
1395  							      "move_directory"
1396  							);
1397  							(*error) = 1;
1398  							return;
1399  						}
1400  						add = 0;
1401  					}
1402  				}
1403  
1404  				/* Do the recursive call on the children */
1405  				if (iterator->child != NULL) {
1406  					cd9660_convert_structure(diskStructure,
1407  						iterator->child, this_node,
1408  						working_level,
1409  						numDirectories, error);
1410  
1411  					if ((*error) == 1) {
1412  						warnx("%s: Error on recursive "
1413  						    "call", __func__);
1414  						return;
1415  					}
1416  				}
1417  
1418  			} else {
1419  				/* Only directories should have children */
1420  				assert(iterator->child == NULL);
1421  
1422  				this_node->type = CD9660_TYPE_FILE;
1423  			}
1424  
1425  			/*
1426  			 * Finally, do a sorted insert
1427  			 */
1428  			if (add) {
1429  				cd9660_sorted_child_insert(
1430  				    parent_node, this_node);
1431  			}
1432  
1433  			/*Allocate new temp_node */
1434  			if (iterator->next != NULL) {
1435  				this_node = cd9660_allocate_cd9660node();
1436  				if (this_node == NULL)
1437  					CD9660_MEM_ALLOC_ERROR(__func__);
1438  			}
1439  		}
1440  		iterator = iterator->next;
1441  	}
1442  
1443  	/* cd9660_handle_collisions(first_node); */
1444  
1445  	/* TODO: need cleanup */
1446  	cd9660_copy_filenames(diskStructure, parent_node);
1447  
1448  	do {
1449  		flag = cd9660_handle_collisions(diskStructure, parent_node,
1450  		    counter);
1451  		counter++;
1452  		cd9660_sorting_nodes(parent_node);
1453  	} while ((flag == 1) && (counter < 100));
1454  }
1455  
1456  /*
1457   * Clean up the cd9660node tree
1458   * This is designed to be called recursively on the root node
1459   * @param struct cd9660node *root The node to free
1460   * @returns void
1461   */
1462  static void
cd9660_free_structure(cd9660node * root)1463  cd9660_free_structure(cd9660node *root)
1464  {
1465  	cd9660node *cn;
1466  
1467  	while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) {
1468  		TAILQ_REMOVE(&root->cn_children, cn, cn_next_child);
1469  		cd9660_free_structure(cn);
1470  	}
1471  	free(root);
1472  }
1473  
1474  /*
1475   * Be a little more memory conservative:
1476   * instead of having the TAILQ_ENTRY as part of the cd9660node,
1477   * just create a temporary structure
1478   */
1479  static struct ptq_entry
1480  {
1481  	TAILQ_ENTRY(ptq_entry) ptq;
1482  	cd9660node *node;
1483  } *n;
1484  
1485  #define PTQUEUE_NEW(n,s,r,t){\
1486  	n = emalloc(sizeof(struct s));	\
1487  	n->node = t;\
1488  }
1489  
1490  /*
1491   * Generate the path tables
1492   * The specific implementation of this function is left as an exercise to the
1493   * programmer. It could be done recursively. Make sure you read how the path
1494   * table has to be laid out, it has levels.
1495   * @param struct iso9660_disk *disk The disk image
1496   * @returns int The number of built path tables (between 1 and 4), 0 on failure
1497   */
1498  static int
cd9660_generate_path_table(iso9660_disk * diskStructure)1499  cd9660_generate_path_table(iso9660_disk *diskStructure)
1500  {
1501  	cd9660node *cn, *dirNode = diskStructure->rootNode;
1502  	cd9660node *last = dirNode;
1503  	int pathTableSize = 0;	/* computed as we go */
1504  	int counter = 1;	/* root gets a count of 0 */
1505  
1506  	TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head;
1507  	TAILQ_INIT(&pt_head);
1508  
1509  	PTQUEUE_NEW(n, ptq_entry, -1, diskStructure->rootNode);
1510  
1511  	/* Push the root node */
1512  	TAILQ_INSERT_HEAD(&pt_head, n, ptq);
1513  
1514  	/* Breadth-first traversal of file structure */
1515  	while (!TAILQ_EMPTY(&pt_head)) {
1516  		n = TAILQ_FIRST(&pt_head);
1517  		dirNode = n->node;
1518  		TAILQ_REMOVE(&pt_head, n, ptq);
1519  		free(n);
1520  
1521  		/* Update the size */
1522  		pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE
1523  		    + dirNode->isoDirRecord->name_len[0]+
1524  			(dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1);
1525  			/* includes the padding bit */
1526  
1527  		dirNode->ptnumber=counter;
1528  		if (dirNode != last) {
1529  			last->ptnext = dirNode;
1530  			dirNode->ptprev = last;
1531  		}
1532  		last = dirNode;
1533  
1534  		/* Push children onto queue */
1535  		TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) {
1536  			/*
1537  			 * Dont add the DOT and DOTDOT types to the path
1538  			 * table.
1539  			 */
1540  			if ((cn->type != CD9660_TYPE_DOT)
1541  				&& (cn->type != CD9660_TYPE_DOTDOT)) {
1542  
1543  				if (S_ISDIR(cn->node->type)) {
1544  					PTQUEUE_NEW(n, ptq_entry, -1, cn);
1545  					TAILQ_INSERT_TAIL(&pt_head, n, ptq);
1546  				}
1547  			}
1548  		}
1549  		counter++;
1550  	}
1551  	return pathTableSize;
1552  }
1553  
1554  void
cd9660_compute_full_filename(cd9660node * node,char * buf)1555  cd9660_compute_full_filename(cd9660node *node, char *buf)
1556  {
1557  	int len;
1558  
1559  	len = PATH_MAX;
1560  	len = snprintf(buf, len, "%s/%s/%s", node->node->root,
1561  	    node->node->path, node->node->name);
1562  	if (len >= PATH_MAX)
1563  		errx(EXIT_FAILURE, "Pathname too long.");
1564  }
1565  
1566  /*
1567   * TODO: These two functions are almost identical.
1568   * Some code cleanup is possible here
1569   *
1570   * XXX bounds checking!
1571   */
1572  static int
cd9660_level1_convert_filename(iso9660_disk * diskStructure,const char * oldname,char * newname,size_t newnamelen,int is_file)1573  cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1574      char *newname, size_t newnamelen, int is_file)
1575  {
1576  	/*
1577  	 * ISO 9660 : 10.1
1578  	 * File Name shall not contain more than 8 d or d1 characters
1579  	 * File Name Extension shall not contain more than 3 d or d1 characters
1580  	 * Directory Identifier shall not contain more than 8 d or d1 characters
1581  	 */
1582  	int namelen = 0;
1583  	int extlen = 0;
1584  	int found_ext = 0;
1585  	char *orignewname = newname;
1586  
1587  	while (*oldname != '\0' && extlen < 3) {
1588  		/* Handle period first, as it is special */
1589  		if (*oldname == '.') {
1590  			if (found_ext) {
1591  				*newname++ = '_';
1592  				extlen ++;
1593  			}
1594  			else {
1595  				*newname++ = '.';
1596  				found_ext = 1;
1597  			}
1598  		} else {
1599  			/* Enforce 12.3 / 8 */
1600  			if (namelen == 8 && !found_ext)
1601  				break;
1602  
1603  			if (islower((unsigned char)*oldname))
1604  				*newname++ = toupper((unsigned char)*oldname);
1605  			else if (isupper((unsigned char)*oldname)
1606  			    || isdigit((unsigned char)*oldname))
1607  				*newname++ = *oldname;
1608  			else
1609  				*newname++ = '_';
1610  
1611  			if (found_ext)
1612  				extlen++;
1613  			else
1614  				namelen++;
1615  		}
1616  		oldname++;
1617  	}
1618  	if (is_file) {
1619  		if (!found_ext && !diskStructure->omit_trailing_period)
1620  			*newname++ = '.';
1621  		/* Add version */
1622  		snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1);
1623  	}
1624  	return namelen + extlen + found_ext;
1625  }
1626  
1627  /* XXX bounds checking! */
1628  static int
cd9660_level2_convert_filename(iso9660_disk * diskStructure,const char * oldname,char * newname,size_t newnamelen,int is_file)1629  cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1630      char *newname, size_t newnamelen, int is_file)
1631  {
1632  	/*
1633  	 * ISO 9660 : 7.5.1
1634  	 * File name : 0+ d or d1 characters
1635  	 * separator 1 (.)
1636  	 * File name extension : 0+ d or d1 characters
1637  	 * separator 2 (;)
1638  	 * File version number (5 characters, 1-32767)
1639  	 * 1 <= Sum of File name and File name extension <= 30
1640  	 */
1641  	int maxlen = is_file ? 30 : 31;
1642  	int namelen = 0;
1643  	int extlen = 0;
1644  	int found_ext = 0;
1645  	char *orignewname = newname;
1646  
1647  	while (*oldname != '\0' && namelen + extlen < maxlen) {
1648  		/* Handle period first, as it is special */
1649  		if (*oldname == '.' && is_file) {
1650  			if (found_ext) {
1651  				if (diskStructure->allow_multidot) {
1652  					*newname++ = '.';
1653  				} else {
1654  					*newname++ = '_';
1655  				}
1656  				extlen ++;
1657  			}
1658  			else {
1659  				*newname++ = '.';
1660  				found_ext = 1;
1661  			}
1662  		} else {
1663  			if (islower((unsigned char)*oldname))
1664  				*newname++ = toupper((unsigned char)*oldname);
1665  			else if (isupper((unsigned char)*oldname) ||
1666  			    isdigit((unsigned char)*oldname))
1667  				*newname++ = *oldname;
1668  			else
1669  				*newname++ = '_';
1670  
1671  			if (found_ext)
1672  				extlen++;
1673  			else
1674  				namelen++;
1675  		}
1676  		oldname ++;
1677  	}
1678  	if (is_file) {
1679  		if (!found_ext && !diskStructure->omit_trailing_period)
1680  			*newname++ = '.';
1681  		/* Add version */
1682  		snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1);
1683  	}
1684  	return namelen + extlen + found_ext;
1685  }
1686  
1687  /*
1688   * Convert a file name to ISO compliant file name
1689   * @param char * oldname The original filename
1690   * @param char ** newname The new file name, in the appropriate character
1691   *                        set and of appropriate length
1692   * @param int 1 if file, 0 if directory
1693   * @returns int The length of the new string
1694   */
1695  static int
cd9660_convert_filename(iso9660_disk * diskStructure,const char * oldname,char * newname,size_t newnamelen,int is_file)1696  cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1697      char *newname, size_t newnamelen, int is_file)
1698  {
1699  	assert(1 <= diskStructure->isoLevel && diskStructure->isoLevel <= 2);
1700  	if (diskStructure->isoLevel == 1)
1701  		return(cd9660_level1_convert_filename(diskStructure,
1702  		    oldname, newname, newnamelen, is_file));
1703  	else if (diskStructure->isoLevel == 2)
1704  		return (cd9660_level2_convert_filename(diskStructure,
1705  		    oldname, newname, newnamelen, is_file));
1706  	abort();
1707  }
1708  
1709  int
cd9660_compute_record_size(iso9660_disk * diskStructure,cd9660node * node)1710  cd9660_compute_record_size(iso9660_disk *diskStructure, cd9660node *node)
1711  {
1712  	int size = node->isoDirRecord->length[0];
1713  
1714  	if (diskStructure->rock_ridge_enabled)
1715  		size += node->susp_entry_size;
1716  	size += node->su_tail_size;
1717  	size += size & 1; /* Ensure length of record is even. */
1718  	assert(size <= 254);
1719  	return size;
1720  }
1721  
1722  static void
cd9660_populate_dot_records(iso9660_disk * diskStructure,cd9660node * node)1723  cd9660_populate_dot_records(iso9660_disk *diskStructure, cd9660node *node)
1724  {
1725  	node->dot_record->fileDataSector = node->fileDataSector;
1726  	memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34);
1727  	node->dot_record->isoDirRecord->name_len[0] = 1;
1728  	node->dot_record->isoDirRecord->name[0] = 0;
1729  	node->dot_record->isoDirRecord->name[1] = 0;
1730  	node->dot_record->isoDirRecord->length[0] = 34;
1731  	node->dot_record->fileRecordSize =
1732  	    cd9660_compute_record_size(diskStructure, node->dot_record);
1733  
1734  	if (node == diskStructure->rootNode) {
1735  		node->dot_dot_record->fileDataSector = node->fileDataSector;
1736  		memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord,
1737  		    34);
1738  	} else {
1739  		node->dot_dot_record->fileDataSector =
1740  		    node->parent->fileDataSector;
1741  		memcpy(node->dot_dot_record->isoDirRecord,
1742  		    node->parent->isoDirRecord,34);
1743  	}
1744  	node->dot_dot_record->isoDirRecord->name_len[0] = 1;
1745  	node->dot_dot_record->isoDirRecord->name[0] = 1;
1746  	node->dot_dot_record->isoDirRecord->name[1] = 0;
1747  	node->dot_dot_record->isoDirRecord->length[0] = 34;
1748  	node->dot_dot_record->fileRecordSize =
1749  	    cd9660_compute_record_size(diskStructure, node->dot_dot_record);
1750  }
1751  
1752  /*
1753   * @param struct cd9660node *node The node
1754   * @param int The offset (in bytes) - SHOULD align to the beginning of a sector
1755   * @returns int The total size of files and directory entries (should be
1756   *              a multiple of sector size)
1757  */
1758  static int64_t
cd9660_compute_offsets(iso9660_disk * diskStructure,cd9660node * node,int64_t startOffset)1759  cd9660_compute_offsets(iso9660_disk *diskStructure, cd9660node *node,
1760      int64_t startOffset)
1761  {
1762  	/*
1763  	 * This function needs to compute the size of directory records and
1764  	 * runs, file lengths, and set the appropriate variables both in
1765  	 * cd9660node and isoDirEntry
1766  	 */
1767  	int64_t used_bytes = 0;
1768  	int64_t current_sector_usage = 0;
1769  	cd9660node *child;
1770  	fsinode *inode;
1771  	int64_t r;
1772  
1773  	assert(node != NULL);
1774  
1775  
1776  	/*
1777  	 * NOTE : There needs to be some special case detection for
1778  	 * the "real root" node, since for it, node->node is undefined
1779  	 */
1780  
1781  	node->fileDataSector = -1;
1782  
1783  	if (node->type & CD9660_TYPE_DIR) {
1784  		node->fileRecordSize = cd9660_compute_record_size(
1785  		    diskStructure, node);
1786  		/*Set what sector this directory starts in*/
1787  		node->fileDataSector =
1788  		    CD9660_BLOCKS(diskStructure->sectorSize,startOffset);
1789  
1790  		cd9660_bothendian_dword(node->fileDataSector,
1791  		    node->isoDirRecord->extent);
1792  
1793  		/*
1794  		 * First loop over children, need to know the size of
1795  		 * their directory records
1796  		 */
1797  		node->fileSectorsUsed = 1;
1798  		TAILQ_FOREACH(child, &node->cn_children, cn_next_child) {
1799  			node->fileDataLength +=
1800  			    cd9660_compute_record_size(diskStructure, child);
1801  			if ((cd9660_compute_record_size(diskStructure, child) +
1802  			    current_sector_usage) >=
1803  			    diskStructure->sectorSize) {
1804  				current_sector_usage = 0;
1805  				node->fileSectorsUsed++;
1806  			}
1807  
1808  			current_sector_usage +=
1809  			    cd9660_compute_record_size(diskStructure, child);
1810  		}
1811  
1812  		cd9660_bothendian_dword(node->fileSectorsUsed *
1813  			diskStructure->sectorSize,node->isoDirRecord->size);
1814  
1815  		/*
1816  		 * This should point to the sector after the directory
1817  		 * record (or, the first byte in that sector)
1818  		 */
1819  		used_bytes += node->fileSectorsUsed * diskStructure->sectorSize;
1820  
1821  		for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child);
1822  		     child != NULL; child = TAILQ_NEXT(child, cn_next_child)) {
1823  			/* Directories need recursive call */
1824  			if (S_ISDIR(child->node->type)) {
1825  				r = cd9660_compute_offsets(diskStructure, child,
1826  				    used_bytes + startOffset);
1827  
1828  				if (r != -1)
1829  					used_bytes += r;
1830  				else
1831  					return -1;
1832  			}
1833  		}
1834  
1835  		/* Explicitly set the . and .. records */
1836  		cd9660_populate_dot_records(diskStructure, node);
1837  
1838  		/* Finally, do another iteration to write the file data*/
1839  		for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child);
1840  		     child != NULL;
1841  		     child = TAILQ_NEXT(child, cn_next_child)) {
1842  			/* Files need extent set */
1843  			if (S_ISDIR(child->node->type))
1844  				continue;
1845  			child->fileRecordSize =
1846  			    cd9660_compute_record_size(diskStructure, child);
1847  
1848  			child->fileSectorsUsed =
1849  			    CD9660_BLOCKS(diskStructure->sectorSize,
1850  				child->fileDataLength);
1851  
1852  			inode = child->node->inode;
1853  			if ((inode->flags & FI_ALLOCATED) == 0) {
1854  				inode->ino =
1855  				    CD9660_BLOCKS(diskStructure->sectorSize,
1856  				        used_bytes + startOffset);
1857  				inode->flags |= FI_ALLOCATED;
1858  				used_bytes += child->fileSectorsUsed *
1859  				    diskStructure->sectorSize;
1860  			} else {
1861  				INODE_WARNX(("%s: already allocated inode %d "
1862  				      "data sectors at %" PRIu32, __func__,
1863  				      (int)inode->st.st_ino, inode->ino));
1864  			}
1865  			child->fileDataSector = inode->ino;
1866  			cd9660_bothendian_dword(child->fileDataSector,
1867  				child->isoDirRecord->extent);
1868  		}
1869  	}
1870  
1871  	return used_bytes;
1872  }
1873  
1874  #if 0
1875  /* Might get rid of this func */
1876  static int
1877  cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file)
1878  {
1879  	to->node->inode->st.st_dev = 0;
1880  	to->node->inode->st.st_ino = 0;
1881  	to->node->inode->st.st_size = 0;
1882  	to->node->inode->st.st_blksize = from->node->inode->st.st_blksize;
1883  	to->node->inode->st.st_atime = from->node->inode->st.st_atime;
1884  	to->node->inode->st.st_mtime = from->node->inode->st.st_mtime;
1885  	to->node->inode->st.st_ctime = from->node->inode->st.st_ctime;
1886  	to->node->inode->st.st_uid = from->node->inode->st.st_uid;
1887  	to->node->inode->st.st_gid = from->node->inode->st.st_gid;
1888  	to->node->inode->st.st_mode = from->node->inode->st.st_mode;
1889  	/* Clear out type */
1890  	to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT);
1891  	if (file)
1892  		to->node->inode->st.st_mode |= S_IFREG;
1893  	else
1894  		to->node->inode->st.st_mode |= S_IFDIR;
1895  	return 1;
1896  }
1897  #endif
1898  
1899  static cd9660node *
cd9660_create_virtual_entry(iso9660_disk * diskStructure,const char * name,cd9660node * parent,int file,int insert)1900  cd9660_create_virtual_entry(iso9660_disk *diskStructure, const char *name,
1901      cd9660node *parent, int file, int insert)
1902  {
1903  	cd9660node *temp;
1904  	fsnode * tfsnode;
1905  
1906  	assert(parent != NULL);
1907  
1908  	temp = cd9660_allocate_cd9660node();
1909  	if (temp == NULL)
1910  		return NULL;
1911  
1912  	tfsnode = emalloc(sizeof(*tfsnode));
1913  	tfsnode->name = estrdup(name);
1914  	temp->isoDirRecord = emalloc(sizeof(*temp->isoDirRecord));
1915  
1916  	cd9660_convert_filename(diskStructure, tfsnode->name,
1917  	    temp->isoDirRecord->name, sizeof(temp->isoDirRecord->name), file);
1918  
1919  	temp->node = tfsnode;
1920  	temp->parent = parent;
1921  
1922  	if (insert) {
1923  		if (temp->parent != NULL) {
1924  			temp->level = temp->parent->level + 1;
1925  			if (!TAILQ_EMPTY(&temp->parent->cn_children))
1926  				cd9660_sorted_child_insert(temp->parent, temp);
1927  			else
1928  				TAILQ_INSERT_HEAD(&temp->parent->cn_children,
1929  				    temp, cn_next_child);
1930  		}
1931  	}
1932  
1933  	if (parent->node != NULL) {
1934  		tfsnode->type = parent->node->type;
1935  	}
1936  
1937  	/* Clear out file type bits */
1938  	tfsnode->type &= ~(S_IFMT);
1939  	if (file)
1940  		tfsnode->type |= S_IFREG;
1941  	else
1942  		tfsnode->type |= S_IFDIR;
1943  
1944  	/* Indicate that there is no spec entry (inode) */
1945  	tfsnode->flags &= ~(FSNODE_F_HASSPEC);
1946  #if 0
1947  	cd9660_copy_stat_info(parent, temp, file);
1948  #endif
1949  	return temp;
1950  }
1951  
1952  static cd9660node *
cd9660_create_file(iso9660_disk * diskStructure,const char * name,cd9660node * parent,cd9660node * me)1953  cd9660_create_file(iso9660_disk *diskStructure, const char *name,
1954      cd9660node *parent, cd9660node *me)
1955  {
1956  	cd9660node *temp;
1957  
1958  	temp = cd9660_create_virtual_entry(diskStructure, name, parent, 1, 1);
1959  	if (temp == NULL)
1960  		return NULL;
1961  
1962  	temp->fileDataLength = 0;
1963  
1964  	temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL;
1965  
1966  	temp->node->inode = ecalloc(1, sizeof(*temp->node->inode));
1967  	*temp->node->inode = *me->node->inode;
1968  
1969  	if (cd9660_translate_node_common(diskStructure, temp) == 0)
1970  		return NULL;
1971  	return temp;
1972  }
1973  
1974  /*
1975   * Create a new directory which does not exist on disk
1976   * @param const char * name The name to assign to the directory
1977   * @param const char * parent Pointer to the parent directory
1978   * @returns cd9660node * Pointer to the new directory
1979   */
1980  static cd9660node *
cd9660_create_directory(iso9660_disk * diskStructure,const char * name,cd9660node * parent,cd9660node * me)1981  cd9660_create_directory(iso9660_disk *diskStructure, const char *name,
1982      cd9660node *parent, cd9660node *me)
1983  {
1984  	cd9660node *temp;
1985  
1986  	temp = cd9660_create_virtual_entry(diskStructure, name, parent, 0, 1);
1987  	if (temp == NULL)
1988  		return NULL;
1989  	temp->node->type |= S_IFDIR;
1990  
1991  	temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL;
1992  
1993  	temp->node->inode = ecalloc(1, sizeof(*temp->node->inode));
1994  	*temp->node->inode = *me->node->inode;
1995  
1996  	if (cd9660_translate_node_common(diskStructure, temp) == 0)
1997  		return NULL;
1998  	return temp;
1999  }
2000  
2001  static cd9660node *
cd9660_create_special_directory(iso9660_disk * diskStructure,u_char type,cd9660node * parent)2002  cd9660_create_special_directory(iso9660_disk *diskStructure, u_char type,
2003      cd9660node *parent)
2004  {
2005  	cd9660node *temp, *first;
2006  	char na[2];
2007  
2008  	assert(parent != NULL);
2009  
2010  	if (type == CD9660_TYPE_DOT)
2011  		na[0] = 0;
2012  	else if (type == CD9660_TYPE_DOTDOT)
2013  		na[0] = 1;
2014  	else
2015  		return 0;
2016  
2017  	na[1] = 0;
2018  	if ((temp = cd9660_create_virtual_entry(diskStructure, na, parent,
2019  	    0, 0)) == NULL)
2020  		return NULL;
2021  
2022  	temp->parent = parent;
2023  	temp->type = type;
2024  	temp->isoDirRecord->length[0] = 34;
2025  	/* Dot record is always first */
2026  	if (type == CD9660_TYPE_DOT) {
2027  		parent->dot_record = temp;
2028  		TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child);
2029  	/* DotDot should be second */
2030  	} else if (type == CD9660_TYPE_DOTDOT) {
2031  		parent->dot_dot_record = temp;
2032  		/*
2033                   * If the first child is the dot record, insert
2034                   * this second.  Otherwise, insert it at the head.
2035  		 */
2036  		if ((first = TAILQ_FIRST(&parent->cn_children)) == NULL ||
2037  		    (first->type & CD9660_TYPE_DOT) == 0) {
2038  			TAILQ_INSERT_HEAD(&parent->cn_children, temp,
2039  			    cn_next_child);
2040  		} else {
2041  			TAILQ_INSERT_AFTER(&parent->cn_children, first, temp,
2042  			    cn_next_child);
2043  		}
2044  	}
2045  
2046  	return temp;
2047  }
2048  
2049  static int
cd9660_add_generic_bootimage(iso9660_disk * diskStructure,const char * bootimage)2050  cd9660_add_generic_bootimage(iso9660_disk *diskStructure, const char *bootimage)
2051  {
2052  	struct stat stbuf;
2053  
2054  	assert(bootimage != NULL);
2055  
2056  	if (*bootimage == '\0') {
2057  		warnx("Error: Boot image must be a filename");
2058  		return 0;
2059  	}
2060  
2061  	diskStructure->generic_bootimage = estrdup(bootimage);
2062  
2063  	/* Get information about the file */
2064  	if (lstat(diskStructure->generic_bootimage, &stbuf) == -1)
2065  		err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
2066  		    diskStructure->generic_bootimage);
2067  
2068  	if (stbuf.st_size > 32768) {
2069  		warnx("Error: Boot image must be no greater than 32768 bytes");
2070  		return 0;
2071  	}
2072  
2073  	if (diskStructure->verbose_level > 0) {
2074  		printf("Generic boot image has size %lld\n",
2075  		    (long long)stbuf.st_size);
2076  	}
2077  
2078  	diskStructure->has_generic_bootimage = 1;
2079  
2080  	return 1;
2081  }
2082