diff options
Diffstat (limited to 'mkudffs')
-rw-r--r-- | mkudffs/Makefile.am | 2 | ||||
-rw-r--r-- | mkudffs/Makefile.in | 8 | ||||
-rw-r--r-- | mkudffs/defaults.c | 2 | ||||
-rw-r--r-- | mkudffs/defaults.h | 2 | ||||
-rw-r--r-- | mkudffs/file.c | 198 | ||||
-rw-r--r-- | mkudffs/file.h | 7 | ||||
-rw-r--r-- | mkudffs/main.c | 11 | ||||
-rw-r--r-- | mkudffs/mkudffs.c | 212 | ||||
-rw-r--r-- | mkudffs/mkudffs.h | 8 | ||||
-rw-r--r-- | mkudffs/options.c | 184 | ||||
-rw-r--r-- | mkudffs/options.h | 2 |
11 files changed, 434 insertions, 202 deletions
diff --git a/mkudffs/Makefile.am b/mkudffs/Makefile.am index 8c8ba8d..fc9e54f 100644 --- a/mkudffs/Makefile.am +++ b/mkudffs/Makefile.am @@ -1,6 +1,6 @@ sbin_PROGRAMS = mkudffs mkudffs_LDADD = $(top_builddir)/libudffs/libudffs.la -mkudffs_SOURCES = main.c mkudffs.c defaults.c file.c options.c mkudffs.h defaults.h file.h options.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h ../include/udf_endian.h ../include/bswap.h +mkudffs_SOURCES = main.c mkudffs.c defaults.c file.c options.c mkudffs.h defaults.h file.h options.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h ../include/bswap.h AM_CPPFLAGS = -I$(top_srcdir)/include diff --git a/mkudffs/Makefile.in b/mkudffs/Makefile.in index 6c24c6b..e8d1ba3 100644 --- a/mkudffs/Makefile.in +++ b/mkudffs/Makefile.in @@ -228,11 +228,17 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ +UDEVDIR = @UDEVDIR@ +UDEV_CFLAGS = @UDEV_CFLAGS@ +UDEV_LIBS = @UDEV_LIBS@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ @@ -288,7 +294,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ mkudffs_LDADD = $(top_builddir)/libudffs/libudffs.la -mkudffs_SOURCES = main.c mkudffs.c defaults.c file.c options.c mkudffs.h defaults.h file.h options.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h ../include/udf_endian.h ../include/bswap.h +mkudffs_SOURCES = main.c mkudffs.c defaults.c file.c options.c mkudffs.h defaults.h file.h options.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h ../include/bswap.h AM_CPPFLAGS = -I$(top_srcdir)/include all: all-am diff --git a/mkudffs/defaults.c b/mkudffs/defaults.c index ed0a4d3..b438deb 100644 --- a/mkudffs/defaults.c +++ b/mkudffs/defaults.c @@ -1,7 +1,7 @@ /* * defaults.c * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> + * Copyright (c) 2001-2002 Ben Fennema * Copyright (c) 2014-2017 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * diff --git a/mkudffs/defaults.h b/mkudffs/defaults.h index 9a6ed99..69ca181 100644 --- a/mkudffs/defaults.h +++ b/mkudffs/defaults.h @@ -1,7 +1,7 @@ /* * defaults.h * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> + * Copyright (c) 2001-2002 Ben Fennema * Copyright (c) 2016-2017 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * diff --git a/mkudffs/file.c b/mkudffs/file.c index a931b69..555bec3 100644 --- a/mkudffs/file.c +++ b/mkudffs/file.c @@ -1,8 +1,8 @@ /* * file.c * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> - * Copyright (c) 2016-2017 Pali Rohár <pali.rohar@gmail.com> + * Copyright (c) 2001-2002 Ben Fennema + * Copyright (c) 2016-2018 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -30,6 +30,7 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include "libudffs.h" @@ -126,16 +127,17 @@ tag query_tag(struct udf_disc *disc, struct udf_extent *ext, struct udf_desc *de * @param SerialNum the serial number to assign * @param Location the block number of the on-disc tag:Ident udf_descriptor * @param data the udf_data list head + * @param skip the skip data length * @param length the summed data length * @return the tag */ -tag udf_query_tag(struct udf_disc *disc, uint16_t Ident, uint16_t SerialNum, uint32_t Location, struct udf_data *data, uint16_t length) +tag udf_query_tag(struct udf_disc *disc, uint16_t Ident, uint16_t SerialNum, uint32_t Location, struct udf_data *data, uint32_t skip, uint32_t length) { tag ret; int i; uint16_t crc = 0; - int offset = sizeof(tag); - int clength; + uint32_t clength; + uint32_t offset = sizeof(tag); ret.tagIdent = cpu_to_le16(Ident); if (disc->udf_rev >= 0x0200) @@ -150,9 +152,10 @@ tag udf_query_tag(struct udf_disc *disc, uint16_t Ident, uint16_t SerialNum, uin { if ((clength = data->length) > length) clength = length; - crc = udf_crc(data->buffer + offset, clength - offset, crc); + crc = udf_crc(data->buffer + skip + offset, clength - offset, crc); length -= clength; offset = 0; + skip = 0; data = data->next; } ret.descCRC = cpu_to_le16(crc); @@ -439,7 +442,7 @@ void insert_fid(struct udf_disc *disc, struct udf_extent *pspace, struct udf_des fid->lengthFileIdent = length; fid->lengthOfImpUse = cpu_to_le16(0); memcpy(fid->fileIdent, name, length); - fid->descTag = udf_query_tag(disc, TAG_IDENT_FID, 1, le32_to_cpu(fid->descTag.tagLocation), data, ilength); + fid->descTag = udf_query_tag(disc, TAG_IDENT_FID, 1, le32_to_cpu(fid->descTag.tagLocation), data, 0, ilength); efe->informationLength = cpu_to_le64(le64_to_cpu(efe->informationLength) + ilength); efe->objectSize = cpu_to_le64(le64_to_cpu(efe->objectSize) + ilength); @@ -472,13 +475,177 @@ void insert_fid(struct udf_disc *disc, struct udf_extent *pspace, struct udf_des fid->lengthFileIdent = length; fid->lengthOfImpUse = cpu_to_le16(0); memcpy(fid->fileIdent, name, length); - fid->descTag = udf_query_tag(disc, TAG_IDENT_FID, 1, le32_to_cpu(fid->descTag.tagLocation), data, ilength); + fid->descTag = udf_query_tag(disc, TAG_IDENT_FID, 1, le32_to_cpu(fid->descTag.tagLocation), data, 0, ilength); fe->informationLength = cpu_to_le64(le64_to_cpu(fe->informationLength) + ilength); } *(tag *)desc->data->buffer = query_tag(disc, pspace, desc, 1); *(tag *)parent->data->buffer = query_tag(disc, pspace, parent, 1); } +void insert_ea(struct udf_disc *disc, struct udf_desc *desc, struct genericFormat *ea, uint32_t length) +{ + struct extendedAttrHeaderDesc *ea_hdr; + struct extendedFileEntry *efe = NULL; + struct fileEntry *fe = NULL; + uint8_t *extendedAttr; + uint32_t lengthExtendedAttr; + uint32_t location = 0; + +#define UPDATE_PTR \ + do { \ + if (disc->flags & FLAG_EFE) \ + { \ + efe = (struct extendedFileEntry *)desc->data->buffer; \ + lengthExtendedAttr = efe->lengthExtendedAttr; \ + extendedAttr = efe->extendedAttr; \ + } \ + else \ + { \ + fe = (struct fileEntry *)desc->data->buffer; \ + lengthExtendedAttr = fe->lengthExtendedAttr; \ + extendedAttr = fe->extendedAttr; \ + } \ + ea_hdr = (struct extendedAttrHeaderDesc *)extendedAttr; \ + } while ( 0 ) + + UPDATE_PTR; + + if (le32_to_cpu(lengthExtendedAttr) && le32_to_cpu(ea_hdr->impAttrLocation) > le32_to_cpu(lengthExtendedAttr)) + ea_hdr->impAttrLocation = cpu_to_le32(0xFFFFFFFF); + if (le32_to_cpu(lengthExtendedAttr) && le32_to_cpu(ea_hdr->appAttrLocation) > le32_to_cpu(lengthExtendedAttr)) + ea_hdr->appAttrLocation = cpu_to_le32(0xFFFFFFFF); + + if (!le32_to_cpu(lengthExtendedAttr)) + { + desc->length += sizeof(*ea_hdr); + desc->data->length += sizeof(*ea_hdr); + desc->data->buffer = realloc(desc->data->buffer, desc->data->length); + + UPDATE_PTR; + + if (disc->flags & FLAG_EFE) + { + lengthExtendedAttr = efe->lengthExtendedAttr = cpu_to_le32(sizeof(*ea_hdr)); + if (le32_to_cpu(efe->lengthAllocDescs)) + memmove(&efe->allocDescs[sizeof(*ea_hdr)], efe->allocDescs, le32_to_cpu(efe->lengthAllocDescs)); + } + else + { + lengthExtendedAttr = fe->lengthExtendedAttr = cpu_to_le32(sizeof(*ea_hdr)); + if (le32_to_cpu(fe->lengthAllocDescs)) + memmove(&fe->allocDescs[sizeof(*ea_hdr)], fe->allocDescs, le32_to_cpu(fe->lengthAllocDescs)); + } + + ea_hdr->impAttrLocation = cpu_to_le32(0xFFFFFFFF); + ea_hdr->appAttrLocation = cpu_to_le32(0xFFFFFFFF); + } + + if (le32_to_cpu(ea->attrType) < 2048) + { + desc->length += length; + desc->data->length += length; + desc->data->buffer = realloc(desc->data->buffer, desc->data->length); + + UPDATE_PTR; + + if (le32_to_cpu(ea_hdr->appAttrLocation) != 0xFFFFFFFF) + { + location = le32_to_cpu(ea_hdr->appAttrLocation); + memmove(&extendedAttr[location+length], &extendedAttr[location], le32_to_cpu(lengthExtendedAttr) - location); + ea_hdr->appAttrLocation = cpu_to_le32(location+length); + } + + if (le32_to_cpu(ea_hdr->impAttrLocation) != 0xFFFFFFFF) + { + location = le32_to_cpu(ea_hdr->impAttrLocation); + if (le32_to_cpu(ea_hdr->appAttrLocation) == 0xFFFFFFFF) + memmove(&extendedAttr[location+length], &extendedAttr[location], le32_to_cpu(lengthExtendedAttr) - location); + else + memmove(&extendedAttr[location+length], &extendedAttr[location], le32_to_cpu(ea_hdr->appAttrLocation) - location); + ea_hdr->impAttrLocation = cpu_to_le32(location+length); + } + else if (le32_to_cpu(ea_hdr->appAttrLocation) == 0xFFFFFFFF) + { + location = le32_to_cpu(lengthExtendedAttr); + } + + memcpy(&extendedAttr[location], ea, length); + lengthExtendedAttr = cpu_to_le32(le32_to_cpu(lengthExtendedAttr) + length); + if (disc->flags & FLAG_EFE) + efe->lengthExtendedAttr = lengthExtendedAttr; + else + fe->lengthExtendedAttr = lengthExtendedAttr; + } + else if (le32_to_cpu(ea->attrType) < 65536) + { + desc->length += length; + desc->data->length += length; + desc->data->buffer = realloc(desc->data->buffer, desc->data->length); + + UPDATE_PTR; + + if (le32_to_cpu(ea_hdr->appAttrLocation) != 0xFFFFFFFF) + { + location = le32_to_cpu(ea_hdr->appAttrLocation); + memmove(&extendedAttr[location+length], &extendedAttr[location], le32_to_cpu(lengthExtendedAttr) - location); + ea_hdr->appAttrLocation = cpu_to_le32(location+length); + } + else + { + location = le32_to_cpu(lengthExtendedAttr); + } + + if (le32_to_cpu(ea_hdr->impAttrLocation) == 0xFFFFFFFF) + { + if (le32_to_cpu(ea_hdr->appAttrLocation) == 0xFFFFFFFF) + ea_hdr->impAttrLocation = lengthExtendedAttr; + else + ea_hdr->impAttrLocation = ea_hdr->appAttrLocation; + } + + memcpy(&extendedAttr[location], ea, length); + lengthExtendedAttr = cpu_to_le32(le32_to_cpu(lengthExtendedAttr) + length); + if (disc->flags & FLAG_EFE) + efe->lengthExtendedAttr = lengthExtendedAttr; + else + fe->lengthExtendedAttr = lengthExtendedAttr; + } + else + { + desc->length += length; + desc->data->length += length; + desc->data->buffer = realloc(desc->data->buffer, desc->data->length); + + UPDATE_PTR; + + if (le32_to_cpu(ea_hdr->appAttrLocation) == 0xFFFFFFFF) + ea_hdr->appAttrLocation = lengthExtendedAttr; + + memcpy(&extendedAttr[le32_to_cpu(lengthExtendedAttr)], ea, length); + lengthExtendedAttr = cpu_to_le32(le32_to_cpu(lengthExtendedAttr) + length); + if (disc->flags & FLAG_EFE) + efe->lengthExtendedAttr = lengthExtendedAttr; + else + fe->lengthExtendedAttr = lengthExtendedAttr; + } + + /* UDF-1.50: 3.3.4.1 Extended Attribute Header Descriptor + * If the attributes associated with the location fields highlighted above do not exist, + * then the value of the location field shall point to the byte after the extended + * attribute space. */ + if (disc->udf_rev < 0x0200) + { + if (le32_to_cpu(lengthExtendedAttr) && le32_to_cpu(ea_hdr->impAttrLocation) == 0xFFFFFFFF) + ea_hdr->impAttrLocation = lengthExtendedAttr; + if (le32_to_cpu(lengthExtendedAttr) && le32_to_cpu(ea_hdr->appAttrLocation) == 0xFFFFFFFF) + ea_hdr->appAttrLocation = lengthExtendedAttr; + } + + ea_hdr->descTag = udf_query_tag(disc, TAG_IDENT_EAHD, 1, desc->offset, desc->data, (disc->flags & FLAG_EFE) ? sizeof(*efe) : sizeof(*fe), sizeof(*ea_hdr)); + +#undef UPDATE_PTR +} + /** * @brief create a file tag:FE/EFE udf_descriptor and add the file to a directory * @param disc the udf_disc @@ -722,6 +889,7 @@ static inline unsigned long udf_find_next_one_bit (void * addr, unsigned long si tmp = leBPL_to_cpup(&tmp); found_first: tmp &= ~0UL >> (BITS_PER_LONG-size); + tmp |= (1UL << size); found_middle: return result + ffz(~tmp); } @@ -791,18 +959,18 @@ int udf_alloc_bitmap_blocks(struct udf_disc *disc, struct udf_desc *bitmap, uint do { start = ((start + alignment - 1) / alignment) * alignment; - if (start + blocks >= sbd->numOfBits) + if (start + blocks > le32_to_cpu(sbd->numOfBits)) { fprintf(stderr, "%s: Error: Not enough blocks on device\n", appname); exit(1); } if (sbd->bitmap[start/8] & (1 << (start%8))) { - end = udf_find_next_zero_bit(sbd->bitmap, sbd->numOfBits, start); + end = udf_find_next_zero_bit(sbd->bitmap, le32_to_cpu(sbd->numOfBits), start); } else - start = end = udf_find_next_one_bit(sbd->bitmap, sbd->numOfBits, start); - } while ((end - start) <= blocks); + start = end = udf_find_next_one_bit(sbd->bitmap, le32_to_cpu(sbd->numOfBits), start); + } while ((end - start) < blocks); clear_bits(sbd->bitmap, start, blocks); return start; @@ -825,7 +993,7 @@ int udf_alloc_table_blocks(struct udf_disc *disc, struct udf_desc *table, uint32 do { - if (offset >= use->lengthAllocDescs) + if (offset >= le32_to_cpu(use->lengthAllocDescs)) { fprintf(stderr, "%s: Error: Not enough blocks on device\n", appname); exit(1); @@ -869,7 +1037,7 @@ int udf_alloc_table_blocks(struct udf_disc *disc, struct udf_desc *table, uint32 sad->extLength = cpu_to_le32(EXT_NOT_RECORDED_ALLOCATED | (end - start - blocks) * disc->blocksize); use->lengthAllocDescs = cpu_to_le32(le32_to_cpu(use->lengthAllocDescs) + sizeof(short_ad)); } - use->descTag = udf_query_tag(disc, TAG_IDENT_USE, 1, table->offset, table->data, sizeof(struct unallocSpaceEntry) + le32_to_cpu(use->lengthAllocDescs)); + use->descTag = udf_query_tag(disc, TAG_IDENT_USE, 1, table->offset, table->data, 0, sizeof(struct unallocSpaceEntry) + le32_to_cpu(use->lengthAllocDescs)); return start; } @@ -923,7 +1091,7 @@ int udf_alloc_blocks(struct udf_disc *disc, struct udf_extent *pspace, uint32_t exit(1); } for (i = 0; i < blocks; ++i) - disc->vat[disc->vat_entries++] = start+i; + disc->vat[disc->vat_entries++] = cpu_to_le32(start+i); return start; } else diff --git a/mkudffs/file.h b/mkudffs/file.h index d9b4efe..bae6f7b 100644 --- a/mkudffs/file.h +++ b/mkudffs/file.h @@ -1,8 +1,8 @@ /* * libudffs.h * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> - * Copyright (c) 2016-2017 Pali Rohár <pali.rohar@gmail.com> + * Copyright (c) 2001-2002 Ben Fennema + * Copyright (c) 2016-2018 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -27,11 +27,12 @@ #include "libudffs.h" tag query_tag(struct udf_disc *, struct udf_extent *, struct udf_desc *, uint16_t); -extern tag udf_query_tag(struct udf_disc *, uint16_t, uint16_t, uint32_t, struct udf_data *, uint16_t); +extern tag udf_query_tag(struct udf_disc *, uint16_t, uint16_t, uint32_t, struct udf_data *, uint32_t, uint32_t); extern struct udf_desc *udf_create(struct udf_disc *, struct udf_extent *, const dchars *, uint8_t, uint32_t, struct udf_desc *, uint8_t, uint8_t, uint16_t); extern struct udf_desc *udf_mkdir(struct udf_disc *, struct udf_extent *, const dchars *, uint8_t, uint32_t, struct udf_desc *); extern void insert_data(struct udf_disc *disc, struct udf_extent *pspace, struct udf_desc *desc, struct udf_data *data); extern void insert_fid(struct udf_disc *, struct udf_extent *, struct udf_desc *, struct udf_desc *, const dchars *, uint8_t, uint8_t); +extern void insert_ea(struct udf_disc *disc, struct udf_desc *desc, struct genericFormat *ea, uint32_t length); extern int udf_alloc_blocks(struct udf_disc *, struct udf_extent *, uint32_t, uint32_t); static inline void clear_bits(uint8_t *bitmap, uint32_t offset, uint64_t length) diff --git a/mkudffs/main.c b/mkudffs/main.c index 066afac..0932013 100644 --- a/mkudffs/main.c +++ b/mkudffs/main.c @@ -1,8 +1,8 @@ /* * main.c * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> - * Copyright (c) 2014-2017 Pali Rohár <pali.rohar@gmail.com> + * Copyright (c) 2001-2002 Ben Fennema + * Copyright (c) 2014-2018 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -30,19 +30,19 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <locale.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> -#include <time.h> -#include <sys/time.h> #include <errno.h> #include <limits.h> #include <dirent.h> #include <sys/ioctl.h> #include <linux/fs.h> #include <linux/fd.h> +#include <sys/sysmacros.h> #include "mkudffs.h" #include "defaults.h" @@ -474,6 +474,9 @@ int main(int argc, char *argv[]) dump_space(&disc); + if (disc.blocks <= 257) + fprintf(stderr, "%s: Warning: UDF filesystem has less than 258 blocks, it can cause problems\n", appname); + if (len == (size_t)-1) fprintf(stderr, "%s: Warning: Volume Set Identifier must be at least 8 characters long\n", appname); else if (len < 16) diff --git a/mkudffs/mkudffs.c b/mkudffs/mkudffs.c index 9ad3500..59b529c 100644 --- a/mkudffs/mkudffs.c +++ b/mkudffs/mkudffs.c @@ -1,8 +1,8 @@ /* * mkudffs.c * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> - * Copyright (c) 2014-2017 Pali Rohár <pali.rohar@gmail.com> + * Copyright (c) 2001-2002 Ben Fennema + * Copyright (c) 2014-2018 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -30,6 +30,7 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -50,9 +51,8 @@ void udf_init_disc(struct udf_disc *disc) struct timeval tv; struct tm *tm; int altzone; - unsigned long int rnd; - - srand(time(NULL)); + uint32_t uuid_time; + char uuid[17]; memset(disc, 0x00, sizeof(*disc)); @@ -62,31 +62,50 @@ void udf_init_disc(struct udf_disc *disc) disc->blkssz = 512; disc->mode = 0755; - gettimeofday(&tv, NULL); - tm = localtime(&tv.tv_sec); - altzone = timezone - 3600; - if (daylight) - ts.typeAndTimezone = cpu_to_le16(((-altzone/60) & 0x0FFF) | 0x1000); + if (gettimeofday(&tv, NULL) != 0 || tv.tv_sec == (time_t)-1 || (tm = localtime(&tv.tv_sec)) == NULL || tm->tm_year < 1-1900 || tm->tm_year > 9999-1900) + { + /* fallback to 1.1.1980 00:00:00 */ + ts.typeAndTimezone = cpu_to_le16(0x1000); + ts.year = cpu_to_le16(1980); + ts.month = 1; + ts.day = 1; + ts.hour = 0; + ts.minute = 0; + ts.second = 0; + ts.centiseconds = 0; + ts.hundredsOfMicroseconds = 0; + ts.microseconds = 0; + /* and for uuid use random bytes */ + uuid_time = randu32(); + } else - ts.typeAndTimezone = cpu_to_le16(((-timezone/60) & 0x0FFF) | 0x1000); - ts.year = cpu_to_le16(1900 + tm->tm_year); - ts.month = 1 + tm->tm_mon; - ts.day = tm->tm_mday; - ts.hour = tm->tm_hour; - ts.minute = tm->tm_min; - ts.second = tm->tm_sec; - ts.centiseconds = tv.tv_usec / 10000; - ts.hundredsOfMicroseconds = (tv.tv_usec - ts.centiseconds * 10000) / 100; - ts.microseconds = tv.tv_usec - ts.centiseconds * 10000 - ts.hundredsOfMicroseconds * 100; - - get_random_bytes(&rnd, sizeof(rnd)); + { + altzone = timezone - 3600; + if (daylight) + ts.typeAndTimezone = cpu_to_le16(((-altzone/60) & 0x0FFF) | 0x1000); + else + ts.typeAndTimezone = cpu_to_le16(((-timezone/60) & 0x0FFF) | 0x1000); + ts.year = cpu_to_le16(1900 + tm->tm_year); + ts.month = 1 + tm->tm_mon; + ts.day = tm->tm_mday; + ts.hour = tm->tm_hour; + ts.minute = tm->tm_min; + ts.second = tm->tm_sec; + ts.centiseconds = tv.tv_usec / 10000; + ts.hundredsOfMicroseconds = (tv.tv_usec - ts.centiseconds * 10000) / 100; + ts.microseconds = tv.tv_usec - ts.centiseconds * 10000 - ts.hundredsOfMicroseconds * 100; + if (tv.tv_sec < 0) + uuid_time = randu32(); + else + uuid_time = tv.tv_sec & 0xFFFFFFFF; + } /* Allocate/Initialize Descriptors */ disc->udf_pvd[0] = malloc(sizeof(struct primaryVolDesc)); memcpy(disc->udf_pvd[0], &default_pvd, sizeof(struct primaryVolDesc)); memcpy(&disc->udf_pvd[0]->recordingDateAndTime, &ts, sizeof(timestamp)); - sprintf((char *)&disc->udf_pvd[0]->volSetIdent[1], "%08lx%08lx%s", - ((unsigned long int)mktime(tm))%0xFFFFFFFF, rnd%0xFFFFFFFF, &disc->udf_pvd[0]->volSetIdent[17]); + snprintf(uuid, sizeof(uuid), "%08lx%08lx", (unsigned long int)uuid_time, (unsigned long int)randu32()); + memcpy(&disc->udf_pvd[0]->volSetIdent[1], uuid, 16); disc->udf_pvd[0]->volIdent[31] = strlen((char *)disc->udf_pvd[0]->volIdent); disc->udf_pvd[0]->volSetIdent[127] = strlen((char *)disc->udf_pvd[0]->volSetIdent); @@ -142,14 +161,16 @@ void udf_init_disc(struct udf_disc *disc) disc->head->tail = NULL; } -int udf_set_version(struct udf_disc *disc, int udf_rev) +int udf_set_version(struct udf_disc *disc, uint16_t udf_rev) { struct logicalVolIntegrityDescImpUse *lvidiu; uint16_t udf_rev_le16; if (disc->udf_rev == udf_rev) return 0; - else if (udf_rev != 0x0102 && + else if ( + udf_rev != 0x0101 && + udf_rev != 0x0102 && udf_rev != 0x0150 && udf_rev != 0x0200 && udf_rev != 0x0201 && @@ -172,7 +193,7 @@ int udf_set_version(struct udf_disc *disc, int udf_rev) disc->flags &= ~FLAG_EFE; strcpy((char *)disc->udf_pd[0]->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02); } - else // 0x0102 + else // 0x0102 and older { disc->flags &= ~FLAG_VAT; disc->flags &= ~FLAG_EFE; @@ -185,33 +206,24 @@ int udf_set_version(struct udf_disc *disc, int udf_rev) memcpy(disc->udf_iuvd[0]->impIdent.identSuffix, &udf_rev_le16, sizeof(udf_rev_le16)); memcpy(disc->udf_stable[0]->sparingIdent.identSuffix, &udf_rev_le16, sizeof(udf_rev_le16)); lvidiu = query_lvidiu(disc); - if (udf_rev == 0x0260) - lvidiu->minUDFReadRev = cpu_to_le16(0x0250); + if (udf_rev < 0x0102) + { + /* The ImplementationUse area for the Logical Volume Integrity Descriptor + * prior to UDF 1.02 does not define UDF revisions, so clear these fields */ + lvidiu->minUDFReadRev = cpu_to_le16(0); + lvidiu->minUDFWriteRev = cpu_to_le16(0); + lvidiu->maxUDFWriteRev = cpu_to_le16(0); + } else - lvidiu->minUDFReadRev = cpu_to_le16(udf_rev); - lvidiu->minUDFWriteRev = cpu_to_le16(udf_rev); - lvidiu->maxUDFWriteRev = cpu_to_le16(udf_rev); - return 0; -} - -void get_random_bytes(void *buffer, size_t count) -{ - int fd; - size_t i; - - fd = open("/dev/urandom", O_RDONLY); - if (fd >= 0) { - if (read(fd, buffer, count) == (ssize_t)count) - { - close(fd); - return; - } - close(fd); + if (udf_rev == 0x0260) + lvidiu->minUDFReadRev = cpu_to_le16(0x0250); + else + lvidiu->minUDFReadRev = cpu_to_le16(udf_rev); + lvidiu->minUDFWriteRev = cpu_to_le16(udf_rev); + lvidiu->maxUDFWriteRev = cpu_to_le16(udf_rev); } - - for (i = 0; i < count; ++i) - ((uint8_t *)buffer)[i] = rand() % 0xFF; + return 0; } void split_space(struct udf_disc *disc) @@ -276,9 +288,12 @@ void split_space(struct udf_disc *disc) } accessType = le32_to_cpu(disc->udf_pd[0]->accessType); - if ((accessType == PD_ACCESS_TYPE_OVERWRITABLE || accessType == PD_ACCESS_TYPE_REWRITABLE) && sizes[LVID_SIZE] * (size_t)disc->blocksize < 8192) + if ((accessType == PD_ACCESS_TYPE_OVERWRITABLE || accessType == PD_ACCESS_TYPE_REWRITABLE) && (uint64_t)sizes[LVID_SIZE] * disc->blocksize < 8192 && blocks > 257) sizes[LVID_SIZE] = (8192 + disc->blocksize-1) / disc->blocksize; + if (sizes[VDS_SIZE] > 6 && blocks <= 257) + sizes[VDS_SIZE] = 6; + if (!(disc->flags & FLAG_VAT) && blocks < 770) start = 0; else @@ -301,7 +316,7 @@ void split_space(struct udf_disc *disc) } set_extent(disc, RVDS, start, sizes[VDS_SIZE]); } - else + else if (blocks > 257) { if (blocks >= 3072) start = find_next_extent_size(disc, (blocks-257+97)/32*32, USPACE, sizes[VDS_SIZE], offsets[VDS_SIZE]); @@ -502,7 +517,7 @@ static void fill_mbr(struct udf_disc *disc, struct mbr *mbr, uint32_t start) } if (!mbr->disk_signature) - get_random_bytes(&mbr->disk_signature, sizeof(mbr->disk_signature)); + mbr->disk_signature = le32_to_cpu(randu32()); lba_blocks = ((uint64_t)disc->blocks * disc->blocksize + disc->blkssz - 1) / disc->blkssz; @@ -608,13 +623,21 @@ void setup_anchor(struct udf_disc *disc) mlen = ext->blocks * disc->blocksize; ext = next_extent(disc->head, RVDS); - if (!ext) + if (!ext && disc->blocks > 257) { fprintf(stderr, "%s: Error: Not enough blocks on device\n", appname); exit(1); } - rloc = ext->start; - rlen = ext->blocks * disc->blocksize; + if (disc->blocks > 257) + { + rloc = ext->start; + rlen = ext->blocks * disc->blocksize; + } + else + { + rloc = mloc; + rlen = mlen; + } ext = next_extent(disc->head, ANCHOR); if (!ext) @@ -720,7 +743,7 @@ int setup_space(struct udf_disc *disc, struct udf_extent *pspace, uint32_t offse if (pspace->blocks%8) sbd->bitmap[nBytes-1] = 0xFF >> (8-(pspace->blocks%8)); clear_bits(sbd->bitmap, offset, (length + disc->blocksize - 1) / disc->blocksize); - sbd->descTag = udf_query_tag(disc, TAG_IDENT_SBD, 1, desc->offset, desc->data, sizeof(struct spaceBitmapDesc)); + sbd->descTag = udf_query_tag(disc, TAG_IDENT_SBD, 1, desc->offset, desc->data, 0, sizeof(struct spaceBitmapDesc)); } else if (disc->flags & FLAG_SPACE_TABLE) { @@ -776,7 +799,7 @@ int setup_space(struct udf_disc *disc, struct udf_extent *pspace, uint32_t offse use->icbTag.parentICBLocation.partitionReferenceNum = cpu_to_le16(0); use->icbTag.fileType = ICBTAG_FILE_TYPE_USE; use->icbTag.flags = cpu_to_le16(ICBTAG_FLAG_AD_SHORT); - use->descTag = udf_query_tag(disc, TAG_IDENT_USE, 1, desc->offset, desc->data, sizeof(struct unallocSpaceEntry) + le32_to_cpu(use->lengthAllocDescs)); + use->descTag = udf_query_tag(disc, TAG_IDENT_USE, 1, desc->offset, desc->data, 0, sizeof(struct unallocSpaceEntry) + le32_to_cpu(use->lengthAllocDescs)); if (disc->flags & FLAG_STRATEGY4096) { @@ -971,7 +994,7 @@ void setup_vds(struct udf_disc *disc) stable[0] = next_extent(disc->head, STABLE); sspace = next_extent(disc->head, SSPACE); - if (!mvds || !rvds || !lvid) + if (!mvds || (!rvds && disc->blocks > 257) || !lvid) { fprintf(stderr, "%s: Error: Not enough blocks on device\n", appname); exit(1); @@ -993,8 +1016,7 @@ void setup_vds(struct udf_disc *disc) setup_pd(disc, mvds, rvds, 2); setup_usd(disc, mvds, rvds, 3); setup_iuvd(disc, mvds, rvds, 4); - if (mvds->blocks > 5) - setup_td(disc, mvds, rvds, 5); + setup_td(disc, mvds, rvds, 5); } void setup_pvd(struct udf_disc *disc, struct udf_extent *mvds, struct udf_extent *rvds, uint32_t offset) @@ -1007,6 +1029,8 @@ void setup_pvd(struct udf_disc *disc, struct udf_extent *mvds, struct udf_extent desc->data->buffer = disc->udf_pvd[0]; disc->udf_pvd[0]->descTag = query_tag(disc, mvds, desc, 1); + if (!rvds) + return; desc = set_desc(rvds, TAG_IDENT_PVD, offset, length, NULL); memcpy(disc->udf_pvd[1] = desc->data->buffer, disc->udf_pvd[0], length); disc->udf_pvd[1]->descTag = query_tag(disc, rvds, desc, 1); @@ -1026,6 +1050,8 @@ void setup_lvd(struct udf_disc *disc, struct udf_extent *mvds, struct udf_extent desc->data->buffer = disc->udf_lvd[0]; disc->udf_lvd[0]->descTag = query_tag(disc, mvds, desc, 1); + if (!rvds) + return; desc = set_desc(rvds, TAG_IDENT_LVD, offset, length, NULL); memcpy(disc->udf_lvd[1] = desc->data->buffer, disc->udf_lvd[0], length); disc->udf_lvd[1]->descTag = query_tag(disc, rvds, desc, 1); @@ -1057,6 +1083,8 @@ void setup_pd(struct udf_disc *disc, struct udf_extent *mvds, struct udf_extent desc->data->buffer = disc->udf_pd[0]; disc->udf_pd[0]->descTag = query_tag(disc, mvds, desc, 1); + if (!rvds) + return; desc = set_desc(rvds, TAG_IDENT_PD, offset, length, NULL); memcpy(disc->udf_pd[1] = desc->data->buffer, disc->udf_pd[0], length); disc->udf_pd[1]->descTag = query_tag(disc, rvds, desc, 1); @@ -1086,6 +1114,8 @@ void setup_usd(struct udf_disc *disc, struct udf_extent *mvds, struct udf_extent desc->data->buffer = disc->udf_usd[0]; disc->udf_usd[0]->descTag = query_tag(disc, mvds, desc, 1); + if (!rvds) + return; desc = set_desc(rvds, TAG_IDENT_USD, offset, length, NULL); memcpy(disc->udf_usd[1] = desc->data->buffer, disc->udf_usd[0], length); disc->udf_usd[1]->descTag = query_tag(disc, rvds, desc, 1); @@ -1103,6 +1133,8 @@ void setup_iuvd(struct udf_disc *disc, struct udf_extent *mvds, struct udf_exten desc->data->buffer = disc->udf_iuvd[0]; disc->udf_iuvd[0]->descTag = query_tag(disc, mvds, desc, 1); + if (!rvds) + return; desc = set_desc(rvds, TAG_IDENT_IUVD, offset, length, NULL); memcpy(disc->udf_iuvd[1] = desc->data->buffer, disc->udf_iuvd[0], length); disc->udf_iuvd[1]->descTag = query_tag(disc, rvds, desc, 1); @@ -1118,6 +1150,8 @@ void setup_td(struct udf_disc *disc, struct udf_extent *mvds, struct udf_extent desc->data->buffer = disc->udf_td[0]; disc->udf_td[0]->descTag = query_tag(disc, mvds, desc, 1); + if (!rvds) + return; desc = set_desc(rvds, TAG_IDENT_TD, offset, length, NULL); memcpy(disc->udf_td[1] = desc->data->buffer, disc->udf_td[0], length); disc->udf_td[1]->descTag = query_tag(disc, rvds, desc, 1); @@ -1211,21 +1245,32 @@ void setup_stable(struct udf_disc *disc, struct udf_extent *stable[4], struct ud void setup_vat(struct udf_disc *disc, struct udf_extent *pspace) { - uint32_t offset = 0; + uint32_t offset; struct udf_extent *anchor; struct udf_desc *vtable; struct udf_data *data; - uint32_t len; + uint32_t len, i; struct virtualAllocationTable15 *vat15; struct virtualAllocationTable20 *vat20; + struct impUseExtAttr *ea_attr; + struct LVExtensionEA *ea_lv; + uint8_t buffer[(sizeof(*ea_attr)+sizeof(*ea_lv)+3)/4*4]; + uint16_t checksum; uint16_t udf_rev_le16; + uint32_t min_blocks; + uint32_t align; + + /* Put VAT to the last sector correctly aligned */ + align = disc->sizing[PSPACE_SIZE].align; + offset = pspace->tail->offset + (pspace->tail->length + disc->blocksize-1) / disc->blocksize; + offset = (offset + align) / align * align - 1; if (disc->flags & FLAG_MIN_300_BLOCKS) { - // On optical discs one track has minimal size of 300 sectors, so put VAT to the last sector - offset = pspace->tail->offset + (pspace->tail->length + disc->blocksize-1) / disc->blocksize; - if (pspace->start + offset < 299) - offset = 299 - pspace->start; + // On optical TAO discs one track has minimal size of 300 sectors + min_blocks = (300 + align) / align * align - 1; + if (pspace->start + offset < min_blocks) + offset = min_blocks - pspace->start; } if (disc->flags & FLAG_CLOSED) @@ -1260,12 +1305,41 @@ void setup_vat(struct udf_disc *disc, struct udf_extent *pspace) { vtable = udf_create(disc, pspace, (const dchars *)"\x08" UDF_ID_ALLOC, strlen(UDF_ID_ALLOC)+1, offset, NULL, FID_FILE_CHAR_HIDDEN, ICBTAG_FILE_TYPE_UNDEF, 0); disc->vat_entries--; // Remove VAT file itself from VAT table + udf_rev_le16 = cpu_to_le16(disc->udf_rev); + memset(&buffer, 0, sizeof(buffer)); + ea_attr = (struct impUseExtAttr *)buffer; + ea_attr->attrType = cpu_to_le32(EXTATTR_IMP_USE); + ea_attr->attrSubtype = EXTATTR_SUBTYPE; + ea_attr->attrLength = cpu_to_le32(sizeof(buffer)); + ea_attr->impUseLength = cpu_to_le32(sizeof(*ea_lv)); + ea_attr->impIdent.identSuffix[2] = UDF_OS_CLASS_UNIX; + ea_attr->impIdent.identSuffix[3] = UDF_OS_ID_LINUX; + memcpy(ea_attr->impIdent.identSuffix, &udf_rev_le16, sizeof(udf_rev_le16)); + strcpy((char *)ea_attr->impIdent.ident, UDF_ID_VAT_LVEXTENSION); + ea_lv = (struct LVExtensionEA *)&ea_attr->impUse[0]; + checksum = 0; + for (i = 0; i < sizeof(*ea_attr); ++i) + checksum += ((uint8_t *)ea_attr)[i]; + ea_lv->headerChecksum = cpu_to_le16(checksum); + if (disc->flags & FLAG_EFE) + { + struct extendedFileEntry *efe = (struct extendedFileEntry *)vtable->data->buffer; + ea_lv->verificationID = efe->uniqueID; + } + else + { + struct fileEntry *fe = (struct fileEntry *)vtable->data->buffer; + ea_lv->verificationID = fe->uniqueID; + } + ea_lv->numFiles = query_lvidiu(disc)->numFiles; + ea_lv->numDirs = query_lvidiu(disc)->numDirs; + memcpy(ea_lv->logicalVolIdent, disc->udf_lvd[0]->logicalVolIdent, 128); + insert_ea(disc, vtable, (struct genericFormat *)buffer, sizeof(buffer)); len = sizeof(struct virtualAllocationTable15); data = alloc_data(disc->vat, disc->vat_entries * sizeof(uint32_t)); insert_data(disc, pspace, vtable, data); data = alloc_data(&default_vat15, len); vat15 = data->buffer; - udf_rev_le16 = cpu_to_le16(disc->udf_rev); memcpy(vat15->vatIdent.identSuffix, &udf_rev_le16, sizeof(udf_rev_le16)); insert_data(disc, pspace, vtable, data); } diff --git a/mkudffs/mkudffs.h b/mkudffs/mkudffs.h index 510c8e0..b9adad3 100644 --- a/mkudffs/mkudffs.h +++ b/mkudffs/mkudffs.h @@ -1,8 +1,8 @@ /* * mkudffs.h * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> - * Copyright (c) 2016-2017 Pali Rohár <pali.rohar@gmail.com> + * Copyright (c) 2001-2002 Ben Fennema + * Copyright (c) 2016-2018 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,6 @@ #include "ecma_167.h" #include "osta_udf.h" -#include "udf_endian.h" #include "libudffs.h" #define CS0 0x00000001 @@ -62,8 +61,7 @@ enum media_type { extern char *udf_space_type_str[UDF_SPACE_TYPE_SIZE]; void udf_init_disc(struct udf_disc *); -int udf_set_version(struct udf_disc *, int); -void get_random_bytes(void *, size_t); +int udf_set_version(struct udf_disc *, uint16_t); void split_space(struct udf_disc *); void dump_space(struct udf_disc *); int write_disc(struct udf_disc *); diff --git a/mkudffs/options.c b/mkudffs/options.c index 67a71db..75be672 100644 --- a/mkudffs/options.c +++ b/mkudffs/options.c @@ -1,8 +1,8 @@ /* * options.c * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> - * Copyright (c) 2014-2017 Pali Rohár <pali.rohar@gmail.com> + * Copyright (c) 2001-2002 Ben Fennema + * Copyright (c) 2014-2018 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -30,6 +30,7 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <getopt.h> #include <ctype.h> #include <errno.h> @@ -85,7 +86,7 @@ void usage(void) "\t--uuid=, -u UDF uuid, first 16 characters of Volume set identifier (default: random)\n" "\t--blocksize=, -b Size of blocks in bytes (512, 1024, 2048, 4096, 8192, 16384, 32768; default: detect)\n" "\t--media-type=, -m Media type (hd, dvd, dvdram, dvdrw, dvdr, worm, mo, cdrw, cdr, cd, bdr; default: hd)\n" - "\t--udfrev=, -r UDF revision (1.02, 1.50, 2.00, 2.01, 2.50, 2.60; default: 2.01)\n" + "\t--udfrev=, -r UDF revision (1.01, 1.02, 1.50, 2.00, 2.01, 2.50, 2.60; default: 2.01)\n" "\t--no-write, -n Not really, do not write to device, just simulate\n" "\t--new-file Create new image file, fail if already exists\n" "\t--lvid= Logical Volume Identifier (default: LinuxUDF)\n" @@ -100,7 +101,7 @@ void usage(void) "\t--strategy= Allocation strategy to use (4, 4096; default: based on media type)\n" "\t--spartable Use Sparing Table (default: based on media type) and set its count (1 - 4; default: 2)\n" "\t--sparspace= Number of entries in Sparing Table (default: 1024, but based on media type)\n" - "\t--packetlen= Packet length in number of blocks for Sparing Table (default: based on media type)\n" + "\t--packetlen= Packet length in number of blocks used for alignment (default: based on media type)\n" "\t--vat Use Virtual Allocation Table (default: based on media type)\n" "\t--closed Close disc with Virtual Allocation Table (default: do not close)\n" "\t--space= Space (freedbitmap, freedtable, unallocbitmap, unalloctable; default: unallocbitmap)\n" @@ -114,26 +115,16 @@ void usage(void) exit(1); } -static unsigned long int strtoul_safe(const char *str, int base, int *failed) -{ - char *endptr = NULL; - unsigned long int ret; - errno = 0; - ret = strtoul(str, &endptr, base); - *failed = (!*str || *endptr || errno) ? 1 : 0; - return ret; -} - void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, int *create_new_file, int *blocksize, int *media_ptr) { int retval; int i; int media = MEDIA_TYPE_NONE; - uint16_t packetlen = 0; - unsigned long int blocks = 0; - int rev = 0; int use_sparable = 0; - unsigned long int sparspace = 0; + uint16_t rev = 0; + uint32_t spartable = 2; + uint32_t sparspace = 0; + uint16_t packetlen = 0; int failed; while ((retval = getopt_long(argc, argv, "l:u:b:m:r:nh", long_options, NULL)) != EOF) @@ -146,7 +137,7 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in break; case OPT_BLK_SIZE: case 'b': - disc->blocksize = strtoul_safe(optarg, 0, &failed); + disc->blocksize = strtou32(optarg, 0, &failed); if (failed || disc->blocksize < 512 || disc->blocksize > 32768 || (disc->blocksize & (disc->blocksize - 1))) { fprintf(stderr, "%s: Error: Invalid value for option --blocksize\n", appname); @@ -161,16 +152,14 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in unsigned char maj = 0; unsigned char min = 0; int len = 0; - if (sscanf(optarg, "%hhx.%hhx%n", &maj, &min, &len) >= 2 && !optarg[len]) + if (sscanf(optarg, "%*[0-9].%*[0-9]%n", &len) >= 0 && !optarg[len] && sscanf(optarg, "%hhx.%hhx%n", &maj, &min, &len) >= 2 && !optarg[len]) { rev = (maj << 8) | min; } else { - unsigned long int rev_opt = strtoul_safe(optarg, 16, &failed); - if (!failed && rev_opt < INT_MAX) - rev = rev_opt; - else + rev = strtou16(optarg, 16, &failed); + if (failed) rev = 0; } if (!rev || udf_set_version(disc, rev)) @@ -418,40 +407,42 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in } case OPT_UID: { - unsigned long int uid = strtoul_safe(optarg, 0, &failed); if (strcmp(optarg, "-1") == 0) { - uid = UINT32_MAX; - failed = 0; + disc->uid = UINT32_MAX; } - if (failed || uid > UINT32_MAX) + else { - fprintf(stderr, "%s: Error: Invalid value for option --uid\n", appname); - exit(1); + disc->uid = strtou32(optarg, 0, &failed); + if (failed) + { + fprintf(stderr, "%s: Error: Invalid value for option --uid\n", appname); + exit(1); + } } - disc->uid = uid; break; } case OPT_GID: { - unsigned long int gid = strtoul_safe(optarg, 0, &failed); if (strcmp(optarg, "-1") == 0) { - gid = UINT32_MAX; - failed = 0; + disc->gid = UINT32_MAX; } - if (failed || gid > UINT32_MAX) + else { - fprintf(stderr, "%s: Error: Invalid value for option --gid\n", appname); - exit(1); + disc->gid = strtou32(optarg, 0, &failed); + if (failed) + { + fprintf(stderr, "%s: Error: Invalid value for option --gid\n", appname); + exit(1); + } } - disc->gid = gid; break; } case OPT_MODE: { - unsigned long int mode = strtoul_safe(optarg, 8, &failed); - if (failed || mode > UINT16_MAX || (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO))) + uint16_t mode = strtou16(optarg, 8, &failed); + if (failed || (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO))) { fprintf(stderr, "%s: Error: Invalid value for option --mode\n", appname); exit(1); @@ -477,25 +468,23 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in } case OPT_STRATEGY: { - unsigned long int strategy = strtoul_safe(optarg, 0, &failed); - if (failed || (strategy != 4 && strategy != 4096)) + if (strcmp(optarg, "4096") == 0) + disc->flags |= FLAG_STRATEGY4096; + else if (strcmp(optarg, "4") == 0) + disc->flags &= ~FLAG_STRATEGY4096; + else { fprintf(stderr, "%s: Error: Invalid value for option --strategy\n", appname); exit(1); } - if (strategy == 4096) - disc->flags |= FLAG_STRATEGY4096; - else - disc->flags &= ~FLAG_STRATEGY4096; break; } case OPT_SPARTABLE: { - unsigned long int spartable = 2; if (optarg) { - spartable = strtoul_safe(optarg, 0, &failed); - if (failed || spartable > 4) + spartable = strtou32(optarg, 0, &failed); + if (failed || spartable == 0 || spartable > 4) { fprintf(stderr, "%s: Error: Invalid value for option --spartable\n", appname); exit(1); @@ -506,7 +495,6 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in fprintf(stderr, "%s: Error: Cannot use Sparing Table when VAT is enabled\n", appname); exit(1); } - add_type2_sparable_partition(disc, 0, spartable, packetlen); use_sparable = 1; break; } @@ -517,8 +505,8 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in fprintf(stderr, "%s: Error: Option --spartable must be specified before option --sparspace\n", appname); exit(1); } - sparspace = strtoul_safe(optarg, 0, &failed); - if (failed || sparspace > UINT32_MAX) + sparspace = strtou32(optarg, 0, &failed); + if (failed) { fprintf(stderr, "%s: Error: Invalid value for option --sparspace\n", appname); exit(1); @@ -527,21 +515,22 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in } case OPT_PACKETLEN: { - struct sparablePartitionMap *spm; - unsigned long int packetlen_opt = strtoul_safe(optarg, 0, &failed); - if (failed || packetlen_opt > UINT16_MAX) + packetlen = strtou16(optarg, 0, &failed); + if (failed || packetlen == 0) { fprintf(stderr, "%s: Error: Invalid value for option --packetlen\n", appname); exit(1); } - packetlen = packetlen_opt; - if ((spm = find_type2_sparable_partition(disc, 0))) - spm->packetLength = cpu_to_le16(packetlen); break; } case OPT_MEDIA_TYPE: case 'm': { + if (media != MEDIA_TYPE_NONE) + { + fprintf(stderr, "%s: Error: Option --media-type was specified more times\n", appname); + exit(1); + } if (rev) { fprintf(stderr, "%s: Error: Option --media-type must be specified before option --udfrev\n", appname); @@ -552,60 +541,59 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in fprintf(stderr, "%s: Error: Option --media-type must be specified before option --packetlen\n", appname); exit(1); } - if (media != MEDIA_TYPE_NONE) - { - fprintf(stderr, "%s: Error: Option --media-type was specified more times\n", appname); - exit(1); - } if (!strcmp(optarg, "hd")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE); media = MEDIA_TYPE_HD; + packetlen = 1; } else if (!strcmp(optarg, "dvd")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY); media = MEDIA_TYPE_DVD; + packetlen = 16; } else if (!strcmp(optarg, "dvdram")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE); media = MEDIA_TYPE_DVDRAM; + packetlen = 16; } else if (!strcmp(optarg, "dvdrw")) { - struct sparablePartitionMap *spm; disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE); media = MEDIA_TYPE_DVDRW; use_sparable = 1; packetlen = 16; - if ((spm = find_type2_sparable_partition(disc, 0))) - spm->packetLength = cpu_to_le16(packetlen); } else if (!strcmp(optarg, "dvdr")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE); media = MEDIA_TYPE_DVDR; - disc->flags |= FLAG_VAT | FLAG_MIN_300_BLOCKS; + disc->flags |= FLAG_VAT; disc->flags &= ~FLAG_CLOSED; + packetlen = 16; } else if (!strcmp(optarg, "worm")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE); media = MEDIA_TYPE_WORM; disc->flags |= (FLAG_STRATEGY4096 | FLAG_BLANK_TERMINAL); + packetlen = 1; } else if (!strcmp(optarg, "mo")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE); media = MEDIA_TYPE_MO; disc->flags |= (FLAG_STRATEGY4096 | FLAG_BLANK_TERMINAL); + packetlen = 1; } else if (!strcmp(optarg, "cdrw")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE); media = MEDIA_TYPE_CDRW; use_sparable = 1; + packetlen = 32; } else if (!strcmp(optarg, "cdr")) { @@ -613,19 +601,22 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in media = MEDIA_TYPE_CDR; disc->flags |= FLAG_VAT | FLAG_MIN_300_BLOCKS; disc->flags &= ~FLAG_CLOSED; + packetlen = 32; } else if (!strcmp(optarg, "cd")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY); media = MEDIA_TYPE_CD; + packetlen = 32; } else if (!strcmp(optarg, "bdr")) { disc->udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE); media = MEDIA_TYPE_BDR; - disc->flags |= FLAG_VAT | FLAG_MIN_300_BLOCKS; + disc->flags |= FLAG_VAT; disc->flags &= ~FLAG_CLOSED; udf_set_version(disc, 0x0250); + packetlen = 32; } else { @@ -685,46 +676,45 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in optind ++; if (optind < argc) { - blocks = strtoul_safe(argv[optind++], 0, &failed); - if (failed || blocks > UINT32_MAX) + disc->blocks = strtou32(argv[optind++], 0, &failed); + if (failed) { fprintf(stderr, "%s: Error: Invalid value for block-count\n", appname); exit(1); } - disc->blocks = blocks; } if (optind < argc) usage(); - if (packetlen && !use_sparable) + /* TODO: autodetection */ + if (media == MEDIA_TYPE_NONE) { - fprintf(stderr, "%s: Error: Option --packetlen cannot be used without Sparing Table\n", appname); - exit(1); + media = MEDIA_TYPE_HD; + packetlen = 1; } - if (le32_to_cpu(disc->udf_lvd[0]->numPartitionMaps) == 0) + if (disc->flags & FLAG_VAT) { - if (disc->flags & FLAG_VAT) + if (disc->udf_rev < 0x0150) { - if (disc->udf_rev < 0x0150) - { - fprintf(stderr, "%s: Error: At least UDF revision 1.50 is needed for VAT\n", appname); - exit(1); - } - add_type1_partition(disc, 0); - add_type2_virtual_partition(disc, 0); + fprintf(stderr, "%s: Error: At least UDF revision 1.50 is needed for VAT\n", appname); + exit(1); } - else if (use_sparable) + add_type1_partition(disc, 0); + add_type2_virtual_partition(disc, 0); + } + else if (use_sparable) + { + if (disc->udf_rev < 0x0150) { - if (disc->udf_rev < 0x0150) - { - fprintf(stderr, "%s: Error: At least UDF revision 1.50 is needed for Sparing Table\n", appname); - exit(1); - } - add_type2_sparable_partition(disc, 0, 2, packetlen); + fprintf(stderr, "%s: Error: At least UDF revision 1.50 is needed for Sparing Table\n", appname); + exit(1); } - else - add_type1_partition(disc, 0); + add_type2_sparable_partition(disc, 0, spartable, packetlen); + } + else + { + add_type1_partition(disc, 0); } /* TODO: UDF 2.50+ require for non-VAT disks Metadata partition which mkudffs cannot create yet */ @@ -749,12 +739,9 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in exit(1); } - /* TODO: autodetection */ - if (media == MEDIA_TYPE_NONE) - media = MEDIA_TYPE_HD; - for (i=0; i<UDF_ALLOC_TYPE_SIZE; i++) { + disc->sizing[i].align = packetlen; if (disc->sizing[i].denomSize == 0) disc->sizing[i] = default_sizing[default_media[media]][i]; } @@ -766,11 +753,6 @@ void parse_args(int argc, char *argv[], struct udf_disc *disc, char **device, in disc->sizing[SSPACE_SIZE].minSize = sparspace; disc->sizing[STABLE_SIZE].minSize = 0; // recalculation is implemented in split_space() } - if (!packetlen) - packetlen = le16_to_cpu(default_sparmap.packetLength); - disc->sizing[PSPACE_SIZE].align = packetlen; - disc->sizing[SSPACE_SIZE].align = packetlen; - disc->sizing[STABLE_SIZE].align = packetlen; if (disc->sizing[SSPACE_SIZE].minSize == 0) disc->sizing[SSPACE_SIZE].minSize = 1024; } diff --git a/mkudffs/options.h b/mkudffs/options.h index 883f5be..a40f1e6 100644 --- a/mkudffs/options.h +++ b/mkudffs/options.h @@ -1,7 +1,7 @@ /* * options.h * - * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> + * Copyright (c) 2001-2002 Ben Fennema * Copyright (c) 2014-2017 Pali Rohár <pali.rohar@gmail.com> * All rights reserved. * |