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

Annotation of src/sbin/newfs_udf/newfs_udf.c, Revision 1.5

1.5     ! pooka       1: /* $NetBSD: newfs_udf.c,v 1.4 2008/07/26 20:20:56 reinoud Exp $ */
1.1       reinoud     2:
                      3: /*
                      4:  * Copyright (c) 2006, 2008 Reinoud Zandijk
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  *
                     27:  */
                     28:
                     29: /*
                     30:  * TODO
                     31:  * - implement meta data partition formatting.
                     32:  * - implement support for a read-only companion partition?
                     33:  */
                     34:
                     35: #define _EXPOSE_MMC
                     36: #if 0
                     37: # define DEBUG
                     38: #endif
                     39:
                     40: #include <stdio.h>
                     41: #include <stdlib.h>
                     42: #include <dirent.h>
                     43: #include <inttypes.h>
                     44: #include <stdint.h>
                     45: #include <string.h>
                     46: #include <errno.h>
                     47: #include <fcntl.h>
                     48: #include <unistd.h>
                     49: #include <util.h>
                     50: #include <time.h>
                     51: #include <assert.h>
1.3       reinoud    52: #include <err.h>
1.1       reinoud    53:
                     54: #include <sys/ioctl.h>
                     55: #include <sys/stat.h>
                     56: #include <sys/types.h>
                     57: #include <sys/cdio.h>
                     58: #include <sys/disklabel.h>
                     59: #include <sys/dkio.h>
                     60: #include <sys/param.h>
                     61: #include <sys/queue.h>
                     62:
                     63: #include <fs/udf/ecma167-udf.h>
                     64: #include <fs/udf/udf_mount.h>
1.5     ! pooka      65:
        !            66: #include "mountprog.h"
1.1       reinoud    67: #include "udf_create.h"
                     68:
                     69: /* general settings */
                     70: #define UDF_512_TRACK  0       /* NOT recommended */
1.4       reinoud    71: #define UDF_META_PERC  20      /* picked */
                     72:
1.1       reinoud    73:
                     74: /* prototypes */
                     75: int newfs_udf(int argc, char **argv);
                     76: static void usage(void) __attribute__((__noreturn__));
                     77:
                     78: int udf_derive_format(int req_en, int req_dis, int force);
                     79: int udf_proces_names(void);
                     80: int udf_do_newfs(void);
                     81:
                     82: /* Identifying myself */
                     83: #define APP_NAME               "*NetBSD newfs"
                     84: #define APP_VERSION_MAIN       0
1.4       reinoud    85: #define APP_VERSION_SUB                3
1.1       reinoud    86: #define IMPL_NAME              "*NetBSD userland UDF"
                     87:
                     88:
                     89: /* global variables describing disc and format requests */
                     90: int     fd;                            /* device: file descriptor */
                     91: char   *dev;                           /* device: name            */
                     92: struct mmc_discinfo mmc_discinfo;      /* device: disc info       */
                     93:
                     94: char   *format_str;                    /* format: string representation */
                     95: int     format_flags;                  /* format: attribute flags       */
                     96: int     media_accesstype;              /* derived from current mmc cap  */
                     97: int     check_surface;                 /* for rewritables               */
                     98:
                     99: int     wrtrack_skew;
1.4       reinoud   100: int     meta_perc = UDF_META_PERC;
                    101: float   meta_fract = (float) UDF_META_PERC / 100.0;
