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

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sbin/newfs_udf/newfs_udf.c between version 1.12 and 1.12.10.1

version 1.12, 2011/05/26 07:59:08 version 1.12.10.1, 2014/08/20 00:02:27
Line 1 
Line 1 
 /* $NetBSD$ */  /* $NetBSD$ */
   
 /*  /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk   * Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
  * All rights reserved.   * All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
Line 65 
Line 65 
   
 #include "mountprog.h"  #include "mountprog.h"
 #include "udf_create.h"  #include "udf_create.h"
   #include "udf_write.h"
 /* general settings */  #include "newfs_udf.h"
 #define UDF_512_TRACK   0       /* NOT recommended */  
 #define UDF_META_PERC  20       /* picked */  
   
   
 /* prototypes */  /* prototypes */
 int newfs_udf(int argc, char **argv);  int newfs_udf(int argc, char **argv);
 static void usage(void) __attribute__((__noreturn__));  static void usage(void) __attribute__((__noreturn__));
   
 int udf_derive_format(int req_en, int req_dis, int force);  
 int udf_proces_names(void);  /* queue for temporary storage of sectors to be written out */
 int udf_do_newfs(void);  struct wrsect {
           uint64_t  sectornr;
 /* Identifying myself */          uint8_t  *sector_data;
 #define APP_NAME                "*NetBSD newfs"          TAILQ_ENTRY(wrsect) next;
 #define APP_VERSION_MAIN        0  };
 #define APP_VERSION_SUB         3  
 #define IMPL_NAME               "*NetBSD userland UDF"  /* write queue and track blocking skew */
   TAILQ_HEAD(wrsect_list, wrsect) write_queue;
   
   
 /* global variables describing disc and format requests */  /* global variables describing disc and format requests */
Line 95  char *format_str;   /* format: string re
Line 93  char *format_str;   /* format: string re
 int      format_flags;                  /* format: attribute flags       */  int      format_flags;                  /* format: attribute flags       */
 int      media_accesstype;              /* derived from current mmc cap  */  int      media_accesstype;              /* derived from current mmc cap  */
 int      check_surface;                 /* for rewritables               */  int      check_surface;                 /* for rewritables               */
   int      imagefile_secsize;             /* for files                     */
   int      emul_packetsize;               /* for discs and files           */
   
 int      wrtrack_skew;  int      wrtrack_skew;
 int      meta_perc = UDF_META_PERC;  int      meta_perc = UDF_META_PERC;
 float    meta_fract = (float) UDF_META_PERC / 100.0;  float    meta_fract = (float) UDF_META_PERC / 100.0;
   
   
 /* shared structure between udf_create.c users */  
 struct udf_create_context context;  
 struct udf_disclayout     layout;  
   
   
 /* queue for temporary storage of sectors to be written out */  
 struct wrsect {  
         uint32_t  sectornr;  
         uint8_t  *sector_data;  
         TAILQ_ENTRY(wrsect) next;  
 };  
   
 /* write queue and track blocking skew */  
 TAILQ_HEAD(wrsect_list, wrsect) write_queue;  
   
   
 /* --------------------------------------------------------------------- */  /* --------------------------------------------------------------------- */
   
 /*  /*
  * write queue implementation   * write queue implementation
  */   */
   
 static int  int
 udf_write_sector(void *sector, uint32_t location)  udf_write_sector(void *sector, uint64_t location)
 {  {
         struct wrsect *pos, *seekpos;          struct wrsect *pos, *seekpos;
   
Line 166  udf_write_sector(void *sector, uint32_t 
Line 150  udf_write_sector(void *sector, uint32_t 
  * XXX support for growing vnd?   * XXX support for growing vnd?
  */   */
   
 static int  int
 writeout_write_queue(void)  writeout_write_queue(void)
 {  {
         struct wrsect *pos;          struct wrsect *pos;
         uint64_t offset;          uint64_t offset;
         uint32_t line_len, line_offset;          uint64_t line_start, new_line_start;
         uint32_t line_start, new_line_start, relpos;          uint32_t line_len, line_offset, relpos;
         uint32_t blockingnr;          uint32_t blockingnr;
         uint8_t *linebuf, *adr;          uint8_t *linebuf, *adr;
   
Line 283  udf_dump_discinfo(struct mmc_discinfo *d
Line 267  udf_dump_discinfo(struct mmc_discinfo *d
 static int  static int
 udf_update_discinfo(struct mmc_discinfo *di)  udf_update_discinfo(struct mmc_discinfo *di)
 {  {
           struct stat st;
         struct disklabel  disklab;          struct disklabel  disklab;
         struct partition *dp;          struct partition *dp;
         struct stat st;          off_t size, sectors, secsize;
         int partnr, error;          int partnr, error;
   
         memset(di, 0, sizeof(struct mmc_discinfo));          memset(di, 0, sizeof(struct mmc_discinfo));
Line 295  udf_update_discinfo(struct mmc_discinfo 
Line 280  udf_update_discinfo(struct mmc_discinfo 
         if (error == 0)          if (error == 0)
                 return 0;                  return 0;
   
         /*          /* (re)fstat the file */
          * disc partition support; note we can't use DIOCGPART in userland so  
          * get disc label and use the stat info to get the partition number.  
          */  
         if (ioctl(fd, DIOCGDINFO, &disklab) == -1) {  
                 /* failed to get disclabel! */  
                 perror("disklabel");  
                 return errno;  
         }  
   
         /* get disk partition it refers to */  
         fstat(fd, &st);          fstat(fd, &st);
         partnr = DISKPART(st.st_rdev);  
         dp = &disklab.d_partitions[partnr];          if (S_ISREG(st.st_mode)) {
                   /* file support; we pick the minimum sector size allowed */
                   size = st.st_size;
                   secsize = imagefile_secsize;
                   sectors = size / secsize;
           } else {
                   /*
                    * disc partition support; note we can't use DIOCGPART in
                    * userland so get disc label and use the stat info to get the
                    * partition number.
                    */
                   if (ioctl(fd, DIOCGDINFO, &disklab) == -1) {
                           /* failed to get disclabel! */
                           perror("disklabel");
                           return errno;
                   }
   
                   /* get disk partition it refers to */
                   fstat(fd, &st);
                   partnr = DISKPART(st.st_rdev);
                   dp = &disklab.d_partitions[partnr];
   
                   /* TODO problem with last_possible_lba on resizable VND */
                   if (dp->p_size == 0) {
                           perror("faulty disklabel partition returned, "
                                   "check label\n");
                           return EIO;
                   }
   
                   sectors = dp->p_size;
                   secsize = disklab.d_secsize;
           }
   
         /* set up a disc info profile for partitions */          /* set up a disc info profile for partitions */
         di->mmc_profile         = 0x01; /* disc type */          di->mmc_profile         = 0x01; /* disc type */
Line 323  udf_update_discinfo(struct mmc_discinfo 
Line 329  udf_update_discinfo(struct mmc_discinfo 
         di->mmc_cap    = di->mmc_cur;          di->mmc_cap    = di->mmc_cur;
         di->disc_flags = MMC_DFLAGS_UNRESTRICTED;          di->disc_flags = MMC_DFLAGS_UNRESTRICTED;
   
         /* TODO problem with last_possible_lba on resizable VND; request */          di->last_possible_lba = sectors - 1;
         if (dp->p_size == 0) {          di->sector_size       = secsize;
                 perror("faulty disklabel partition returned, check label\n");  
                 return EIO;  
         }  
         di->last_possible_lba = dp->p_size - 1;  
         di->sector_size       = disklab.d_secsize;  
   
         di->num_sessions = 1;          di->num_sessions = 1;
         di->num_tracks   = 1;          di->num_tracks   = 1;
Line 341  udf_update_discinfo(struct mmc_discinfo 
Line 342  udf_update_discinfo(struct mmc_discinfo 
 }  }
   
   
 static int  int
 udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti)  udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti)
 {  {
         int error, class;          int error, class;
Line 365  udf_update_trackinfo(struct mmc_discinfo
Line 366  udf_update_trackinfo(struct mmc_discinfo
         ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;          ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;
   
         ti->track_start    = 0;          ti->track_start    = 0;
         ti->packet_size    = 1;          ti->packet_size    = emul_packetsize;
   
         /* TODO support for resizable vnd */          /* TODO support for resizable vnd */
         ti->track_size    = di->last_possible_lba;          ti->track_size    = di->last_possible_lba;
Line 431  udf_synchronise_caches(void)
Line 432  udf_synchronise_caches(void)
 /* --------------------------------------------------------------------- */  /* --------------------------------------------------------------------- */
   
 static int  static int
 udf_write_dscr_phys(union dscrptr *dscr, uint32_t location,  
         uint32_t sects)  
 {  
         uint32_t phys, cnt;  
         uint8_t *bpos;  
         int error;  
   
         dscr->tag.tag_loc = udf_rw32(location);  
         (void) udf_validate_tag_and_crc_sums(dscr);  
   
         for (cnt = 0; cnt < sects; cnt++) {  
                 bpos  = (uint8_t *) dscr;  
                 bpos += context.sector_size * cnt;  
   
                 phys = location + cnt;  
                 error = udf_write_sector(bpos, phys);  
                 if (error)  
                         return error;  
         }  
         return 0;  
 }  
   
   
 static int  
 udf_write_dscr_virt(union dscrptr *dscr, uint32_t location, uint32_t vpart,  
         uint32_t sects)  
 {  
         struct file_entry *fe;  
         struct extfile_entry *efe;  
         struct extattrhdr_desc *extattrhdr;  
         uint32_t phys, cnt;  
         uint8_t *bpos;  
         int error;  
   
         extattrhdr = NULL;  
         if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {  
                 fe = (struct file_entry *) dscr;  
                 if (udf_rw32(fe->l_ea) > 0)  
                         extattrhdr = (struct extattrhdr_desc *) fe->data;  
         }  
         if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {  
                 efe = (struct extfile_entry *) dscr;  
                 if (udf_rw32(efe->l_ea) > 0)  
                         extattrhdr = (struct extattrhdr_desc *) efe->data;  
         }  
         if (extattrhdr) {  
                 extattrhdr->tag.tag_loc = udf_rw32(location);  
                 udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr);  
         }  
   
         dscr->tag.tag_loc = udf_rw32(location);  
         udf_validate_tag_and_crc_sums(dscr);  
   
         for (cnt = 0; cnt < sects; cnt++) {  
                 bpos  = (uint8_t *) dscr;  
                 bpos += context.sector_size * cnt;  
   
                 /* NOTE linear mapping assumed in the ranges used */  
                 phys = context.vtop_offset[vpart] + location + cnt;  
   
                 error = udf_write_sector(bpos, phys);  
                 if (error)  
                         return error;  
         }  
         return 0;  
 }  
   
 /* --------------------------------------------------------------------- */  
   
 /*  
  * udf_derive_format derives the format_flags from the disc's mmc_discinfo.  
  * The resulting flags uniquely define a disc format. Note there are at least  
  * 7 distinct format types defined in UDF.  
  */  
   
 #define UDF_VERSION(a) \  
         (((a) == 0x100) || ((a) == 0x102) || ((a) == 0x150) || ((a) == 0x200) || \  
          ((a) == 0x201) || ((a) == 0x250) || ((a) == 0x260))  
   
 int  
 udf_derive_format(int req_enable, int req_disable, int force)  
 {  
         /* disc writability, formatted, appendable */  
         if ((mmc_discinfo.mmc_cur & MMC_CAP_RECORDABLE) == 0) {  
                 (void)printf("Can't newfs readonly device\n");  
                 return EROFS;  
         }  
         if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {  
                 /* sequentials need sessions appended */  
                 if (mmc_discinfo.disc_state == MMC_STATE_CLOSED) {  
                         (void)printf("Can't append session to a closed disc\n");  
                         return EROFS;  
                 }  
                 if ((mmc_discinfo.disc_state != MMC_STATE_EMPTY) && !force) {  
                         (void)printf("Disc not empty! Use -F to force "  
                             "initialisation\n");  
                         return EROFS;  
                 }  
         } else {  
                 /* check if disc (being) formatted or has been started on */  
                 if (mmc_discinfo.disc_state == MMC_STATE_EMPTY) {  
                         (void)printf("Disc is not formatted\n");  
                         return EROFS;  
                 }  
         }  
   
         /* determine UDF format */  
         format_flags = 0;  
         if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {  
                 /* all rewritable media */  
                 format_flags |= FORMAT_REWRITABLE;  
                 if (context.min_udf >= 0x0250) {  
                         /* standard dictates meta as default */  
                         format_flags |= FORMAT_META;  
                 }  
   
                 if ((mmc_discinfo.mmc_cur & MMC_CAP_HW_DEFECTFREE) == 0) {  
                         /* sparables for defect management */  
                         if (context.min_udf >= 0x150)  
                                 format_flags |= FORMAT_SPARABLE;  
                 }  
         } else {  
                 /* all once recordable media */  
                 format_flags |= FORMAT_WRITEONCE;  
                 if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {  
                         format_flags |= FORMAT_SEQUENTIAL;  
   
                         if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE) {  
                                 /* logical overwritable */  
                                 format_flags |= FORMAT_LOW;  
                         } else {  
                                 /* have to use VAT for overwriting */  
                                 format_flags |= FORMAT_VAT;  
                         }  
                 } else {  
                         /* rare WORM devices, but BluRay has one, strat4096 */  
                         format_flags |= FORMAT_WORM;  
                 }  
         }  
   
         /* enable/disable requests */  
         if (req_disable & FORMAT_META) {  
                 format_flags &= ~(FORMAT_META | FORMAT_LOW);  
                 req_disable  &= ~FORMAT_META;  
         }  
         if (req_disable || req_enable) {  
                 (void)printf("Internal error\n");  
                 (void)printf("\tunrecognised enable/disable req.\n");  
                 return EIO;  
         }  
         if ((format_flags & FORMAT_VAT) & UDF_512_TRACK)  
                 format_flags |= FORMAT_TRACK512;  
   
         /* determine partition/media access type */  
         media_accesstype = UDF_ACCESSTYPE_NOT_SPECIFIED;  
         if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {  
                 media_accesstype = UDF_ACCESSTYPE_OVERWRITABLE;  
                 if (mmc_discinfo.mmc_cur & MMC_CAP_ERASABLE)  
                         media_accesstype = UDF_ACCESSTYPE_REWRITEABLE;  
         } else {  
                 /* all once recordable media */  
                 media_accesstype = UDF_ACCESSTYPE_WRITE_ONCE;  
         }  
         if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE)  
                 media_accesstype = UDF_ACCESSTYPE_PSEUDO_OVERWITE;  
   
         /* adjust minimum version limits */  
         if (format_flags & FORMAT_VAT)  
                 context.min_udf = MAX(context.min_udf, 0x0150);  
         if (format_flags & FORMAT_SPARABLE)  
                 context.min_udf = MAX(context.min_udf, 0x0150);  
         if (format_flags & FORMAT_META)  
                 context.min_udf = MAX(context.min_udf, 0x0250);  
         if (format_flags & FORMAT_LOW)  
                 context.min_udf = MAX(context.min_udf, 0x0260);  
   
         /* adjust maximum version limits not to tease or break things */  
         if (!(format_flags & (FORMAT_META | FORMAT_LOW)) &&  
             (context.max_udf > 0x200))  
                 context.max_udf = 0x201;  
   
         if ((format_flags & (FORMAT_VAT | FORMAT_SPARABLE)) == 0)  
                 if (context.max_udf <= 0x150)  
                         context.min_udf = 0x102;  
   
         /* limit Ecma 167 descriptor if possible/needed */  
         context.dscrver = 3;  
         if ((context.min_udf < 0x200) || (context.max_udf < 0x200)) {  
                 context.dscrver = 2;  
                 context.max_udf = 0x150;        /* last version < 0x200 */  
         }  
   
         /* is it possible ? */  
         if (context.min_udf > context.max_udf) {  
                 (void)printf("Initialisation prohibited by specified maximum "  
                     "UDF version 0x%04x. Minimum version required 0x%04x\n",  
                     context.max_udf, context.min_udf);  
                 return EPERM;  
         }  
   
         if (!UDF_VERSION(context.min_udf) || !UDF_VERSION(context.max_udf)) {  
                 printf("Choose UDF version numbers from "  
                         "0x102, 0x150, 0x200, 0x201, 0x250 and 0x260\n");  
                 printf("Default version is 0x201\n");  
                 return EPERM;  
         }  
   
         return 0;  
 }  
   
 #undef UDF_VERSION  
   
   
 /* --------------------------------------------------------------------- */  
   
 int  
 udf_proces_names(void)  
 {  
         uint32_t primary_nr;  
         uint64_t volset_nr;  
   
         if (context.logvol_name == NULL)  
                 context.logvol_name = strdup("anonymous");  
         if (context.primary_name == NULL) {  
                 if (mmc_discinfo.disc_flags & MMC_DFLAGS_DISCIDVALID) {  
                         primary_nr = mmc_discinfo.disc_id;  
                 } else {  
                         primary_nr = (uint32_t) random();  
                 }  
                 context.primary_name = calloc(32, 1);  
                 sprintf(context.primary_name, "%08"PRIx32, primary_nr);  
         }  
         if (context.volset_name == NULL) {  
                 if (mmc_discinfo.disc_flags & MMC_DFLAGS_BARCODEVALID) {  
                         volset_nr = mmc_discinfo.disc_barcode;  
                 } else {  
                         volset_nr  =  (uint32_t) random();  
                         volset_nr |= ((uint64_t) random()) << 32;  
                 }  
                 context.volset_name = calloc(128,1);  
                 sprintf(context.volset_name, "%016"PRIx64, volset_nr);  
         }  
         if (context.fileset_name == NULL)  
                 context.fileset_name = strdup("anonymous");  
   
         /* check passed/created identifiers */  
         if (strlen(context.logvol_name)  > 128) {  
                 (void)printf("Logical volume name too long\n");  
                 return EINVAL;  
         }  
         if (strlen(context.primary_name) >  32) {  
                 (void)printf("Primary volume name too long\n");  
                 return EINVAL;  
         }  
         if (strlen(context.volset_name)  > 128) {  
                 (void)printf("Volume set name too long\n");  
                 return EINVAL;  
         }  
         if (strlen(context.fileset_name) > 32) {  
                 (void)printf("Fileset name too long\n");  
                 return EINVAL;  
         }  
   
         /* signal all OK */  
         return 0;  
 }  
   
 /* --------------------------------------------------------------------- */  
   
 static int  
 udf_prepare_disc(void)  udf_prepare_disc(void)
 {  {
         struct mmc_trackinfo ti;          struct mmc_trackinfo ti;
Line 817  udf_prepare_disc(void)
Line 548  udf_prepare_disc(void)
   
 /* --------------------------------------------------------------------- */  /* --------------------------------------------------------------------- */
   
 static int  int
 udf_surface_check(void)  udf_surface_check(void)
 {  {
         uint32_t loc, block_bytes;          uint32_t loc, block_bytes;
Line 885  udf_surface_check(void)
Line 616  udf_surface_check(void)
         return 0;          return 0;
 }  }
   
 /* --------------------------------------------------------------------- */  
   
 static int  
 udf_write_iso9660_vrs(void)  
 {  
         struct vrs_desc *iso9660_vrs_desc;  
         uint32_t pos;  
         int error, cnt, dpos;  
   
         /* create ISO/Ecma-167 identification descriptors */  
         if ((iso9660_vrs_desc = calloc(1, context.sector_size)) == NULL)  
                 return ENOMEM;  
   
         /*  
          * All UDF formats should have their ISO/Ecma-167 descriptors written  
          * except when not possible due to track reservation in the case of  
          * VAT  
          */  
         if ((format_flags & FORMAT_TRACK512) == 0) {  
                 dpos = (2048 + context.sector_size - 1) / context.sector_size;  
   
                 /* wipe at least 6 times 2048 byte `sectors' */  
                 for (cnt = 0; cnt < 6 *dpos; cnt++) {  
                         pos = layout.iso9660_vrs + cnt;  
                         if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {  
                                 free(iso9660_vrs_desc);  
                                 return error;  
                         }  
                 }  
   
                 /* common VRS fields in all written out ISO descriptors */  
                 iso9660_vrs_desc->struct_type = 0;  
                 iso9660_vrs_desc->version     = 1;  
                 pos = layout.iso9660_vrs;  
   
                 /* BEA01, NSR[23], TEA01 */  
                 memcpy(iso9660_vrs_desc->identifier, "BEA01", 5);  
                 if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {  
                         free(iso9660_vrs_desc);  
                         return error;  
                 }  
                 pos += dpos;  
   
                 if (context.dscrver == 2)  
                         memcpy(iso9660_vrs_desc->identifier, "NSR02", 5);  
                 else  
                         memcpy(iso9660_vrs_desc->identifier, "NSR03", 5);  
                 ;  
                 if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {  
                         free(iso9660_vrs_desc);  
                         return error;  
                 }  
                 pos += dpos;  
   
                 memcpy(iso9660_vrs_desc->identifier, "TEA01", 5);  
                 if ((error = udf_write_sector(iso9660_vrs_desc, pos))) {  
                         free(iso9660_vrs_desc);  
                         return error;  
                 }  
         }  
   
         free(iso9660_vrs_desc);  
         /* return success */  
         return 0;  
 }  
   
   
 /* --------------------------------------------------------------------- */  /* --------------------------------------------------------------------- */
   
 /*  static int
  * Main function that creates and writes out disc contents based on the  
  * format_flags's that uniquely define the type of disc to create.  
  */  
   
 int  
 udf_do_newfs(void)  udf_do_newfs(void)
 {  {
         union dscrptr *zero_dscr;          int error;
         union dscrptr *terminator_dscr;  
         union dscrptr *root_dscr;  
         union dscrptr *vat_dscr;  
         union dscrptr *dscr;  
         struct mmc_trackinfo ti;  
         uint32_t sparable_blocks;  
         uint32_t sector_size, blockingnr;  
         uint32_t cnt, loc, len;  
         int sectcopy;  
         int error, integrity_type;  
         int data_part, metadata_part;  
   
         /* init */  
         sector_size = mmc_discinfo.sector_size;  
   
         /* determine span/size */  
         ti.tracknr = mmc_discinfo.first_track_last_session;  
         error = udf_update_trackinfo(&mmc_discinfo, &ti);  
         if (error)  
                 return error;  
   
         if (mmc_discinfo.sector_size < context.sector_size) {  
                 fprintf(stderr, "Impossible to format: sectorsize too small\n");  
                 return EIO;  
         }  
         context.sector_size = sector_size;  
   
         /* determine blockingnr */  
         blockingnr = ti.packet_size;  
         if (blockingnr <= 1) {  
                 /* paranoia on blockingnr */  
                 switch (mmc_discinfo.mmc_profile) {  
                 case 0x09 : /* CD-R    */  
                 case 0x0a : /* CD-RW   */  
                         blockingnr = 32;        /* UDF requirement */  
                         break;  
                 case 0x11 : /* DVD-R (DL) */  
                 case 0x1b : /* DVD+R      */  
                 case 0x2b : /* DVD+R Dual layer */  
                 case 0x13 : /* DVD-RW restricted overwrite */  
                 case 0x14 : /* DVD-RW sequential */  
                         blockingnr = 16;        /* SCSI definition */  
                         break;  
                 case 0x41 : /* BD-R Sequential recording (SRM) */  
                 case 0x51 : /* HD DVD-R   */  
                         blockingnr = 32;        /* SCSI definition */  
                         break;  
                 default:  
                         break;  
                 }  
   
         }  
         if (blockingnr <= 0) {  
                 printf("Can't fixup blockingnumber for device "  
                         "type %d\n", mmc_discinfo.mmc_profile);  
   
                 printf("Device is not returning valid blocking"  
                         " number and media type is unknown.\n");  
   
                 return EINVAL;  
         }  
   
         /* setup sector writeout queue's */  
         TAILQ_INIT(&write_queue);  
         wrtrack_skew = ti.track_start % blockingnr;  
   
         if (mmc_discinfo.mmc_class == MMC_CLASS_CD) {  
                 /* not too much for CD-RW, still 20MiB */  
                 sparable_blocks = 32;  
         } else {  
                 /* take a value for DVD*RW mainly, BD is `defect free' */  
                 sparable_blocks = 512;  
         }  
   
         /* get layout */  
         error = udf_calculate_disc_layout(format_flags, context.min_udf,  
                 wrtrack_skew,  
                 ti.track_start, mmc_discinfo.last_possible_lba,  
                 sector_size, blockingnr, sparable_blocks,  
                 meta_fract);  
   
         /* cache partition for we need it often */  
         data_part     = context.data_part;  
         metadata_part = context.metadata_part;  
   
         /* Create sparing table descriptor if applicable */  
         if (format_flags & FORMAT_SPARABLE) {  
                 if ((error = udf_create_sparing_tabled()))  
                         return error;  
   
                 if (check_surface) {  
                         if ((error = udf_surface_check()))  
                                 return error;  
                 }  
         }  
   
         /* Create a generic terminator descriptor */  
         terminator_dscr = calloc(1, sector_size);  
         if (terminator_dscr == NULL)  
                 return ENOMEM;  
         udf_create_terminator(terminator_dscr, 0);  
   
         /*  
          * Start with wipeout of VRS1 upto start of partition. This allows  
          * formatting for sequentials with the track reservation and it  
          * cleans old rubbish on rewritables. For sequentuals without the  
          * track reservation all is wiped from track start.  
          */  
         if ((zero_dscr = calloc(1, context.sector_size)) == NULL)  
                 return ENOMEM;  
   
         loc = (format_flags & FORMAT_TRACK512) ? layout.vds1 : ti.track_start;  
         for (; loc < layout.part_start_lba; loc++) {  
                 if ((error = udf_write_sector(zero_dscr, loc))) {  
                         free(zero_dscr);  
                         return error;  
                 }  
         }  
         free(zero_dscr);  
   
         /* Create anchors */  
         for (cnt = 0; cnt < 3; cnt++) {  
                 if ((error = udf_create_anchor(cnt))) {  
                         return error;  
                 }  
         }  
   
         /*  
          * Create the two Volume Descriptor Sets (VDS) each containing the  
          * following descriptors : primary volume, partition space,  
          * unallocated space, logical volume, implementation use and the  
          * terminator  
          */  
   
         /* start of volume recognision sequence building */  
         context.vds_seq = 0;  
   
         /* Create primary volume descriptor */  
         if ((error = udf_create_primaryd()))  
                 return error;  
   
         /* Create partition descriptor */  
         if ((error = udf_create_partitiond(context.data_part, media_accesstype)))  
                 return error;  
   
         /* Create unallocated space descriptor */  
         if ((error = udf_create_unalloc_spaced()))  
                 return error;  
   
         /* Create logical volume descriptor */  
         if ((error = udf_create_logical_dscr(format_flags)))  
                 return error;  
   
         /* Create implementation use descriptor */  
         /* TODO input of fields 1,2,3 and passing them */  
         if ((error = udf_create_impvold(NULL, NULL, NULL)))  
                 return error;  
   
         /* write out what we've created so far */  
   
         /* writeout iso9660 vrs */  
         if ((error = udf_write_iso9660_vrs()))  
                 return error;  
   
         /* Writeout anchors */  
         for (cnt = 0; cnt < 3; cnt++) {  
                 dscr = (union dscrptr *) context.anchors[cnt];  
                 loc  = layout.anchors[cnt];  
                 if ((error = udf_write_dscr_phys(dscr, loc, 1)))  
                         return error;  
   
                 /* sequential media has only one anchor */  
                 if (format_flags & FORMAT_SEQUENTIAL)  
                         break;  
         }  
   
         /* write out main and secondary VRS */  
         for (sectcopy = 1; sectcopy <= 2; sectcopy++) {  
                 loc = (sectcopy == 1) ? layout.vds1 : layout.vds2;  
   
                 /* primary volume descriptor */  
                 dscr = (union dscrptr *) context.primary_vol;  
                 error = udf_write_dscr_phys(dscr, loc, 1);  
                 if (error)  
                         return error;  
                 loc++;  
   
                 /* partition descriptor(s) */  
                 for (cnt = 0; cnt < UDF_PARTITIONS; cnt++) {  
                         dscr = (union dscrptr *) context.partitions[cnt];  
                         if (dscr) {  
                                 error = udf_write_dscr_phys(dscr, loc, 1);  
                                 if (error)  
                                         return error;  
                                 loc++;  
                         }  
                 }  
   
                 /* unallocated space descriptor */  
                 dscr = (union dscrptr *) context.unallocated;  
                 error = udf_write_dscr_phys(dscr, loc, 1);  
                 if (error)  
                         return error;  
                 loc++;  
   
                 /* logical volume descriptor */  
                 dscr = (union dscrptr *) context.logical_vol;  
                 error = udf_write_dscr_phys(dscr, loc, 1);  
                 if (error)  
                         return error;  
                 loc++;  
   
                 /* implementation use descriptor */  
                 dscr = (union dscrptr *) context.implementation;  
                 error = udf_write_dscr_phys(dscr, loc, 1);  
                 if (error)  
                         return error;  
                 loc++;  
   
                 /* terminator descriptor */  
                 error = udf_write_dscr_phys(terminator_dscr, loc, 1);  
                 if (error)  
                         return error;  
                 loc++;  
         }  
   
         /* writeout the two sparable table descriptors (if needed) */  
         if (format_flags & FORMAT_SPARABLE) {  
                 for (sectcopy = 1; sectcopy <= 2; sectcopy++) {  
                         loc  = (sectcopy == 1) ? layout.spt_1 : layout.spt_2;  
                         dscr = (union dscrptr *) context.sparing_table;  
                         len  = layout.sparing_table_dscr_lbas;  
   
                         /* writeout */  
                         error = udf_write_dscr_phys(dscr, loc, len);  
                         if (error)  
                                 return error;  
                 }  
         }  
   
         /*  
          * Create unallocated space bitmap descriptor. Sequential recorded  
          * media report their own free/used space; no free/used space tables  
          * should be recorded for these.  
          */  
         if ((format_flags & FORMAT_SEQUENTIAL) == 0) {  
                 error = udf_create_space_bitmap(  
                                 layout.alloc_bitmap_dscr_size,  
                                 layout.part_size_lba,  
                                 &context.part_unalloc_bits[data_part]);  
                 if (error)  
                         return error;  
                 /* TODO: freed space bitmap if applicable */  
   
                 /* mark space allocated for the unallocated space bitmap */  
                 udf_mark_allocated(layout.unalloc_space, data_part,  
                         layout.alloc_bitmap_dscr_size);  
         }  
   
         /*  
          * Create metadata partition file entries and allocate and init their  
          * space and free space maps.  
          */  
         if (format_flags & FORMAT_META) {  
                 error = udf_create_space_bitmap(  
                                 layout.meta_bitmap_dscr_size,  
                                 layout.meta_part_size_lba,  
                                 &context.part_unalloc_bits[metadata_part]);  
                 if (error)  
                         return error;  
   
                 error = udf_create_meta_files();  
                 if (error)  
                         return error;  
   
                 /* mark space allocated for meta partition and its bitmap */  
                 udf_mark_allocated(layout.meta_file,   data_part, 1);  
                 udf_mark_allocated(layout.meta_mirror, data_part, 1);  
                 udf_mark_allocated(layout.meta_bitmap, data_part, 1);  
                 udf_mark_allocated(layout.meta_part_start_lba, data_part,  
                         layout.meta_part_size_lba);  
   
                 /* mark space allocated for the unallocated space bitmap */  
                 udf_mark_allocated(layout.meta_bitmap_space, data_part,  
                         layout.meta_bitmap_dscr_size);  
         }  
   
         /* create logical volume integrity descriptor */  
         context.num_files = 0;  
         context.num_directories = 0;  
         integrity_type = UDF_INTEGRITY_OPEN;  
         if ((error = udf_create_lvintd(integrity_type)))  
                 return error;  
   
         /* create FSD */  
         if ((error = udf_create_fsd()))  
                 return error;  
         udf_mark_allocated(layout.fsd, metadata_part, 1);  
   
         /* create root directory */  
         assert(context.unique_id == 0x10);  
         context.unique_id = 0;  
         if ((error = udf_create_new_rootdir(&root_dscr)))  
                 return error;  
         udf_mark_allocated(layout.rootdir, metadata_part, 1);  
   
         /* writeout FSD + rootdir */  
         dscr = (union dscrptr *) context.fileset_desc;  
         error = udf_write_dscr_virt(dscr, layout.fsd, metadata_part, 1);  
         if (error)  
                 return error;  
   
         error = udf_write_dscr_virt(root_dscr, layout.rootdir, metadata_part, 1);  
         if (error)  
                 return error;  
   
         /* writeout initial open integrity sequence + terminator */          error = udf_do_newfs_prefix();
         loc = layout.lvis;  
         dscr = (union dscrptr *) context.logvol_integrity;  
         error = udf_write_dscr_phys(dscr, loc, 1);  
         if (error)          if (error)
                 return error;                  return error;
         loc++;          error = udf_do_rootdir();
         error = udf_write_dscr_phys(terminator_dscr, loc, 1);  
         if (error)          if (error)
                 return error;                  return error;
           error = udf_do_newfs_postfix();
   
           return error;
         /* XXX the place to add more files */  
   
   
         if ((format_flags & FORMAT_SEQUENTIAL) == 0) {  
                 /* update lvint and mark it closed */  
                 udf_update_lvintd(UDF_INTEGRITY_CLOSED);  
   
                 /* overwrite initial terminator */  
                 loc = layout.lvis+1;  
                 dscr = (union dscrptr *) context.logvol_integrity;  
                 error = udf_write_dscr_phys(dscr, loc, 1);  
                 if (error)  
                         return error;  
                 loc++;  
   
                 /* mark end of integrity desciptor sequence again */  
                 error = udf_write_dscr_phys(terminator_dscr, loc, 1);  
                 if (error)  
                         return error;  
         }  
   
         /* write out unallocated space bitmap on non sequential media */  
         if ((format_flags & FORMAT_SEQUENTIAL) == 0) {  
                 /* writeout unallocated space bitmap */  
                 loc  = layout.unalloc_space;  
                 dscr = (union dscrptr *) (context.part_unalloc_bits[data_part]);  
                 len  = layout.alloc_bitmap_dscr_size;  
                 error = udf_write_dscr_virt(dscr, loc, data_part, len);  
                 if (error)  
                         return error;  
         }  
   
         if (format_flags & FORMAT_META) {  
                 loc = layout.meta_file;  
                 dscr = (union dscrptr *) context.meta_file;  
                 error = udf_write_dscr_virt(dscr, loc, data_part, 1);  
                 if (error)  
                         return error;  
   
                 loc = layout.meta_mirror;  
                 dscr = (union dscrptr *) context.meta_mirror;  
                 error = udf_write_dscr_virt(dscr, loc, data_part, 1);  
                 if (error)  
                         return error;  
   
                 loc = layout.meta_bitmap;  
                 dscr = (union dscrptr *) context.meta_bitmap;  
                 error = udf_write_dscr_virt(dscr, loc, data_part, 1);  
                 if (error)  
                         return error;  
   
                 /* writeout unallocated space bitmap */  
                 loc  = layout.meta_bitmap_space;  
                 dscr = (union dscrptr *) (context.part_unalloc_bits[metadata_part]);  
                 len  = layout.meta_bitmap_dscr_size;  
                 error = udf_write_dscr_virt(dscr, loc, data_part, len);  
                 if (error)  
                         return error;  
         }  
   
         /* create a VAT and account for FSD+root */  
         vat_dscr = NULL;  
         if (format_flags & FORMAT_VAT) {  
                 /* update lvint to reflect the newest values (no writeout) */  
                 udf_update_lvintd(UDF_INTEGRITY_CLOSED);  
   
                 error = udf_create_new_VAT(&vat_dscr);  
                 if (error)  
                         return error;  
   
                 loc = layout.vat;  
                 error = udf_write_dscr_virt(vat_dscr, loc, metadata_part, 1);  
                 if (error)  
                         return error;  
         }  
   
         /* write out sectors */  
         if ((error = writeout_write_queue()))  
                 return error;  
   
         /* done */  
         return 0;  
 }  
   
 /* --------------------------------------------------------------------- */  
   
 /* version can be specified as 0xabc or a.bc */  
 static int  
 parse_udfversion(const char *pos, uint32_t *version) {  
         int hex = 0;  
         char c1, c2, c3, c4;  
   
         *version = 0;  
         if (*pos == '0') {  
                 pos++;  
                 /* expect hex format */  
                 hex = 1;  
                 if (*pos++ != 'x')  
                         return 1;  
         }  
   
         c1 = *pos++;  
         if (c1 < '0' || c1 > '9')  
                 return 1;  
         c1 -= '0';  
   
         c2 = *pos++;  
         if (!hex) {  
                 if (c2 != '.')  
                         return 1;  
                 c2 = *pos++;  
         }  
         if (c2 < '0' || c2 > '9')  
                 return 1;  
         c2 -= '0';  
   
         c3 = *pos++;  
         if (c3 < '0' || c3 > '9')  
                 return 1;  
         c3 -= '0';  
   
         c4 = *pos++;  
         if (c4 != 0)  
                 return 1;  
   
         *version = c1 * 0x100 + c2 * 0x10 + c3;  
         return 0;  
 }  }
   
   
 static int  
 a_udf_version(const char *s, const char *id_type)  
 {  
         uint32_t version;  
   
         if (parse_udfversion(s, &version))  
                 errx(1, "unknown %s id %s; specify as hex or float", id_type, s);  
         return version;  
 }  
   
 /* --------------------------------------------------------------------- */  /* --------------------------------------------------------------------- */
   
Line 1437  static void
Line 643  static void
 usage(void)  usage(void)
 {  {
         (void)fprintf(stderr, "Usage: %s [-cFM] [-L loglabel] "          (void)fprintf(stderr, "Usage: %s [-cFM] [-L loglabel] "
             "[-P discid] [-S setlabel] [-s size] [-p perc] "              "[-P discid] [-S sectorsize] [-s size] [-p perc] "
             "[-t gmtoff] [-v min_udf] [-V max_udf] special\n", getprogname());              "[-t gmtoff] [-v min_udf] [-V max_udf] special\n", getprogname());
         exit(EXIT_FAILURE);          exit(EXIT_FAILURE);
 }  }
Line 1449  main(int argc, char **argv)
Line 655  main(int argc, char **argv)
         struct tm *tm;          struct tm *tm;
         struct stat st;          struct stat st;
         time_t now;          time_t now;
         char  scrap[255];          off_t setsize;
           char  scrap[255], *colon;
         int ch, req_enable, req_disable, force;          int ch, req_enable, req_disable, force;
         int error;          int error;
   
Line 1461  main(int argc, char **argv)
Line 668  main(int argc, char **argv)
         format_flags  = FORMAT_INVALID;          format_flags  = FORMAT_INVALID;
         force         = 0;          force         = 0;
         check_surface = 0;          check_surface = 0;
           setsize       = 0;
           imagefile_secsize = 512;        /* minimum allowed sector size */
           emul_packetsize   = 32;         /* reasonable default */
   
         srandom((unsigned long) time(NULL));          srandom((unsigned long) time(NULL));
         udf_init_create_context();          udf_init_create_context();
         context.app_name  = APP_NAME;          context.app_name         = "*NetBSD newfs";
         context.impl_name = IMPL_NAME;  
         context.app_version_main = APP_VERSION_MAIN;          context.app_version_main = APP_VERSION_MAIN;
         context.app_version_sub  = APP_VERSION_SUB;          context.app_version_sub  = APP_VERSION_SUB;
           context.impl_name        = IMPL_NAME;
   
         /* minimum and maximum UDF versions we advise */          /* minimum and maximum UDF versions we advise */
         context.min_udf = 0x201;          context.min_udf = 0x201;
Line 1479  main(int argc, char **argv)
Line 689  main(int argc, char **argv)
         context.gmtoff = tm->tm_gmtoff;          context.gmtoff = tm->tm_gmtoff;
   
         /* process options */          /* process options */
         while ((ch = getopt(argc, argv, "cFL:Mp:P:s:S:t:v:V:")) != -1) {          while ((ch = getopt(argc, argv, "cFL:Mp:P:s:S:B:t:v:V:")) != -1) {
                 switch (ch) {                  switch (ch) {
                 case 'c' :                  case 'c' :
                         check_surface = 1;                          check_surface = 1;
Line 1512  main(int argc, char **argv)
Line 722  main(int argc, char **argv)
                                 context.min_udf = context.max_udf;                                  context.min_udf = context.max_udf;
                         break;                          break;
                 case 'P' :                  case 'P' :
                           /* check if there is a ':' in the name */
                           if ((colon = strstr(optarg, ":"))) {
                                   if (context.volset_name)
                                           free(context.volset_name);
                                   *colon = 0;
                                   context.volset_name = strdup(optarg);
                                   optarg = colon+1;
                           }
                           if (context.primary_name)
                                   free(context.primary_name);
                           if ((strstr(optarg, ":"))) {
                                   perror("primary name can't have ':' in its name");
                                   return EXIT_FAILURE;
                           }
                         context.primary_name = strdup(optarg);                          context.primary_name = strdup(optarg);
                         break;                          break;
                 case 's' :                  case 's' :
                         /* TODO size argument; recordable emulation */                          /* support for files, set file size */
                           /* XXX support for formatting recordables on vnd/file? */
                           if (dehumanize_number(optarg, &setsize) < 0) {
                                   perror("can't parse size argument");
                                   return EXIT_FAILURE;
                           }
                           setsize = MAX(0, setsize);
                         break;                          break;
                 case 'S' :                  case 'S' :
                         if (context.volset_name) free(context.volset_name);                          imagefile_secsize = a_num(optarg, "secsize");
                         context.volset_name = strdup(optarg);                          imagefile_secsize = MAX(512, imagefile_secsize);
                           break;
                   case 'B' :
                           emul_packetsize = a_num(optarg,
                                   "blockingnr, packetsize");
                           emul_packetsize = MAX(emul_packetsize, 1);
                           emul_packetsize = MIN(emul_packetsize, 32);
                         break;                          break;
                 case 't' :                  case 't' :
                         /* time zone overide */                          /* time zone overide */
Line 1539  main(int argc, char **argv)
Line 775  main(int argc, char **argv)
   
         /* open device */          /* open device */
         if ((fd = open(dev, O_RDWR, 0)) == -1) {          if ((fd = open(dev, O_RDWR, 0)) == -1) {
                 perror("can't open device");                  /* check if we need to create a file */
                 return EXIT_FAILURE;                  fd = open(dev, O_RDONLY, 0);
                   if (fd > 0) {
                           perror("device is there but can't be opened for read/write");
                           return EXIT_FAILURE;
                   }
                   if (!force) {
                           perror("can't open device");
                           return EXIT_FAILURE;
                   }
                   if (setsize == 0) {
                           perror("need to create image file but no size specified");
                           return EXIT_FAILURE;
                   }
                   /* need to create a file */
                   fd = open(dev, O_RDWR | O_CREAT | O_TRUNC, 0777);
                   if (fd == -1) {
                           perror("can't create image file");
                           return EXIT_FAILURE;
                   }
         }          }
   
         /* stat the device */          /* stat the device */
Line 1550  main(int argc, char **argv)
Line 804  main(int argc, char **argv)
                 return EXIT_FAILURE;                  return EXIT_FAILURE;
         }          }
   
           if (S_ISREG(st.st_mode)) {
                   if (setsize == 0)
                           setsize = st.st_size;
                   /* sanitise arguments */
                   imagefile_secsize &= ~511;
                   setsize &= ~(imagefile_secsize-1);
   
                   if (ftruncate(fd, setsize)) {
                           perror("can't resize file");
                           return EXIT_FAILURE;
                   }
           }
   
         /* formatting can only be done on raw devices */          /* formatting can only be done on raw devices */
         if (!S_ISCHR(st.st_mode)) {          if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
                 printf("%s is not a raw device\n", dev);                  printf("%s is not a raw device\n", dev);
                 close(fd);                  close(fd);
                 return EXIT_FAILURE;                  return EXIT_FAILURE;
Line 1560  main(int argc, char **argv)
Line 827  main(int argc, char **argv)
         /* just in case something went wrong, synchronise the drive's cache */          /* just in case something went wrong, synchronise the drive's cache */
         udf_synchronise_caches();          udf_synchronise_caches();
   
         /* get disc information */          /* get 'disc' information */
         error = udf_update_discinfo(&mmc_discinfo);          error = udf_update_discinfo(&mmc_discinfo);
         if (error) {          if (error) {
                 perror("can't retrieve discinfo");                  perror("can't retrieve discinfo");
Line 1605  main(int argc, char **argv)
Line 872  main(int argc, char **argv)
                 return EXIT_FAILURE;                  return EXIT_FAILURE;
         };          };
   
         /* set up administration */          /* setup sector writeout queue's */
           TAILQ_INIT(&write_queue);
   
           /* perform the newfs itself */
         error = udf_do_newfs();          error = udf_do_newfs();
           if (!error) {
                   /* write out sectors */
                   error = writeout_write_queue();
           }
   
         /* in any case, synchronise the drive's cache to prevent lockups */          /* in any case, synchronise the drive's cache to prevent lockups */
         udf_synchronise_caches();          udf_synchronise_caches();

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.12.10.1

CVSweb <webmaster@jp.NetBSD.org>