File: | src/usr.sbin/makefs/cd9660.c |
Warning: | line 1423, column 13 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: cd9660.c,v 1.23 2022/01/11 05:34:32 jsg 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 initialize 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)do { (&temp->cn_children)->tqh_first = ((void *)0); (&temp->cn_children)->tqh_last = &(&temp-> cn_children)->tqh_first; } while (0); | ||||
175 | temp->parent = temp->dot_record = temp->dot_dot_record = NULL((void *)0); | ||||
176 | temp->ptnext = temp->ptprev = temp->ptlast = NULL((void *)0); | ||||
177 | temp->node = NULL((void *)0); | ||||
178 | temp->isoDirRecord = NULL((void *)0); | ||||
179 | temp->isoExtAttributes = NULL((void *)0); | ||||
180 | temp->rr_real_parent = temp->rr_relocated = NULL((void *)0); | ||||
181 | temp->su_tail_data = NULL((void *)0); | ||||
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((void *)0); | ||||
228 | |||||
229 | /*memset(diskStructure->boot_descriptor, 0, 2048);*/ | ||||
230 | |||||
231 | diskStructure->is_bootable = 0; | ||||
232 | TAILQ_INIT(&diskStructure->boot_images)do { (&diskStructure->boot_images)->tqh_first = ((void *)0); (&diskStructure->boot_images)->tqh_last = & (&diskStructure->boot_images)->tqh_first; } while ( 0); | ||||
233 | LIST_INIT(&diskStructure->boot_entries)do { ((&diskStructure->boot_entries)->lh_first) = ( (void *)0); } while (0); | ||||
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){ name, ((void *)0), OPT_STRBUF, 0, 0 } \ | ||||
242 | { name, NULL((void *)0), OPT_STRBUF, 0, 0 } | ||||
243 | |||||
244 | #define OPT_NUM(name, field, min, max){ name, &diskStructure->field, sizeof(diskStructure-> field) == 8 ? OPT_INT64 : (sizeof(diskStructure->field) == 4 ? OPT_INT32 : (sizeof(diskStructure->field) == 2 ? OPT_INT16 : OPT_INT8)), 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){ name, &diskStructure->field, OPT_BOOL } \ | ||||
252 | { name, &diskStructure->field, OPT_BOOL } | ||||
253 | |||||
254 | const option_t cd9660_options[] = { | ||||
255 | OPT_BOOL("allow-deep-trees", allow_deep_trees){ "allow-deep-trees", &diskStructure->allow_deep_trees , OPT_BOOL }, | ||||
256 | OPT_BOOL("allow-multidot", allow_multidot){ "allow-multidot", &diskStructure->allow_multidot, OPT_BOOL }, | ||||
257 | OPT_STR("applicationid"){ "applicationid", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
258 | OPT_STR("boot-load-segment"){ "boot-load-segment", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
259 | OPT_STR("bootimage"){ "bootimage", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
260 | OPT_STR("generic-bootimage"){ "generic-bootimage", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
261 | OPT_STR("hard-disk-boot"){ "hard-disk-boot", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
262 | OPT_NUM("isolevel", isoLevel, 1, 3){ "isolevel", &diskStructure->isoLevel, sizeof(diskStructure ->isoLevel) == 8 ? OPT_INT64 : (sizeof(diskStructure->isoLevel ) == 4 ? OPT_INT32 : (sizeof(diskStructure->isoLevel) == 2 ? OPT_INT16 : OPT_INT8)), 1, 3 }, | ||||
263 | OPT_STR("label"){ "label", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
264 | OPT_STR("no-boot"){ "no-boot", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
265 | OPT_STR("no-emul-boot"){ "no-emul-boot", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
266 | OPT_BOOL("no-trailing-padding", include_padding_areas){ "no-trailing-padding", &diskStructure->include_padding_areas , OPT_BOOL }, | ||||
267 | OPT_BOOL("omit-trailing-period", omit_trailing_period){ "omit-trailing-period", &diskStructure->omit_trailing_period , OPT_BOOL }, | ||||
268 | OPT_STR("preparer"){ "preparer", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
269 | OPT_STR("publisher"){ "publisher", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
270 | OPT_BOOL("rockridge", rock_ridge_enabled){ "rockridge", &diskStructure->rock_ridge_enabled, OPT_BOOL }, | ||||
271 | OPT_STR("volumeid"){ "volumeid", ((void *)0), OPT_STRBUF, 0, 0 }, | ||||
272 | { .name = NULL((void *)0) } | ||||
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((void *)0)) | ||||
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)((option != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 329, __func__, "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((void *)0)) | ||||
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 ret, 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)((image != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 417, __func__, "image != NULL")); | ||||
418 | assert(dir != NULL)((dir != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 418, __func__, "dir != NULL")); | ||||
419 | assert(root != NULL)((root != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 419, __func__, "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_PADDING37); | ||||
434 | |||||
435 | real_root->level = 0; | ||||
436 | diskStructure->rootNode = real_root; | ||||
437 | real_root->type = CD9660_TYPE_DIR0x02; | ||||
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)(((&real_root->cn_children)->tqh_first) == ((void * )0))) { | ||||
444 | errx(1, "%s: converted directory is empty. " | ||||
445 | "Tree conversion failed", __func__); | ||||
446 | } else if (error
| ||||
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((void *)0)); | ||||
459 | } | ||||
460 | |||||
461 | /* Build path table structure */ | ||||
462 | diskStructure->pathTableLength = cd9660_generate_path_table( | ||||
463 | diskStructure); | ||||
464 | |||||
465 | pathTableSectors = CD9660_BLOCKS(diskStructure->sectorSize,((((diskStructure->pathTableLength)) + (((diskStructure-> sectorSize)) - 1)) / ((diskStructure->sectorSize))) | ||||
466 | diskStructure->pathTableLength)((((diskStructure->pathTableLength)) + (((diskStructure-> sectorSize)) - 1)) / ((diskStructure->sectorSize))); | ||||
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)((((totalSpace)) + (((diskStructure->sectorSize)) - 1)) / ( (diskStructure->sectorSize))); | ||||
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,((((diskStructure->susp_continuation_area_size)) + (((diskStructure ->sectorSize)) - 1)) / ((diskStructure->sectorSize))) | ||||
500 | diskStructure->susp_continuation_area_size)((((diskStructure->susp_continuation_area_size)) + (((diskStructure ->sectorSize)) - 1)) / ((diskStructure->sectorSize))); | ||||
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 | ret = cd9660_write_image(diskStructure, image); | ||||
518 | |||||
519 | /* Clean up data structures */ | ||||
520 | cd9660_free_structure(real_root); | ||||
521 | |||||
522 | if (ret == 0) /* cd9660_write_image() failed */ | ||||
523 | exit(1); | ||||
524 | } | ||||
525 | |||||
526 | /* Generic function pointer - implement later */ | ||||
527 | typedef int (*cd9660node_func)(cd9660node *); | ||||
528 | |||||
529 | static void | ||||
530 | cd9660_finalize_PVD(iso9660_disk *diskStructure) | ||||
531 | { | ||||
532 | time_t tstamp = Tflag ? stampts : time(NULL((void *)0)); | ||||
533 | |||||
534 | /* root should be a fixed size of 34 bytes since it has no name */ | ||||
535 | memcpy(diskStructure->primaryDescriptor.root_directory_record, | ||||
536 | diskStructure->rootNode->dot_record->isoDirRecord, 34); | ||||
537 | |||||
538 | /* In RRIP, this might be longer than 34 */ | ||||
539 | diskStructure->primaryDescriptor.root_directory_record[0] = 34; | ||||
540 | |||||
541 | /* Set up all the important numbers in the PVD */ | ||||
542 | cd9660_bothendian_dword(diskStructure->totalSectors, | ||||
543 | (unsigned char *)diskStructure->primaryDescriptor.volume_space_size); | ||||
544 | cd9660_bothendian_word(1, | ||||
545 | (unsigned char *)diskStructure->primaryDescriptor.volume_set_size); | ||||
546 | cd9660_bothendian_word(1, | ||||
547 | (unsigned char *) | ||||
548 | diskStructure->primaryDescriptor.volume_sequence_number); | ||||
549 | cd9660_bothendian_word(diskStructure->sectorSize, | ||||
550 | (unsigned char *) | ||||
551 | diskStructure->primaryDescriptor.logical_block_size); | ||||
552 | cd9660_bothendian_dword(diskStructure->pathTableLength, | ||||
553 | (unsigned char *)diskStructure->primaryDescriptor.path_table_size); | ||||
554 | |||||
555 | cd9660_731(diskStructure->primaryLittleEndianTableSector, | ||||
556 | (u_char *)diskStructure->primaryDescriptor.type_l_path_table); | ||||
557 | cd9660_732(diskStructure->primaryBigEndianTableSector, | ||||
558 | (u_char *)diskStructure->primaryDescriptor.type_m_path_table); | ||||
559 | |||||
560 | diskStructure->primaryDescriptor.file_structure_version[0] = 1; | ||||
561 | |||||
562 | /* Pad all strings with spaces instead of nulls */ | ||||
563 | cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_id, 32); | ||||
564 | cd9660_pad_string_spaces(diskStructure->primaryDescriptor.system_id, 32); | ||||
565 | cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_set_id, | ||||
566 | 128); | ||||
567 | cd9660_pad_string_spaces(diskStructure->primaryDescriptor.publisher_id, | ||||
568 | 128); | ||||
569 | cd9660_pad_string_spaces(diskStructure->primaryDescriptor.preparer_id, | ||||
570 | 128); | ||||
571 | cd9660_pad_string_spaces(diskStructure->primaryDescriptor.application_id, | ||||
572 | 128); | ||||
573 | cd9660_pad_string_spaces( | ||||
574 | diskStructure->primaryDescriptor.copyright_file_id, 37); | ||||
575 | cd9660_pad_string_spaces( | ||||
576 | diskStructure->primaryDescriptor.abstract_file_id, 37); | ||||
577 | cd9660_pad_string_spaces( | ||||
578 | diskStructure->primaryDescriptor.bibliographic_file_id, 37); | ||||
579 | |||||
580 | /* Setup dates */ | ||||
581 | cd9660_time_8426( | ||||
582 | (unsigned char *)diskStructure->primaryDescriptor.creation_date, | ||||
583 | tstamp); | ||||
584 | cd9660_time_8426( | ||||
585 | (unsigned char *)diskStructure->primaryDescriptor.modification_date, | ||||
586 | tstamp); | ||||
587 | |||||
588 | #if 0 | ||||
589 | cd9660_set_date(diskStructure->primaryDescriptor.expiration_date, | ||||
590 | tstamp); | ||||
591 | #endif | ||||
592 | memset(diskStructure->primaryDescriptor.expiration_date, '0' ,16); | ||||
593 | diskStructure->primaryDescriptor.expiration_date[16] = 0; | ||||
594 | |||||
595 | cd9660_time_8426( | ||||
596 | (unsigned char *)diskStructure->primaryDescriptor.effective_date, | ||||
597 | tstamp); | ||||
598 | } | ||||
599 | |||||
600 | static void | ||||
601 | cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 *record, | ||||
602 | u_char ext_attr_length, u_char flags, | ||||
603 | u_char name_len, const char * name) | ||||
604 | { | ||||
605 | record->ext_attr_length[0] = ext_attr_length; | ||||
606 | record->flags[0] = ISO_FLAG_CLEAR0x00 | flags; | ||||
607 | record->file_unit_size[0] = 0; | ||||
608 | record->interleave[0] = 0; | ||||
609 | cd9660_bothendian_word(1, record->volume_sequence_number); | ||||
610 | record->name_len[0] = name_len; | ||||
611 | memset(record->name, '\0', sizeof (record->name)); | ||||
612 | memcpy(record->name, name, name_len); | ||||
613 | record->length[0] = 33 + name_len; | ||||
614 | |||||
615 | /* Todo : better rounding */ | ||||
616 | record->length[0] += (record->length[0] & 1) ? 1 : 0; | ||||
617 | } | ||||
618 | |||||
619 | static void | ||||
620 | cd9660_setup_root_node(iso9660_disk *diskStructure) | ||||
621 | { | ||||
622 | cd9660_populate_iso_dir_record(diskStructure->rootNode->isoDirRecord, | ||||
623 | 0, ISO_FLAG_DIRECTORY0x02, 1, "\0"); | ||||
624 | |||||
625 | } | ||||
626 | |||||
627 | /*********** SUPPORT FUNCTIONS ***********/ | ||||
628 | static int | ||||
629 | cd9660_setup_volume_descriptors(iso9660_disk *diskStructure) | ||||
630 | { | ||||
631 | /* Boot volume descriptor should come second */ | ||||
632 | int sector = 16; | ||||
633 | /* For now, a fixed 2 : PVD and terminator */ | ||||
634 | volume_descriptor *temp, *t; | ||||
635 | |||||
636 | /* Set up the PVD */ | ||||
637 | temp = emalloc(sizeof(*temp)); | ||||
638 | temp->volumeDescriptorData = | ||||
639 | (unsigned char *)&diskStructure->primaryDescriptor; | ||||
640 | temp->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_PVD1; | ||||
641 | temp->volumeDescriptorData[6] = 1; | ||||
642 | temp->sector = sector; | ||||
643 | memcpy(temp->volumeDescriptorData + 1, | ||||
644 | ISO_VOLUME_DESCRIPTOR_STANDARD_ID"CD001", 5); | ||||
645 | diskStructure->firstVolumeDescriptor = temp; | ||||
646 | |||||
647 | sector++; | ||||
648 | /* Set up boot support if enabled. BVD must reside in sector 17 */ | ||||
649 | if (diskStructure->is_bootable) { | ||||
650 | t = emalloc(sizeof(*t)); | ||||
651 | t->volumeDescriptorData = ecalloc(1, 2048); | ||||
652 | temp->next = t; | ||||
653 | temp = t; | ||||
654 | t->sector = 17; | ||||
655 | cd9660_setup_boot_volume_descriptor(diskStructure, t); | ||||
656 | sector++; | ||||
657 | } | ||||
658 | |||||
659 | /* Set up the terminator */ | ||||
660 | t = emalloc(sizeof(*t)); | ||||
661 | t->volumeDescriptorData = ecalloc(1, 2048); | ||||
662 | temp->next = t; | ||||
663 | t->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_TERMINATOR255; | ||||
664 | t->next = 0; | ||||
665 | t->volumeDescriptorData[6] = 1; | ||||
666 | t->sector = sector; | ||||
667 | memcpy(t->volumeDescriptorData + 1, | ||||
668 | ISO_VOLUME_DESCRIPTOR_STANDARD_ID"CD001", 5); | ||||
669 | |||||
670 | sector++; | ||||
671 | return sector; | ||||
672 | } | ||||
673 | |||||
674 | #if 0 | ||||
675 | /* | ||||
676 | * Populate EAR at some point. Not required, but is used by NetBSD's | ||||
677 | * cd9660 support | ||||
678 | */ | ||||
679 | static int | ||||
680 | cd9660_fill_extended_attribute_record(cd9660node *node) | ||||
681 | { | ||||
682 | node->isoExtAttributes = emalloc(sizeof(*node->isoExtAttributes)); | ||||
683 | return 1; | ||||
684 | } | ||||
685 | #endif | ||||
686 | |||||
687 | static int | ||||
688 | cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode) | ||||
689 | { | ||||
690 | time_t tstamp = Tflag ? stampts : time(NULL((void *)0)); | ||||
691 | u_char flag; | ||||
692 | char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING37]; | ||||
693 | |||||
694 | /* Now populate the isoDirRecord structure */ | ||||
695 | memset(temp, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING37); | ||||
696 | |||||
697 | (void)cd9660_convert_filename(diskStructure, newnode->node->name, | ||||
698 | temp, sizeof temp, !(S_ISDIR(newnode->node->type)((newnode->node->type & 0170000) == 0040000))); | ||||
699 | |||||
700 | flag = ISO_FLAG_CLEAR0x00; | ||||
701 | if (S_ISDIR(newnode->node->type)((newnode->node->type & 0170000) == 0040000)) | ||||
702 | flag |= ISO_FLAG_DIRECTORY0x02; | ||||
703 | |||||
704 | cd9660_populate_iso_dir_record(newnode->isoDirRecord, 0, | ||||
705 | flag, strlen(temp), temp); | ||||
706 | |||||
707 | /* Set the various dates */ | ||||
708 | |||||
709 | /* If we want to use the current date and time */ | ||||
710 | |||||
711 | cd9660_time_915(newnode->isoDirRecord->date, tstamp); | ||||
712 | |||||
713 | cd9660_bothendian_dword(newnode->fileDataLength, | ||||
714 | newnode->isoDirRecord->size); | ||||
715 | /* If the file is a link, we want to set the size to 0 */ | ||||
716 | if (S_ISLNK(newnode->node->type)((newnode->node->type & 0170000) == 0120000)) | ||||
717 | newnode->fileDataLength = 0; | ||||
718 | |||||
719 | return 1; | ||||
720 | } | ||||
721 | |||||
722 | /* | ||||
723 | * Translate fsnode to cd9660node | ||||
724 | * Translate filenames and other metadata, including dates, sizes, | ||||
725 | * permissions, etc | ||||
726 | * @param struct fsnode * The node generated by makefs | ||||
727 | * @param struct cd9660node * The intermediate node to be written to | ||||
728 | * @returns int 0 on failure, 1 on success | ||||
729 | */ | ||||
730 | static int | ||||
731 | cd9660_translate_node(iso9660_disk *diskStructure, fsnode *node, | ||||
732 | cd9660node *newnode) | ||||
733 | { | ||||
734 | if (node == NULL((void *)0)) | ||||
735 | return 0; | ||||
736 | |||||
737 | newnode->isoDirRecord = emalloc(sizeof(*newnode->isoDirRecord)); | ||||
738 | /* Set the node pointer */ | ||||
739 | newnode->node = node; | ||||
740 | |||||
741 | /* Set the size */ | ||||
742 | if (!(S_ISDIR(node->type)((node->type & 0170000) == 0040000))) | ||||
743 | newnode->fileDataLength = node->inode->st.st_size; | ||||
744 | |||||
745 | if (cd9660_translate_node_common(diskStructure, newnode) == 0) | ||||
746 | return 0; | ||||
747 | |||||
748 | /* Finally, overwrite some of the values that are set by default */ | ||||
749 | cd9660_time_915(newnode->isoDirRecord->date, | ||||
750 | Tflag ? stampts : node->inode->st.st_mtimest_mtim.tv_sec); | ||||
751 | |||||
752 | return 1; | ||||
753 | } | ||||
754 | |||||
755 | /* | ||||
756 | * Compares two ISO filenames | ||||
757 | * @param const char * The first file name | ||||
758 | * @param const char * The second file name | ||||
759 | * @returns : -1 if first is less than second, 0 if they are the same, 1 if | ||||
760 | * the second is greater than the first | ||||
761 | */ | ||||
762 | static int | ||||
763 | cd9660_compare_filename(const char *first, const char *second) | ||||
764 | { | ||||
765 | /* | ||||
766 | * This can be made more optimal once it has been tested | ||||
767 | * (the extra character, for example, is for testing) | ||||
768 | */ | ||||
769 | |||||
770 | int p1 = 0; | ||||
771 | int p2 = 0; | ||||
772 | char c1, c2; | ||||
773 | /* First, on the filename */ | ||||
774 | |||||
775 | while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION30-1 | ||||
776 | && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION30-1) { | ||||
777 | c1 = first[p1]; | ||||
778 | c2 = second[p2]; | ||||
779 | if (c1 == '.' && c2 =='.') | ||||
780 | break; | ||||
781 | else if (c1 == '.') { | ||||
782 | p2++; | ||||
783 | c1 = ' '; | ||||
784 | } else if (c2 == '.') { | ||||
785 | p1++; | ||||
786 | c2 = ' '; | ||||
787 | } else { | ||||
788 | p1++; | ||||
789 | p2++; | ||||
790 | } | ||||
791 | |||||
792 | if (c1 < c2) | ||||
793 | return -1; | ||||
794 | else if (c1 > c2) { | ||||
795 | return 1; | ||||
796 | } | ||||
797 | } | ||||
798 | |||||
799 | if (first[p1] == '.' && second[p2] == '.') { | ||||
800 | p1++; | ||||
801 | p2++; | ||||
802 | while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION30 - 1 | ||||
803 | && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION30 - 1) { | ||||
804 | c1 = first[p1]; | ||||
805 | c2 = second[p2]; | ||||
806 | if (c1 == ';' && c2 == ';') | ||||
807 | break; | ||||
808 | else if (c1 == ';') { | ||||
809 | p2++; | ||||
810 | c1 = ' '; | ||||
811 | } else if (c2 == ';') { | ||||
812 | p1++; | ||||
813 | c2 = ' '; | ||||
814 | } else { | ||||
815 | p1++; | ||||
816 | p2++; | ||||
817 | } | ||||
818 | |||||
819 | if (c1 < c2) | ||||
820 | return -1; | ||||
821 | else if (c1 > c2) | ||||
822 | return 1; | ||||
823 | } | ||||
824 | } | ||||
825 | return 0; | ||||
826 | } | ||||
827 | |||||
828 | /* | ||||
829 | * Insert a node into list with ISO sorting rules | ||||
830 | * @param cd9660node * The head node of the list | ||||
831 | * @param cd9660node * The node to be inserted | ||||
832 | */ | ||||
833 | static void | ||||
834 | cd9660_sorted_child_insert(cd9660node *parent, cd9660node *cn_new) | ||||
835 | { | ||||
836 | int compare; | ||||
837 | cd9660node *cn; | ||||
838 | struct cd9660_children_head *head = &parent->cn_children; | ||||
839 | |||||
840 | /* TODO: Optimize? */ | ||||
841 | cn_new->parent = parent; | ||||
842 | |||||
843 | /* | ||||
844 | * first will either be 0, the . or the .. | ||||
845 | * if . or .., this means no other entry may be written before first | ||||
846 | * if 0, the new node may be inserted at the head | ||||
847 | */ | ||||
848 | |||||
849 | TAILQ_FOREACH(cn, head, cn_next_child)for((cn) = ((head)->tqh_first); (cn) != ((void *)0); (cn) = ((cn)->cn_next_child.tqe_next)) { | ||||
850 | /* | ||||
851 | * Dont insert a node twice - | ||||
852 | * that would cause an infinite loop | ||||
853 | */ | ||||
854 | if (cn_new == cn) | ||||
855 | return; | ||||
856 | |||||
857 | compare = cd9660_compare_filename(cn_new->isoDirRecord->name, | ||||
858 | cn->isoDirRecord->name); | ||||
859 | |||||
860 | if (compare == 0) | ||||
861 | compare = cd9660_compare_filename(cn_new->node->name, | ||||
862 | cn->node->name); | ||||
863 | |||||
864 | if (compare < 0) | ||||
865 | break; | ||||
866 | } | ||||
867 | if (cn == NULL((void *)0)) | ||||
868 | TAILQ_INSERT_TAIL(head, cn_new, cn_next_child)do { (cn_new)->cn_next_child.tqe_next = ((void *)0); (cn_new )->cn_next_child.tqe_prev = (head)->tqh_last; *(head)-> tqh_last = (cn_new); (head)->tqh_last = &(cn_new)-> cn_next_child.tqe_next; } while (0); | ||||
869 | else | ||||
870 | TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child)do { (cn_new)->cn_next_child.tqe_prev = (cn)->cn_next_child .tqe_prev; (cn_new)->cn_next_child.tqe_next = (cn); *(cn)-> cn_next_child.tqe_prev = (cn_new); (cn)->cn_next_child.tqe_prev = &(cn_new)->cn_next_child.tqe_next; } while (0); | ||||
871 | } | ||||
872 | |||||
873 | /* | ||||
874 | * Called After cd9660_sorted_child_insert | ||||
875 | * handles file collisions by suffixing each filename with ~n | ||||
876 | * where n represents the files respective place in the ordering | ||||
877 | */ | ||||
878 | static int | ||||
879 | cd9660_handle_collisions(iso9660_disk *diskStructure, cd9660node *colliding, | ||||
880 | int past) | ||||
881 | { | ||||
882 | cd9660node *iter, *next, *prev; | ||||
883 | int skip; | ||||
884 | int delete_chars = 0; | ||||
885 | int temp_past = past; | ||||
886 | int temp_skip; | ||||
887 | int flag = 0; | ||||
888 | cd9660node *end_of_range; | ||||
889 | |||||
890 | for (iter = TAILQ_FIRST(&colliding->cn_children)((&colliding->cn_children)->tqh_first); | ||||
891 | iter != NULL((void *)0) && (next = TAILQ_NEXT(iter, cn_next_child)((iter)->cn_next_child.tqe_next)) != NULL((void *)0);) { | ||||
892 | if (strcmp(iter->isoDirRecord->name, | ||||
893 | next->isoDirRecord->name) != 0) { | ||||
894 | iter = TAILQ_NEXT(iter, cn_next_child)((iter)->cn_next_child.tqe_next); | ||||
895 | continue; | ||||
896 | } | ||||
897 | flag = 1; | ||||
898 | temp_skip = skip = cd9660_count_collisions(iter); | ||||
899 | end_of_range = iter; | ||||
900 | while (temp_skip > 0) { | ||||
901 | temp_skip--; | ||||
902 | end_of_range = TAILQ_NEXT(end_of_range, cn_next_child)((end_of_range)->cn_next_child.tqe_next); | ||||
903 | } | ||||
904 | temp_past = past; | ||||
905 | while (temp_past > 0) { | ||||
906 | if ((next = TAILQ_NEXT(end_of_range, cn_next_child)((end_of_range)->cn_next_child.tqe_next)) != NULL((void *)0)) | ||||
907 | end_of_range = next; | ||||
908 | else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)(*(((struct cd9660_children_head *)((iter)->cn_next_child. tqe_prev))->tqh_last))) != NULL((void *)0)) | ||||
909 | iter = prev; | ||||
910 | else | ||||
911 | delete_chars++; | ||||
912 | temp_past--; | ||||
913 | } | ||||
914 | skip += past; | ||||
915 | iter = cd9660_rename_filename(diskStructure, iter, skip, | ||||
916 | delete_chars); | ||||
917 | } | ||||
918 | return flag; | ||||
919 | } | ||||
920 | |||||
921 | |||||
922 | static cd9660node * | ||||
923 | cd9660_rename_filename(iso9660_disk *diskStructure, cd9660node *iter, int num, | ||||
924 | int delete_chars) | ||||
925 | { | ||||
926 | int i = 0; | ||||
927 | int numbts, dot, semi, digit, digits, temp, powers, multiplier, count; | ||||
928 | char *naming; | ||||
929 | int maxlength; | ||||
930 | char *tmp; | ||||
931 | |||||
932 | /* TODO : A LOT of chanes regarding 8.3 filenames */ | ||||
933 | if (diskStructure->isoLevel == 1) | ||||
934 | maxlength = 8; | ||||
935 | else if (diskStructure->isoLevel == 2) | ||||
936 | maxlength = 31; | ||||
937 | else | ||||
938 | maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION30; | ||||
939 | |||||
940 | tmp = emalloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING37); | ||||
941 | |||||
942 | while (i < num && iter) { | ||||
943 | powers = 1; | ||||
944 | count = 0; | ||||
945 | digits = 1; | ||||
946 | multiplier = 1; | ||||
947 | while (((int)(i / powers) ) >= 10) { | ||||
948 | digits++; | ||||
949 | powers = powers * 10; | ||||
950 | } | ||||
951 | |||||
952 | naming = iter->o_name; | ||||
953 | |||||
954 | /* | ||||
955 | while ((*naming != '.') && (*naming != ';')) { | ||||
956 | naming++; | ||||
957 | count++; | ||||
958 | } | ||||
959 | */ | ||||
960 | |||||
961 | dot = -1; | ||||
962 | semi = -1; | ||||
963 | while (count < maxlength) { | ||||
964 | if (*naming == '.') | ||||
965 | dot = count; | ||||
966 | else if (*naming == ';') { | ||||
967 | semi = count; | ||||
968 | break; | ||||
969 | } | ||||
970 | naming++; | ||||
971 | count++; | ||||
972 | } | ||||
973 | |||||
974 | if ((count + digits) < maxlength) | ||||
975 | numbts = count; | ||||
976 | else | ||||
977 | numbts = maxlength - (digits); | ||||
978 | numbts -= delete_chars; | ||||
979 | |||||
980 | /* 8.3 rules - keep the extension, add before the dot */ | ||||
981 | |||||
982 | /* | ||||
983 | * This code makes a bunch of assumptions. | ||||
984 | * See if you can spot them all :) | ||||
985 | */ | ||||
986 | |||||
987 | #if 0 | ||||
988 | if (diskStructure->isoLevel == 1) { | ||||
989 | numbts = 8 - digits - delete_chars; | ||||
990 | if (dot < 0) { | ||||
991 | |||||
992 | } else { | ||||
993 | if (dot < 8) { | ||||
994 | memmove(&tmp[numbts],&tmp[dot],4); | ||||
995 | } | ||||
996 | } | ||||
997 | } | ||||
998 | #else | ||||
999 | (void)dot; | ||||
1000 | (void)semi; | ||||
1001 | (void)multiplier; | ||||
1002 | #endif | ||||
1003 | |||||
1004 | /* (copying just the filename before the '.' */ | ||||
1005 | memcpy(tmp, (iter->o_name), numbts); | ||||
1006 | |||||
1007 | /* adding the appropriate number following the name */ | ||||
1008 | temp = i; | ||||
1009 | while (digits > 0) { | ||||
1010 | digit = (int)(temp / powers); | ||||
1011 | temp = temp - digit * powers; | ||||
1012 | snprintf(&tmp[numbts] , ISO_FILENAME_MAXLENGTH_WITH_PADDING37 - numbts, "%d", digit); | ||||
1013 | digits--; | ||||
1014 | numbts++; | ||||
1015 | powers = powers / 10; | ||||
1016 | } | ||||
1017 | |||||
1018 | while ((*naming != ';') && (numbts < maxlength)) { | ||||
1019 | tmp[numbts] = (*naming); | ||||
1020 | naming++; | ||||
1021 | numbts++; | ||||
1022 | } | ||||
1023 | |||||
1024 | tmp[numbts] = ';'; | ||||
1025 | tmp[numbts+1] = '1'; | ||||
1026 | tmp[numbts+2] = '\0'; | ||||
1027 | |||||
1028 | /* | ||||
1029 | * now tmp has exactly the identifier | ||||
1030 | * we want so we'll copy it back to record | ||||
1031 | */ | ||||
1032 | memcpy((iter->isoDirRecord->name), tmp, numbts + 3); | ||||
1033 | |||||
1034 | iter = TAILQ_NEXT(iter, cn_next_child)((iter)->cn_next_child.tqe_next); | ||||
1035 | i++; | ||||
1036 | } | ||||
1037 | |||||
1038 | free(tmp); | ||||
1039 | return iter; | ||||
1040 | } | ||||
1041 | |||||
1042 | /* Todo: Figure out why these functions are nec. */ | ||||
1043 | static void | ||||
1044 | cd9660_copy_filenames(iso9660_disk *diskStructure, cd9660node *node) | ||||
1045 | { | ||||
1046 | cd9660node *cn; | ||||
1047 | |||||
1048 | if (TAILQ_EMPTY(&node->cn_children)(((&node->cn_children)->tqh_first) == ((void *)0))) | ||||
1049 | return; | ||||
1050 | |||||
1051 | if (TAILQ_FIRST(&node->cn_children)((&node->cn_children)->tqh_first)->isoDirRecord == NULL((void *)0)) { | ||||
1052 | debug_print_tree(diskStructure, diskStructure->rootNode, 0); | ||||
1053 | exit(1); | ||||
1054 | } | ||||
1055 | |||||
1056 | TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)for((cn) = ((&node->cn_children)->tqh_first); (cn) != ((void *)0); (cn) = ((cn)->cn_next_child.tqe_next)) { | ||||
1057 | cd9660_copy_filenames(diskStructure, cn); | ||||
1058 | memcpy(cn->o_name, cn->isoDirRecord->name, | ||||
1059 | ISO_FILENAME_MAXLENGTH_WITH_PADDING37); | ||||
1060 | } | ||||
1061 | } | ||||
1062 | |||||
1063 | static void | ||||
1064 | cd9660_sorting_nodes(cd9660node *node) | ||||
1065 | { | ||||
1066 | cd9660node *cn; | ||||
1067 | |||||
1068 | TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)for((cn) = ((&node->cn_children)->tqh_first); (cn) != ((void *)0); (cn) = ((cn)->cn_next_child.tqe_next)) | ||||
1069 | cd9660_sorting_nodes(cn); | ||||
1070 | cd9660_sort_nodes(node); | ||||
1071 | } | ||||
1072 | |||||
1073 | /* XXX Bubble sort. */ | ||||
1074 | static void | ||||
1075 | cd9660_sort_nodes(cd9660node *node) | ||||
1076 | { | ||||
1077 | cd9660node *cn, *next; | ||||
1078 | |||||
1079 | do { | ||||
1080 | TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)for((cn) = ((&node->cn_children)->tqh_first); (cn) != ((void *)0); (cn) = ((cn)->cn_next_child.tqe_next)) { | ||||
1081 | if ((next = TAILQ_NEXT(cn, cn_next_child)((cn)->cn_next_child.tqe_next)) == NULL((void *)0)) | ||||
1082 | return; | ||||
1083 | else if (strcmp(next->isoDirRecord->name, | ||||
1084 | cn->isoDirRecord->name) >= 0) | ||||
1085 | continue; | ||||
1086 | TAILQ_REMOVE(&node->cn_children, next, cn_next_child)do { if (((next)->cn_next_child.tqe_next) != ((void *)0)) ( next)->cn_next_child.tqe_next->cn_next_child.tqe_prev = (next)->cn_next_child.tqe_prev; else (&node->cn_children )->tqh_last = (next)->cn_next_child.tqe_prev; *(next)-> cn_next_child.tqe_prev = (next)->cn_next_child.tqe_next; ; ; } while (0); | ||||
1087 | TAILQ_INSERT_BEFORE(cn, next, cn_next_child)do { (next)->cn_next_child.tqe_prev = (cn)->cn_next_child .tqe_prev; (next)->cn_next_child.tqe_next = (cn); *(cn)-> cn_next_child.tqe_prev = (next); (cn)->cn_next_child.tqe_prev = &(next)->cn_next_child.tqe_next; } while (0); | ||||
1088 | break; | ||||
1089 | } | ||||
1090 | } while (cn != NULL((void *)0)); | ||||
1091 | } | ||||
1092 | |||||
1093 | static int | ||||
1094 | cd9660_count_collisions(cd9660node *copy) | ||||
1095 | { | ||||
1096 | int count = 0; | ||||
1097 | cd9660node *iter, *next; | ||||
1098 | |||||
1099 | for (iter = copy; | ||||
1100 | (next = TAILQ_NEXT(iter, cn_next_child)((iter)->cn_next_child.tqe_next)) != NULL((void *)0); | ||||
1101 | iter = next) { | ||||
1102 | if (cd9660_compare_filename(iter->isoDirRecord->name, | ||||
1103 | next->isoDirRecord->name) == 0) | ||||
1104 | count++; | ||||
1105 | else | ||||
1106 | return count; | ||||
1107 | } | ||||
1108 | #if 0 | ||||
1109 | if ((next = TAILQ_NEXT(iter, cn_next_child)((iter)->cn_next_child.tqe_next)) != NULL((void *)0)) { | ||||
1110 | printf("%s: count is %i \n", __func__, count); | ||||
1111 | compare = cd9660_compare_filename(iter->isoDirRecord->name, | ||||
1112 | next->isoDirRecord->name); | ||||
1113 | if (compare == 0) { | ||||
1114 | count++; | ||||
1115 | return cd9660_recurse_on_collision(next, count); | ||||
1116 | } else | ||||
1117 | return count; | ||||
1118 | } | ||||
1119 | #endif | ||||
1120 | return count; | ||||
1121 | } | ||||
1122 | |||||
1123 | static cd9660node * | ||||
1124 | cd9660_rrip_move_directory(iso9660_disk *diskStructure, cd9660node *dir) | ||||
1125 | { | ||||
1126 | char newname[9]; | ||||
1127 | cd9660node *tfile; | ||||
1128 | |||||
1129 | /* | ||||
1130 | * This function needs to: | ||||
1131 | * 1) Create an empty virtual file in place of the old directory | ||||
1132 | * 2) Point the virtual file to the new directory | ||||
1133 | * 3) Point the relocated directory to its old parent | ||||
1134 | * 4) Move the directory specified by dir into rr_moved_dir, | ||||
1135 | * and rename it to "diskStructure->rock_ridge_move_count" (as a string) | ||||
1136 | */ | ||||
1137 | |||||
1138 | /* First see if the moved directory even exists */ | ||||
1139 | if (diskStructure->rr_moved_dir == NULL((void *)0)) { | ||||
1140 | diskStructure->rr_moved_dir = cd9660_create_directory( | ||||
1141 | diskStructure, ISO_RRIP_DEFAULT_MOVE_DIR_NAME"RR_MOVED", | ||||
1142 | diskStructure->rootNode, dir); | ||||
1143 | if (diskStructure->rr_moved_dir == NULL((void *)0)) | ||||
1144 | return 0; | ||||
1145 | cd9660_time_915(diskStructure->rr_moved_dir->isoDirRecord->date, | ||||
1146 | Tflag ? stampts : start_time.tv_sec); | ||||
1147 | } | ||||
1148 | |||||
1149 | /* Create a file with the same ORIGINAL name */ | ||||
1150 | tfile = cd9660_create_file(diskStructure, dir->node->name, dir->parent, | ||||
1151 | dir); | ||||
1152 | if (tfile == NULL((void *)0)) | ||||
1153 | return NULL((void *)0); | ||||
1154 | |||||
1155 | diskStructure->rock_ridge_move_count++; | ||||
1156 | snprintf(newname, sizeof(newname), "%08i", | ||||
1157 | diskStructure->rock_ridge_move_count); | ||||
1158 | |||||
1159 | /* Point to old parent */ | ||||
1160 | dir->rr_real_parent = dir->parent; | ||||
1161 | |||||
1162 | /* Place the placeholder file */ | ||||
1163 | if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)(((&dir->rr_real_parent->cn_children)->tqh_first ) == ((void *)0))) { | ||||
1164 | TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile,do { if (((tfile)->cn_next_child.tqe_next = (&dir-> rr_real_parent->cn_children)->tqh_first) != ((void *)0) ) (&dir->rr_real_parent->cn_children)->tqh_first ->cn_next_child.tqe_prev = &(tfile)->cn_next_child. tqe_next; else (&dir->rr_real_parent->cn_children)-> tqh_last = &(tfile)->cn_next_child.tqe_next; (&dir ->rr_real_parent->cn_children)->tqh_first = (tfile); (tfile)->cn_next_child.tqe_prev = &(&dir->rr_real_parent ->cn_children)->tqh_first; } while (0) | ||||
1165 | cn_next_child)do { if (((tfile)->cn_next_child.tqe_next = (&dir-> rr_real_parent->cn_children)->tqh_first) != ((void *)0) ) (&dir->rr_real_parent->cn_children)->tqh_first ->cn_next_child.tqe_prev = &(tfile)->cn_next_child. tqe_next; else (&dir->rr_real_parent->cn_children)-> tqh_last = &(tfile)->cn_next_child.tqe_next; (&dir ->rr_real_parent->cn_children)->tqh_first = (tfile); (tfile)->cn_next_child.tqe_prev = &(&dir->rr_real_parent ->cn_children)->tqh_first; } while (0); | ||||
1166 | } else { | ||||
1167 | cd9660_sorted_child_insert(dir->rr_real_parent, tfile); | ||||
1168 | } | ||||
1169 | |||||
1170 | /* Point to new parent */ | ||||
1171 | dir->parent = diskStructure->rr_moved_dir; | ||||
1172 | |||||
1173 | /* Point the file to the moved directory */ | ||||
1174 | tfile->rr_relocated = dir; | ||||
1175 | |||||
1176 | /* Actually move the directory */ | ||||
1177 | cd9660_sorted_child_insert(diskStructure->rr_moved_dir, dir); | ||||
1178 | |||||
1179 | /* TODO: Inherit permissions / ownership (basically the entire inode) */ | ||||
1180 | |||||
1181 | /* Set the new name */ | ||||
1182 | memset(dir->isoDirRecord->name, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING37); | ||||
1183 | strncpy(dir->isoDirRecord->name, newname, 8); | ||||
1184 | dir->isoDirRecord->length[0] = 34 + 8; | ||||
1185 | dir->isoDirRecord->name_len[0] = 8; | ||||
1186 | |||||
1187 | return dir; | ||||
1188 | } | ||||
1189 | |||||
1190 | static int | ||||
1191 | cd9660_add_dot_records(iso9660_disk *diskStructure, cd9660node *root) | ||||
1192 | { | ||||
1193 | struct cd9660_children_head *head = &root->cn_children; | ||||
1194 | cd9660node *cn; | ||||
1195 | |||||
1196 | TAILQ_FOREACH(cn, head, cn_next_child)for((cn) = ((head)->tqh_first); (cn) != ((void *)0); (cn) = ((cn)->cn_next_child.tqe_next)) { | ||||
1197 | if ((cn->type & CD9660_TYPE_DIR0x02) == 0) | ||||
1198 | continue; | ||||
1199 | /* Recursion first */ | ||||
1200 | cd9660_add_dot_records(diskStructure, cn); | ||||
1201 | } | ||||
1202 | cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOT0x04, root); | ||||
1203 | cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOTDOT0x08, | ||||
1204 | root); | ||||
1205 | return 1; | ||||
1206 | } | ||||
1207 | |||||
1208 | /* | ||||
1209 | * Convert node to cd9660 structure | ||||
1210 | * This function is designed to be called recursively on the root node of | ||||
1211 | * the filesystem | ||||
1212 | * Lots of recursion going on here, want to make sure it is efficient | ||||
1213 | * @param struct fsnode * The root node to be converted | ||||
1214 | * @param struct cd9660* The parent node (should not be NULL) | ||||
1215 | * @param int Current directory depth | ||||
1216 | * @param int* Running count of the number of directories that are being created | ||||
1217 | */ | ||||
1218 | static void | ||||
1219 | cd9660_convert_structure(iso9660_disk *diskStructure, fsnode *root, | ||||
1220 | cd9660node *parent_node, int level, int *numDirectories, int *error) | ||||
1221 | { | ||||
1222 | fsnode *iterator = root; | ||||
1223 | cd9660node *this_node; | ||||
1224 | int working_level; | ||||
1225 | int add; | ||||
1226 | int flag = 0; | ||||
1227 | int counter = 0; | ||||
1228 | |||||
1229 | /* | ||||
1230 | * Newer, more efficient method, reduces recursion depth | ||||
1231 | */ | ||||
1232 | if (root == NULL((void *)0)) { | ||||
1233 | warnx("%s: root is null", __func__); | ||||
1234 | return; | ||||
1235 | } | ||||
1236 | |||||
1237 | /* Test for an empty directory - makefs still gives us the . record */ | ||||
1238 | if ((S_ISDIR(root->type)((root->type & 0170000) == 0040000)) && (root->name[0] == '.') | ||||
1239 | && (root->name[1] == '\0')) { | ||||
1240 | root = root->next; | ||||
1241 | if (root == NULL((void *)0)) | ||||
1242 | return; | ||||
1243 | } | ||||
1244 | if ((this_node = cd9660_allocate_cd9660node()) == NULL((void *)0)) { | ||||
1245 | CD9660_MEM_ALLOC_ERROR(__func__)err(1, "%s, %s l. %d", __func__, "/usr/src/usr.sbin/makefs/cd9660.c" , 1245); | ||||
1246 | } | ||||
1247 | |||||
1248 | /* | ||||
1249 | * To reduce the number of recursive calls, we will iterate over | ||||
1250 | * the next pointers to the right. | ||||
1251 | */ | ||||
1252 | while (iterator != NULL((void *)0)) { | ||||
1253 | add = 1; | ||||
1254 | /* | ||||
1255 | * Increment the directory count if this is a directory | ||||
1256 | * Ignore "." entries. We will generate them later | ||||
1257 | */ | ||||
1258 | if (!S_ISDIR(iterator->type)((iterator->type & 0170000) == 0040000) || | ||||
1259 | strcmp(iterator->name, ".") != 0) { | ||||
1260 | |||||
1261 | /* Translate the node, including its filename */ | ||||
1262 | this_node->parent = parent_node; | ||||
1263 | cd9660_translate_node(diskStructure, iterator, | ||||
1264 | this_node); | ||||
1265 | this_node->level = level; | ||||
1266 | |||||
1267 | if (S_ISDIR(iterator->type)((iterator->type & 0170000) == 0040000)) { | ||||
1268 | (*numDirectories)++; | ||||
1269 | this_node->type = CD9660_TYPE_DIR0x02; | ||||
1270 | working_level = level + 1; | ||||
1271 | |||||
1272 | /* | ||||
1273 | * If at level 8, directory would be at 8 | ||||
1274 | * and have children at 9 which is not | ||||
1275 | * allowed as per ISO spec | ||||
1276 | */ | ||||
1277 | if (level == 8) { | ||||
1278 | if ((!diskStructure->allow_deep_trees) && | ||||
1279 | (!diskStructure->rock_ridge_enabled)) { | ||||
1280 | warnx("error: found entry " | ||||
1281 | "with depth greater " | ||||
1282 | "than 8."); | ||||
1283 | (*error) = 1; | ||||
1284 | return; | ||||
1285 | } else if (diskStructure-> | ||||
1286 | rock_ridge_enabled) { | ||||
1287 | working_level = 3; | ||||
1288 | /* | ||||
1289 | * Moved directory is actually | ||||
1290 | * at level 2. | ||||
1291 | */ | ||||
1292 | this_node->level = | ||||
1293 | working_level - 1; | ||||
1294 | if (cd9660_rrip_move_directory( | ||||
1295 | diskStructure, | ||||
1296 | this_node) == 0) { | ||||
1297 | warnx("Failure in " | ||||
1298 | "cd9660_rrip_" | ||||
1299 | "move_directory" | ||||
1300 | ); | ||||
1301 | (*error) = 1; | ||||
1302 | return; | ||||
1303 | } | ||||
1304 | add = 0; | ||||
1305 | } | ||||
1306 | } | ||||
1307 | |||||
1308 | /* Do the recursive call on the children */ | ||||
1309 | if (iterator->child != 0) { | ||||
1310 | cd9660_convert_structure(diskStructure, | ||||
1311 | iterator->child, this_node, | ||||
1312 | working_level, | ||||
1313 | numDirectories, error); | ||||
1314 | |||||
1315 | if ((*error) == 1) { | ||||
1316 | warnx("%s: Error on recursive " | ||||
1317 | "call", __func__); | ||||
1318 | return; | ||||
1319 | } | ||||
1320 | } | ||||
1321 | |||||
1322 | } else { | ||||
1323 | /* Only directories should have children */ | ||||
1324 | assert(iterator->child == NULL)((iterator->child == ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 1324, __func__, "iterator->child == NULL")); | ||||
1325 | |||||
1326 | this_node->type = CD9660_TYPE_FILE0x01; | ||||
1327 | } | ||||
1328 | |||||
1329 | /* | ||||
1330 | * Finally, do a sorted insert | ||||
1331 | */ | ||||
1332 | if (add) { | ||||
1333 | cd9660_sorted_child_insert( | ||||
1334 | parent_node, this_node); | ||||
1335 | } | ||||
1336 | |||||
1337 | /*Allocate new temp_node */ | ||||
1338 | if (iterator->next != 0) { | ||||
1339 | this_node = cd9660_allocate_cd9660node(); | ||||
1340 | if (this_node == NULL((void *)0)) | ||||
1341 | CD9660_MEM_ALLOC_ERROR(__func__)err(1, "%s, %s l. %d", __func__, "/usr/src/usr.sbin/makefs/cd9660.c" , 1341); | ||||
1342 | } | ||||
1343 | } | ||||
1344 | iterator = iterator->next; | ||||
1345 | } | ||||
1346 | |||||
1347 | /* cd9660_handle_collisions(first_node); */ | ||||
1348 | |||||
1349 | /* TODO: need cleanup */ | ||||
1350 | cd9660_copy_filenames(diskStructure, parent_node); | ||||
1351 | |||||
1352 | do { | ||||
1353 | flag = cd9660_handle_collisions(diskStructure, parent_node, | ||||
1354 | counter); | ||||
1355 | counter++; | ||||
1356 | cd9660_sorting_nodes(parent_node); | ||||
1357 | } while ((flag == 1) && (counter < 100)); | ||||
1358 | } | ||||
1359 | |||||
1360 | /* | ||||
1361 | * Clean up the cd9660node tree | ||||
1362 | * This is designed to be called recursively on the root node | ||||
1363 | * @param struct cd9660node *root The node to free | ||||
1364 | * @returns void | ||||
1365 | */ | ||||
1366 | static void | ||||
1367 | cd9660_free_structure(cd9660node *root) | ||||
1368 | { | ||||
1369 | cd9660node *cn; | ||||
1370 | |||||
1371 | while ((cn = TAILQ_FIRST(&root->cn_children)((&root->cn_children)->tqh_first)) != NULL((void *)0)) { | ||||
1372 | TAILQ_REMOVE(&root->cn_children, cn, cn_next_child)do { if (((cn)->cn_next_child.tqe_next) != ((void *)0)) (cn )->cn_next_child.tqe_next->cn_next_child.tqe_prev = (cn )->cn_next_child.tqe_prev; else (&root->cn_children )->tqh_last = (cn)->cn_next_child.tqe_prev; *(cn)->cn_next_child .tqe_prev = (cn)->cn_next_child.tqe_next; ; ; } while (0); | ||||
1373 | cd9660_free_structure(cn); | ||||
1374 | } | ||||
1375 | free(root); | ||||
1376 | } | ||||
1377 | |||||
1378 | /* | ||||
1379 | * Be a little more memory conservative: | ||||
1380 | * instead of having the TAILQ_ENTRY as part of the cd9660node, | ||||
1381 | * just create a temporary structure | ||||
1382 | */ | ||||
1383 | struct ptq_entry | ||||
1384 | { | ||||
1385 | TAILQ_ENTRY(ptq_entry)struct { struct ptq_entry *tqe_next; struct ptq_entry **tqe_prev ; } ptq; | ||||
1386 | cd9660node *node; | ||||
1387 | } *n; | ||||
1388 | |||||
1389 | #define PTQUEUE_NEW(n,s,r,t){ n = emalloc(sizeof(struct s)); if (n == ((void *)0)) return r; n->node = t;}{\ | ||||
1390 | n = emalloc(sizeof(struct s)); \ | ||||
1391 | if (n == NULL((void *)0)) \ | ||||
1392 | return r; \ | ||||
1393 | n->node = t;\ | ||||
1394 | } | ||||
1395 | |||||
1396 | /* | ||||
1397 | * Generate the path tables | ||||
1398 | * The specific implementation of this function is left as an exercise to the | ||||
1399 | * programmer. It could be done recursively. Make sure you read how the path | ||||
1400 | * table has to be laid out, it has levels. | ||||
1401 | * @param struct iso9660_disk *disk The disk image | ||||
1402 | * @returns int The number of built path tables (between 1 and 4), 0 on failure | ||||
1403 | */ | ||||
1404 | static int | ||||
1405 | cd9660_generate_path_table(iso9660_disk *diskStructure) | ||||
1406 | { | ||||
1407 | cd9660node *cn, *dirNode = diskStructure->rootNode; | ||||
1408 | cd9660node *last = dirNode; | ||||
1409 | int pathTableSize = 0; /* computed as we go */ | ||||
1410 | int counter = 1; /* root gets a count of 0 */ | ||||
1411 | |||||
1412 | TAILQ_HEAD(cd9660_pt_head, ptq_entry)struct cd9660_pt_head { struct ptq_entry *tqh_first; struct ptq_entry **tqh_last; } pt_head; | ||||
1413 | TAILQ_INIT(&pt_head)do { (&pt_head)->tqh_first = ((void *)0); (&pt_head )->tqh_last = &(&pt_head)->tqh_first; } while ( 0); | ||||
1414 | |||||
1415 | PTQUEUE_NEW(n, ptq_entry, -1, diskStructure->rootNode){ n = emalloc(sizeof(struct ptq_entry)); if (n == ((void *)0) ) return -1; n->node = diskStructure->rootNode;}; | ||||
1416 | |||||
1417 | /* Push the root node */ | ||||
1418 | TAILQ_INSERT_HEAD(&pt_head, n, ptq)do { if (((n)->ptq.tqe_next = (&pt_head)->tqh_first ) != ((void *)0)) (&pt_head)->tqh_first->ptq.tqe_prev = &(n)->ptq.tqe_next; else (&pt_head)->tqh_last = &(n)->ptq.tqe_next; (&pt_head)->tqh_first = ( n); (n)->ptq.tqe_prev = &(&pt_head)->tqh_first; } while (0); | ||||
1419 | |||||
1420 | /* Breadth-first traversal of file structure */ | ||||
1421 | while (pt_head.tqh_first
| ||||
1422 | n = pt_head.tqh_first; | ||||
1423 | dirNode = n->node; | ||||
| |||||
1424 | TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq)do { if (((pt_head.tqh_first)->ptq.tqe_next) != ((void *)0 )) (pt_head.tqh_first)->ptq.tqe_next->ptq.tqe_prev = (pt_head .tqh_first)->ptq.tqe_prev; else (&pt_head)->tqh_last = (pt_head.tqh_first)->ptq.tqe_prev; *(pt_head.tqh_first) ->ptq.tqe_prev = (pt_head.tqh_first)->ptq.tqe_next; ; ; } while (0); | ||||
1425 | free(n); | ||||
1426 | |||||
1427 | /* Update the size */ | ||||
1428 | pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE8 | ||||
1429 | + dirNode->isoDirRecord->name_len[0]+ | ||||
1430 | (dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1); | ||||
1431 | /* includes the padding bit */ | ||||
1432 | |||||
1433 | dirNode->ptnumber=counter; | ||||
1434 | if (dirNode
| ||||
1435 | last->ptnext = dirNode; | ||||
1436 | dirNode->ptprev = last; | ||||
1437 | } | ||||
1438 | last = dirNode; | ||||
1439 | |||||
1440 | /* Push children onto queue */ | ||||
1441 | TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child)for((cn) = ((&dirNode->cn_children)->tqh_first); (cn ) != ((void *)0); (cn) = ((cn)->cn_next_child.tqe_next)) { | ||||
1442 | /* | ||||
1443 | * Dont add the DOT and DOTDOT types to the path | ||||
1444 | * table. | ||||
1445 | */ | ||||
1446 | if ((cn->type != CD9660_TYPE_DOT0x04) | ||||
1447 | && (cn->type != CD9660_TYPE_DOTDOT0x08)) { | ||||
1448 | |||||
1449 | if (S_ISDIR(cn->node->type)((cn->node->type & 0170000) == 0040000)) { | ||||
1450 | PTQUEUE_NEW(n, ptq_entry, -1, cn){ n = emalloc(sizeof(struct ptq_entry)); if (n == ((void *)0) ) return -1; n->node = cn;}; | ||||
1451 | TAILQ_INSERT_TAIL(&pt_head, n, ptq)do { (n)->ptq.tqe_next = ((void *)0); (n)->ptq.tqe_prev = (&pt_head)->tqh_last; *(&pt_head)->tqh_last = (n); (&pt_head)->tqh_last = &(n)->ptq.tqe_next ; } while (0); | ||||
1452 | } | ||||
1453 | } | ||||
1454 | } | ||||
1455 | counter++; | ||||
1456 | } | ||||
1457 | return pathTableSize; | ||||
1458 | } | ||||
1459 | |||||
1460 | char * | ||||
1461 | cd9660_compute_full_filename(cd9660node *node) | ||||
1462 | { | ||||
1463 | static char buf[PATH_MAX1024]; | ||||
1464 | int len; | ||||
1465 | |||||
1466 | len = snprintf(buf, PATH_MAX1024, "%s/%s/%s", node->node->root, | ||||
1467 | node->node->path, node->node->name); | ||||
1468 | if (len < 0) { | ||||
1469 | warn(NULL((void *)0)); | ||||
1470 | return NULL((void *)0); | ||||
1471 | } else if (len >= PATH_MAX1024) { | ||||
1472 | warnc(ENAMETOOLONG63, NULL((void *)0)); | ||||
1473 | return NULL((void *)0); | ||||
1474 | } | ||||
1475 | return buf; | ||||
1476 | } | ||||
1477 | |||||
1478 | /* | ||||
1479 | * TODO: These two functions are almost identical. | ||||
1480 | * Some code cleanup is possible here | ||||
1481 | * | ||||
1482 | * XXX bounds checking! | ||||
1483 | */ | ||||
1484 | static int | ||||
1485 | cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname, | ||||
1486 | char *newname, size_t newnamelen, int is_file) | ||||
1487 | { | ||||
1488 | /* | ||||
1489 | * ISO 9660 : 10.1 | ||||
1490 | * File Name shall not contain more than 8 d or d1 characters | ||||
1491 | * File Name Extension shall not contain more than 3 d or d1 characters | ||||
1492 | * Directory Identifier shall not contain more than 8 d or d1 characters | ||||
1493 | */ | ||||
1494 | int namelen = 0; | ||||
1495 | int extlen = 0; | ||||
1496 | int found_ext = 0; | ||||
1497 | char *orignewname = newname; | ||||
1498 | |||||
1499 | while (*oldname != '\0' && extlen < 3) { | ||||
1500 | /* Handle period first, as it is special */ | ||||
1501 | if (*oldname == '.') { | ||||
1502 | if (found_ext) { | ||||
1503 | *newname++ = '_'; | ||||
1504 | extlen ++; | ||||
1505 | } | ||||
1506 | else { | ||||
1507 | *newname++ = '.'; | ||||
1508 | found_ext = 1; | ||||
1509 | } | ||||
1510 | } else { | ||||
1511 | /* Enforce 12.3 / 8 */ | ||||
1512 | if (namelen == 8 && !found_ext) | ||||
1513 | break; | ||||
1514 | |||||
1515 | if (islower((unsigned char)*oldname)) | ||||
1516 | *newname++ = toupper((unsigned char)*oldname); | ||||
1517 | else if (isupper((unsigned char)*oldname) | ||||
1518 | || isdigit((unsigned char)*oldname)) | ||||
1519 | *newname++ = *oldname; | ||||
1520 | else | ||||
1521 | *newname++ = '_'; | ||||
1522 | |||||
1523 | if (found_ext) | ||||
1524 | extlen++; | ||||
1525 | else | ||||
1526 | namelen++; | ||||
1527 | } | ||||
1528 | oldname++; | ||||
1529 | } | ||||
1530 | if (is_file) { | ||||
1531 | if (!found_ext && !diskStructure->omit_trailing_period) | ||||
1532 | *newname++ = '.'; | ||||
1533 | /* Add version */ | ||||
1534 | snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1); | ||||
1535 | } | ||||
1536 | return namelen + extlen + found_ext; | ||||
1537 | } | ||||
1538 | |||||
1539 | /* XXX bounds checking! */ | ||||
1540 | static int | ||||
1541 | cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname, | ||||
1542 | char *newname, size_t newnamelen, int is_file) | ||||
1543 | { | ||||
1544 | /* | ||||
1545 | * ISO 9660 : 7.5.1 | ||||
1546 | * File name : 0+ d or d1 characters | ||||
1547 | * separator 1 (.) | ||||
1548 | * File name extension : 0+ d or d1 characters | ||||
1549 | * separator 2 (;) | ||||
1550 | * File version number (5 characters, 1-32767) | ||||
1551 | * 1 <= Sum of File name and File name extension <= 30 | ||||
1552 | */ | ||||
1553 | int namelen = 0; | ||||
1554 | int extlen = 0; | ||||
1555 | int found_ext = 0; | ||||
1556 | char *orignewname = newname; | ||||
1557 | |||||
1558 | while (*oldname != '\0' && namelen + extlen < 30) { | ||||
1559 | /* Handle period first, as it is special */ | ||||
1560 | if (*oldname == '.') { | ||||
1561 | if (found_ext) { | ||||
1562 | if (diskStructure->allow_multidot) { | ||||
1563 | *newname++ = '.'; | ||||
1564 | } else { | ||||
1565 | *newname++ = '_'; | ||||
1566 | } | ||||
1567 | extlen ++; | ||||
1568 | } | ||||
1569 | else { | ||||
1570 | *newname++ = '.'; | ||||
1571 | found_ext = 1; | ||||
1572 | } | ||||
1573 | } else { | ||||
1574 | if (islower((unsigned char)*oldname)) | ||||
1575 | *newname++ = toupper((unsigned char)*oldname); | ||||
1576 | else if (isupper((unsigned char)*oldname) || | ||||
1577 | isdigit((unsigned char)*oldname)) | ||||
1578 | *newname++ = *oldname; | ||||
1579 | else if (diskStructure->allow_multidot && | ||||
1580 | *oldname == '.') { | ||||
1581 | *newname++ = '.'; | ||||
1582 | } else { | ||||
1583 | *newname++ = '_'; | ||||
1584 | } | ||||
1585 | |||||
1586 | if (found_ext) | ||||
1587 | extlen++; | ||||
1588 | else | ||||
1589 | namelen++; | ||||
1590 | } | ||||
1591 | oldname ++; | ||||
1592 | } | ||||
1593 | if (is_file) { | ||||
1594 | if (!found_ext && !diskStructure->omit_trailing_period) | ||||
1595 | *newname++ = '.'; | ||||
1596 | /* Add version */ | ||||
1597 | snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1); | ||||
1598 | } | ||||
1599 | return namelen + extlen + found_ext; | ||||
1600 | } | ||||
1601 | |||||
1602 | /* | ||||
1603 | * Convert a file name to ISO compliant file name | ||||
1604 | * @param char * oldname The original filename | ||||
1605 | * @param char ** newname The new file name, in the appropriate character | ||||
1606 | * set and of appropriate length | ||||
1607 | * @param int 1 if file, 0 if directory | ||||
1608 | * @returns int The length of the new string | ||||
1609 | */ | ||||
1610 | static int | ||||
1611 | cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname, | ||||
1612 | char *newname, size_t newnamelen, int is_file) | ||||
1613 | { | ||||
1614 | if (diskStructure->isoLevel == 1) | ||||
1615 | return cd9660_level1_convert_filename(diskStructure, | ||||
1616 | oldname, newname, newnamelen, is_file); | ||||
1617 | else if (diskStructure->isoLevel == 2) | ||||
1618 | return cd9660_level2_convert_filename(diskStructure, | ||||
1619 | oldname, newname, newnamelen, is_file); | ||||
1620 | abort(); | ||||
1621 | } | ||||
1622 | |||||
1623 | int | ||||
1624 | cd9660_compute_record_size(iso9660_disk *diskStructure, cd9660node *node) | ||||
1625 | { | ||||
1626 | int size = node->isoDirRecord->length[0]; | ||||
1627 | |||||
1628 | if (diskStructure->rock_ridge_enabled) | ||||
1629 | size += node->susp_entry_size; | ||||
1630 | size += node->su_tail_size; | ||||
1631 | size += size & 1; /* Ensure length of record is even. */ | ||||
1632 | assert(size <= 254)((size <= 254) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 1632, __func__, "size <= 254")); | ||||
1633 | return size; | ||||
1634 | } | ||||
1635 | |||||
1636 | static void | ||||
1637 | cd9660_populate_dot_records(iso9660_disk *diskStructure, cd9660node *node) | ||||
1638 | { | ||||
1639 | node->dot_record->fileDataSector = node->fileDataSector; | ||||
1640 | memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34); | ||||
1641 | node->dot_record->isoDirRecord->name_len[0] = 1; | ||||
1642 | node->dot_record->isoDirRecord->name[0] = 0; | ||||
1643 | node->dot_record->isoDirRecord->name[1] = 0; | ||||
1644 | node->dot_record->isoDirRecord->length[0] = 34; | ||||
1645 | node->dot_record->fileRecordSize = | ||||
1646 | cd9660_compute_record_size(diskStructure, node->dot_record); | ||||
1647 | |||||
1648 | if (node == diskStructure->rootNode) { | ||||
1649 | node->dot_dot_record->fileDataSector = node->fileDataSector; | ||||
1650 | memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord, | ||||
1651 | 34); | ||||
1652 | } else { | ||||
1653 | node->dot_dot_record->fileDataSector = | ||||
1654 | node->parent->fileDataSector; | ||||
1655 | memcpy(node->dot_dot_record->isoDirRecord, | ||||
1656 | node->parent->isoDirRecord,34); | ||||
1657 | } | ||||
1658 | node->dot_dot_record->isoDirRecord->name_len[0] = 1; | ||||
1659 | node->dot_dot_record->isoDirRecord->name[0] = 1; | ||||
1660 | node->dot_dot_record->isoDirRecord->name[1] = 0; | ||||
1661 | node->dot_dot_record->isoDirRecord->length[0] = 34; | ||||
1662 | node->dot_dot_record->fileRecordSize = | ||||
1663 | cd9660_compute_record_size(diskStructure, node->dot_dot_record); | ||||
1664 | } | ||||
1665 | |||||
1666 | /* | ||||
1667 | * @param struct cd9660node *node The node | ||||
1668 | * @param int The offset (in bytes) - SHOULD align to the beginning of a sector | ||||
1669 | * @returns int The total size of files and directory entries (should be | ||||
1670 | * a multiple of sector size) | ||||
1671 | */ | ||||
1672 | static int64_t | ||||
1673 | cd9660_compute_offsets(iso9660_disk *diskStructure, cd9660node *node, | ||||
1674 | int64_t startOffset) | ||||
1675 | { | ||||
1676 | /* | ||||
1677 | * This function needs to compute the size of directory records and | ||||
1678 | * runs, file lengths, and set the appropriate variables both in | ||||
1679 | * cd9660node and isoDirEntry | ||||
1680 | */ | ||||
1681 | int64_t used_bytes = 0; | ||||
1682 | int64_t current_sector_usage = 0; | ||||
1683 | cd9660node *child; | ||||
1684 | fsinode *inode; | ||||
1685 | int64_t r; | ||||
1686 | |||||
1687 | assert(node != NULL)((node != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 1687, __func__, "node != NULL")); | ||||
1688 | |||||
1689 | |||||
1690 | /* | ||||
1691 | * NOTE : There needs to be some special case detection for | ||||
1692 | * the "real root" node, since for it, node->node is undefined | ||||
1693 | */ | ||||
1694 | |||||
1695 | node->fileDataSector = -1; | ||||
1696 | |||||
1697 | if (node->type & CD9660_TYPE_DIR0x02) { | ||||
1698 | node->fileRecordSize = cd9660_compute_record_size( | ||||
1699 | diskStructure, node); | ||||
1700 | /*Set what sector this directory starts in*/ | ||||
1701 | node->fileDataSector = | ||||
1702 | CD9660_BLOCKS(diskStructure->sectorSize,startOffset)((((startOffset)) + (((diskStructure->sectorSize)) - 1)) / ((diskStructure->sectorSize))); | ||||
1703 | |||||
1704 | cd9660_bothendian_dword(node->fileDataSector, | ||||
1705 | node->isoDirRecord->extent); | ||||
1706 | |||||
1707 | /* | ||||
1708 | * First loop over children, need to know the size of | ||||
1709 | * their directory records | ||||
1710 | */ | ||||
1711 | node->fileSectorsUsed = 1; | ||||
1712 | TAILQ_FOREACH(child, &node->cn_children, cn_next_child)for((child) = ((&node->cn_children)->tqh_first); (child ) != ((void *)0); (child) = ((child)->cn_next_child.tqe_next )) { | ||||
1713 | node->fileDataLength += | ||||
1714 | cd9660_compute_record_size(diskStructure, child); | ||||
1715 | if ((cd9660_compute_record_size(diskStructure, child) + | ||||
1716 | current_sector_usage) >= | ||||
1717 | diskStructure->sectorSize) { | ||||
1718 | current_sector_usage = 0; | ||||
1719 | node->fileSectorsUsed++; | ||||
1720 | } | ||||
1721 | |||||
1722 | current_sector_usage += | ||||
1723 | cd9660_compute_record_size(diskStructure, child); | ||||
1724 | } | ||||
1725 | |||||
1726 | cd9660_bothendian_dword(node->fileSectorsUsed * | ||||
1727 | diskStructure->sectorSize,node->isoDirRecord->size); | ||||
1728 | |||||
1729 | /* | ||||
1730 | * This should point to the sector after the directory | ||||
1731 | * record (or, the first byte in that sector) | ||||
1732 | */ | ||||
1733 | used_bytes += node->fileSectorsUsed * diskStructure->sectorSize; | ||||
1734 | |||||
1735 | for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child)((node->dot_dot_record)->cn_next_child.tqe_next); | ||||
1736 | child != NULL((void *)0); child = TAILQ_NEXT(child, cn_next_child)((child)->cn_next_child.tqe_next)) { | ||||
1737 | /* Directories need recursive call */ | ||||
1738 | if (S_ISDIR(child->node->type)((child->node->type & 0170000) == 0040000)) { | ||||
1739 | r = cd9660_compute_offsets(diskStructure, child, | ||||
1740 | used_bytes + startOffset); | ||||
1741 | |||||
1742 | if (r != -1) | ||||
1743 | used_bytes += r; | ||||
1744 | else | ||||
1745 | return -1; | ||||
1746 | } | ||||
1747 | } | ||||
1748 | |||||
1749 | /* Explicitly set the . and .. records */ | ||||
1750 | cd9660_populate_dot_records(diskStructure, node); | ||||
1751 | |||||
1752 | /* Finally, do another iteration to write the file data*/ | ||||
1753 | for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child)((node->dot_dot_record)->cn_next_child.tqe_next); | ||||
1754 | child != NULL((void *)0); | ||||
1755 | child = TAILQ_NEXT(child, cn_next_child)((child)->cn_next_child.tqe_next)) { | ||||
1756 | /* Files need extent set */ | ||||
1757 | if (S_ISDIR(child->node->type)((child->node->type & 0170000) == 0040000)) | ||||
1758 | continue; | ||||
1759 | child->fileRecordSize = | ||||
1760 | cd9660_compute_record_size(diskStructure, child); | ||||
1761 | |||||
1762 | child->fileSectorsUsed = | ||||
1763 | CD9660_BLOCKS(diskStructure->sectorSize,((((child->fileDataLength)) + (((diskStructure->sectorSize )) - 1)) / ((diskStructure->sectorSize))) | ||||
1764 | child->fileDataLength)((((child->fileDataLength)) + (((diskStructure->sectorSize )) - 1)) / ((diskStructure->sectorSize))); | ||||
1765 | |||||
1766 | inode = child->node->inode; | ||||
1767 | if ((inode->flags & FI_ALLOCATED) == 0) { | ||||
1768 | inode->ino = | ||||
1769 | CD9660_BLOCKS(diskStructure->sectorSize,((((used_bytes + startOffset)) + (((diskStructure->sectorSize )) - 1)) / ((diskStructure->sectorSize))) | ||||
1770 | used_bytes + startOffset)((((used_bytes + startOffset)) + (((diskStructure->sectorSize )) - 1)) / ((diskStructure->sectorSize))); | ||||
1771 | inode->flags |= FI_ALLOCATED; | ||||
1772 | used_bytes += child->fileSectorsUsed * | ||||
1773 | diskStructure->sectorSize; | ||||
1774 | } else { | ||||
1775 | INODE_WARNX(("%s: already allocated inode %d " | ||||
1776 | "data sectors at %" PRIu32, __func__, | ||||
1777 | (int)inode->st.st_ino, inode->ino)); | ||||
1778 | } | ||||
1779 | child->fileDataSector = inode->ino; | ||||
1780 | cd9660_bothendian_dword(child->fileDataSector, | ||||
1781 | child->isoDirRecord->extent); | ||||
1782 | } | ||||
1783 | } | ||||
1784 | |||||
1785 | return used_bytes; | ||||
1786 | } | ||||
1787 | |||||
1788 | #if 0 | ||||
1789 | /* Might get rid of this func */ | ||||
1790 | static int | ||||
1791 | cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file) | ||||
1792 | { | ||||
1793 | to->node->inode->st.st_dev = 0; | ||||
1794 | to->node->inode->st.st_ino = 0; | ||||
1795 | to->node->inode->st.st_size = 0; | ||||
1796 | to->node->inode->st.st_blksize = from->node->inode->st.st_blksize; | ||||
1797 | to->node->inode->st.st_atimest_atim.tv_sec = from->node->inode->st.st_atimest_atim.tv_sec; | ||||
1798 | to->node->inode->st.st_mtimest_mtim.tv_sec = from->node->inode->st.st_mtimest_mtim.tv_sec; | ||||
1799 | to->node->inode->st.st_ctimest_ctim.tv_sec = from->node->inode->st.st_ctimest_ctim.tv_sec; | ||||
1800 | to->node->inode->st.st_uid = from->node->inode->st.st_uid; | ||||
1801 | to->node->inode->st.st_gid = from->node->inode->st.st_gid; | ||||
1802 | to->node->inode->st.st_mode = from->node->inode->st.st_mode; | ||||
1803 | /* Clear out type */ | ||||
1804 | to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT0170000); | ||||
1805 | if (file) | ||||
1806 | to->node->inode->st.st_mode |= S_IFREG0100000; | ||||
1807 | else | ||||
1808 | to->node->inode->st.st_mode |= S_IFDIR0040000; | ||||
1809 | return 1; | ||||
1810 | } | ||||
1811 | #endif | ||||
1812 | |||||
1813 | static cd9660node * | ||||
1814 | cd9660_create_virtual_entry(iso9660_disk *diskStructure, const char *name, | ||||
1815 | cd9660node *parent, int file, int insert) | ||||
1816 | { | ||||
1817 | cd9660node *temp; | ||||
1818 | fsnode * tfsnode; | ||||
1819 | |||||
1820 | assert(parent != NULL)((parent != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 1820, __func__, "parent != NULL")); | ||||
1821 | |||||
1822 | temp = cd9660_allocate_cd9660node(); | ||||
1823 | if (temp == NULL((void *)0)) | ||||
1824 | return NULL((void *)0); | ||||
1825 | |||||
1826 | tfsnode = emalloc(sizeof(*tfsnode)); | ||||
1827 | tfsnode->name = estrdup(name); | ||||
1828 | temp->isoDirRecord = emalloc(sizeof(*temp->isoDirRecord)); | ||||
1829 | |||||
1830 | cd9660_convert_filename(diskStructure, tfsnode->name, | ||||
1831 | temp->isoDirRecord->name, sizeof temp->isoDirRecord->name, file); | ||||
1832 | |||||
1833 | temp->node = tfsnode; | ||||
1834 | temp->parent = parent; | ||||
1835 | |||||
1836 | if (insert) { | ||||
1837 | if (temp->parent != NULL((void *)0)) { | ||||
1838 | temp->level = temp->parent->level + 1; | ||||
1839 | if (!TAILQ_EMPTY(&temp->parent->cn_children)(((&temp->parent->cn_children)->tqh_first) == (( void *)0))) | ||||
1840 | cd9660_sorted_child_insert(temp->parent, temp); | ||||
1841 | else | ||||
1842 | TAILQ_INSERT_HEAD(&temp->parent->cn_children,do { if (((temp)->cn_next_child.tqe_next = (&temp-> parent->cn_children)->tqh_first) != ((void *)0)) (& temp->parent->cn_children)->tqh_first->cn_next_child .tqe_prev = &(temp)->cn_next_child.tqe_next; else (& temp->parent->cn_children)->tqh_last = &(temp)-> cn_next_child.tqe_next; (&temp->parent->cn_children )->tqh_first = (temp); (temp)->cn_next_child.tqe_prev = &(&temp->parent->cn_children)->tqh_first; } while (0) | ||||
1843 | temp, cn_next_child)do { if (((temp)->cn_next_child.tqe_next = (&temp-> parent->cn_children)->tqh_first) != ((void *)0)) (& temp->parent->cn_children)->tqh_first->cn_next_child .tqe_prev = &(temp)->cn_next_child.tqe_next; else (& temp->parent->cn_children)->tqh_last = &(temp)-> cn_next_child.tqe_next; (&temp->parent->cn_children )->tqh_first = (temp); (temp)->cn_next_child.tqe_prev = &(&temp->parent->cn_children)->tqh_first; } while (0); | ||||
1844 | } | ||||
1845 | } | ||||
1846 | |||||
1847 | if (parent->node != NULL((void *)0)) { | ||||
1848 | tfsnode->type = parent->node->type; | ||||
1849 | } | ||||
1850 | |||||
1851 | /* Clear out file type bits */ | ||||
1852 | tfsnode->type &= ~(S_IFMT0170000); | ||||
1853 | if (file) | ||||
1854 | tfsnode->type |= S_IFREG0100000; | ||||
1855 | else | ||||
1856 | tfsnode->type |= S_IFDIR0040000; | ||||
1857 | |||||
1858 | /* Indicate that there is no spec entry (inode) */ | ||||
1859 | tfsnode->flags &= ~(FSNODE_F_HASSPEC0x01); | ||||
1860 | #if 0 | ||||
1861 | cd9660_copy_stat_info(parent, temp, file); | ||||
1862 | #endif | ||||
1863 | return temp; | ||||
1864 | } | ||||
1865 | |||||
1866 | static cd9660node * | ||||
1867 | cd9660_create_file(iso9660_disk *diskStructure, const char *name, | ||||
1868 | cd9660node *parent, cd9660node *me) | ||||
1869 | { | ||||
1870 | cd9660node *temp; | ||||
1871 | |||||
1872 | temp = cd9660_create_virtual_entry(diskStructure, name, parent, 1, 1); | ||||
1873 | if (temp == NULL((void *)0)) | ||||
1874 | return NULL((void *)0); | ||||
1875 | |||||
1876 | temp->fileDataLength = 0; | ||||
1877 | |||||
1878 | temp->type = CD9660_TYPE_FILE0x01 | CD9660_TYPE_VIRTUAL0x80; | ||||
1879 | |||||
1880 | temp->node->inode = ecalloc(1, sizeof(*temp->node->inode)); | ||||
1881 | *temp->node->inode = *me->node->inode; | ||||
1882 | |||||
1883 | if (cd9660_translate_node_common(diskStructure, temp) == 0) | ||||
1884 | return NULL((void *)0); | ||||
1885 | return temp; | ||||
1886 | } | ||||
1887 | |||||
1888 | /* | ||||
1889 | * Create a new directory which does not exist on disk | ||||
1890 | * @param const char * name The name to assign to the directory | ||||
1891 | * @param const char * parent Pointer to the parent directory | ||||
1892 | * @returns cd9660node * Pointer to the new directory | ||||
1893 | */ | ||||
1894 | static cd9660node * | ||||
1895 | cd9660_create_directory(iso9660_disk *diskStructure, const char *name, | ||||
1896 | cd9660node *parent, cd9660node *me) | ||||
1897 | { | ||||
1898 | cd9660node *temp; | ||||
1899 | |||||
1900 | temp = cd9660_create_virtual_entry(diskStructure, name, parent, 0, 1); | ||||
1901 | if (temp == NULL((void *)0)) | ||||
1902 | return NULL((void *)0); | ||||
1903 | temp->node->type |= S_IFDIR0040000; | ||||
1904 | |||||
1905 | temp->type = CD9660_TYPE_DIR0x02 | CD9660_TYPE_VIRTUAL0x80; | ||||
1906 | |||||
1907 | temp->node->inode = ecalloc(1, sizeof(*temp->node->inode)); | ||||
1908 | *temp->node->inode = *me->node->inode; | ||||
1909 | |||||
1910 | if (cd9660_translate_node_common(diskStructure, temp) == 0) | ||||
1911 | return NULL((void *)0); | ||||
1912 | return temp; | ||||
1913 | } | ||||
1914 | |||||
1915 | static cd9660node * | ||||
1916 | cd9660_create_special_directory(iso9660_disk *diskStructure, u_char type, | ||||
1917 | cd9660node *parent) | ||||
1918 | { | ||||
1919 | cd9660node *temp, *first; | ||||
1920 | char na[2]; | ||||
1921 | |||||
1922 | assert(parent != NULL)((parent != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 1922, __func__, "parent != NULL")); | ||||
1923 | |||||
1924 | if (type == CD9660_TYPE_DOT0x04) | ||||
1925 | na[0] = 0; | ||||
1926 | else if (type == CD9660_TYPE_DOTDOT0x08) | ||||
1927 | na[0] = 1; | ||||
1928 | else | ||||
1929 | return 0; | ||||
1930 | |||||
1931 | na[1] = 0; | ||||
1932 | if ((temp = cd9660_create_virtual_entry(diskStructure, na, parent, | ||||
1933 | 0, 0)) == NULL((void *)0)) | ||||
1934 | return NULL((void *)0); | ||||
1935 | |||||
1936 | temp->parent = parent; | ||||
1937 | temp->type = type; | ||||
1938 | temp->isoDirRecord->length[0] = 34; | ||||
1939 | /* Dot record is always first */ | ||||
1940 | if (type == CD9660_TYPE_DOT0x04) { | ||||
1941 | parent->dot_record = temp; | ||||
1942 | TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child)do { if (((temp)->cn_next_child.tqe_next = (&parent-> cn_children)->tqh_first) != ((void *)0)) (&parent-> cn_children)->tqh_first->cn_next_child.tqe_prev = & (temp)->cn_next_child.tqe_next; else (&parent->cn_children )->tqh_last = &(temp)->cn_next_child.tqe_next; (& parent->cn_children)->tqh_first = (temp); (temp)->cn_next_child .tqe_prev = &(&parent->cn_children)->tqh_first; } while (0); | ||||
1943 | /* DotDot should be second */ | ||||
1944 | } else if (type == CD9660_TYPE_DOTDOT0x08) { | ||||
1945 | parent->dot_dot_record = temp; | ||||
1946 | /* | ||||
1947 | * If the first child is the dot record, insert | ||||
1948 | * this second. Otherwise, insert it at the head. | ||||
1949 | */ | ||||
1950 | if ((first = TAILQ_FIRST(&parent->cn_children)((&parent->cn_children)->tqh_first)) == NULL((void *)0) || | ||||
1951 | (first->type & CD9660_TYPE_DOT0x04) == 0) { | ||||
1952 | TAILQ_INSERT_HEAD(&parent->cn_children, temp,do { if (((temp)->cn_next_child.tqe_next = (&parent-> cn_children)->tqh_first) != ((void *)0)) (&parent-> cn_children)->tqh_first->cn_next_child.tqe_prev = & (temp)->cn_next_child.tqe_next; else (&parent->cn_children )->tqh_last = &(temp)->cn_next_child.tqe_next; (& parent->cn_children)->tqh_first = (temp); (temp)->cn_next_child .tqe_prev = &(&parent->cn_children)->tqh_first; } while (0) | ||||
1953 | cn_next_child)do { if (((temp)->cn_next_child.tqe_next = (&parent-> cn_children)->tqh_first) != ((void *)0)) (&parent-> cn_children)->tqh_first->cn_next_child.tqe_prev = & (temp)->cn_next_child.tqe_next; else (&parent->cn_children )->tqh_last = &(temp)->cn_next_child.tqe_next; (& parent->cn_children)->tqh_first = (temp); (temp)->cn_next_child .tqe_prev = &(&parent->cn_children)->tqh_first; } while (0); | ||||
1954 | } else { | ||||
1955 | TAILQ_INSERT_AFTER(&parent->cn_children, first, temp,do { if (((temp)->cn_next_child.tqe_next = (first)->cn_next_child .tqe_next) != ((void *)0)) (temp)->cn_next_child.tqe_next-> cn_next_child.tqe_prev = &(temp)->cn_next_child.tqe_next ; else (&parent->cn_children)->tqh_last = &(temp )->cn_next_child.tqe_next; (first)->cn_next_child.tqe_next = (temp); (temp)->cn_next_child.tqe_prev = &(first)-> cn_next_child.tqe_next; } while (0) | ||||
1956 | cn_next_child)do { if (((temp)->cn_next_child.tqe_next = (first)->cn_next_child .tqe_next) != ((void *)0)) (temp)->cn_next_child.tqe_next-> cn_next_child.tqe_prev = &(temp)->cn_next_child.tqe_next ; else (&parent->cn_children)->tqh_last = &(temp )->cn_next_child.tqe_next; (first)->cn_next_child.tqe_next = (temp); (temp)->cn_next_child.tqe_prev = &(first)-> cn_next_child.tqe_next; } while (0); | ||||
1957 | } | ||||
1958 | } | ||||
1959 | |||||
1960 | return temp; | ||||
1961 | } | ||||
1962 | |||||
1963 | static int | ||||
1964 | cd9660_add_generic_bootimage(iso9660_disk *diskStructure, const char *bootimage) | ||||
1965 | { | ||||
1966 | struct stat stbuf; | ||||
1967 | |||||
1968 | assert(bootimage != NULL)((bootimage != ((void *)0)) ? (void)0 : __assert2("/usr/src/usr.sbin/makefs/cd9660.c" , 1968, __func__, "bootimage != NULL")); | ||||
1969 | |||||
1970 | if (*bootimage == '\0') { | ||||
1971 | warnx("Error: Boot image must be a filename"); | ||||
1972 | return 0; | ||||
1973 | } | ||||
1974 | |||||
1975 | diskStructure->generic_bootimage = estrdup(bootimage); | ||||
1976 | |||||
1977 | if (unveil(diskStructure->generic_bootimage, "r") == -1) | ||||
1978 | err(1, "unveil %s", diskStructure->generic_bootimage); | ||||
1979 | /* Get information about the file */ | ||||
1980 | if (lstat(diskStructure->generic_bootimage, &stbuf) == -1) | ||||
1981 | err(1, "%s: lstat(\"%s\")", __func__, | ||||
1982 | diskStructure->generic_bootimage); | ||||
1983 | |||||
1984 | if (stbuf.st_size > 32768) { | ||||
1985 | warnx("Error: Boot image must be no greater than 32768 bytes"); | ||||
1986 | return 0; | ||||
1987 | } | ||||
1988 | |||||
1989 | diskStructure->has_generic_bootimage = 1; | ||||
1990 | return 1; | ||||
1991 | } |