1.1       reinoud   102:
                    103:
                    104: /* shared structure between udf_create.c users */
                    105: struct udf_create_context context;
                    106: struct udf_disclayout     layout;
                    107:
                    108:
                    109: /* queue for temporary storage of sectors to be written out */
                    110: struct wrsect {
                    111:        uint32_t  sectornr;
                    112:        uint8_t  *sector_data;
                    113:        TAILQ_ENTRY(wrsect) next;
                    114: };
                    115:
                    116: /* write queue and track blocking skew */
                    117: TAILQ_HEAD(wrsect_list, wrsect) write_queue;
                    118:
                    119:
                    120: /* --------------------------------------------------------------------- */
                    121:
                    122: /*
                    123:  * write queue implementation
                    124:  */
                    125:
                    126: static int
                    127: udf_write_sector(void *sector, uint32_t location)
                    128: {
                    129:        struct wrsect *pos, *seekpos;
                    130:
                    131:
                    132:        /* search location */
                    133:        TAILQ_FOREACH_REVERSE(seekpos, &write_queue, wrsect_list, next) {
                    134:                if (seekpos->sectornr <= location)
                    135:                        break;
                    136:        }
                    137:        if ((seekpos == NULL) || (seekpos->sectornr != location)) {
                    138:                pos = calloc(1, sizeof(struct wrsect));
                    139:                if (pos == NULL)
                    140:                        return ENOMEM;
                    141:                /* allocate space for copy of sector data */
                    142:                pos->sector_data = calloc(1, context.sector_size);
                    143:                if (pos->sector_data == NULL)
                    144:                        return ENOMEM;
                    145:                pos->sectornr = location;
                    146:
                    147:                if (seekpos) {
                    148:                        TAILQ_INSERT_AFTER(&write_queue, seekpos, pos, next);
                    149:                } else {
                    150:                        TAILQ_INSERT_HEAD(&write_queue, pos, next);
                    151:                }
                    152:        } else {
                    153:                pos = seekpos;
                    154:        }
                    155:        memcpy(pos->sector_data, sector, context.sector_size);
                    156:
                    157:        return 0;
                    158: }
                    159:
                    160:
                    161: /*
                    162:  * Now all write requests are queued in the TAILQ, write them out to the
                    163:  * disc/file image. Special care needs to be taken for devices that are only
                    164:  * strict overwritable i.e. only in packet size chunks
                    165:  *
                    166:  * XXX support for growing vnd?
                    167:  */
                    168:
                    169: static int
                    170: writeout_write_queue(void)
                    171: {
                    172:        struct wrsect *pos;
                    173:        uint64_t offset;
                    174:        uint32_t line_len, line_offset;
                    175:        uint32_t line_start, new_line_start, relpos;
                    176:        uint32_t blockingnr;
                    177:        uint8_t *linebuf, *adr;
                    178:
                    179:        blockingnr  = layout.blockingnr;
                    180:        line_len    = blockingnr   * context.sector_size;
                    181:        line_offset = wrtrack_skew * context.sector_size;
                    182:
                    183:        linebuf     = malloc(line_len);
                    184:        if (linebuf == NULL)
                    185:                return ENOMEM;
                    186:
                    187:        pos = TAILQ_FIRST(&write_queue);
                    188:        bzero(linebuf, line_len);
                    189:
                    190:        /*
                    191:         * Always writing out in whole lines now; this is slightly wastefull
                    192:         * on logical overwrite volumes but it reduces complexity and the loss
                    193:         * is near zero compared to disc size.
                    194:         */
                    195:        line_start = (pos->sectornr - wrtrack_skew) / blockingnr;
                    196:        TAILQ_FOREACH(pos, &write_queue, next) {
                    197:                new_line_start = (pos->sectornr - wrtrack_skew) / blockingnr;
                    198:                if (new_line_start != line_start) {
                    199:                        /* write out */
                    200:                        offset = (uint64_t) line_start * line_len + line_offset;
                    201: #ifdef DEBUG
                    202:                        printf("WRITEOUT %08"PRIu64" + %02d -- "
                    203:                                "[%08"PRIu64"..%08"PRIu64"]\n",
                    204:                                offset / context.sector_size, blockingnr,
                    205:                                offset / context.sector_size,
                    206:                                offset / context.sector_size + blockingnr-1);
                    207: #endif
                    208:                        if (pwrite(fd, linebuf, line_len, offset) < 0) {
                    209:                                perror("Writing failed");
                    210:                                return errno;
                    211:                        }
                    212:                        line_start = new_line_start;
                    213:                        bzero(linebuf, line_len);
                    214:                }
                    215:
                    216:                relpos = (pos->sectornr - wrtrack_skew) % blockingnr;
                    217:                adr = linebuf + relpos * context.sector_size;
                    218:                memcpy(adr, pos->sector_data, context.sector_size);
                    219:        }
                    220:        /* writeout last chunk */
                    221:        offset = (uint64_t) line_start * line_len + line_offset;
                    222: #ifdef DEBUG
                    223:        printf("WRITEOUT %08"PRIu64" + %02d -- [%08"PRIu64"..%08"PRIu64"]\n",
                    224:                offset / context.sector_size, blockingnr,
                    225:                offset / context.sector_size,
                    226:                offset / context.sector_size + blockingnr-1);
                    227: #endif
                    228:        if (pwrite(fd, linebuf, line_len, offset) < 0) {
                    229:                perror("Writing failed");
                    230:                return errno;
                    231:        }
                    232:
                    233:        /* success */
                    234:        return 0;
                    235: }
                    236:
                    237: /* --------------------------------------------------------------------- */
                    238:
                    239: /*
                    240:  * mmc_discinfo and mmc_trackinfo readers modified from origional in udf main
                    241:  * code in sys/fs/udf/
                    242:  */
                    243:
                    244: #ifdef DEBUG
                    245: static void
                    246: udf_dump_discinfo(struct mmc_discinfo *di)
                    247: {
                    248:        char bits[128];
                    249:
                    250:        printf("Device/media info  :\n");
                    251:        printf("\tMMC profile        0x%02x\n", di->mmc_profile);
                    252:        printf("\tderived class      %d\n", di->mmc_class);
                    253:        printf("\tsector size        %d\n", di->sector_size);
                    254:        printf("\tdisc state         %d\n", di->disc_state);
                    255:        printf("\tlast ses state     %d\n", di->last_session_state);
                    256:        printf("\tbg format state    %d\n", di->bg_format_state);
                    257:        printf("\tfrst track         %d\n", di->first_track);
                    258:        printf("\tfst on last ses    %d\n", di->first_track_last_session);
                    259:        printf("\tlst on last ses    %d\n", di->last_track_last_session);
                    260:        printf("\tlink block penalty %d\n", di->link_block_penalty);
                    261:        snprintb(bits, sizeof(bits), MMC_DFLAGS_FLAGBITS, (uint64_t) di->disc_flags);
                    262:        printf("\tdisc flags         %s\n", bits);
                    263:        printf("\tdisc id            %x\n", di->disc_id);
                    264:        printf("\tdisc barcode       %"PRIx64"\n", di->disc_barcode);
                    265:
                    266:        printf("\tnum sessions       %d\n", di->num_sessions);
                    267:        printf("\tnum tracks         %d\n", di->num_tracks);
                    268:
                    269:        snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cur);
                    270:        printf("\tcapabilities cur   %s\n", bits);
                    271:        snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cap);
                    272:        printf("\tcapabilities cap   %s\n", bits);
                    273:        printf("\n");
                    274:        printf("\tlast_possible_lba  %d\n", di->last_possible_lba);
                    275:        printf("\n");
                    276: }
                    277: #else
                    278: #define udf_dump_discinfo(a);
                    279: #endif
                    280:
                    281: /* --------------------------------------------------------------------- */
                    282:
                    283: static int
                    284: udf_update_discinfo(struct mmc_discinfo *di)
                    285: {
                    286:        struct disklabel  disklab;
                    287:        struct partition *dp;
                    288:        struct stat st;
                    289:        int partnr, error;
                    290:
                    291:        memset(di, 0, sizeof(struct mmc_discinfo));
                    292:
                    293:        /* check if we're on a MMC capable device, i.e. CD/DVD */
                    294:        error = ioctl(fd, MMCGETDISCINFO, di);
                    295:        if (error == 0)
                    296:                return 0;
                    297:
                    298:        /*
                    299:         * disc partition support; note we can't use DIOCGPART in userland so
                    300:         * get disc label and use the stat info to get the partition number.
                    301:         */
                    302:        if (ioctl(fd, DIOCGDINFO, &disklab) == -1) {
                    303:                /* failed to get disclabel! */
                    304:                perror("disklabel");
                    305:                return errno;
                    306:        }
                    307:
                    308:        /* get disk partition it refers to */
                    309:        fstat(fd, &st);
                    310:        partnr = DISKPART(st.st_rdev);
                    311:        dp = &disklab.d_partitions[partnr];
                    312:
                    313:        /* set up a disc info profile for partitions */
                    314:        di->mmc_profile         = 0x01; /* disc type */
                    315:        di->mmc_class           = MMC_CLASS_DISC;
                    316:        di->disc_state          = MMC_STATE_CLOSED;
                    317:        di->last_session_state  = MMC_STATE_CLOSED;
                    318:        di->bg_format_state     = MMC_BGFSTATE_COMPLETED;
                    319:        di->link_block_penalty  = 0;
                    320:
                    321:        di->mmc_cur     = MMC_CAP_RECORDABLE | MMC_CAP_REWRITABLE |
                    322:                MMC_CAP_ZEROLINKBLK | MMC_CAP_HW_DEFECTFREE;
                    323:        di->mmc_cap    = di->mmc_cur;
                    324:        di->disc_flags = MMC_DFLAGS_UNRESTRICTED;
                    325:
                    326:        /* TODO problem with last_possible_lba on resizable VND; request */
                    327:        if (dp->p_size == 0) {
                    328:                perror("faulty disklabel partition returned, check label\n");
                    329:                return EIO;
                    330:        }
                    331:        di->last_possible_lba = dp->p_size - 1;
                    332:        di->sector_size       = disklab.d_secsize;
                    333:
                    334:        di->num_sessions = 1;
                    335:        di->num_tracks   = 1;
                    336:
                    337:        di->first_track  = 1;
                    338:        di->first_track_last_session = di->last_track_last_session = 1;
                    339:
                    340:        return 0;
                    341: }
                    342:
                    343:
                    344: static int
                    345: udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti)
                    346: {
                    347:        int error, class;
                    348:
                    349:        class = di->mmc_class;
                    350:        if (class != MMC_CLASS_DISC) {
                    351:                /* tracknr specified in struct ti */
                    352:                error = ioctl(fd, MMCGETTRACKINFO, ti);
                    353:                return error;
                    354:        }
                    355:
                    356:        /* discs partition support */
                    357:        if (ti->tracknr != 1)
                    358:                return EIO;
                    359:
                    360:        /* create fake ti (TODO check for resized vnds) */
                    361:        ti->sessionnr  = 1;
                    362:
                    363:        ti->track_mode = 0;     /* XXX */
                    364:        ti->data_mode  = 0;     /* XXX */
                    365:        ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;
                    366:
                    367:        ti->track_start    = 0;
                    368:        ti->packet_size    = 1;
                    369:
                    370:        /* TODO support for resizable vnd */
                    371:        ti->track_size    = di->last_possible_lba;
                    372:        ti->next_writable = di->last_possible_lba;
                    373:        ti->last_recorded = ti->next_writable;
                    374:        ti->free_blocks   = 0;
                    375:
                    376:        return 0;
                    377: }
                    378:
                    379:
                    380: static int
                    381: udf_setup_writeparams(struct mmc_discinfo *di)
                    382: {
                    383:        struct mmc_writeparams mmc_writeparams;
                    384:        int error;
                    385:
                    386:        if (di->mmc_class == MMC_CLASS_DISC)
                    387:                return 0;
                    388:
                    389:        /*
                    390:         * only CD burning normally needs setting up, but other disc types
                    391:         * might need other settings to be made. The MMC framework will set up
                    392:         * the nessisary recording parameters according to the disc
                    393:         * characteristics read in. Modifications can be made in the discinfo
                    394:         * structure passed to change the nature of the disc.
                    395:         */
                    396:        memset(&mmc_writeparams, 0, sizeof(struct mmc_writeparams));
                    397:        mmc_writeparams.mmc_class  = di->mmc_class;
                    398:        mmc_writeparams.mmc_cur    = di->mmc_cur;
                    399:
                    400:        /*
                    401:         * UDF dictates first track to determine track mode for the whole
                    402:         * disc. [UDF 1.50/6.10.1.1, UDF 1.50/6.10.2.1]
                    403:         * To prevent problems with a `reserved' track in front we start with
                    404:         * the 2nd track and if that is not valid, go for the 1st.
                    405:         */
                    406:        mmc_writeparams.tracknr = 2;
                    407:        mmc_writeparams.data_mode  = MMC_DATAMODE_DEFAULT;      /* XA disc */
                    408:        mmc_writeparams.track_mode = MMC_TRACKMODE_DEFAULT;     /* data */
                    409:
                    410:        error = ioctl(fd, MMCSETUPWRITEPARAMS, &mmc_writeparams);
                    411:        if (error) {
                    412:                mmc_writeparams.tracknr = 1;
                    413:                error = ioctl(fd, MMCSETUPWRITEPARAMS, &mmc_writeparams);
                    414:        }
                    415:        return error;
                    416: }
                    417:
                    418:
                    419: static void
                    420: udf_synchronise_caches(void)
                    421: {
                    422:        struct mmc_op mmc_op;
                    423:
                    424:        bzero(&mmc_op, sizeof(struct mmc_op));
                    425:        mmc_op.operation = MMC_OP_SYNCHRONISECACHE;
                    426:
                    427:        /* this device might not know this ioct, so just be ignorant */
                    428:        (void) ioctl(fd, MMCOP, &mmc_op);
                    429: }
                    430:
                    431: /* --------------------------------------------------------------------- */
                    432:
                    433: static int
                    434: udf_write_dscr_phys(union dscrptr *dscr, uint32_t location,
                    435:        uint32_t sects)
                    436: {
                    437:        uint32_t phys;
                    438:        uint8_t *bpos;
                    439:        int error, cnt;
                    440:
                    441:        dscr->tag.tag_loc = udf_rw32(location);
                    442:        (void) udf_validate_tag_and_crc_sums(dscr);
                    443:
                    444:        for (cnt = 0; cnt < sects; cnt++) {
                    445:                bpos  = (uint8_t *) dscr;
                    446:                bpos += context.sector_size * cnt;
                    447:
                    448:                phys = location + cnt;
                    449:                error = udf_write_sector(bpos, phys);
                    450:                if (error)
                    451:                        return error;
                    452:        }
                    453:        return 0;
                    454: }
                    455:
                    456:
                    457: static int
                    458: udf_write_dscr_virt(union dscrptr *dscr, uint32_t location, uint32_t vpart,
                    459:        uint32_t sects)
                    460: {
1.2       reinoud   461:        struct file_entry *fe;
                    462:        struct extfile_entry *efe;
                    463:        struct extattrhdr_desc *extattrhdr;
1.1       reinoud   464:        uint32_t phys;
                    465:        uint8_t *bpos;
                    466:        int error, cnt;
                    467:
1.2       reinoud   468:        extattrhdr = NULL;
                    469:        if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
                    470:                fe = (struct file_entry *) dscr;
                    471:                if (udf_rw32(fe->l_ea) > 0)
                    472:                        extattrhdr = (struct extattrhdr_desc *) fe->data;
                    473:        }
                    474:        if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
                    475:                efe = (struct extfile_entry *) dscr;
                    476:                if (udf_rw32(efe->l_ea) > 0)
                    477:                        extattrhdr = (struct extattrhdr_desc *) efe->data;
                    478:        }
                    479:        if (extattrhdr) {
                    480:                extattrhdr->tag.tag_loc = udf_rw32(location);
                    481:                udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr);
                    482:        }
                    483:
