GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/makefs/cd9660.c Lines: 0 743 0.0 %
Date: 2017-11-07 Branches: 0 400 0.0 %

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