[BACK]Return to cd9660.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / makefs

Annotation of src/usr.sbin/makefs/cd9660.c, Revision 1.49

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

CVSweb <webmaster@jp.NetBSD.org>