1.1       reinoud   484:        dscr->tag.tag_loc = udf_rw32(location);
1.2       reinoud   485:        udf_validate_tag_and_crc_sums(dscr);
1.1       reinoud   486:
                    487:        for (cnt = 0; cnt < sects; cnt++) {
                    488:                bpos  = (uint8_t *) dscr;
                    489:                bpos += context.sector_size * cnt;
                    490:
1.2       reinoud   491:                /* NOTE linear mapping assumed in the ranges used */
1.4       reinoud   492:                phys = context.vtop_offset[vpart] + location + cnt;
1.1       reinoud   493:
                    494:                error = udf_write_sector(bpos, phys);
                    495:                if (error)
                    496:                        return error;
                    497:        }
                    498:        return 0;
                    499: }
                    500:
                    501: /* --------------------------------------------------------------------- */
                    502:
                    503: /*
                    504:  * udf_derive_format derives the format_flags from the disc's mmc_discinfo.
                    505:  * The resulting flags uniquely define a disc format. Note there are at least
                    506:  * 7 distinct format types defined in UDF.
                    507:  */
                    508:
                    509: #define UDF_VERSION(a) \
                    510:        (((a) == 0x100) || ((a) == 0x102) || ((a) == 0x150) || ((a) == 0x200) || \
                    511:         ((a) == 0x201) || ((a) == 0x250) || ((a) == 0x260))
                    512:
                    513: int
                    514: udf_derive_format(int req_enable, int req_disable, int force)
                    515: {
                    516:        /* disc writability, formatted, appendable */
                    517:        if ((mmc_discinfo.mmc_cur & MMC_CAP_RECORDABLE) == 0) {
                    518:                (void)printf("Can't newfs readonly device\n");
                    519:                return EROFS;
                    520:        }
                    521:        if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
                    522:                /* sequentials need sessions appended */
                    523:                if (mmc_discinfo.disc_state == MMC_STATE_CLOSED) {
                    524:                        (void)printf("Can't append session to a closed disc\n");
                    525:                        return EROFS;
                    526:                }
                    527:                if ((mmc_discinfo.disc_state != MMC_STATE_EMPTY) && !force) {
                    528:                        (void)printf("Disc not empty! Use -F to force "
                    529:                            "initialisation\n");
                    530:                        return EROFS;
                    531:                }
                    532:        } else {
                    533:                /* check if disc (being) formatted or has been started on */
                    534:                if (mmc_discinfo.disc_state == MMC_STATE_EMPTY) {
                    535:                        (void)printf("Disc is not formatted\n");
                    536:                        return EROFS;
                    537:                }
                    538:        }
                    539:
                    540:        /* determine UDF format */
                    541:        format_flags = 0;
                    542:        if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {
                    543:                /* all rewritable media */
                    544:                format_flags |= FORMAT_REWRITABLE;
                    545:                if (context.min_udf >= 0x0250) {
                    546:                        /* standard dictates meta as default */
                    547:                        format_flags |= FORMAT_META;
                    548:                }
                    549:
                    550:                if ((mmc_discinfo.mmc_cur & MMC_CAP_HW_DEFECTFREE) == 0) {
                    551:                        /* sparables for defect management */
                    552:                        if (context.min_udf >= 0x150)
                    553:                                format_flags |= FORMAT_SPARABLE;
                    554:                }
                    555:        } else {
                    556:                /* all once recordable media */
                    557:                format_flags |= FORMAT_WRITEONCE;
                    558:                if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
                    559:                        format_flags |= FORMAT_SEQUENTIAL;
                    560:
                    561:                        if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE) {
                    562:                                /* logical overwritable */
                    563:                                format_flags |= FORMAT_LOW;
                    564:                        } else {
                    565:                                /* have to use VAT for overwriting */
                    566:                                format_flags |= FORMAT_VAT;
                    567:                        }
                    568:                } else {
                    569:                        /* rare WORM devices, but BluRay has one, strat4096 */
                    570:                        format_flags |= FORMAT_WORM;
                    571:                }
                    572:        }
                    573:
                    574:        /* enable/disable requests */
                    575:        if (req_disable & FORMAT_META) {
                    576:                format_flags &= ~FORMAT_META;
                    577:                req_disable  &= ~FORMAT_META;
                    578:        }
                    579:        if (req_disable || req_enable) {
                    580:                (void)printf("Internal error\n");
                    581:                (void)printf("\tunrecognised enable/disable req.\n");
                    582:                return EIO;
                    583:        }
                    584:        if ((format_flags && FORMAT_VAT) && UDF_512_TRACK)
                    585:                format_flags |= FORMAT_TRACK512;
                    586:
                    587:        /* determine partition/media access type */
                    588:        media_accesstype = UDF_ACCESSTYPE_NOT_SPECIFIED;
                    589:        if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {
                    590:                media_accesstype = UDF_ACCESSTYPE_OVERWRITABLE;
                    591:                if (mmc_discinfo.mmc_cur & MMC_CAP_ERASABLE)
                    592:                        media_accesstype = UDF_ACCESSTYPE_REWRITEABLE;
                    593:        } else {
                    594:                /* all once recordable media */
                    595:                media_accesstype = UDF_ACCESSTYPE_WRITE_ONCE;
                    596:        }
                    597:        if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE)
                    598:                media_accesstype = UDF_ACCESSTYPE_PSEUDO_OVERWITE;
                    599:
                    600:        /* adjust minimum version limits */
                    601:        if (format_flags & FORMAT_VAT)
                    602:                context.min_udf = MAX(context.min_udf, 0x0150);
                    603:        if (format_flags & FORMAT_SPARABLE)
                    604:                context.min_udf = MAX(context.min_udf, 0x0150);
                    605:        if (format_flags & FORMAT_META)
                    606:                context.min_udf = MAX(context.min_udf, 0x0250);
                    607:        if (format_flags & FORMAT_LOW)
                    608:                context.min_udf = MAX(context.min_udf, 0x0260);
                    609:
                    610:        /* adjust maximum version limits not to tease or break things */
                    611:        if (!(format_flags & FORMAT_META) && (context.max_udf > 0x200))
                    612:                context.max_udf = 0x201;
                    613:
                    614:        if ((format_flags & (FORMAT_VAT | FORMAT_SPARABLE)) == 0)
                    615:                if (context.max_udf <= 0x150)
                    616:                        context.min_udf = 0x102;
                    617:
                    618:        /* limit Ecma 167 descriptor if possible/needed */
                    619:        context.dscrver = 3;
                    620:        if ((context.min_udf < 0x200) || (context.max_udf < 0x200)) {
                    621:                context.dscrver = 2;
                    622:                context.max_udf = 0x150;        /* last version < 0x200 */
                    623:        }
                    624:
                    625:        /* is it possible ? */
                    626:        if (context.min_udf > context.max_udf) {
                    627:                (void)printf("Initialisation prohibited by specified maximum "
                    628:                    "UDF version 0x%04x. Minimum version required 0x%04x\n",
                    629:                    context.max_udf, context.min_udf);
                    630:                return EPERM;
                    631:        }
                    632:
                    633:        if (!UDF_VERSION(context.min_udf) || !UDF_VERSION(context.max_udf)) {
                    634:                printf("Choose UDF version numbers from "
                    635:                        "0x102, 0x150, 0x200, 0x201, 0x250 and 0x260\n");
                    636:                printf("Default version is 0x201\n");
                    637:                return EPERM;
                    638:        }
                    639:
                    640:        return 0;
                    641: }
                    642:
                    643: #undef UDF_VERSION
                    644:
                    645:
                    646: /* --------------------------------------------------------------------- */
                    647:
                    648: int
                    649: udf_proces_names(void)
                    650: {
                    651:        uint32_t primary_nr;
                    652:        uint64_t volset_nr;
                    653:
                    654:        if (context.logvol_name == NULL)
                    655:                context.logvol_name = strdup("anonymous");
                    656:        if (context.primary_name == NULL) {
                    657:                if (mmc_discinfo.disc_flags & MMC_DFLAGS_DISCIDVALID) {
                    658:                        primary_nr = mmc_discinfo.disc_id;
                    659:                } else {
                    660:                        primary_nr = (uint32_t) random();
                    661:                }
                    662:                context.primary_name = calloc(32, 1);
                    663:                sprintf(context.primary_name, "%08"PRIx32, primary_nr);
                    664:        }
                    665:        if (context.volset_name == NULL) {
                    666:                if (mmc_discinfo.disc_flags & MMC_DFLAGS_BARCODEVALID) {
                    667:                        volset_nr = mmc_discinfo.disc_barcode;
                    668:                } else {
                    669:                        volset_nr  =  (uint32_t) random();
                    670:                        volset_nr |= ((uint64_t) random()) << 32;
                    671:                }
                    672:                context.volset_name = calloc(128,1);
                    673:                sprintf(context.volset_name, "%016"PRIx64, volset_nr);
                    674:        }
                    675:        if (context.fileset_name == NULL)
                    676:                context.fileset_name = strdup("anonymous");
                    677:
                    678:        /* check passed/created identifiers */
                    679:        if (strlen(context.logvol_name)  > 128) {
                    680:                (void)printf("Logical volume name too long\n");
                    681:                return EINVAL;
                    682:        }
                    683:        if (strlen(context.primary_name) >  32) {
                    684:                (void)printf("Primary volume name too long\n");
                    685:                return EINVAL;
                    686:        }
                    687:        if (strlen(context.volset_name)  > 128) {
                    688:                (void)printf("Volume set name too long\n");
                    689:                return EINVAL;
                    690:        }
                    691:        if (strlen(context.fileset_name) > 32) {
                    692:                (void)printf("Fileset name too long\n");
                    693:                return EINVAL;
                    694:        }
                    695:
                    696:        /* signal all OK */
                    697:        return 0;
                    698: }
                    699:
                    700: /* --------------------------------------------------------------------- */
                    701:
                    702: static int
                    703: udf_prepare_disc(void)
                    704: {
                    705:        struct mmc_trackinfo ti;
                    706:        struct mmc_op        op;
                    707:        int tracknr, error;
                    708:
                    709:        /* If the last track is damaged, repair it */
                    710:        ti.tracknr = mmc_discinfo.last_track_last_session;
                    711:        error = udf_update_trackinfo(&mmc_discinfo, &ti);
                    712:        if (error)
                    713:                return error;
                    714:
                    715:        if (ti.flags & MMC_TRACKINFO_DAMAGED) {
                    716:                /*
                    717:                 * Need to repair last track before anything can be done.
                    718:                 * this is an optional command, so ignore its error but report
                    719:                 * warning.
                    720:                 */
                    721:                memset(&op, 0, sizeof(op));
                    722:                op.operation   = MMC_OP_REPAIRTRACK;
                    723:                op.mmc_profile = mmc_discinfo.mmc_profile;
                    724:                op.tracknr     = ti.tracknr;
                    725:                error = ioctl(fd, MMCOP, &op);
                    726:
                    727:                if (error)
                    728:                        (void)printf("Drive can't explicitly repair last "
                    729:                                "damaged track, but it might autorepair\n");
                    730:        }
                    731:        /* last track (if any) might not be damaged now, operations are ok now */
                    732:
                    733:        /* setup write parameters from discinfo */
                    734:        error = udf_setup_writeparams(&mmc_discinfo);
                    735:        if (error)
                    736:                return error;
                    737:
                    738:        /* if the drive is not sequential, we're done */
                    739:        if ((mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) == 0)
                    740:                return 0;
                    741:
                    742: #ifdef notyet
                    743:        /* if last track is not the reserved but an empty track, unreserve it */
                    744:        if (ti.flags & MMC_TRACKINFO_BLANK) {
                    745:                if (ti.flags & MMC_TRACKINFO_RESERVED == 0) {
                    746:                        memset(&op, 0, sizeof(op));
                    747:                        op.operation   = MMC_OP_UNRESERVETRACK;
                    748:                        op.mmc_profile = mmc_discinfo.mmc_profile;
                    749:                        op.tracknr     = ti.tracknr;
                    750:                        error = ioctl(fd, MMCOP, &op);
                    751:                        if (error)
                    752:                                return error;
                    753:
                    754:                        /* update discinfo since it changed by the operation */
                    755:                        error = udf_update_discinfo(&mmc_discinfo);
                    756:                        if (error)
                    757:                                return error;
                    758:                }
                    759:        }
                    760: #endif
                    761:
                    762:        /* close the last session if its still open */
                    763:        if (mmc_discinfo.last_session_state == MMC_STATE_INCOMPLETE) {
                    764:                printf("Closing last open session if present\n");
                    765:                /* close all associated tracks */
                    766:                tracknr = mmc_discinfo.first_track_last_session;
                    767:                while (tracknr <= mmc_discinfo.last_track_last_session) {
                    768:                        ti.tracknr = tracknr;
                    769:                        error = udf_update_trackinfo(&mmc_discinfo, &ti);
                    770:                        if (error)
                    771:                                return error;
                    772:                        printf("\tClosing open track %d\n", tracknr);
                    773:                        memset(&op, 0, sizeof(op));
                    774:                        op.operation   = MMC_OP_CLOSETRACK;
                    775:                        op.mmc_profile = mmc_discinfo.mmc_profile;
                    776:                        op.tracknr     = tracknr;
                    777:                        error = ioctl(fd, MMCOP, &op);
                    778:                        if (error)
                    779:                                return error;
                    780:                        tracknr ++;
                    781:                }
                    782:                printf("Closing session\n");
                    783:                memset(&op, 0, sizeof(op));
                    784:                op.operation   = MMC_OP_CLOSESESSION;
                    785:                op.mmc_profile = mmc_discinfo.mmc_profile;
                    786:                op.sessionnr   = mmc_discinfo.num_sessions;
                    787:                error = ioctl(fd, MMCOP, &op);
                    788:                if (error)
                    789:                        return error;
                    790:
                    791:                /* update discinfo since it changed by the operations */
                    792:                error = udf_update_discinfo(&mmc_discinfo);
                    793:                if (error)
                    794:                        return error;
                    795:        }
                    796:
                    797:        if (format_flags & FORMAT_TRACK512) {
                    798:                /* get last track again */
                    799:                ti.tracknr = mmc_discinfo.last_track_last_session;
                    800:                error = udf_update_trackinfo(&mmc_discinfo, &ti);
                    801:                if (error)
                    802:                        return error;
                    803:
                    804:                /* Split up the space at 512 for iso cd9660 hooking */
                    805:                memset(&op, 0, sizeof(op));
                    806:                op.operation   = MMC_OP_RESERVETRACK_NWA;       /* UPTO nwa */
                    807:                op.mmc_profile = mmc_discinfo.mmc_profile;
                    808:                op.extent      = 512;                           /* size */
                    809:                error = ioctl(fd, MMCOP, &op);
                    810:                if (error)
                    811:                        return error;
                    812:        }
                    813:
                    814:        return 0;
                    815: }
                    816:
                    817: /* --------------------------------------------------------------------- */
                    818:
                    819: static int
                    820: udf_surface_check(void)
                    821: {
                    822:        uint32_t loc, block_bytes;
                    823:        uint32_t sector_size, blockingnr;
                    824:        uint8_t *buffer;
                    825:        int error, num_errors;
                    826:        int bpos;
                    827:
                    828:        sector_size = context.sector_size;
                    829:        blockingnr  = layout.blockingnr;
                    830:
                    831:        block_bytes = layout.blockingnr * sector_size;
                    832:        if ((buffer = malloc(block_bytes)) == NULL)
                    833:                return ENOMEM;
                    834:
                    835:        /* set all one to not kill Flash memory? */
                    836:        for (bpos = 0; bpos < block_bytes; bpos++)
                    837:                buffer[bpos] = 0x00;
                    838:
                    839:        printf("\nChecking disc surface : phase 1 - writing\n");
                    840:        num_errors = 0;
                    841:        loc = layout.first_lba;
                    842:        while (loc <= layout.last_lba) {
                    843:                /* write blockingnr sectors */
                    844:                error = pwrite(fd, buffer, block_bytes, loc*sector_size);
                    845:                printf("   %08d + %d (%02d %%)\r", loc, blockingnr,
                    846:                        (int)((100.0 * loc)/layout.last_lba));
                    847:                fflush(stdout);
                    848:                if (error == -1) {
                    849:                        /* block is bad */
                    850:                        printf("BAD block at %08d + %d         \n",
                    851:                                loc, layout.blockingnr);
                    852:                        if ((error = udf_register_bad_block(loc)))
                    853:                                return error;
                    854:                        num_errors ++;
                    855:                }
                    856:                loc += layout.blockingnr;
                    857:        }
                    858:
                    859:        printf("\nChecking disc surface : phase 2 - reading\n");
                    860:        num_errors = 0;
                    861:        loc = layout.first_lba;
                    862:        while (loc <= layout.last_lba) {
                    863:                /* read blockingnr sectors */
                    864:                error = pread(fd, buffer, block_bytes, loc*sector_size);
                    865:                printf("   %08d + %d (%02d %%)\r", loc, blockingnr,
                    866:                        (int)((100.0 * loc)/layout.last_lba));
                    867:                fflush(stdout);
                    868:                if (error == -1) {
                    869:                        /* block is bad */
                    870:                        printf("BAD block at %08d + %d         \n",
                    871:                                loc, layout.blockingnr);
                    872:                        if ((error = udf_register_bad_block(loc)))
                    873:                                return error;
                    874:                        num_errors ++;
                    875:                }
                    876:                loc += layout.blockingnr;
                    877:        }
                    878:        printf("Scan complete : %d bad blocks found\n", num_errors);
                    879:        free(buffer);
                    880:
                    881:        return 0;
                    882: }
                    883:
                    884: /* --------------------------------------------------------------------- */
                    885:
                    886: static int
                    887: udf_write_iso9660_vrs(void)
                    888: {
                    889:        struct vrs_desc *iso9660_vrs_desc;
                    890:        uint32_t pos;
                    891:        int error, cnt, dpos;
                    892:
                    893:        /* create ISO/Ecma-167 identification descriptors */
                    894:        if ((iso9660_vrs_desc = calloc(1, context.sector_size)) == NULL)
                    895:                return ENOMEM;
                    896:
                    897:        /*
                    898:         * All UDF formats should have their ISO/Ecma-167 descriptors written
                    899:         * except when not possible due to track reservation in the case of
                    900:         * VAT
                    901:         */
                    902:        if ((format_flags & FORMAT_TRACK512) == 0) {
                    903:                dpos = (2048 + context.sector_size - 1) / context.sector_size;
                    904:
                    905:                /* wipe at least 6 times 2048 byte `sectors' */
                    906:                for (cnt = 0; cnt < 6 *dpos; cnt++) {
                    907:                        pos = layout.iso9660_vrs + cnt;
                    908:                        if ((error = udf_write_sector(iso9660_vrs_desc, pos)))
                    909:                                return error;
1.4       reinoud   910:                }
1.1       reinoud   911:
                    912:                /* common VRS fields in all written out ISO descriptors */
                    913:                iso9660_vrs_desc->struct_type = 0;
                    914:                iso9660_vrs_desc->version     = 1;
                    915:                pos = layout.iso9660_vrs;
                    916:
                    917:                /* BEA01, NSR[23], TEA01 */
                    918:                memcpy(iso9660_vrs_desc->identifier, "BEA01", 5);
                    919:                if ((error = udf_write_sector(iso9660_vrs_desc, pos)))
                    920:                        return error;
                    921:                pos += dpos;
                    922:
                    923:                if (context.dscrver == 2)
                    924:                        memcpy(iso9660_vrs_desc->identifier, "NSR02", 5);
                    925:                else
                    926:                        memcpy(iso9660_vrs_desc->identifier, "NSR03", 5);
                    927:                ;
                    928:                if ((error = udf_write_sector(iso9660_vrs_desc, pos)))
                    929:                        return error;
                    930:                pos += dpos;
                    931:
                    932:                memcpy(iso9660_vrs_desc->identifier, "TEA01", 5);
                    933:                if ((error = udf_write_sector(iso9660_vrs_desc, pos)))
                    934:                        return error;
                    935:        }
                    936:
                    937:        /* return success */
                    938:        return 0;
                    939: }
                    940:
                    941:
                    942: /* --------------------------------------------------------------------- */
                    943:
                    944: /*
                    945:  * Main function that creates and writes out disc contents based on the
                    946:  * format_flags's that uniquely define the type of disc to create.
                    947:  */
                    948:
                    949: int
                    950: udf_do_newfs(void)
                    951: {
                    952:        union dscrptr *zero_dscr;
                    953:        union dscrptr *terminator_dscr;
                    954:        union dscrptr *root_dscr;
                    955:        union dscrptr *vat_dscr;
                    956:        union dscrptr *dscr;
                    957:        struct mmc_trackinfo ti;
                    958:        uint32_t sparable_blocks;
                    959:        uint32_t sector_size, blockingnr;
                    960:        uint32_t cnt, loc, len;
                    961:        int sectcopy;
                    962:        int error, integrity_type;
                    963:        int data_part, metadata_part;
                    964:
                    965:        /* init */
                    966:        sector_size = mmc_discinfo.sector_size;
                    967:
                    968:        /* determine span/size */
                    969:        ti.tracknr = mmc_discinfo.first_track_last_session;
                    970:        error = udf_update_trackinfo(&mmc_discinfo, &ti);
                    971:        if (error)
                    972:                return error;
                    973:
                    974:        if (mmc_discinfo.sector_size < context.sector_size) {
                    975:                fprintf(stderr, "Impossible to format: sectorsize too small\n");
                    976:                return EIO;
                    977:        }
                    978:        context.sector_size = sector_size;
                    979:
                    980:        /* determine blockingnr */
                    981:        blockingnr = ti.packet_size;
                    982:        if (blockingnr <= 1) {
                    983:                /* paranoia on blockingnr */
                    984:                switch (mmc_discinfo.mmc_profile) {
                    985:                case 0x09 : /* CD-R    */
                    986:                case 0x0a : /* CD-RW   */
                    987:                        blockingnr = 32;        /* UDF requirement */
                    988:                        break;
                    989:                case 0x11 : /* DVD-R (DL) */
                    990:                case 0x1b : /* DVD+R      */
                    991:                case 0x2b : /* DVD+R Dual layer */
                    992:                case 0x13 : /* DVD-RW restricted overwrite */
                    993:                case 0x14 : /* DVD-RW sequential */
                    994:                        blockingnr = 16;        /* SCSI definition */
                    995:                        break;
                    996:                case 0x41 : /* BD-R Sequential recording (SRM) */
                    997:                case 0x51 : /* HD DVD-R   */
                    998:                        blockingnr = 32;        /* SCSI definition */
                    999:                        break;
                   1000:                default:
                   1001:                        break;
                   1002:                }
                   1003:
                   1004:        }
                   1005:        if (blockingnr <= 0) {
                   1006:                printf("Can't fixup blockingnumber for device "
                   1007:                        "type %d\n", mmc_discinfo.mmc_profile);
                   1008:
                   1009:                printf("Device is not returning valid blocking"
                   1010:                        " number and media type is unknown.\n");
                   1011:
                   1012:                return EINVAL;
                   1013:        }
                   1014:
                   1015:        /* setup sector writeout queue's */
                   1016:        TAILQ_INIT(&write_queue);
                   1017:        wrtrack_skew = ti.track_start % blockingnr;
                   1018:
                   1019:        if (mmc_discinfo.mmc_class == MMC_CLASS_CD) {
                   1020:                /* not too much for CD-RW, still 20Mb */
                   1021:                sparable_blocks = 32;
                   1022:        } else {
                   1023:                /* take a value for DVD*RW mainly, BD is `defect free' */
                   1024:                sparable_blocks = 512;
                   1025:        }
                   1026:
                   1027:        /* get layout */
                   1028:        error = udf_calculate_disc_layout(format_flags, context.min_udf,
                   1029:                wrtrack_skew,
                   1030:                ti.track_start, mmc_discinfo.last_possible_lba,
1.4       reinoud  1031:                sector_size, blockingnr, sparable_blocks,
                   1032:                meta_fract);
1.1       reinoud  1033:
                   1034:        /* cache partition for we need it often */
                   1035:        data_part     = context.data_part;
                   1036:        metadata_part = context.metadata_part;
                   1037:
                   1038:        /* Create sparing table descriptor if applicable */
                   1039:        if (format_flags & FORMAT_SPARABLE) {
                   1040:                if ((error = udf_create_sparing_tabled()))
                   1041:                        return error;
                   1042:
                   1043:                if (check_surface) {
                   1044:                        if ((error = udf_surface_check()))
                   1045:                                return error;
                   1046:                }
                   1047:        }
                   1048:
                   1049:        /* Create a generic terminator descriptor */
                   1050:        terminator_dscr = calloc(1, sector_size);
                   1051:        if (terminator_dscr == NULL)
                   1052:                return ENOMEM;
                   1053:        udf_create_terminator(terminator_dscr, 0);
                   1054:
                   1055:        /*
                   1056:         * Start with wipeout of VRS1 upto start of partition. This allows
                   1057:         * formatting for sequentials with the track reservation and it
                   1058:         * cleans old rubbish on rewritables. For sequentuals without the
                   1059:         * track reservation all is wiped from track start.
                   1060:         */
                   1061:        if ((zero_dscr = calloc(1, context.sector_size)) == NULL)
                   1062:                return ENOMEM;
                   1063:
                   1064:        loc = (format_flags & FORMAT_TRACK512) ? layout.vds1 : ti.track_start;
                   1065:        for (; loc < layout.part_start_lba; loc++) {
                   1066:                if ((error = udf_write_sector(zero_dscr, loc)))
                   1067:                        return error;
                   1068:        }
                   1069:
                   1070:        /* Create anchors */
                   1071:        for (cnt = 0; cnt < 3; cnt++) {
                   1072:                if ((error = udf_create_anchor(cnt)))
                   1073:                        return error;
                   1074:        }
                   1075:
                   1076:        /*
                   1077:         * Create the two Volume Descriptor Sets (VDS) each containing the
                   1078:         * following descriptors : primary volume, partition space,
                   1079:         * unallocated space, logical volume, implementation use and the
                   1080:         * terminator
                   1081:         */
                   1082:
                   1083:        /* start of volume recognision sequence building */
                   1084:        context.vds_seq = 0;
                   1085:
                   1086:        /* Create primary volume descriptor */
                   1087:        if ((error = udf_create_primaryd()))
                   1088:                return error;
                   1089:
                   1090:        /* Create partition descriptor */
                   1091:        if ((error = udf_create_partitiond(context.data_part, media_accesstype)))
                   1092:                return error;
                   1093:
                   1094:        /* Create unallocated space descriptor */
                   1095:        if ((error = udf_create_unalloc_spaced()))
                   1096:                return error;
                   1097:
                   1098:        /* Create logical volume descriptor */
                   1099:        if ((error = udf_create_logical_dscr(format_flags)))
                   1100:                return error;
                   1101:
                   1102:        /* Create implementation use descriptor */
                   1103:        /* TODO input of fields 1,2,3 and passing them */
                   1104:        if ((error = udf_create_impvold(NULL, NULL, NULL)))
                   1105:                return error;
                   1106:
                   1107:        /* write out what we've created so far */
                   1108:
                   1109:        /* writeout iso9660 vrs */
                   1110:        if ((error = udf_write_iso9660_vrs()))
                   1111:                return error;
                   1112:
                   1113:        /* Writeout anchors */
                   1114:        for (cnt = 0; cnt < 3; cnt++) {
                   1115:                dscr = (union dscrptr *) context.anchors[cnt];
                   1116:                loc  = layout.anchors[cnt];
                   1117:                if ((error = udf_write_dscr_phys(dscr, loc, 1)))
                   1118:                        return error;
                   1119:
                   1120:                /* sequential media has only one anchor */
                   1121:                if (format_flags & FORMAT_SEQUENTIAL)
                   1122:                        break;
                   1123:        }
                   1124:
                   1125:        /* write out main and secondary VRS */
                   1126:        for (sectcopy = 1; sectcopy <= 2; sectcopy++) {
                   1127:                loc = (sectcopy == 1) ? layout.vds1 : layout.vds2;
                   1128:
                   1129:                /* primary volume descriptor */
                   1130:                dscr = (union dscrptr *) context.primary_vol;
                   1131:                error = udf_write_dscr_phys(dscr, loc, 1);
                   1132:                if (error)
                   1133:                        return error;
                   1134:                loc++;
                   1135:
                   1136:                /* partition descriptor(s) */
                   1137:                for (cnt = 0; cnt < UDF_PARTITIONS; cnt++) {
                   1138:                        dscr = (union dscrptr *) context.partitions[cnt];
                   1139:                        if (dscr) {
                   1140:                                error = udf_write_dscr_phys(dscr, loc, 1);
                   1141:                                if (error)
                   1142:                                        return error;
                   1143:                                loc++;
                   1144:                        }
                   1145:                }
                   1146:
                   1147:                /* unallocated space descriptor */
                   1148:                dscr = (union dscrptr *) context.unallocated;
                   1149:                error = udf_write_dscr_phys(dscr, loc, 1);
                   1150:                if (error)
                   1151:                        return error;
                   1152:                loc++;
                   1153:
                   1154:                /* logical volume descriptor */
                   1155:                dscr = (union dscrptr *) context.logical_vol;
                   1156:                error = udf_write_dscr_phys(dscr, loc, 1);
                   1157:                if (error)
                   1158:                        return error;
                   1159:                loc++;
                   1160:
                   1161:                /* implementation use descriptor */
                   1162:                dscr = (union dscrptr *) context.implementation;
                   1163:                error = udf_write_dscr_phys(dscr, loc, 1);
                   1164:                if (error)
                   1165:                        return error;
                   1166:                loc++;
                   1167:
                   1168:                /* terminator descriptor */
                   1169:                error = udf_write_dscr_phys(terminator_dscr, loc, 1);
                   1170:                if (error)
                   1171:                        return error;
                   1172:                loc++;
                   1173:        }
                   1174:
                   1175:        /* writeout the two sparable table descriptors (if needed) */
                   1176:        if (format_flags & FORMAT_SPARABLE) {
                   1177:                for (sectcopy = 1; sectcopy <= 2; sectcopy++) {
                   1178:                        loc  = (sectcopy == 1) ? layout.spt_1 : layout.spt_2;
                   1179:                        dscr = (union dscrptr *) context.sparing_table;
                   1180:                        len  = layout.sparing_table_dscr_lbas;
                   1181:
                   1182:                        /* writeout */
                   1183:                        error = udf_write_dscr_phys(dscr, loc, len);
                   1184:                        if (error)
                   1185:                                return error;
                   1186:                }
                   1187:        }
                   1188:
                   1189:        /*
                   1190:         * Create unallocated space bitmap descriptor. Sequential recorded
                   1191:         * media report their own free/used space; no free/used space tables
                   1192:         * should be recorded for these.
                   1193:         */
                   1194:        if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
                   1195:                error = udf_create_space_bitmap(
1.4       reinoud  1196:                                layout.alloc_bitmap_dscr_size,
                   1197:                                layout.part_size_lba,
1.1       reinoud  1198:                                &context.part_unalloc_bits[data_part]);
1.4       reinoud  1199:                if (error)
                   1200:                        return error;
1.1       reinoud  1201:                /* TODO: freed space bitmap if applicable */
1.4       reinoud  1202:
                   1203:                /* mark space allocated for the unallocated space bitmap */
1.1       reinoud  1204:                udf_mark_allocated(layout.unalloc_space, data_part,
1.4       reinoud  1205:                        layout.alloc_bitmap_dscr_size);
                   1206:        }
                   1207:
                   1208:        /*
                   1209:         * Create metadata partition file entries and allocate and init their
                   1210:         * space and free space maps.
                   1211:         */
                   1212:        if (format_flags & FORMAT_META) {
                   1213:                error = udf_create_space_bitmap(
                   1214:                                layout.meta_bitmap_dscr_size,
                   1215:                                layout.meta_part_size_lba,
                   1216:                                &context.part_unalloc_bits[metadata_part]);
                   1217:                if (error)
                   1218:                        return error;
                   1219:
                   1220:                error = udf_create_meta_files();
                   1221:                if (error)
                   1222:                        return error;
                   1223:
                   1224:                /* mark space allocated for meta partition and its bitmap */
                   1225:                udf_mark_allocated(layout.meta_file,   data_part, 1);
                   1226:                udf_mark_allocated(layout.meta_mirror, data_part, 1);
                   1227:                udf_mark_allocated(layout.meta_bitmap, data_part, 1);
                   1228:                udf_mark_allocated(layout.meta_part_start_lba, data_part,
                   1229:                        layout.meta_part_size_lba);
                   1230:
                   1231:                /* mark space allocated for the unallocated space bitmap */
                   1232:                udf_mark_allocated(layout.meta_bitmap_space, data_part,
                   1233:                        layout.meta_bitmap_dscr_size);
1.1       reinoud  1234:        }
                   1235:
                   1236:        /* create logical volume integrity descriptor */
                   1237:        context.num_files = 0;
                   1238:        context.num_directories = 0;
                   1239:        integrity_type = UDF_INTEGRITY_OPEN;
                   1240:        if ((error = udf_create_lvintd(integrity_type)))
                   1241:                return error;
                   1242:
                   1243:        /* create FSD */
                   1244:        if ((error = udf_create_fsd()))
                   1245:                return error;
                   1246:        udf_mark_allocated(layout.fsd, metadata_part, 1);
                   1247:
                   1248:        /* create root directory */
                   1249:        assert(context.unique_id == 0x10);
                   1250:        context.unique_id = 0;
                   1251:        if ((error = udf_create_new_rootdir(&root_dscr)))
                   1252:                return error;
                   1253:        udf_mark_allocated(layout.rootdir, metadata_part, 1);
                   1254:
                   1255:        /* writeout FSD + rootdir */
                   1256:        dscr = (union dscrptr *) context.fileset_desc;
                   1257:        error = udf_write_dscr_virt(dscr, layout.fsd, metadata_part, 1);
                   1258:        if (error)
                   1259:                return error;
                   1260:
                   1261:        error = udf_write_dscr_virt(root_dscr, layout.rootdir, metadata_part, 1);
                   1262:        if (error)
                   1263:                return error;
                   1264:
                   1265:        /* writeout initial open integrity sequence + terminator */
                   1266:        loc = layout.lvis;
                   1267:        dscr = (union dscrptr *) context.logvol_integrity;
                   1268:        error = udf_write_dscr_phys(dscr, loc, 1);
                   1269:        if (error)
                   1270:                return error;
                   1271:        loc++;
                   1272:        error = udf_write_dscr_phys(terminator_dscr, loc, 1);
                   1273:        if (error)
                   1274:                return error;
                   1275:
                   1276:
                   1277:        /* XXX the place to add more files */
                   1278:
                   1279:
                   1280:        if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
                   1281:                /* update lvint and mark it closed */
                   1282:                udf_update_lvintd(UDF_INTEGRITY_CLOSED);
                   1283:
                   1284:                /* overwrite initial terminator */
                   1285:                loc = layout.lvis+1;
                   1286:                dscr = (union dscrptr *) context.logvol_integrity;
                   1287:                error = udf_write_dscr_phys(dscr, loc, 1);
                   1288:                if (error)
                   1289:                        return error;
                   1290:                loc++;
                   1291:
                   1292:                /* mark end of integrity desciptor sequence again */
                   1293:                error = udf_write_dscr_phys(terminator_dscr, loc, 1);
                   1294:                if (error)
                   1295:                        return error;
                   1296:        }
                   1297:
                   1298:        /* write out unallocated space bitmap on non sequential media */
                   1299:        if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
1.4       reinoud  1300:                /* writeout unallocated space bitmap */
1.1       reinoud  1301:                loc  = layout.unalloc_space;
                   1302:                dscr = (union dscrptr *) (context.part_unalloc_bits[data_part]);
1.4       reinoud  1303:                len  = layout.alloc_bitmap_dscr_size;
                   1304:                error = udf_write_dscr_virt(dscr, loc, data_part, len);
                   1305:                if (error)
                   1306:                        return error;
                   1307:        }
                   1308:
                   1309:        if (format_flags & FORMAT_META) {
                   1310:                loc = layout.meta_file;
                   1311:                dscr = (union dscrptr *) context.meta_file;
                   1312:                error = udf_write_dscr_virt(dscr, loc, data_part, 1);
                   1313:                if (error)
                   1314:                        return error;
                   1315:
                   1316:                loc = layout.meta_mirror;
                   1317:                dscr = (union dscrptr *) context.meta_mirror;
                   1318:                error = udf_write_dscr_virt(dscr, loc, data_part, 1);
                   1319:                if (error)
                   1320:                        return error;
                   1321:
                   1322:                loc = layout.meta_bitmap;
                   1323:                dscr = (union dscrptr *) context.meta_bitmap;
                   1324:                error = udf_write_dscr_virt(dscr, loc, data_part, 1);
                   1325:                if (error)
                   1326:                        return error;
                   1327:
                   1328:                /* writeout unallocated space bitmap */
                   1329:                loc  = layout.meta_bitmap_space;
                   1330:                dscr = (union dscrptr *) (context.part_unalloc_bits[metadata_part]);
                   1331:                len  = layout.meta_bitmap_dscr_size;
                   1332:                error = udf_write_dscr_virt(dscr, loc, data_part, len);
1.1       reinoud  1333:                if (error)
                   1334:                        return error;
                   1335:        }
                   1336:
                   1337:        /* create a VAT and account for FSD+root */
                   1338:        vat_dscr = NULL;
                   1339:        if (format_flags & FORMAT_VAT) {
                   1340:                /* update lvint to reflect the newest values (no writeout) */
                   1341:                udf_update_lvintd(UDF_INTEGRITY_CLOSED);
                   1342:
                   1343:                error = udf_create_new_VAT(&vat_dscr);
                   1344:                if (error)
                   1345:                        return error;
                   1346:
                   1347:                loc = layout.vat;
                   1348:                error = udf_write_dscr_virt(vat_dscr, loc, metadata_part, 1);
                   1349:                if (error)
                   1350:                        return error;
                   1351:        }
                   1352:
                   1353:        /* write out sectors */
                   1354:        if ((error = writeout_write_queue()))
                   1355:                return error;
                   1356:
                   1357:        /* done */
                   1358:        return 0;
                   1359: }
                   1360:
                   1361: /* --------------------------------------------------------------------- */
                   1362:
1.3       reinoud  1363: /* version can be specified as 0xabc or a.bc */
                   1364: static int
                   1365: parse_udfversion(const char *pos, uint32_t *version) {
                   1366:        int hex = 0;
                   1367:        char c1, c2, c3, c4;
                   1368:
                   1369:        *version = 0;
                   1370:        if (*pos == '0') {
                   1371:                pos++;
                   1372:                /* expect hex format */
                   1373:                hex = 1;
                   1374:                if (*pos++ != 'x')
                   1375:                        return 1;
                   1376:        }
                   1377:
                   1378:        c1 = *pos++;
                   1379:        if (c1 < '0' || c1 > '9')
                   1380:                return 1;
                   1381:        c1 -= '0';
                   1382:
                   1383:        c2 = *pos++;
                   1384:        if (!hex) {
                   1385:                if (c2 != '.')
                   1386:                        return 1;
                   1387:                c2 = *pos++;
                   1388:        }
                   1389:        if (c2 < '0' || c2 > '9')
                   1390:                return 1;
                   1391:        c2 -= '0';
                   1392:
                   1393:        c3 = *pos++;
                   1394:        if (c3 < '0' || c3 > '9')
                   1395:                return 1;
                   1396:        c3 -= '0';
                   1397:
                   1398:        c4 = *pos++;
                   1399:        if (c4 != 0)
                   1400:                return 1;
                   1401:
                   1402:        *version = c1 * 0x100 + c2 * 0x10 + c3;
                   1403:        return 0;
                   1404: }
                   1405:
                   1406:
                   1407: static int
                   1408: a_udf_version(const char *s, const char *id_type)
                   1409: {
                   1410:        uint32_t version;
                   1411:
                   1412:        if (parse_udfversion(s, &version))
                   1413:                errx(1, "unknown %s id %s; specify as hex or float", id_type, s);
                   1414:        return version;
                   1415: }
                   1416:
                   1417: /* --------------------------------------------------------------------- */
                   1418:
1.1       reinoud  1419: static void
                   1420: usage(void)
                   1421: {
1.4       reinoud  1422:        (void)fprintf(stderr, "Usage: %s [-cFM] [-L loglabel] "
                   1423:            "[-P discid] [-S setlabel] [-s size] [-p perc] "
                   1424:            "[-t gmtoff] [-v min_udf] [-V max_udf] special\n", getprogname());
1.1       reinoud  1425:        exit(EXIT_FAILURE);
                   1426: }
                   1427:
                   1428:
                   1429: int
                   1430: main(int argc, char **argv)
                   1431: {
                   1432:        struct tm *tm;
                   1433:        struct stat st;
                   1434:        time_t now;
                   1435:        char  scrap[255];
                   1436:        int ch, req_enable, req_disable, force;
                   1437:        int error;
                   1438:
                   1439:        setprogname(argv[0]);
                   1440:
                   1441:        /* initialise */
                   1442:        format_str    = strdup("");
                   1443:        req_enable    = req_disable = 0;
                   1444:        format_flags  = FORMAT_INVALID;
                   1445:        force         = 0;
                   1446:        check_surface = 0;
                   1447:
                   1448:        srandom((unsigned long) time(NULL));
                   1449:        udf_init_create_context();
                   1450:        context.app_name  = APP_NAME;
                   1451:        context.impl_name = IMPL_NAME;
                   1452:        context.app_version_main = APP_VERSION_MAIN;
                   1453:        context.app_version_sub  = APP_VERSION_SUB;
                   1454:
                   1455:        /* minimum and maximum UDF versions we advise */
                   1456:        context.min_udf = 0x201;
                   1457:        context.max_udf = 0x201;
                   1458:
                   1459:        /* use user's time zone as default */
                   1460:        (void)time(&now);
                   1461:        tm = localtime(&now);
                   1462:        context.gmtoff = tm->tm_gmtoff;
                   1463:
                   1464:        /* process options */
1.4       reinoud  1465:        while ((ch = getopt(argc, argv, "cFL:Mp:P:s:S:t:v:V:")) != -1) {
1.1       reinoud  1466:                switch (ch) {
                   1467:                case 'c' :
                   1468:                        check_surface = 1;
                   1469:                        break;
                   1470:                case 'F' :
                   1471:                        force = 1;
                   1472:                        break;
                   1473:                case 'L' :
                   1474:                        if (context.logvol_name) free(context.logvol_name);
                   1475:                        context.logvol_name = strdup(optarg);
                   1476:                        break;
                   1477:                case 'M' :
                   1478:                        req_disable |= FORMAT_META;
                   1479:                        break;
1.4       reinoud  1480:                case 'p' :
                   1481:                        meta_perc = a_num(optarg, "meta_perc");
                   1482:                        /* limit to `sensible` values */
                   1483:                        meta_perc = MIN(meta_perc, 99);
                   1484:                        meta_perc = MAX(meta_perc, 1);
                   1485:                        meta_fract = (float) meta_perc/100.0;
                   1486:                        break;
1.1       reinoud  1487:                case 'v' :
1.3       reinoud  1488:                        context.min_udf = a_udf_version(optarg, "min_udf");
1.1       reinoud  1489:                        if (context.min_udf > context.max_udf)
                   1490:                                context.max_udf = context.min_udf;
                   1491:                        break;
                   1492:                case 'V' :
1.3       reinoud  1493:                        context.max_udf = a_udf_version(optarg, "max_udf");
1.1       reinoud  1494:                        if (context.min_udf > context.max_udf)
                   1495:                                context.min_udf = context.max_udf;
                   1496:                        break;
                   1497:                case 'P' :
                   1498:                        context.primary_name = strdup(optarg);
                   1499:                        break;
                   1500:                case 's' :
                   1501:                        /* TODO size argument; recordable emulation */
                   1502:                        break;
                   1503:                case 'S' :
                   1504:                        if (context.volset_name) free(context.volset_name);
                   1505:                        context.volset_name = strdup(optarg);
                   1506:                        break;
                   1507:                case 't' :
                   1508:                        /* time zone overide */
                   1509:                        context.gmtoff = a_num(optarg, "gmtoff");
                   1510:                        break;
                   1511:                default  :
                   1512:                        usage();
                   1513:                        /* NOTREACHED */
                   1514:                }
                   1515:        }
                   1516:
                   1517:        if (optind + 1 != argc)
                   1518:                usage();
                   1519:
                   1520:        /* get device and directory specifier */
                   1521:        dev = argv[optind];
                   1522:
                   1523:        /* open device */
                   1524:        if ((fd = open(dev, O_RDWR, 0)) == -1) {
                   1525:                perror("can't open device");
                   1526:                return EXIT_FAILURE;
                   1527:        }
                   1528:
                   1529:        /* stat the device */
                   1530:        if (fstat(fd, &st) != 0) {
                   1531:                perror("can't stat the device");
                   1532:                close(fd);
                   1533:                return EXIT_FAILURE;
                   1534:        }
                   1535:
                   1536:        /* Formatting can only be done on raw devices */
                   1537:        if (!S_ISCHR(st.st_mode)) {
                   1538:                printf("%s is not a raw device\n", dev);
                   1539:                close(fd);
                   1540:                return EXIT_FAILURE;
                   1541:        }
                   1542:
                   1543:        /* just in case something went wrong, synchronise the drive's cache */
                   1544:        udf_synchronise_caches();
                   1545:
                   1546:        /* get disc information */
                   1547:        error = udf_update_discinfo(&mmc_discinfo);
                   1548:        if (error) {
                   1549:                perror("can't retrieve discinfo");
                   1550:                close(fd);
                   1551:                return EXIT_FAILURE;
                   1552:        }
                   1553:
                   1554:        /* derive disc identifiers when not specified and check given */
                   1555:        error = udf_proces_names();
                   1556:        if (error) {
                   1557:                /* error message has been printed */
                   1558:                close(fd);
                   1559:                return EXIT_FAILURE;
                   1560:        }
                   1561:
                   1562:        /* derive newfs disc format from disc profile */
                   1563:        error = udf_derive_format(req_enable, req_disable, force);
                   1564:        if (error)  {
                   1565:                /* error message has been printed */
                   1566:                close(fd);
                   1567:                return EXIT_FAILURE;
                   1568:        }
                   1569:
                   1570:        udf_dump_discinfo(&mmc_discinfo);
                   1571:        printf("Formatting disc compatible with UDF version %x to %x\n\n",
                   1572:                context.min_udf, context.max_udf);
                   1573:        (void)snprintb(scrap, sizeof(scrap), FORMAT_FLAGBITS,
                   1574:            (uint64_t) format_flags);
1.4       reinoud  1575:        printf("UDF properties       %s\n", scrap);
                   1576:        printf("Volume set          `%s'\n", context.volset_name);
                   1577:        printf("Primary volume      `%s`\n", context.primary_name);
                   1578:        printf("Logical volume      `%s`\n", context.logvol_name);
                   1579:        if (format_flags & FORMAT_META)
                   1580:                printf("Metadata percentage  %d %%\n", meta_perc);
1.1       reinoud  1581:        printf("\n");
                   1582:
                   1583:        /* prepare disc if nessisary (recordables mainly) */
                   1584:        error = udf_prepare_disc();
                   1585:        if (error) {
                   1586:                perror("preparing disc failed");
                   1587:                close(fd);
                   1588:                return EXIT_FAILURE;
                   1589:        };
                   1590:
                   1591:        /* set up administration */
                   1592:        error = udf_do_newfs();
                   1593:
                   1594:        /* in any case, synchronise the drive's cache to prevent lockups */
                   1595:        udf_synchronise_caches();
                   1596:
                   1597:        close(fd);
                   1598:        if (error)
                   1599:                return EXIT_FAILURE;
                   1600:
                   1601:        return EXIT_SUCCESS;
                   1602: }
                   1603:
                   1604: /* --------------------------------------------------------------------- */
                   1605:

CVSweb <webmaster@jp.NetBSD.org>