├── .travis.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── Doxyfile ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── autogen.sh ├── cdrwtool ├── Makefile.am ├── cdrwtool.c ├── cdrwtool.h ├── main.c ├── options.c └── options.h ├── configure.ac ├── doc ├── HOWTO.udf ├── Makefile.am ├── UDF-Specifications ├── cdrwtool.1 ├── mkfs.udf.8 ├── mkudffs.8 ├── pktsetup.8 ├── udfinfo.1 ├── udflabel.8 └── wrudf.1 ├── include ├── bswap.h ├── ecma_167.h ├── libudffs.h └── osta_udf.h ├── libudffs ├── Makefile.am ├── crc.c ├── extent.c ├── misc.c └── unicode.c ├── mkudffs ├── Makefile.am ├── defaults.c ├── defaults.h ├── file.c ├── file.h ├── main.c ├── mkudffs.c ├── mkudffs.h ├── options.c └── options.h ├── pktsetup ├── Makefile.am ├── pktcdvd-check.c ├── pktsetup.c └── pktsetup.rules ├── udffsck ├── Makefile.am └── main.c ├── udfinfo ├── Makefile.am ├── main.c ├── options.c ├── options.h ├── readdisc.c └── readdisc.h ├── udflabel ├── Makefile.am ├── main.c ├── options.c └── options.h └── wrudf ├── Makefile.am ├── ide-pc.c ├── ide-pc.h ├── wrudf-cdr.c ├── wrudf-cdrw.c ├── wrudf-cmnd.c ├── wrudf-desc.c ├── wrudf.c └── wrudf.h /AUTHORS: -------------------------------------------------------------------------------- 1 | libudffs 2 | Ben Fennema 3 | Pali Rohár 4 | 5 | mkudffs 6 | Ben Fennema 7 | Pali Rohár 8 | Steve Kenton 9 | 10 | udfinfo 11 | Pali Rohár 12 | 13 | udflabel 14 | Pali Rohár 15 | 16 | cdrwtool 17 | Jens Axboe 18 | Ben Fennema 19 | 20 | pktsetup 21 | Jens Axboe 22 | Pali Rohár 23 | 24 | wrudf 25 | Enno Fennema 26 | Pali Rohár 27 | 28 | doc 29 | Paul Thompson 30 | Ben Fennema 31 | Pali Rohár 32 | Steve Kenton 33 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | See git log 2 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Basic Installation 2 | ================== 3 | 4 | These are generic installation instructions. 5 | 6 | The `configure' shell script attempts to guess correct values for 7 | various system-dependent variables used during compilation. It uses 8 | those values to create a `Makefile' in each directory of the package. 9 | It may also create one or more `.h' files containing system-dependent 10 | definitions. Finally, it creates a shell script `config.status' that 11 | you can run in the future to recreate the current configuration, a file 12 | `config.cache' that saves the results of its tests to speed up 13 | reconfiguring, and a file `config.log' containing compiler output 14 | (useful mainly for debugging `configure'). 15 | 16 | If you need to do unusual things to compile the package, please try 17 | to figure out how `configure' could check whether to do them, and mail 18 | diffs or instructions to the address given in the `README' so they can 19 | be considered for the next release. If at some point `config.cache' 20 | contains results you don't want to keep, you may remove or edit it. 21 | 22 | The file `configure.in' is used to create `configure' by a program 23 | called `autoconf'. You only need `configure.in' if you want to change 24 | it or regenerate `configure' using a newer version of `autoconf'. 25 | 26 | The simplest way to compile this package is: 27 | 28 | 1. `cd' to the directory containing the package's source code and type 29 | `./configure' to configure the package for your system. If you're 30 | using `csh' on an old version of System V, you might need to type 31 | `sh ./configure' instead to prevent `csh' from trying to execute 32 | `configure' itself. 33 | 34 | Running `configure' takes awhile. While running, it prints some 35 | messages telling which features it is checking for. 36 | 37 | 2. Type `make' to compile the package. 38 | 39 | 3. Optionally, type `make check' to run any self-tests that come with 40 | the package. 41 | 42 | 4. Type `make install' to install the programs and any data files and 43 | documentation. 44 | 45 | 5. You can remove the program binaries and object files from the 46 | source code directory by typing `make clean'. To also remove the 47 | files that `configure' created (so you can compile the package for 48 | a different kind of computer), type `make distclean'. There is 49 | also a `make maintainer-clean' target, but that is intended mainly 50 | for the package's developers. If you use it, you may have to get 51 | all sorts of other programs in order to regenerate files that came 52 | with the distribution. 53 | 54 | Compilers and Options 55 | ===================== 56 | 57 | Some systems require unusual options for compilation or linking that 58 | the `configure' script does not know about. You can give `configure' 59 | initial values for variables by setting them in the environment. Using 60 | a Bourne-compatible shell, you can do that on the command line like 61 | this: 62 | CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure 63 | 64 | Or on systems that have the `env' program, you can do it like this: 65 | env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure 66 | 67 | Compiling For Multiple Architectures 68 | ==================================== 69 | 70 | You can compile the package for more than one kind of computer at the 71 | same time, by placing the object files for each architecture in their 72 | own directory. To do this, you must use a version of `make' that 73 | supports the `VPATH' variable, such as GNU `make'. `cd' to the 74 | directory where you want the object files and executables to go and run 75 | the `configure' script. `configure' automatically checks for the 76 | source code in the directory that `configure' is in and in `..'. 77 | 78 | If you have to use a `make' that does not supports the `VPATH' 79 | variable, you have to compile the package for one architecture at a time 80 | in the source code directory. After you have installed the package for 81 | one architecture, use `make distclean' before reconfiguring for another 82 | architecture. 83 | 84 | Installation Names 85 | ================== 86 | 87 | By default, `make install' will install the package's files in 88 | `/usr/local/bin', `/usr/local/man', etc. You can specify an 89 | installation prefix other than `/usr/local' by giving `configure' the 90 | option `--prefix=PATH'. 91 | 92 | You can specify separate installation prefixes for 93 | architecture-specific files and architecture-independent files. If you 94 | give `configure' the option `--exec-prefix=PATH', the package will use 95 | PATH as the prefix for installing programs and libraries. 96 | Documentation and other data files will still use the regular prefix. 97 | 98 | In addition, if you use an unusual directory layout you can give 99 | options like `--bindir=PATH' to specify different values for particular 100 | kinds of files. Run `configure --help' for a list of the directories 101 | you can set and what kinds of files go in them. 102 | 103 | If the package supports it, you can cause programs to be installed 104 | with an extra prefix or suffix on their names by giving `configure' the 105 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 106 | 107 | Optional Features 108 | ================= 109 | 110 | Some packages pay attention to `--enable-FEATURE' options to 111 | `configure', where FEATURE indicates an optional part of the package. 112 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 113 | is something like `gnu-as' or `x' (for the X Window System). The 114 | `README' should mention any `--enable-' and `--with-' options that the 115 | package recognizes. 116 | 117 | For packages that use the X Window System, `configure' can usually 118 | find the X include and library files automatically, but if it doesn't, 119 | you can use the `configure' options `--x-includes=DIR' and 120 | `--x-libraries=DIR' to specify their locations. 121 | 122 | Specifying the System Type 123 | ========================== 124 | 125 | There may be some features `configure' can not figure out 126 | automatically, but needs to determine by the type of host the package 127 | will run on. Usually `configure' can figure that out, but if it prints 128 | a message saying it can not guess the host type, give it the 129 | `--host=TYPE' option. TYPE can either be a short name for the system 130 | type, such as `sun4', or a canonical name with three fields: 131 | CPU-COMPANY-SYSTEM 132 | 133 | See the file `config.sub' for the possible values of each field. If 134 | `config.sub' isn't included in this package, then this package doesn't 135 | need to know the host type. 136 | 137 | If you are building compiler tools for cross-compiling, you can also 138 | use the `--target=TYPE' option to select the type of system they will 139 | produce code for and the `--build=TYPE' option to select the type of 140 | system on which you are compiling the package. 141 | 142 | Sharing Defaults 143 | ================ 144 | 145 | If you want to set default values for `configure' scripts to share, 146 | you can create a site shell script called `config.site' that gives 147 | default values for variables like `CC', `cache_file', and `prefix'. 148 | `configure' looks for `PREFIX/share/config.site' if it exists, then 149 | `PREFIX/etc/config.site' if it exists. Or, you can set the 150 | `CONFIG_SITE' environment variable to the location of the site script. 151 | A warning: not all `configure' scripts look for a site script. 152 | 153 | Operation Controls 154 | ================== 155 | 156 | `configure' recognizes the following options to control how it 157 | operates. 158 | 159 | `--cache-file=FILE' 160 | Use and save the results of the tests in FILE instead of 161 | `./config.cache'. Set FILE to `/dev/null' to disable caching, for 162 | debugging `configure'. 163 | 164 | `--help' 165 | Print a summary of the options to `configure', and exit. 166 | 167 | `--quiet' 168 | `--silent' 169 | `-q' 170 | Do not print messages saying which checks are being made. To 171 | suppress all normal output, redirect it to `/dev/null' (any error 172 | messages will still be shown). 173 | 174 | `--srcdir=DIR' 175 | Look for the package's source code in directory DIR. Usually 176 | `configure' can determine that directory automatically. 177 | 178 | `--version' 179 | Print the version of Autoconf used to generate the `configure' 180 | script, and exit. 181 | 182 | `configure' also accepts some other, not widely useful, options. 183 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = libudffs mkudffs cdrwtool pktsetup udffsck udfinfo udflabel wrudf doc 2 | dist_doc_DATA = AUTHORS COPYING NEWS README 3 | EXTRA_DIST = autogen.sh Doxyfile 4 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Changes in 2.3 2 | * mkudffs: 3 | * Added support for creating Multisession UDF disc images via new --startblock option 4 | * Added new options for specifying owner, organization and contact information 5 | * Added new option --bootarea=mbr:sec-size to allow specifying MBR sector size 6 | * Added udftools version string into Application Identifier 7 | * Fixed default value of Packet Length in Sparable Partition for UDF 1.50 and 2.00 rev to 32 blocks 8 | * Fixed detecting all 33 types of optical discs defined in all versions of SCSI MMC specifications 9 | * Fixed filling CHS sector number into MBR partition table 10 | * Fixed alignment of VAT block for CD-R, DVD-R and BD-R disc 11 | * Fixed alignment for CD-R discs 12 | * Fixed generating unclosed CD-R image with blocks more than 3072 13 | * udfinfo & udflabel: 14 | * Added support for Multisession UDF optical discs via new --startblock and --lastblock options 15 | * Added support for showing and changing owner, organization, contact, appid and impid UDF identifiers 16 | * Added more checks to validation of UDF structures 17 | * Throw error when trying to modify UDF disc with unsupported Pseudo OverWrite partition 18 | * pktsetup: 19 | * Added new option -i to ignore errors when device is already mapped or unmapped 20 | * Added new tool pktcdvd-check which checks if optical disc can be used by kernel pktcdvd.ko driver for write operations 21 | * Update udev rule to map only optical discs which are supported for write operation (check done by pktcdvd-check tool) 22 | * cdrwtool: 23 | * Fixed formatting of CD-RW disc in modern optical drives according to MMC-6 standard (via Format Code 1) 24 | * Fixed support for progress bar 25 | 26 | Changes in 2.2 27 | * Allow to build udftools without udev 28 | * Use standard ISO C99 features instead of GCC extensions 29 | * Detect optional readline dependency via pkg-config when possible 30 | * Added support for UTF-16 surrogate pairs 31 | * udfinfo & udflabel: 32 | * Added support for UDF 2.50 and UDF 2.60 revisions 33 | * Fixed calculating free space blocks 34 | * In read-only mode throw warning when device is busy 35 | * Do not fail on disks with too many Sparing Tables 36 | * Show and respect UDF write protect flags 37 | * mkudffs: 38 | * Fixed accessing invalid memory on disks with small number of sectors 39 | * Added new option --read-only which sets UDF disk to read-only mode 40 | * Adjust partition size to work around Windows chkdsk bug 41 | * Autodetect media type 42 | 43 | Changes in 2.1 44 | * Fixed compilation with glibc >= 2.25 45 | * Allow to compile without libreadline 46 | * Use pkgconfig for detection of udev rules directory 47 | * Set minimal version of autoconf to 2.64 48 | * Enforce ISO C99 compiler 49 | * Fixed support for big endian systems 50 | * Fixed converting strings to integers 51 | * Added support for UDF 1.50 Logical Volume Extended Information (contains volume label) 52 | * Added support for UDF 1.01 revision 53 | * Added workaround for Year 2038 Bug 54 | * udfinfo & udflabel: 55 | * Fixed accessing disks when MVDS and RVDS descriptors points to same location 56 | * Fixed support for disks >= 4GB on 32bit systems 57 | * Implemented reading VAT outside of outside of ICB 58 | * Various fixes for reading UDF descriptors 59 | * mkudffs: 60 | * Space optimization for small disks 61 | * Allow to set alignment of UDF structures via --packetlen option for any media type 62 | * Fixed alignment of VAT and generation of DVD-R and BD-R discs 63 | * cdrwtool: 64 | * Disallow specifying unsupported UDF revisions 65 | 66 | Changes in 2.0 67 | * For UDF uuid is used same algorithm as in util-linux v2.30 68 | * Fixed Unicode encode/decode functions to correctly process OSTA Unicode d-string and d-characters 69 | * Corrections and updates in man pages, mkudffs now contains lot of compatibility information 70 | * New tool udfinfo which shows various information about UDF (incuding label, uuid, free space) 71 | * New tool udflabel which shows or changes UDF label or UDF uuid 72 | * cdrwtool: 73 | * Set default UDF revision to 1.50 74 | * pktsetup: 75 | * Make dev_name argument for setup optional 76 | * Allow to setup and remove optical device by major:minor numbers 77 | * Include udev rule file for automatic managing of packet writing devices 78 | * mkudffs: 79 | * Fixed support for VAT and CD-R disks 80 | * Fixed crashes and infinite loops on disks with small number of sectors 81 | * Allow 128 (resp. 63) characters in --label option 82 | * Allow to enable VAT via new --vat option for any disk type 83 | * Allow to enable Sparing Table via --spartable option also for any disk type 84 | * Allow to specify number of entries in Sparing Table via new --sparspace option 85 | * Added support for UDF revision 2.50 and 2.60 for disc with VAT (e.g. Blu-Ray Disc Recordable) 86 | * Added support for CD-ROM, DVD-R and BD-R discs 87 | * Added new option --new-file for enforcing to create a new image file 88 | * Added new option --mode for specifying permissions of root directory 89 | * Added new option --bootarea=preserve|erase|mbr to specify what to do with first 32kB of disk 90 | --bootarea=mbr put MBR with one partition which starts at sector 0 and spans whole disk device (compatibility for MS Windows) 91 | * Added new option --locale for specifying that command line arguments are encoded according to current locale and make it default 92 | * Added support for disks which have logical sector size 8192, 16384 or 32768 bytes 93 | * For hard disk set fallback block size to 512 bytes (default is still logical sector size of block device) 94 | * Check that block device is not mounted before format process starts 95 | * Optimize splitting disk space to maximize available free space for data 96 | 97 | Changes in 1.3 98 | * Fixed Large File Support 99 | * Fixed pktsetup to work 100 | * Fixed wrudf to work with CD-RW disk images 101 | * Fixed memory leaks & buffer overflows 102 | * Print error message when mkudffs fails 103 | 104 | Changes in 1.2 105 | * Manpage redirect for mkfs.udf(8) 106 | * Manpage fix for pktsetup(8) 107 | * Fixed compile and install procedure 108 | * Fixed parsing cdrwtool --file parameter 109 | 110 | Changes in 1.1 111 | * Included various patches from Linux distributions (mostly bug fixes and documentation updates) 112 | * Lots of fixes for compilation, crashes, buffer overflows, memory corruptions, reading from uninitialized memory, etc ... 113 | * Fixed UTF-8 support 114 | * Fixed detection of device blocksize 115 | * Corrections and updates in man pages 116 | * mkudffs: 117 | * Set first 16 chars of Volume Set Identifier to timestamp and random value 118 | * Set default block-size to device logical block (sector) size 119 | * Add support for label and uuid options 120 | * Add support for setting uid and gid of the root directory 121 | * Fixed support for UDF 1.02 122 | * Symlink to mkfs.udf 123 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Linux tools for UDF filesystems and DVD/CD-R(W) drives 2 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | find . \( -name autom4te.cache -o -name libtool \) -exec rm -r {} \; 3 | aclocal 4 | libtoolize --force --copy 5 | autoheader 6 | automake --add-missing --copy 7 | autoconf 8 | -------------------------------------------------------------------------------- /cdrwtool/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = cdrwtool 2 | cdrwtool_LDADD = $(top_builddir)/libudffs/libudffs.la 3 | cdrwtool_SOURCES = main.c options.c cdrwtool.c ../mkudffs/mkudffs.c ../mkudffs/defaults.c ../mkudffs/file.c options.h cdrwtool.h ../include/ecma_167.h ../include/osta_udf.h ../mkudffs/mkudffs.h ../mkudffs/defaults.h ../mkudffs/file.h ../include/libudffs.h 4 | 5 | AM_CPPFLAGS = -I$(top_srcdir)/include 6 | -------------------------------------------------------------------------------- /cdrwtool/cdrwtool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Perform all sort of actions on a CD-R, CD-RW, and DVD-R drive. 3 | * 4 | * Copyright Jens Axboe, 1999, 2000 5 | * 6 | * Released under the GPL licences. 7 | * 8 | */ 9 | 10 | #ifndef _CDRWTOOL_H 11 | #define _CDRWTOOL_H 1 12 | 13 | #include 14 | #include 15 | #include "../include/libudffs.h" 16 | 17 | /* 18 | * define this to be the default cdrom device 19 | */ 20 | #define CDROM_DEVICE "/dev/scd1" 21 | 22 | #ifndef HZ 23 | #define HZ sysconf(_SC_CLK_TCK) 24 | #endif 25 | 26 | /* 27 | * adjust these values if commands are timing out before completion 28 | */ 29 | #define WAIT_PC (5 * HZ) 30 | #define WAIT_SYNC (25 * HZ) 31 | #define WAIT_BLANK (60 * 60 * HZ) 32 | 33 | /* 34 | * define this to 0 to make format and blank block until the entire 35 | * operation has succeeded. otherwise control is returned as soon as 36 | * the drive has verified the command -- this can be used for polling 37 | * the device for completion. 38 | */ 39 | #define USE_IMMED 1 40 | /* 41 | * With FORMAT UNIT Format Code 1 on 12x CD-RW, LG BD-RE BH16NS40 gets stuck 42 | * if not the Immed bit is set. So even when setting USE_IMMED to 0, better 43 | * let this macro stay 1, in order to prevent such a mishap. 44 | */ 45 | #define USE_IMMED_WITH_FORMAT_1 1 46 | 47 | #define PAGE_CURRENT 0 48 | #define PAGE_CHANGE 1 49 | #define PAGE_DEFAULT 2 50 | #define PAGE_SAVE 3 51 | 52 | #define BLANK_FULL 1 53 | #define BLANK_FAST 2 54 | 55 | #define WRITE_MODE1 1 56 | #define WRITE_MODE2 2 /* mode2, form 1 */ 57 | 58 | #define CDROM_BLOCK 2048 59 | #define PACKET_BLOCK 32 60 | #define PACKET_SIZE CDROM_BLOCK*PACKET_BLOCK 61 | 62 | #define DEFAULT_SPEED 12 63 | 64 | typedef struct 65 | { 66 | unsigned char ls_v; /* link_size valid */ 67 | unsigned char border; /* or session */ 68 | unsigned char fpacket; /* fixed, variable */ 69 | unsigned char track_mode; /* control nibbler, sub q */ 70 | unsigned char data_block; /* write type */ 71 | unsigned char link_size; /* links loss size */ 72 | unsigned char session_format; /* session closure settings */ 73 | unsigned long packet_size; /* fixed packet size */ 74 | } write_params_t; 75 | 76 | struct cdrw_disc 77 | { 78 | const char * filename; /* file to write */ 79 | unsigned long offset; /* write file / format */ 80 | unsigned char get_settings; /* just print settings */ 81 | unsigned char set_settings; /* save settings */ 82 | unsigned char blank; /* blank cdrw disc */ 83 | unsigned char fpacket; /* fixed/variable packets */ 84 | unsigned char packet_size; /* fixed packet size */ 85 | unsigned char link_size; /* link loss size */ 86 | unsigned char write_type; /* mode1 or mode2 */ 87 | unsigned char disc_track_info; /* list disc/track info */ 88 | unsigned char format; /* format disc */ 89 | unsigned char border; /* border/session */ 90 | unsigned char speed; /* writing speed */ 91 | unsigned int buffer; /* buffer size */ 92 | unsigned int reserve_track; /* reserve a track */ 93 | unsigned char quick_setup; 94 | unsigned char mkudf; 95 | unsigned int close_track; 96 | unsigned int close_session; 97 | struct udf_disc udf_disc; 98 | }; 99 | 100 | typedef struct disc_info { 101 | uint16_t length; 102 | #ifdef WORDS_BIGENDIAN 103 | unsigned char reserved1 : 3; 104 | unsigned char erasable : 1; 105 | unsigned char border : 2; 106 | unsigned char status : 2; 107 | #else 108 | unsigned char status : 2; 109 | unsigned char border : 2; 110 | unsigned char erasable : 1; 111 | unsigned char reserved1 : 3; 112 | #endif 113 | uint8_t n_first_track; 114 | uint8_t n_sessions_l; 115 | uint8_t first_track_l; 116 | uint8_t last_track_l; 117 | #ifdef WORDS_BIGENDIAN 118 | unsigned char did_v : 1; 119 | unsigned char dbc_v : 1; 120 | unsigned char uru : 1; 121 | unsigned char reserved2 : 5; 122 | #else 123 | unsigned char reserved2 : 5; 124 | unsigned char uru : 1; 125 | unsigned char dbc_v : 1; 126 | unsigned char did_v : 1; 127 | #endif 128 | uint8_t disc_type; 129 | uint8_t n_sessions_m; 130 | uint8_t first_track_m; 131 | uint8_t last_track_m; 132 | uint32_t disc_id; 133 | uint8_t lead_in_r; 134 | uint8_t lead_in_m; 135 | uint8_t lead_in_s; 136 | uint8_t lead_in_f; 137 | uint8_t lead_out_r; 138 | uint8_t lead_out_m; 139 | uint8_t lead_out_s; 140 | uint8_t lead_out_f; 141 | uint8_t disc_bar_code[8]; 142 | uint8_t reserved3; 143 | uint8_t opc_entries; 144 | } disc_info_t; 145 | 146 | typedef struct track_info { 147 | uint16_t info_length; 148 | uint8_t track_number_l; 149 | uint8_t session_number_l; 150 | uint8_t reserved1; 151 | #ifdef WORDS_BIGENDIAN 152 | uint8_t reserved2 : 2; 153 | uint8_t damage : 1; 154 | uint8_t copy : 1; 155 | uint8_t track_mode : 4; 156 | uint8_t rt : 1; 157 | uint8_t blank : 1; 158 | uint8_t packet : 1; 159 | uint8_t fp : 1; 160 | uint8_t data_mode : 4; 161 | uint8_t reserved3 : 6; 162 | uint8_t lra_v : 1; 163 | uint8_t nwa_v : 1; 164 | #else 165 | uint8_t track_mode : 4; 166 | uint8_t copy : 1; 167 | uint8_t damage : 1; 168 | uint8_t reserved2 : 2; 169 | uint8_t data_mode : 4; 170 | uint8_t fp : 1; 171 | uint8_t packet : 1; 172 | uint8_t blank : 1; 173 | uint8_t rt : 1; 174 | uint8_t nwa_v : 1; 175 | uint8_t lra_v : 1; 176 | uint8_t reserved3 : 6; 177 | #endif 178 | uint32_t track_start; 179 | uint32_t next_writable; 180 | uint32_t free_blocks; 181 | uint32_t packet_size; 182 | uint32_t track_size; 183 | uint32_t last_recorded; 184 | uint8_t track_number_m; 185 | uint8_t session_number_m; 186 | uint8_t reserved4; 187 | uint8_t reserved5; 188 | } track_info_t; 189 | 190 | typedef struct opc_table { 191 | uint16_t speed; 192 | uint8_t opc_value[6]; 193 | } opc_table_t; 194 | 195 | typedef struct disc_capacity { 196 | uint32_t lba; 197 | uint32_t block_length; 198 | } disc_capacity_t; 199 | 200 | int msf_to_lba(int, int, int); 201 | void hexdump(const void *, int); 202 | void dump_sense(unsigned char *, struct request_sense *); 203 | int wait_cmd(int, struct cdrom_generic_command *, unsigned char *, int, int); 204 | int mode_select(int, unsigned char *, int); 205 | int mode_sense(int, unsigned char *, int, char, int); 206 | int set_write_mode(int, write_params_t *); 207 | int get_write_mode(int, write_params_t *); 208 | int sync_cache(int); 209 | int write_blocks(int, unsigned char *, int, int); 210 | int write_file(int, struct cdrw_disc *); 211 | int blank_disc(int, int); 212 | int format_disc(int, struct cdrw_disc *, write_params_t *); 213 | int read_disc_info(int, disc_info_t *); 214 | int read_track_info(int, track_info_t *, int); 215 | int reserve_track(int, struct cdrw_disc *); 216 | int close_track(int, unsigned int); 217 | int close_session(int, unsigned int); 218 | int read_buffer_cap(int, struct cdrw_disc *); 219 | int set_cd_speed(int, int); 220 | void cdrom_close(int); 221 | int cdrom_open_check(int); 222 | void print_disc_info(disc_info_t *); 223 | void print_track_info(track_info_t *); 224 | int print_disc_track_info(int); 225 | void make_write_page(write_params_t *, struct cdrw_disc *); 226 | void print_params(write_params_t *); 227 | void cdrw_init_disc(struct cdrw_disc *); 228 | 229 | #endif /* _CDRWTOOL_H */ 230 | -------------------------------------------------------------------------------- /cdrwtool/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | * 4 | * Copyright (c) 2002 Ben Fennema 5 | * All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "cdrwtool.h" 37 | #include "options.h" 38 | 39 | #include "../mkudffs/defaults.h" 40 | #include "../mkudffs/mkudffs.h" 41 | 42 | int write_func(struct udf_disc *disc, struct udf_extent *ext) 43 | { 44 | static unsigned char *buffer = NULL; 45 | static size_t bufferlen = 0; 46 | static int lastpacket = -1; 47 | int fd = *(int *)disc->write_data; 48 | size_t offset; 49 | int packet; 50 | struct udf_desc *desc; 51 | struct udf_data *data; 52 | 53 | if (buffer == NULL) 54 | { 55 | bufferlen = disc->blocksize * 32; 56 | buffer = calloc(bufferlen, 1); 57 | if (buffer == NULL) 58 | return -1; 59 | } 60 | 61 | if (ext == NULL) 62 | { 63 | if (lastpacket != -1) 64 | { 65 | if (write_blocks(fd, buffer, lastpacket * 32, 32) < 0) 66 | return -1; 67 | } 68 | } 69 | else if (!(ext->space_type & (USPACE|RESERVED))) 70 | { 71 | desc = ext->head; 72 | while (desc != NULL) 73 | { 74 | packet = (uint64_t)(ext->start + desc->offset) / 32; 75 | if (lastpacket != -1 && packet != lastpacket) 76 | { 77 | if (write_blocks(fd, buffer, lastpacket * 32, 32) < 0) 78 | return -1; 79 | memset(buffer, 0x00, bufferlen); 80 | } 81 | data = desc->data; 82 | offset = ((uint64_t)(ext->start + desc->offset) - (packet * 32)) * disc->blocksize; 83 | while (data != NULL) 84 | { 85 | if (data->length + offset > bufferlen) 86 | { 87 | memcpy(buffer + offset, data->buffer, bufferlen - offset); 88 | if (write_blocks(fd, buffer, packet * 32, 32) < 0) 89 | return -1; 90 | memset(buffer, 0x00, bufferlen); 91 | lastpacket = ++ packet; 92 | 93 | memcpy(buffer, (uint8_t *)data->buffer + (bufferlen - offset), data->length - (bufferlen - offset)); 94 | offset = data->length - (bufferlen - offset); 95 | } 96 | else 97 | { 98 | lastpacket = packet; 99 | memcpy(buffer + offset, data->buffer, data->length); 100 | offset += data->length; 101 | } 102 | 103 | if (offset == disc->blocksize * 32) 104 | { 105 | if (write_blocks(fd, buffer, packet * 32, 32) < 0) 106 | return -1; 107 | memset(buffer, 0x00, bufferlen); 108 | lastpacket = -1; 109 | offset = 0; 110 | packet ++; 111 | } 112 | data = data->next; 113 | } 114 | desc = desc->next; 115 | } 116 | } 117 | return 0; 118 | } 119 | 120 | int quick_setup(int fd, struct cdrw_disc *disc, const char *device, 121 | write_params_t *w) 122 | { 123 | disc_info_t di; 124 | track_info_t ti; 125 | int ret, i; 126 | unsigned blocks; 127 | 128 | printf("Settings for %s:\n", device); 129 | printf("\t%s packets, size %u\n", disc->fpacket ? "Fixed" : "Variable", 130 | disc->packet_size); 131 | printf("\tMode-%d disc\n", disc->write_type); 132 | 133 | printf( "\nI'm going to do a quick setup of %s. The disc is going to " 134 | "be blanked and formatted with one big track. All data on " 135 | "the device will be lost!! Press CTRL-C to cancel now.\n" 136 | "ENTER to continue.\n", 137 | device); 138 | 139 | getchar(); 140 | 141 | printf("Initiating quick disc blank\n"); 142 | 143 | if ((ret = blank_disc(fd, BLANK_FAST))) 144 | return ret; 145 | 146 | if ((ret = read_disc_info(fd, &di)) < 0) 147 | return ret; 148 | 149 | if ((ret = read_track_info(fd, &ti, 1)) < 0) 150 | return ret; 151 | 152 | blocks = msf_to_lba(di.lead_out_m, di.lead_out_s, di.lead_out_f) - 152; 153 | if (disc->fpacket) 154 | { 155 | /* fixed packets format usable blocks */ 156 | blocks = ((blocks + 7) / (disc->packet_size + 7)) * disc->packet_size; 157 | } 158 | printf("Disc capacity is %u blocks (%uKB/%uMB)\n", 159 | blocks, blocks * 2, blocks / 512); 160 | 161 | if (!disc->offset) 162 | disc->udf_disc.head->blocks = blocks; 163 | else 164 | disc->udf_disc.head->blocks = disc->offset; 165 | 166 | disc->udf_disc.blocks = disc->udf_disc.head->blocks; 167 | 168 | if (disc->fpacket) 169 | { 170 | if (!disc->offset) 171 | disc->offset = blocks; 172 | printf("Formatting track\n"); 173 | if ((ret = format_disc(fd, disc, w))) 174 | return ret; 175 | add_type2_sparable_partition(&disc->udf_disc, 0, 2, 32); 176 | disc->udf_disc.udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE); 177 | } 178 | else 179 | { 180 | disc->reserve_track = blocks; 181 | printf("Reserving track\n"); 182 | if ((ret = reserve_track(fd, disc))) 183 | return ret; 184 | } 185 | 186 | disc->udf_disc.flags |= FLAG_UNALLOC_BITMAP; 187 | for (i=0; iudf_disc.sizing[i].denomSize == 0) 190 | memcpy(&disc->udf_disc.sizing[i], &default_sizing[DEFAULT_CDRW][i], sizeof(default_sizing[DEFAULT_CDRW][i])); 191 | } 192 | 193 | strcpy((char *)disc->udf_disc.udf_pvd[0]->appIdent.ident, "*Linux cdrwtool " PACKAGE_VERSION); 194 | 195 | split_space(&disc->udf_disc); 196 | 197 | setup_vrs(&disc->udf_disc); 198 | setup_anchor(&disc->udf_disc); 199 | setup_partition(&disc->udf_disc); 200 | setup_vds(&disc->udf_disc); 201 | 202 | dump_space(&disc->udf_disc); 203 | 204 | printf("Writing UDF structures to disc\n"); 205 | write_disc(&disc->udf_disc); 206 | disc->udf_disc.write(&disc->udf_disc, NULL); 207 | sync_cache(fd); 208 | 209 | printf("Quick setup complete!\n"); 210 | return 0; 211 | } 212 | 213 | int mkudf_session(int fd, struct cdrw_disc *disc) 214 | { 215 | int i; 216 | 217 | disc->udf_disc.head->blocks = disc->offset; 218 | disc->udf_disc.blocks = disc->udf_disc.head->blocks; 219 | add_type2_sparable_partition(&disc->udf_disc, 0, 2, 32); 220 | disc->udf_disc.udf_pd[0]->accessType = cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE); 221 | 222 | disc->udf_disc.flags |= FLAG_UNALLOC_BITMAP; 223 | for (i=0; iudf_disc.sizing[i].denomSize == 0) 226 | memcpy(&disc->udf_disc.sizing[i], &default_sizing[DEFAULT_CDRW][i], sizeof(default_sizing[DEFAULT_CDRW][i])); 227 | } 228 | 229 | strcpy((char *)disc->udf_disc.udf_pvd[0]->appIdent.ident, "*Linux cdrwtool " PACKAGE_VERSION); 230 | 231 | split_space(&disc->udf_disc); 232 | 233 | setup_vrs(&disc->udf_disc); 234 | setup_anchor(&disc->udf_disc); 235 | setup_partition(&disc->udf_disc); 236 | setup_vds(&disc->udf_disc); 237 | 238 | dump_space(&disc->udf_disc); 239 | 240 | printf("Writing UDF structures to disc\n"); 241 | write_disc(&disc->udf_disc); 242 | disc->udf_disc.write(&disc->udf_disc, NULL); 243 | sync_cache(fd); 244 | return 0; 245 | } 246 | 247 | int main(int argc, char *argv[]) 248 | { 249 | struct cdrw_disc disc; 250 | write_params_t w; 251 | const char *filename; 252 | int fd, ret; 253 | 254 | appname = "cdrwtool"; 255 | 256 | memset(&disc, 0x00, sizeof(disc)); 257 | cdrw_init_disc(&disc); 258 | udf_init_disc(&disc.udf_disc); 259 | udf_set_version(&disc.udf_disc, 0x150); 260 | disc.udf_disc.flags |= FLAG_BOOTAREA_PRESERVE; 261 | filename = CDROM_DEVICE; 262 | parse_args(argc, argv, &disc, &filename); 263 | if (((fd = open(filename, O_RDWR | O_NONBLOCK)) < 0) && 264 | ((errno != EROFS) || 265 | ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0))) 266 | { 267 | perror("open cdrom device"); 268 | return fd; 269 | } 270 | disc.udf_disc.write = write_func; 271 | disc.udf_disc.write_data = &fd; 272 | 273 | if ((ret = cdrom_open_check(fd))) 274 | { 275 | fprintf(stderr, "set_options\n"); 276 | cdrom_close(fd); 277 | return ret; 278 | } 279 | 280 | if ((ret = read_buffer_cap(fd, &disc))) 281 | { 282 | cdrom_close(fd); 283 | return ret; 284 | } 285 | 286 | if ((ret = get_write_mode(fd, &w))) 287 | { 288 | fprintf(stderr, "get_write\n"); 289 | cdrom_close(fd); 290 | return ret; 291 | } 292 | 293 | if ((ret = set_cd_speed(fd, disc.speed))) 294 | { 295 | fprintf(stderr, "set speed\n"); 296 | cdrom_close(fd); 297 | return ret; 298 | } 299 | 300 | if (disc.get_settings || disc.disc_track_info) 301 | { 302 | if (disc.get_settings) 303 | print_params(&w); 304 | if (disc.disc_track_info) 305 | print_disc_track_info(fd); 306 | cdrom_close(fd); 307 | return ret; 308 | } 309 | 310 | /* define write parameters based on command line options */ 311 | make_write_page(&w, &disc); 312 | 313 | if ((ret = set_write_mode(fd, &w))) 314 | { 315 | printf("set_write\n"); 316 | cdrom_close(fd); 317 | return ret; 318 | } 319 | 320 | if (disc.close_track) 321 | { 322 | ret = close_track(fd, disc.close_track); 323 | cdrom_close(fd); 324 | return ret; 325 | } 326 | 327 | if (disc.close_session) 328 | { 329 | ret = close_session(fd, disc.close_session); 330 | cdrom_close(fd); 331 | return ret; 332 | } 333 | 334 | if (disc.quick_setup) 335 | { 336 | ret = quick_setup(fd, &disc, filename, &w); 337 | cdrom_close(fd); 338 | return ret; 339 | } 340 | 341 | if (disc.blank) 342 | { 343 | ret = blank_disc(fd, disc.blank); 344 | cdrom_close(fd); 345 | return ret; 346 | } 347 | 348 | if (disc.format) 349 | { 350 | ret = format_disc(fd, &disc, &w); 351 | cdrom_close(fd); 352 | return ret; 353 | } 354 | 355 | if (disc.mkudf) 356 | { 357 | ret = mkudf_session(fd, &disc); 358 | cdrom_close(fd); 359 | return ret; 360 | } 361 | 362 | if (disc.filename) 363 | { 364 | ret = write_file(fd, &disc); 365 | cdrom_close(fd); 366 | return ret; 367 | } 368 | 369 | if (disc.reserve_track) 370 | { 371 | ret = reserve_track(fd, &disc); 372 | cdrom_close(fd); 373 | return ret; 374 | } 375 | 376 | cdrom_close(fd); 377 | return 0; 378 | } 379 | -------------------------------------------------------------------------------- /cdrwtool/options.c: -------------------------------------------------------------------------------- 1 | /* 2 | * options.c 3 | * 4 | * Copyright (c) 2002 Ben Fennema 5 | * All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "cdrwtool.h" 30 | #include "libudffs.h" 31 | #include "options.h" 32 | 33 | #include "../mkudffs/mkudffs.h" 34 | 35 | struct option long_options[] = { 36 | { "help", no_argument, NULL, OPT_HELP }, 37 | { "device", 1, NULL, 'd' }, 38 | { "set write parameters", no_argument, NULL, 's' }, 39 | { "get write parameters", no_argument, NULL, 'g' }, 40 | { "blank cdrw disc", 1, NULL, 'b' }, 41 | { "format cdrw disc", 1,NULL, 'm' }, 42 | { "run mkudffs on track", 1, NULL, 'u' }, 43 | { "set mkudffs version", 1, NULL, 'v' }, 44 | { "set cd writing speed", 1, NULL, 't' }, 45 | { "write fixed packets", 1, NULL, 'p' }, 46 | { "perform quick setup", optional_argument, NULL, 'q' }, 47 | { "reserve track", 1, NULL, 'r' }, 48 | { "close track", 1, NULL, 'c' }, 49 | { "fixed packet size", 1, NULL, 'z' }, 50 | { "border/session setting", 1, NULL, 'l' }, 51 | { "write type", 1, NULL, 'w' }, 52 | { "file to write", 1, NULL, 'f' }, 53 | { "start at this lba for file write", 1, NULL,'o' }, 54 | { "print detailed disc info", no_argument, NULL, 'i' }, 55 | { 0, 0, NULL, 0 }, 56 | }; 57 | 58 | void usage(void) 59 | { 60 | int i; 61 | 62 | printf("cdrwtool from " PACKAGE_NAME " " PACKAGE_VERSION "\nUsage:\n\tcdrwtool [options]\nOptions:\n"); 63 | for (i = 0; long_options[i].name != NULL; i++) 64 | if (long_options[i].val >= 0xFF) 65 | printf("\t--%s\t%s\n", long_options[i].name, long_options[i].name); 66 | else 67 | printf("\t-%c\t%s\n", long_options[i].val, long_options[i].name); 68 | exit(1); 69 | } 70 | 71 | void parse_args(int argc, char *argv[], struct cdrw_disc *disc, const char **device) 72 | { 73 | int retval; 74 | 75 | while ((retval = getopt_long(argc, argv, "r:t:im:u:v:d:sgq::c:C:b:p:z:l:w:f:o:h", long_options, NULL)) != EOF) 76 | { 77 | switch (retval) 78 | { 79 | case OPT_HELP: 80 | case 'h': 81 | usage(); 82 | break; 83 | case 'c': 84 | { 85 | disc->close_track = strtol(optarg, NULL, 10); 86 | break; 87 | } 88 | case 'C': 89 | { 90 | disc->close_session = strtol(optarg, NULL, 10); 91 | break; 92 | } 93 | case 'q': 94 | { 95 | disc->quick_setup = 1; 96 | if (optarg) 97 | disc->offset = strtol(optarg, NULL, 10); 98 | else 99 | disc->offset = 0; 100 | break; 101 | } 102 | case 'u': 103 | { 104 | disc->mkudf = 1; 105 | disc->offset = strtol(optarg, NULL, 10); 106 | printf("mkudffs %lu blocks\n", disc->offset); 107 | break; 108 | } 109 | case 'v': 110 | { 111 | int udf_rev = strtol(optarg, NULL, 16); 112 | if (udf_rev < 0x0150 || udf_rev > 0x0201 || udf_set_version(&disc->udf_disc, udf_rev)) 113 | { 114 | fprintf(stderr, "invalid/unsupported udf revision\n"); 115 | exit(1); 116 | } 117 | printf("udf version set to 0x%04x\n", disc->udf_disc.udf_rev); 118 | break; 119 | } 120 | case 'r': 121 | { 122 | disc->reserve_track = strtol(optarg, NULL, 10); 123 | printf("reserving track %u\n", disc->reserve_track); 124 | break; 125 | } 126 | case 't': 127 | { 128 | disc->speed = strtol(optarg, NULL, 10); 129 | printf("setting speed to %d\n", disc->speed); 130 | break; 131 | } 132 | case 'm': 133 | { 134 | disc->format = 1; 135 | disc->offset = strtol(optarg, NULL, 10); 136 | printf("formatting %lu blocks\n", disc->offset); 137 | break; 138 | } 139 | case 'i': 140 | { 141 | disc->disc_track_info = 1; 142 | break; 143 | } 144 | case 'd': 145 | { 146 | *device = optarg; 147 | printf("using device %s\n", *device); 148 | break; 149 | } 150 | case 'g': 151 | { 152 | printf("ok, want to get\n"); 153 | disc->get_settings = 1; 154 | break; 155 | } 156 | case 's': 157 | { 158 | printf("ok, want to set\n"); 159 | disc->set_settings = 1; 160 | break; 161 | } 162 | case 'b': 163 | { 164 | if (!strcmp("full", optarg)) 165 | { 166 | printf("full blank\n"); 167 | disc->blank = BLANK_FULL; 168 | } 169 | else if (!strcmp("fast", optarg)) 170 | { 171 | printf("fast blank\n"); 172 | disc->blank = BLANK_FAST; 173 | } 174 | else 175 | { 176 | printf("full or fast blanking only\n"); 177 | exit(1); 178 | } 179 | break; 180 | } 181 | case 'p': 182 | { 183 | disc->fpacket = !!strtol(optarg, NULL, 10); 184 | printf("%s packets\n", disc->fpacket?"fixed":"variable"); 185 | break; 186 | } 187 | case 'z': 188 | { 189 | disc->packet_size = strtol(optarg, NULL, 10); 190 | printf("packet size: %d\n", disc->packet_size); 191 | break; 192 | } 193 | case 'l': 194 | { 195 | disc->border = strtol(optarg, NULL, 10); 196 | printf("border type: %d\n", disc->border); 197 | break; 198 | } 199 | case 'w': 200 | { 201 | if (!strcmp("mode1", optarg)) 202 | { 203 | printf("mode1\n"); 204 | disc->write_type = 1; 205 | } 206 | else if (!strcmp("mode2", optarg)) 207 | { 208 | printf("mode2\n"); 209 | disc->write_type = 2; 210 | } 211 | else 212 | { 213 | fprintf(stderr, "mode1 or mode2 writing only\n"); 214 | exit(1); 215 | } 216 | break; 217 | } 218 | case 'f': 219 | { 220 | disc->filename = optarg; 221 | printf("write file %s\n", disc->filename); 222 | break; 223 | } 224 | case 'o': 225 | { 226 | disc->offset = strtoul(optarg, NULL, 10); 227 | printf("write offset %lu\n", disc->offset); 228 | break; 229 | } 230 | } 231 | } 232 | 233 | if (optind < argc) 234 | usage(); 235 | } 236 | -------------------------------------------------------------------------------- /cdrwtool/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | * options.h 3 | * 4 | * Copyright (c) 2002 Ben Fennema 5 | * All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | #ifndef _OPTIONS_H 24 | #define _OPTIONS_H 1 25 | 26 | #include 27 | 28 | void usage(void); 29 | void parse_args(int, char *[], struct cdrw_disc *, const char **); 30 | 31 | /* 32 | * Command line option token values. 33 | * 0x0000-0x00ff Single characters 34 | * 0x1000-0x1fff Long switches (no arg) 35 | * 0x2000-0x2fff Long settings (arg required) 36 | */ 37 | 38 | #define OPT_HELP 0x1000 39 | 40 | #endif /* _OPTIONS_H */ 41 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | AC_PREREQ([2.64]) 3 | AC_INIT(udftools, 2.3, , , [https://github.com/pali/udftools/]) 4 | AC_CONFIG_AUX_DIR(config) 5 | AM_CONFIG_HEADER(include/config.h:include/config.in) 6 | AM_INIT_AUTOMAKE 7 | 8 | dnl Checks for programs. 9 | AC_PROG_CC_C99 10 | AC_DISABLE_SHARED 11 | AM_PROG_LIBTOOL 12 | AC_PROG_LN_S 13 | AC_PROG_MKDIR_P 14 | 15 | AS_IF([test "$ac_cv_prog_cc_c99" = "no"], [AC_MSG_ERROR([Your C compiler does not support ISO C99.])]) 16 | 17 | dnl Checks for libraries, by using pkg-config when available 18 | PKG_PROG_PKG_CONFIG 19 | AS_IF([test -n "${PKG_CONFIG}"], [PKG_CHECK_MODULES([READLINE], [readline], [readline_found=yes], [readline_found=no])]) 20 | 21 | AS_IF([test "${readline_found}" != "yes"], 22 | [AC_CHECK_LIB(readline, readline, 23 | [AC_CHECK_HEADERS(readline/readline.h, 24 | [AC_SUBST([READLINE_LIBS], [-lreadline]) 25 | readline_found=yes], 26 | [readline_found=no])], 27 | [readline_found=no]) 28 | ]) 29 | 30 | dnl Checks for typedefs, structures, and compiler characteristics. 31 | AC_C_INLINE 32 | AC_C_BIGENDIAN 33 | AC_SYS_LARGEFILE 34 | 35 | PKG_CHECK_MODULES(UDEV, [udev], [ac_cv_udevdir=`$PKG_CONFIG --variable=udevdir udev`], [ac_cv_udevdir=""]) 36 | AM_CONDITIONAL(UDEVDIR, [test "$ac_cv_udevdir" != ""]) 37 | AC_SUBST(UDEVDIR, $ac_cv_udevdir) 38 | 39 | dnl Checks for library functions. 40 | AC_SUBST(LTLIBOBJS) 41 | 42 | AM_CONDITIONAL(USE_READLINE, test "$readline_found" = "yes") 43 | 44 | AC_CONFIG_FILES(Makefile libudffs/Makefile mkudffs/Makefile cdrwtool/Makefile pktsetup/Makefile udffsck/Makefile udfinfo/Makefile udflabel/Makefile wrudf/Makefile doc/Makefile) 45 | 46 | AC_OUTPUT 47 | -------------------------------------------------------------------------------- /doc/HOWTO.udf: -------------------------------------------------------------------------------- 1 | udftools 2 | =================== 3 | 4 | Kernel support for packet writing 5 | --------------------------------- 6 | 7 | Packet writing is a technique by which a writable medium (typically a 8 | CD or DVD) can be used just like a USB stick or a directory on the 9 | hard disc: Files and directories can be created/renamed/removed 10 | freely, and no separate "burning" step is necessary to write the data 11 | to the medium. Packet writing is possible both with write-once media 12 | (CD-R, DVD+R, DVD-R) and rewritable media (CD-RW, DVD+RW, 13 | DVD-RW). Obviously, with write-once media the free space on the 14 | filesystem will not increase if you delete files. 15 | 16 | In order to do packet writing under Linux, your kernel needs 17 | both support for UDF (Universal Disc Format) filesystems and for 18 | packet writing. This is the case for kernels later than about 2.6.10. 19 | This package tries to support both old-style packet writing 20 | (kernel <2.6.8), and the newer variant (>=2.6.10), with and without 21 | udev. Use a recent 2.6 kernel for optimum results! 22 | 23 | 24 | Formatting and using a UDF DVD-RW or CD-RW for packet writing 25 | ------------------------------------------------------------- 26 | 27 | The commands differ depending on whether you are using DVD or CD 28 | media. 29 | 30 | 1) Edit /etc/udftools.conf and add your drive for packet writing. 31 | For example, if your CD/DVD writer is /dev/hdc and you want it 32 | available as the default /dev/pktcdvd/0, then use the setting 33 | "DEVICES=/dev/hdc". Execute "/etc/rc.d/rc.udftools start" afterwards to 34 | register the device. 35 | 36 | If the device name /dev/hdc differs on your system, adjust the 37 | following commands as appropriate. 38 | 39 | 2) Prepare the medium in restricted overwrite mode: 40 | 41 | DVD-RW: dvd+rw-format -force /dev/hdc 42 | CD-RW: Do nothing, skip this step! 43 | 44 | 3) Write an empty session spanning the whole medium. It seems that 45 | without this step, any attempt to create the UDF filesystem will fail. 46 | 47 | DVD-RW: growisofs -Z /dev/hdc=/dev/zero 48 | CD-RW: cdrwtool -d /dev/hdc -q 49 | 50 | 4) Format the packet device in UDF format. 51 | 52 | DVD-RW: mkudffs --udfrev=0x0150 --spartable=2 --media-type=dvdrw /dev/pktcdvd/0 53 | CD-RW: mkudffs --udfrev=0x0150 --spartable=2 --media-type=cdrw /dev/pktcdvd/0 54 | 55 | The parameters require some more explanation: For --udfrev, use either 56 | 0x0150 for UDF version 1.50, or 0x0201 for UDF version 2.01. The 57 | version decision has mostly to do with compatibility: 58 | - Windows 98/ME can read up to v1.02 59 | - Windows 2000, Mac OS 9, Linux 2.4 can read up to v1.50 60 | - Windows 2003/XP can read up to v2.01 61 | - Linux 2.6 can read up to v2.60 62 | For normal data, UDF 1.50 is OK. UDF 2.00 and 2.01 introduce 63 | additional functionality for streaming audio/video. 64 | 65 | Possible values for --media-type are: hd dvdram dvdrw worm mo cdrw cdr. 66 | Use the one appropriate for your medium/device. 67 | 68 | 5) Mount the disc. The "noatime" option is important: It will reduce 69 | the amount of writes to the device and thus increase its lifetime. You 70 | may first have to create the mount directory using "mkdir 71 | /media/dvd0": 72 | 73 | mount -t udf -o rw,noatime /dev/pktcdvd/0 /media/dvd0 74 | 75 | The "sync" mount option might also be useful, but will typically cause 76 | an increased number of write accesses to the medium. From now on, the 77 | root user can access the filesystem under /media/dvd0 using read and 78 | write operations. 79 | 80 | 6) If regular users should also have write access, modify the 81 | permissions as follows _while the filesystem is mounted_: 82 | 83 | chgrp plugdev /media/dvd0 # Set group ownership to "plugdev" 84 | chmod g+rwx /media/dvd0 # Give full read/write access to group 85 | 86 | Now all users who should have access to the disc need to be added to 87 | the "plugdev" group using "adduser plugdev". 88 | 89 | To also allow these users to mount and unmount/eject the medium, you 90 | can use either of these two routes: 91 | 92 | - Install the "pmount" package and add the device to the list of 93 | allowed devices using "echo /dev/pktcdvd/0 >>/etc/pmount.allow". 94 | All members of the group "plugdev" will then be able to mount the 95 | disc using "pmount /dev/pktcdvd/0 dvd0" and unmount it using 96 | "pumount /media/dvd0". 97 | 98 | - Add a line like the following to /etc/fstab: 99 | /dev/pktcdvd/0 /media/dvd0 udf rw,noatime,users,noauto 0 0 100 | This will enable _all_ users to mount the disc using 101 | "mount /media/dvd0" and unmount it with 102 | "umount /media/dvd0". However, with the permissions from step 5) 103 | above, only the members of group "plugdev" ought to be able to 104 | write to it. 105 | 106 | 107 | Support for UDF filesystems 108 | --------------------------- 109 | 110 | UDF (not packet writing) support in Linux 2.4 and later kernels is 111 | sufficient to read from and write to UDF filesystems. For example, you 112 | can create a regular file, "format" it using mkudffs, and then 113 | loop-mount it. To do this, execute the following commands as root: 114 | (After "count=", supply the required size in MB of the filesystem.) 115 | 116 | dd if=/dev/zero of=udfimage bs=1M count=10 117 | mkudffs udfimage 118 | mkdir udfmnt 119 | mount -o loop -t udf udfimage udfmnt 120 | 121 | You need Linux 2.4+ with UDF read *and* write support enabled. Now you 122 | can copy data to the "udfmnt" directory. After an "umount udfmnt", the 123 | file "udfimage" could theoretically be written to a CD-R(W) or 124 | DVD-R(W). In practice, you will not want to do that, as the whole 125 | point of using UDF is to do packet writing. 126 | 127 | 128 | "/dev/pktcdvd0" not present? 129 | ---------------------------- 130 | 131 | The "pktsetup" tool requires a device like /dev/pktcdvd0, 132 | /dev/pktcdvd1 etc. If the device is not present on your system, this 133 | means one of two things: 134 | 135 | - You are using devfs (the file /dev/.devfsd is present). In this 136 | case, just try to use the device, and the appropriate driver should 137 | be loaded automatically. 138 | 139 | - You are not using devfs now, but it was being used at the time the 140 | udftools package was installed. In this case, you need to create 141 | the devices as root now, using the command: 142 | 143 | dpkg-reconfigure udftools 144 | 145 | - You are using udev, and there is no packet writing support in your 146 | kernel. 147 | 148 | 149 | -- Richard Atterer Wed, 22 Nov 2006 23:38:16 +0100 150 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | dist_man_MANS = cdrwtool.1 udfinfo.1 wrudf.1 mkfs.udf.8 mkudffs.8 pktsetup.8 udflabel.8 2 | dist_doc_DATA = HOWTO.udf UDF-Specifications 3 | -------------------------------------------------------------------------------- /doc/UDF-Specifications: -------------------------------------------------------------------------------- 1 | The UDF Specifications are available as free PDF files from OSTA at: 2 | 3 | http://www.osta.org/specs/ 4 | 5 | Many IEC/ISO standards that they reference are co-published by ECMA. 6 | For example, Ecma publication ECMA-167 is also approved as ISO/IEC 13346. 7 | They are available as free PDF files from ECMA at: 8 | 9 | http://www.ecma-international.org/publications/ 10 | -------------------------------------------------------------------------------- /doc/cdrwtool.1: -------------------------------------------------------------------------------- 1 | .\" Copyright 2002 Paul Thompson 2 | .\" 3 | .\" This is free documentation; you can redistribute it and/or 4 | .\" modify it under the terms of the GNU General Public License as 5 | .\" published by the Free Software Foundation; either version 2 of 6 | .\" the License, or (at your option) any later version. 7 | .\" 8 | .\" The GNU General Public License's references to "object code" 9 | .\" and "executables" are to be interpreted as the output of any 10 | .\" document formatting or typesetting system, including 11 | .\" intermediate and printed output. 12 | .\" 13 | .\" This manual is distributed in the hope that it will be useful, 14 | .\" but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | .\" GNU General Public License for more details. 17 | .\" 18 | .\" You should have received a copy of the GNU General Public 19 | .\" License along with this manual; if not, write to the Free 20 | .\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, 21 | .\" USA. 22 | .\" 23 | .\" References consulted: 24 | .\" udf-0.9.5 source 25 | .\" 26 | .\" 27 | .TH CDRWTOOL 1 "udftools" "Commands" 28 | 29 | .SH NAME 30 | cdrwtool \- perform various actions on a CD-R, CD-RW, and DVD-R 31 | 32 | .SH SYNOPSIS 33 | .BI "cdrwtool \-d " device " \-i | \-g" 34 | .PP 35 | .BI "cdrwtool \-d " device " \-s [ " write-parameters " ]" 36 | .PP 37 | .BI "cdrwtool \-d " device " \-q [ " write-parameters " ]" 38 | .PP 39 | .BI "cdrwtool \-d " device " \-m " offset " [ " write-parameters " ]" 40 | .PP 41 | .BI "cdwrtool \-d " device " \-u " blocks " [ " write-parameters " ]" 42 | .PP 43 | .BI "cdrwtool \-d " device " \-b " b_mode " [ " write-parameters " ]" 44 | .PP 45 | .BI "cdrwtool \-d " device " \-c " blocks " [ " write-parameters " ]" 46 | .PP 47 | .BI "cdwrtool \-d " device " \-f " filename " [ " write-parameters " ]" 48 | .PP 49 | .BI "cdwrtool \-d " device " \-r " track " [ " write-parameters " ]" 50 | .PP 51 | .BI "cdrwtool \-h" 52 | 53 | .SH DESCRIPTION 54 | The \fBcdwrtool\fP command can perform certain actions on a CD-R, 55 | CD-RW, or DVD-R device. Mainly these are blanking the media, 56 | formatting it for use with the packet-cd device, and applying an 57 | UDF filesystem. 58 | .PP 59 | The most common usage is probably the `quick setup' option: 60 | .IP 61 | .BI "cdrwtool \-d " device " \-q" 62 | .PP 63 | which will blank the disc, format it as one large track, and 64 | write the UDF filesystem structures. 65 | .PP 66 | Other options get and set various parameters of how the device is 67 | set up, and provide for different offsets, modes and settings 68 | from the defaults. 69 | .PP 70 | The usefulness of most of the options is not explained. 71 | 72 | .SH OPTIONS 73 | Main directives: 74 | .IP "\fB\-d \fIdevice\fP" 75 | Specify the device to use. eg. \fI/dev/sr0\fP 76 | 77 | .IP \fB\-i\fP 78 | Print disc track info. 79 | 80 | .IP \fB\-g\fP 81 | Print write parameters. 82 | 83 | .IP "\fB\-u \fIlength\fP" 84 | Make a UDF filesystem using \fIlength\fP number of blocks. 85 | 86 | .IP "\fB\-q\fP" 87 | `Quick setup': blank the disc, format it as one large track and write a UDF filesystem. 88 | 89 | .IP "\fB\-m \fIoffset\fP" 90 | Format the disc at \fIoffset\fP number of blocks. 91 | 92 | .IP "\fB\-b \fImode\fP" 93 | Blank the disk using a \fImode\fP of `full' or `fast'. 94 | 95 | .IP "\fB\-f \fIfilename\fP" 96 | Write file. 97 | 98 | .IP "\fB\-c \fItrack\fP" 99 | Close track. 100 | .IP "\fB\-r \fItrack\fP" 101 | Reserve track. 102 | 103 | .IP "\fB\-z \fIlength\fP" 104 | Fixed packet length. 105 | 106 | 107 | .IP \fB\-s\fP 108 | Set write parameters determined by 109 | .BR "\-l" , " \-w" ", and" " \-p" 110 | options for the disc. 111 | 112 | .IP "\fB\-v \fIversion\fP" 113 | Specify the udf revision to use. Valid revisions are 0x0201, 0x0200 and 0x0150. 114 | If omitted, 115 | .B mkudffs 116 | udf-version is 0x0150. 117 | 118 | .IP \fB\-h\fP 119 | Prints a sparse help message. 120 | .PP 121 | 122 | Write parameters: 123 | .IP "\fB\-t \fIspeed\fP" 124 | Set write speed. (Defaults to 12x ?) 125 | .IP "\fB\-l \fItype\fP" 126 | Set multi\-session field. Either `0' (default), `1', or `3', corresponding to 127 | `No B0 pointer. Next Session not allowed', 128 | `B0 pointer = FF:FF:FF. Next session not allowed', and 129 | `Next session allowed. B0 pointer = next possible program area' respectively. 130 | .IP "\fB\-w \fImode\fP" 131 | Set write mode. Either `mode1' or `mode2' (default). 132 | .IP "\fB\-p \fItype\fP" 133 | Set packet type. Either `0' or `1' (default), corresponding to 134 | variable and fixed packet sizes respectively. 135 | .IP "\fB\-o \fIoffset\fP" 136 | Set write offset. 137 | 138 | .SH BUGS 139 | Many modern drives refuse on the preparations to format new, 140 | blanked, or appendable CD-RW media. This causes a message like 141 | .IP 142 | .B Command failed: 55 ... - sense ... 143 | .PP 144 | The remedy is to use a CD-capable burn program for writing a session 145 | and closing the medium. For example by using any of "cdrecord", 146 | "wodim", "cdrskin", or "xorriso -as cdrecord" as content of 147 | variable \fBprog\fP in: 148 | .PP 149 | .in +4n 150 | .EX 151 | prog="xorriso -as cdrecord" 152 | drive="/dev/sr0" 153 | dd if=/dev/zero bs=1M count=10 | $prog -v -eject dev="$drive" - 154 | .EE 155 | .in 156 | 157 | .SH AUTHORS 158 | .nf 159 | Jens Axboe 160 | Ben Fennema 161 | Some additions by Richard Atterer 162 | BUGS note about closing medium by Thomas Schmitt 163 | .fi 164 | 165 | .SH AVAILABILITY 166 | .B cdrwtool 167 | is part of the udftools package and is available from 168 | https://github.com/pali/udftools/. 169 | 170 | .SH "SEE ALSO" 171 | \fBpktsetup\fP(8), \fBcdrecord\fP(1), \fBwodim\fP(1), \fBcdrskin\fP(1), 172 | \fBxorriso\fP(1) 173 | -------------------------------------------------------------------------------- /doc/mkfs.udf.8: -------------------------------------------------------------------------------- 1 | .so mkudffs.8 2 | -------------------------------------------------------------------------------- /doc/pktsetup.8: -------------------------------------------------------------------------------- 1 | .\" Copyright 2002 Paul Thompson 2 | .\" 3 | .\" This is free documentation; you can redistribute it and/or 4 | .\" modify it under the terms of the GNU General Public License as 5 | .\" published by the Free Software Foundation; either version 2 of 6 | .\" the License, or (at your option) any later version. 7 | .\" 8 | .\" The GNU General Public License's references to "object code" 9 | .\" and "executables" are to be interpreted as the output of any 10 | .\" document formatting or typesetting system, including 11 | .\" intermediate and printed output. 12 | .\" 13 | .\" This manual is distributed in the hope that it will be useful, 14 | .\" but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | .\" GNU General Public License for more details. 17 | .\" 18 | .\" You should have received a copy of the GNU General Public 19 | .\" License along with this manual; if not, write to the Free 20 | .\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, 21 | .\" USA. 22 | .\" 23 | .\" References consulted: 24 | .\" losetup.8 25 | .\" udftools src 26 | .\" 27 | .TH PKTSETUP 8 "udftools" "System Management Commands" 28 | 29 | .SH NAME 30 | pktsetup \- set up and tear down packet device associations 31 | 32 | .SH SYNOPSIS 33 | .ad l 34 | .B pktsetup 35 | .I packet_device block_device 36 | .br 37 | .B pktsetup 38 | .B \-d 39 | .I packet_device 40 | .br 41 | .B pktsetup 42 | .B \-s 43 | .ad b 44 | .SH DESCRIPTION 45 | .B Pktsetup 46 | is used to associate packet devices with CD or DVD block devices, 47 | so that the packet device can then be mounted and potentially 48 | used as a read/write filesystem. This requires kernel support for 49 | the packet device, and the UDF filesystem. 50 | .PP 51 | See: HOWTO.udf (in the udftools documents directory) 52 | 53 | .SH EXIT STATUS 54 | .B Pktsetup 55 | returns 0 on success, nonzero on failure. 56 | 57 | .SH OPTIONS 58 | .IP "\fB\-d \fIpacket-device\fP" 59 | Delete the association between the specified \fIpacket-device\fP 60 | and its block device. 61 | 62 | .IP "\fB\-s\fP" 63 | Show the current device mapping, one device per line, in the format 64 | \fIname\fP : \fIpktdevid\fP -> \fIblkdevid\fP 65 | .br 66 | (e.g. "0 : 253:0 -> 22:0") 67 | 68 | .SH EXAMPLE 69 | The following commands provide an example of using the 70 | packet device. 71 | .nf 72 | .IP 73 | cdrwtool \-d /dev/sr0 \-q 74 | pktsetup 0 /dev/sr0 75 | 76 | mount \-t udf /dev/pktcdvd0 /mnt 77 | ... 78 | umount /dev/pktcdvd0 79 | pktsetup \-d 0 80 | .fi 81 | .LP 82 | 83 | .SH FILES 84 | .nf 85 | /dev/pktcdvd0,/dev/pktcdvd1,... CD/DVD packet devices 86 | .fi 87 | 88 | .SH AUTHOR 89 | .nf 90 | Jens Axboe 91 | Some additions by Richard Atterer 92 | .fi 93 | 94 | .SH AVAILABILITY 95 | .B pktsetup 96 | is part of the udftools package and is available from 97 | https://github.com/pali/udftools/. 98 | 99 | .SH "SEE ALSO" 100 | .BR cdrwtool (1) 101 | -------------------------------------------------------------------------------- /doc/udfinfo.1: -------------------------------------------------------------------------------- 1 | '\" t -*- coding: UTF-8 -*- 2 | .\" Copyright (C) 2017-2021 Pali Rohár 3 | .\" 4 | .\" This program is free software; you can redistribute it and/or modify 5 | .\" it under the terms of the GNU General Public License as published by 6 | .\" the Free Software Foundation; either version 2 of the License, or 7 | .\" (at your option) any later version. 8 | .\" 9 | .\" This program is distributed in the hope that it will be useful, 10 | .\" but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | .\" GNU General Public License for more details. 13 | .\" 14 | .\" You should have received a copy of the GNU General Public License along 15 | .\" with this program; if not, write to the Free Software Foundation, Inc., 16 | .\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | .\" 18 | .TH UDFINFO 1 "udftools" "Commands" 19 | 20 | .SH NAME 21 | udfinfo \(em show information about UDF filesystem 22 | 23 | .SH SYNOPSIS 24 | .BI "udfinfo [ options ] " device 25 | 26 | .SH DESCRIPTION 27 | \fBudfinfo\fP shows various information about a UDF filesystem stored either on 28 | the block device or in the disk file image. The output from the \fBudfinfo\fP is 29 | suitable for parsing by external applications or scripts. 30 | 31 | .SH OPTIONS 32 | .TP 33 | .B \-h,\-\-help 34 | Display the usage and the list of options. 35 | 36 | .TP 37 | .BI \-b,\-\-blocksize= " block\-size " 38 | Specify the size of blocks in bytes. Valid block size for a UDF filesystem is 39 | a power of two in the range from \fI512\fP to \fI32768\fP and must match a 40 | device logical (sector) size. If omitted, \fBudfinfo\fP tries to autodetect 41 | block size. First it tries logical (sector) size and then all valid block sizes. 42 | 43 | .TP 44 | .BI \-\-startblock= " start\-block " 45 | Specify the block location where the UDF filesystem starts. It is used for 46 | calculating the block location of the Volume Recognition Sequence (32 kB after 47 | the start block) and the first Anchor Volume Descriptor Pointer (256 blocks 48 | after the start block). 49 | 50 | Normally start block is \fI0\fP, but for Multisession UDF optical discs it is 51 | the block location where the last session of Multisession UDF disc starts. 52 | 53 | If omitted, \fBudfinfo\fP for optical disc tries to detect start block of the 54 | last session from disc Table Of Contents. Otherwise value \fI0\fP is used. 55 | 56 | For accessing some previous session of Multisession UDF optical disc, it is 57 | required to specify correct block where that previous session starts. And also 58 | to specify where that session ends via \fB\-\-lastblock\fP option. 59 | 60 | For Multisession UDF disc images stored in file there is no way to detect where 61 | the last session starts and therefore it is necessary to specify the correct 62 | start block location manually from the original optical disc Table Of Contents. 63 | 64 | (Option available since udfinfo 2.3) 65 | 66 | .TP 67 | .BI \-\-lastblock= " last\-block " 68 | Specify the block location where the UDF filesystem ends. It is used for 69 | calculating the block location of second and third Anchor Volume Descriptor 70 | Pointer (256 blocks prior the last block and the last block itself). 71 | 72 | Normally last block is \fInumber of disk blocks minus one\fP, but for 73 | Multisession UDF optical discs when reading different session than the last one 74 | (specified by \fB\-\-startblock\fP) it is the block location where the specified 75 | session ends. 76 | 77 | If omitted, \fBudfinfo\fP for optical disc tried to detect the last recorded 78 | block with fallback to the last block of device or disk file image. 79 | 80 | For accessing some previous session of Multisession UDF optical disc, it is 81 | required to specify correct value for both \fB\-\-startblock\fP and 82 | \fB\-\-lastblock\fP options. 83 | 84 | (Option available since udfinfo 2.3) 85 | 86 | .TP 87 | .BI \-\-vatblock= " vat\-block " 88 | Specify the block location of the Virtual Allocation Table. Virtual Allocation 89 | Table is present only on UDF disks with Virtual Partition Map and must be at the 90 | last written/recorded disk block. 91 | 92 | If omitted, \fBudfinfo\fP for optical disc tries to detect the last recorded 93 | block with fallback to the last block of block device or disk file image or 94 | block specified by \fB\-\-lastblock\fP. In most cases, this fallback does not 95 | have to work and for disk file images with Virtual Allocation Table it is 96 | necessary to specify the correct location. 97 | 98 | Virtual Allocation Table contains locations of UDF disk blocks needed to read 99 | data storage, determinate used and free space blocks, read File Set Identifier 100 | and calculate Windows-specific Volume Serial Number. Also, it contains Logical 101 | Volume Identifier and overwrite previously stored in Logical Volume Descriptor. 102 | 103 | .TP 104 | .B \-\-locale 105 | Encode UDF string identifiers on output according to current locale settings 106 | (default). 107 | 108 | .TP 109 | .B \-\-u8 110 | Encode UDF string identifiers on output to 8-bit OSTA Compressed Unicode format 111 | without leading Compression ID byte, which is equivalent to Latin1 (ISO-8859-1) 112 | encoding. This will work only for strings which all Unicode code points are 113 | below U+100. 114 | 115 | .TP 116 | .B \-\-u16 117 | Encode UDF string identifiers on output to 16-bit OSTA Compressed Unicode 118 | format without leading Compression ID byte, which is equivalent to UTF-16BE. 119 | 120 | .TP 121 | .B \-\-utf8 122 | Encode UDF string identifiers on output to UTF-8. 123 | 124 | .SH "EXIT STATUS" 125 | \fBudfinfo\fP returns 0 if successful, non-zero if there are problems like a 126 | block device does not contain UDF filesystem. 127 | 128 | .SH "OUTPUT FORMAT" 129 | First part of the \fBudfinfo\fP standard output contains information in 130 | \fIkey\fP=\fIvalue\fP format. List of all keys with their meaning are in the 131 | following table: 132 | 133 | .RS 134 | .TP 1.7i 135 | .I filename 136 | File name of the selected block device or disk file image 137 | .TP 138 | .I label 139 | label is an alias for \fIlvid\fP, see \fBudflabel\fP(8) section 140 | \fBUDF LABEL AND UUID\fP 141 | .TP 142 | .I uuid 143 | UUID are first 16 hexadecimal lowercase digits of \fIfullvsid\fP, but see 144 | \fBudflabel\fP(8) section \fBUDF LABEL AND UUID\fP 145 | .TP 146 | .I lvid 147 | UDF Logical Volume Identifier stored in UDF Logical Volume Descriptor 148 | .TP 149 | .I vid 150 | UDF Volume Identifier stored in UDF Primary Volume Descriptor 151 | .TP 152 | .I vsid 153 | \fIfullvsid\fP after \fIuuid\fP part, typically 17.\(en127. character 154 | .TP 155 | .I fsid 156 | UDF File Set Identifier stored in UDF File Set Descriptor 157 | .TP 158 | .I fullvsid 159 | UDF Volume Set Identifier stored in UDF Primary Volume Descriptor 160 | .TP 161 | .I owner 162 | UDF Logical Volume Info1 stored in UDF Implementation Use Volume Descriptor, 163 | represents Owner name, person creating the medium or filesystem 164 | (available since udfinfo 2.3) 165 | .TP 166 | .I organization 167 | UDF Logical Volume Info2 stored in UDF Implementation Use Volume Descriptor, 168 | represents Organization name responsible for creating the medium or filesystem 169 | (available since udfinfo 2.3) 170 | .TP 171 | .I contact 172 | UDF Logical Volume Info3 stored in UDF Implementation Use Volume Descriptor, 173 | represents Contact information for the medium or filesystem 174 | (available since udfinfo 2.3) 175 | .TP 176 | .I appid 177 | UDF Application Identifier stored in UDF Primary Volume Descriptor, identifies 178 | application that created medium or filesystem 179 | (available since udfinfo 2.3) 180 | .TP 181 | .I impid 182 | UDF Developer Identifier stored in UDF Implementation Identifier of UDF Primary 183 | Volume Descriptor, uniquely identifies the implementation which created medium 184 | or filesystem 185 | (available since udfinfo 2.3) 186 | .TP 187 | .I winserialnum 188 | Windows-specific Volume Serial Number 189 | .TP 190 | .I blocksize 191 | UDF block size 192 | .TP 193 | .I blocks 194 | Number of all blocks on the selected block device or disk file image 195 | .TP 196 | .I usedblocks 197 | Number of used space blocks on UDF disk for data storage 198 | .TP 199 | .I freeblocks 200 | Number of free space blocks on UDF disk for data storage 201 | .TP 202 | .I behindblocks 203 | Number of blocks which are behind the last block used by UDF disk 204 | .TP 205 | .I numfiles 206 | Number of stored files on UDF disk 207 | .TP 208 | .I numdirs 209 | Number of stored directories on UDF disk 210 | .TP 211 | .I udfrev 212 | UDF revision needed for reading UDF disk 213 | .TP 214 | .I udfwriterev 215 | UDF revision needed for writing or modifying UDF disk 216 | .TP 217 | .I startblock 218 | Block location where the UDF filesystem starts (visible only when non-zero, 219 | available since udfinfo 2.3) 220 | .TP 221 | .I lastblock 222 | Block location where the UDF filesystem ends (visible only when it is not same 223 | as the last block on disk, available since udfinfo 2.3) 224 | .TP 225 | .I vatblock 226 | Block location of the UDF Virtual Allocation Table (visible only when available) 227 | .TP 228 | .I integrity 229 | UDF integrity of Logical Volume, one of: \fIopened\fP, \fIclosed\fP, 230 | \fIunknown\fP 231 | .TP 232 | .I accesstype 233 | UDF Access Type, one of: \fIoverwritable\fP, \fIrewritable\fP, \fIwriteonce\fP, 234 | \fIreadonly\fP, \fIpseudo\-overwritable\fP, \fIunknown\fP 235 | .TP 236 | .I softwriteprotect 237 | Status of UDF SoftWriteProtect flag, either \fIyes\fP or \fIno\fP 238 | (available since udfinfo 2.2) 239 | .TP 240 | .I hardwriteprotect 241 | Status of UDF HardWriteProtect flag, either \fIyes\fP or \fIno\fP 242 | (available since udfinfo 2.2) 243 | .RE 244 | 245 | When UDF integrity is not \fIclosed\fP it means that the UDF disk was not 246 | properly unmounted, is in an inconsistent state and needs repairing. 247 | 248 | When either \fIsoftwriteprotect\fP or \fIhardwriteprotect\fP flag is set then 249 | UDF disk should be treated as read-only. 250 | 251 | All UDF string identifiers are stored on UDF disk in Unicode, therefore they are 252 | locale or code page agnostic. Options \fB\-\-locale\fP, \fB\-\-u8\fP, 253 | \fB\-\-u16\fP and \fB\-\-utf8\fP controls how are identifiers encoded on output. 254 | 255 | All newline characters from the UDF string identifiers are removed, so it is 256 | guaranteed that the newline character is present only as a separator. 257 | 258 | Second part of the \fBudfinfo\fP standard output contains list of UDF block 259 | types stored on device, one per line in the following format: 260 | 261 | .RS 262 | start=\fIblock\-num\fP, blocks=\fIblock\-count\fP, type=\fIblock\-type\fP 263 | .RE 264 | 265 | With meaning that \fIblock\-type\fP starts at UDF block \fIblock\-num\fP and 266 | span \fIblock\-count\fP blocks on device. 267 | 268 | Windows-specific \fIVolume Serial Number\fP is a non-standard 32-bit checksum, 269 | calculated as four separate 8-bit XOR checksums of 512 bytes long UDF File Set 270 | Descriptor. Therefore, it cannot be set or changed as opposed to UUID which is 271 | 64-bit long. This non-standard checksum is used only by Windows systems 272 | (since Windows 98 era when it was introduced) and can be displayed on Windows 273 | systems by applications like \fBvol\fP, \fBdir\fP or \fBfsutil.exe\fP. 274 | 275 | .SH LIMITATIONS 276 | \fBudfinfo\fP prior to version 2.3 was unable to handle Multisession UDF discs 277 | correctly. It always printed only information about the first session (the 278 | oldest one) and not about the last session (the most recent). 279 | 280 | \fBudfinfo\fP prior to version 2.2 was unable to print Unicode strings with 281 | code points above U+FFFF correctly. 282 | 283 | \fBudfinfo\fP prior to version 2.2 was unable to read Metadata Partition. \ 284 | Therefore, determining used and free space blocks, reading File Set Identifier 285 | and calculating Windows-specific Volume Serial Number did not have to be 286 | available or correctly calculated for disks with UDF revisions higher than 2.01 287 | which had Metadata Partition. 288 | 289 | \fBudfinfo\fP prior to version 2.1 was unable to read Virtual Allocation Table 290 | stored outside of Information Control Block. Therefore above limitation applied 291 | also for some Write Once media. 292 | 293 | .SH AUTHOR 294 | .nf 295 | Pali Rohár 296 | .fi 297 | 298 | .SH AVAILABILITY 299 | \fBudfinfo\fP is part of the udftools package since version 2.0 and is available 300 | from https://github.com/pali/udftools/. 301 | 302 | .SH "SEE ALSO" 303 | \fBmkudffs\fP(8), \fBpktsetup\fP(8), \fBudflabel\fP(8), \fBcdrwtool\fP(1), 304 | \fBwrudf\fP(1) 305 | -------------------------------------------------------------------------------- /doc/wrudf.1: -------------------------------------------------------------------------------- 1 | .\" Text automatically generated by txt2man 2 | .TH wrudf 1 "udftools" "Linux Reference Manual" 3 | .SH NAME 4 | \fBwrudf \fP- Maintain a UDF filesystem. 5 | .SH SYNOPSIS 6 | .nf 7 | .fam C 8 | \fBwrudf\fP \fIdevice\fP 9 | \fBwrudf\fP \fB--help\fP | \fB-help\fP | \fB-h\fP 10 | .fam T 11 | .fi 12 | .fam T 13 | .fi 14 | .SH DESCRIPTION 15 | \fBwrudf\fP provides an interactive shell with operations on existing UDF filesystem: cp, rm, mkdir, rmdir, ls, cd. 16 | .SS COMMANDS 17 | .TP 18 | .B 19 | cp 20 | copy 21 | .TP 22 | .B 23 | rm 24 | remove 25 | .TP 26 | .B 27 | mkdir 28 | make directory 29 | .TP 30 | .B 31 | rmdir 32 | remove directory 33 | .TP 34 | .B 35 | lsc 36 | list files (Compact disc version) 37 | .TP 38 | .B 39 | lsh 40 | list files (Hard disc version) 41 | .TP 42 | .B 43 | cdc 44 | change working directory (Compact disc) 45 | .TP 46 | .B 47 | cdh 48 | change working directory (Hard disc) 49 | .TP 50 | .B 51 | quit 52 | quit \fBwrudf\fP 53 | .TP 54 | .B 55 | exit 56 | quit \fBwrudf\fP 57 | .SH AVAILABILITY 58 | \fBwrudf\fP is part of the udftools package and is available from https://github.com/pali/udftools/. 59 | .SH SEE ALSO 60 | \fBcdrwtool\fP(1), \fBmkudffs\fP(8), \fBpktsetup\fP(8) 61 | -------------------------------------------------------------------------------- /include/bswap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * bswap.h 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | #ifndef __BSWAP_H 24 | #define __BSWAP_H 25 | 26 | #include "config.h" 27 | 28 | #include 29 | #include 30 | 31 | #define constant_swap16(x) \ 32 | ((uint16_t)((((uint16_t)(x) & 0x00FFU) << 8) | \ 33 | (((uint16_t)(x) & 0xFF00U) >> 8))) 34 | 35 | #define constant_swap32(x) \ 36 | ((uint32_t)((((uint32_t)(x) & 0x000000FFU) << 24) | \ 37 | (((uint32_t)(x) & 0x0000FF00U) << 8) | \ 38 | (((uint32_t)(x) & 0x00FF0000U) >> 8) | \ 39 | (((uint32_t)(x) & 0xFF000000U) >> 24))) 40 | 41 | #define constant_swap64(x) \ 42 | ((uint64_t)((((uint64_t)(x) & 0x00000000000000FFULL) << 56) | \ 43 | (((uint64_t)(x) & 0x000000000000FF00ULL) << 40) | \ 44 | (((uint64_t)(x) & 0x0000000000FF0000ULL) << 24) | \ 45 | (((uint64_t)(x) & 0x00000000FF000000ULL) << 8) | \ 46 | (((uint64_t)(x) & 0x000000FF00000000ULL) >> 8) | \ 47 | (((uint64_t)(x) & 0x0000FF0000000000ULL) >> 24) | \ 48 | (((uint64_t)(x) & 0x00FF000000000000ULL) >> 40) | \ 49 | (((uint64_t)(x) & 0xFF00000000000000ULL) >> 56))) 50 | 51 | static inline uint16_t swap16(uint16_t x) 52 | { 53 | return ((uint16_t)((((uint16_t)(x) & 0x00FFU) << 8) | \ 54 | (((uint16_t)(x) & 0xFF00U) >> 8))); 55 | } 56 | 57 | static inline uint32_t swap32(uint32_t x) 58 | { 59 | return ((uint32_t)((((uint32_t)(x) & 0x000000FFU) << 24) | \ 60 | (((uint32_t)(x) & 0x0000FF00U) << 8) | \ 61 | (((uint32_t)(x) & 0x00FF0000U) >> 8) | \ 62 | (((uint32_t)(x) & 0xFF000000U) >> 24))); 63 | } 64 | 65 | static inline uint64_t swap64(uint64_t x) 66 | { 67 | return ((uint64_t)((((uint64_t)(x) & 0x00000000000000FFULL) << 56) | \ 68 | (((uint64_t)(x) & 0x000000000000FF00ULL) << 40) | \ 69 | (((uint64_t)(x) & 0x0000000000FF0000ULL) << 24) | \ 70 | (((uint64_t)(x) & 0x00000000FF000000ULL) << 8) | \ 71 | (((uint64_t)(x) & 0x000000FF00000000ULL) >> 8) | \ 72 | (((uint64_t)(x) & 0x0000FF0000000000ULL) >> 24) | \ 73 | (((uint64_t)(x) & 0x00FF000000000000ULL) >> 40) | \ 74 | (((uint64_t)(x) & 0xFF00000000000000ULL) >> 56))); 75 | } 76 | 77 | #define constant_swap16p(x) \ 78 | ((uint16_t)(((*(uint16_t *)(x) & 0x00FFU) << 8) | \ 79 | ((*(uint16_t *)(x) & 0xFF00U) >> 8))) 80 | 81 | #define constant_swap32p(x) \ 82 | ((uint32_t)(((*(uint32_t *)(x) & 0x000000FFU) << 24) | \ 83 | ((*(uint32_t *)(x) & 0x0000FF00U) << 8) | \ 84 | ((*(uint32_t *)(x) & 0x00FF0000U) >> 8) | \ 85 | ((*(uint32_t *)(x) & 0xFF000000U) >> 24))) 86 | 87 | #define constant_swap64p(x) \ 88 | ((uint64_t)(((*(uint64_t *)(x) & 0x00000000000000FFULL) << 56) | \ 89 | ((*(uint64_t *)(x) & 0x000000000000FF00ULL) << 40) | \ 90 | ((*(uint64_t *)(x) & 0x0000000000FF0000ULL) << 24) | \ 91 | ((*(uint64_t *)(x) & 0x00000000FF000000ULL) << 8) | \ 92 | ((*(uint64_t *)(x) & 0x000000FF00000000ULL) >> 8) | \ 93 | ((*(uint64_t *)(x) & 0x0000FF0000000000ULL) >> 24) | \ 94 | ((*(uint64_t *)(x) & 0x00FF000000000000ULL) >> 40) | \ 95 | ((*(uint64_t *)(x) & 0xFF00000000000000ULL) >> 56))) 96 | 97 | 98 | static inline uint16_t swap16p(uint16_t *x) 99 | { 100 | return ((uint16_t)(((*(uint16_t *)(x) & 0x00FFU) << 8) | \ 101 | ((*(uint16_t *)(x) & 0xFF00U) >> 8))); 102 | } 103 | 104 | static inline uint32_t swap32p(uint32_t *x) 105 | { 106 | return ((uint32_t)(((*(uint32_t *)(x) & 0x000000FFU) << 24) | \ 107 | ((*(uint32_t *)(x) & 0x0000FF00U) << 8) | \ 108 | ((*(uint32_t *)(x) & 0x00FF0000U) >> 8) | \ 109 | ((*(uint32_t *)(x) & 0xFF000000U) >> 24))); 110 | } 111 | 112 | static inline uint64_t swap64p(uint64_t *x) 113 | { 114 | return ((uint64_t)(((*(uint64_t *)(x) & 0x00000000000000FFULL) << 56) | \ 115 | ((*(uint64_t *)(x) & 0x000000000000FF00ULL) << 40) | \ 116 | ((*(uint64_t *)(x) & 0x0000000000FF0000ULL) << 24) | \ 117 | ((*(uint64_t *)(x) & 0x00000000FF000000ULL) << 8) | \ 118 | ((*(uint64_t *)(x) & 0x000000FF00000000ULL) >> 8) | \ 119 | ((*(uint64_t *)(x) & 0x0000FF0000000000ULL) >> 24) | \ 120 | ((*(uint64_t *)(x) & 0x00FF000000000000ULL) >> 40) | \ 121 | ((*(uint64_t *)(x) & 0xFF00000000000000ULL) >> 56))); 122 | } 123 | 124 | #ifdef WORDS_BIGENDIAN 125 | 126 | #define le16_to_cpu(x) (__builtin_constant_p(x) ? \ 127 | constant_swap16(x) : \ 128 | swap16(x)) 129 | 130 | #define le32_to_cpu(x) (__builtin_constant_p(x) ? \ 131 | constant_swap32(x) : \ 132 | swap32(x)) 133 | 134 | #define le64_to_cpu(x) (__builtin_constant_p(x) ? \ 135 | constant_swap64(x) : \ 136 | swap64(x)) 137 | 138 | 139 | #define constant_le16_to_cpu(x) constant_swap16((x)) 140 | #define constant_le32_to_cpu(x) constant_swap32((x)) 141 | #define constant_le64_to_cpu(x) constant_swap64((x)) 142 | 143 | #define le16_to_cpup(x) (__builtin_constant_p(x) ? \ 144 | constant_swap16p(x) : \ 145 | swap16p(x)) 146 | 147 | #define le32_to_cpup(x) (__builtin_constant_p(x) ? \ 148 | constant_swap32p(x) : \ 149 | swap32p(x)) 150 | 151 | #define le64_to_cpup(x) (__builtin_constant_p(x) ? \ 152 | constant_swap64p(x) : \ 153 | swap64p(x)) 154 | 155 | #define constant_le16_to_cpup(x) constant_swap16p((x)) 156 | #define constant_le32_to_cpup(x) constant_swap32p((x)) 157 | #define constant_le64_to_cpup(x) constant_swap64p((x)) 158 | 159 | #define be16_to_cpu(x) ((uint16_t)(x)) 160 | #define be32_to_cpu(x) ((uint32_t)(x)) 161 | #define be64_to_cpu(x) ((uint64_t)(x)) 162 | 163 | #define constant_be16_to_cpu(x) ((uint16_t)(x)) 164 | #define constant_be32_to_cpu(x) ((uint32_t)(x)) 165 | #define constant_be64_to_cpu(x) ((uint64_t)(x)) 166 | 167 | #define be16_to_cpup(x) (*(uint16_t *)(x)) 168 | #define be32_to_cpup(x) (*(uint32_t *)(x)) 169 | #define be64_to_cpup(x) (*(uint64_t *)(x)) 170 | 171 | #define constant_be16_to_cpup(x) (*(uint16_t *)(x)) 172 | #define constant_be32_to_cpup(x) (*(uint32_t *)(x)) 173 | #define constant_be64_to_cpup(x) (*(uint64_t *)(x)) 174 | 175 | #else /* WORDS_BIGENDIAN */ 176 | 177 | #define le16_to_cpu(x) ((uint16_t)(x)) 178 | #define le32_to_cpu(x) ((uint32_t)(x)) 179 | #define le64_to_cpu(x) ((uint64_t)(x)) 180 | 181 | #define constant_le16_to_cpu(x) ((uint16_t)(x)) 182 | #define constant_le32_to_cpu(x) ((uint32_t)(x)) 183 | #define constant_le64_to_cpu(x) ((uint64_t)(x)) 184 | 185 | #define le16_to_cpup(x) (*(uint16_t *)(x)) 186 | #define le32_to_cpup(x) (*(uint32_t *)(x)) 187 | #define le64_to_cpup(x) (*(uint64_t *)(x)) 188 | 189 | #define constant_le16_to_cpup(x) (*(uint16_t *)(x)) 190 | #define constant_le32_to_cpup(x) (*(uint32_t *)(x)) 191 | #define constant_le64_to_cpup(x) (*(uint64_t *)(x)) 192 | 193 | #define be16_to_cpu(x) (__builtin_constant_p(x) ? \ 194 | constant_swap16(x) : \ 195 | swap16(x)) 196 | 197 | #define be32_to_cpu(x) (__builtin_constant_p(x) ? \ 198 | constant_swap32(x) : \ 199 | swap32(x)) 200 | 201 | #define be64_to_cpu(x) (__builtin_constant_p(x) ? \ 202 | constant_swap64(x) : \ 203 | swap64(x)) 204 | 205 | 206 | #define constant_be16_to_cpu(x) constant_swap16((x)) 207 | #define constant_be32_to_cpu(x) constant_swap32((x)) 208 | #define constant_be64_to_cpu(x) constant_swap64((x)) 209 | 210 | #define be16_to_cpup(x) (__builtin_constant_p(x) ? \ 211 | constant_swap16p(x) : \ 212 | swap16p(x)) 213 | 214 | #define be32_to_cpup(x) (__builtin_constant_p(x) ? \ 215 | constant_swap32p(x) : \ 216 | swap32p(x)) 217 | 218 | #define be64_to_cpup(x) (__builtin_constant_p(x) ? \ 219 | constant_swap64p(x) : \ 220 | swap64p(x)) 221 | 222 | #define constant_be16_to_cpup(x) constant_swap16p((x)) 223 | #define constant_be32_to_cpup(x) constant_swap32p((x)) 224 | #define constant_be64_to_cpup(x) constant_swap64p((x)) 225 | 226 | #endif /* WORDS_BIGENDIAN */ 227 | 228 | #define cpu_to_le16(x) le16_to_cpu((x)) 229 | #define cpu_to_le32(x) le32_to_cpu((x)) 230 | #define cpu_to_le64(x) le64_to_cpu((x)) 231 | 232 | #define constant_cpu_to_le16(x) constant_le16_to_cpu((x)) 233 | #define constant_cpu_to_le32(x) constant_le32_to_cpu((x)) 234 | #define constant_cpu_to_le64(x) constant_le64_to_cpu((x)) 235 | 236 | #define cpu_to_le16p(x) le16_to_cpup((x)) 237 | #define cpu_to_le32p(x) le32_to_cpup((x)) 238 | #define cpu_to_le64p(x) le64_to_cpup((x)) 239 | 240 | #define constant_cpu_to_le16p(x) constant_le16_to_cpup((x)) 241 | #define constant_cpu_to_le32p(x) constant_le32_to_cpup((x)) 242 | #define constant_cpu_to_le64p(x) constant_le64_to_cpup((x)) 243 | 244 | #define cpu_to_be16(x) be16_to_cpu((x)) 245 | #define cpu_to_be32(x) be32_to_cpu((x)) 246 | #define cpu_to_be64(x) be64_to_cpu((x)) 247 | 248 | #define constant_cpu_to_be16(x) constant_be16_to_cpu((x)) 249 | #define constant_cpu_to_be32(x) constant_be32_to_cpu((x)) 250 | #define constant_cpu_to_be64(x) constant_be64_to_cpu((x)) 251 | 252 | #define cpu_to_be16p(x) be16_to_cpup((x)) 253 | #define cpu_to_be32p(x) be32_to_cpup((x)) 254 | #define cpu_to_be64p(x) be64_to_cpup((x)) 255 | 256 | #define constant_cpu_to_be16p(x) constant_be16_to_cpup((x)) 257 | #define constant_cpu_to_be32p(x) constant_be32_to_cpup((x)) 258 | #define constant_cpu_to_be64p(x) constant_be64_to_cpup((x)) 259 | 260 | #endif /* __BSWAP_H */ 261 | -------------------------------------------------------------------------------- /include/libudffs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libudffs.h 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * Copyright (c) 2014-2021 Pali Rohár 6 | * All rights reserved. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | /** 25 | * @file 26 | * libudffs defines and structure definitions 27 | */ 28 | 29 | #ifndef __LIBUDFFS_H 30 | #define __LIBUDFFS_H 31 | 32 | #include 33 | 34 | #include "ecma_167.h" 35 | #include "osta_udf.h" 36 | #include "bswap.h" 37 | 38 | #define FLAG_FREED_BITMAP 0x00000001 39 | #define FLAG_FREED_TABLE 0x00000002 40 | #define FLAG_UNALLOC_BITMAP 0x00000004 41 | #define FLAG_UNALLOC_TABLE 0x00000008 42 | #define FLAG_SPACE_BITMAP (FLAG_FREED_BITMAP|FLAG_UNALLOC_BITMAP) 43 | #define FLAG_SPACE_TABLE (FLAG_FREED_TABLE|FLAG_UNALLOC_TABLE) 44 | #define FLAG_SPACE (FLAG_SPACE_BITMAP|FLAG_SPACE_TABLE) 45 | 46 | #define FLAG_LOCALE 0x00000010 47 | #define FLAG_UNICODE8 0x00000020 48 | #define FLAG_UNICODE16 0x00000040 49 | #define FLAG_UTF8 0x00000080 50 | #define FLAG_CHARSET (FLAG_LOCALE|FLAG_UNICODE8|FLAG_UNICODE16|FLAG_UTF8) 51 | 52 | #define FLAG_STRATEGY4096 0x00000100 53 | #define FLAG_BLANK_TERMINAL 0x00000200 54 | 55 | #define FLAG_CLOSED 0x00000800 56 | #define FLAG_VAT 0x00001000 57 | 58 | #define FLAG_EFE 0x00002000 59 | 60 | #define FLAG_NO_WRITE 0x00004000 61 | 62 | #define FLAG_BOOTAREA_PRESERVE 0x00010000 63 | #define FLAG_BOOTAREA_ERASE 0x00020000 64 | #define FLAG_BOOTAREA_MBR 0x00040000 65 | #define FLAG_BOOTAREA_MASK (FLAG_BOOTAREA_PRESERVE|FLAG_BOOTAREA_ERASE|FLAG_BOOTAREA_MBR) 66 | 67 | struct udf_extent; 68 | struct udf_desc; 69 | struct udf_data; 70 | 71 | enum udf_space_type 72 | { 73 | RESERVED = 0x0001, /* Reserved Space */ 74 | VRS = 0x0002, /* Volume Recognition Sequence */ 75 | ANCHOR = 0x0004, /* Anchor */ 76 | MVDS = 0x0008, /* Main Volume Descriptor Sequence */ 77 | RVDS = 0x0010, /* Reserve Volume Descriptor Sequence */ 78 | LVID = 0x0020, /* Logical Volume Integrity Descriptor */ 79 | STABLE = 0x0040, /* Sparing Table */ 80 | SSPACE = 0x0080, /* Sparing Space */ 81 | PSPACE = 0x0100, /* Partition Space */ 82 | USPACE = 0x0200, /* Unallocated Space */ 83 | BAD = 0x0400, /* Bad Blocks */ 84 | MBR = 0x0800, /* MBR Boot Area */ 85 | UDF_SPACE_TYPE_SIZE = 12, 86 | }; 87 | 88 | struct udf_sizing 89 | { 90 | uint32_t align; 91 | uint32_t numSize; 92 | uint32_t denomSize; 93 | uint32_t minSize; 94 | }; 95 | 96 | enum udf_alloc_type 97 | { 98 | VDS_SIZE, 99 | LVID_SIZE, 100 | STABLE_SIZE, 101 | SSPACE_SIZE, 102 | PSPACE_SIZE, 103 | UDF_ALLOC_TYPE_SIZE, 104 | }; 105 | 106 | struct udf_disc 107 | { 108 | uint16_t udf_rev; 109 | uint16_t udf_write_rev; 110 | uint32_t blocksize; 111 | uint32_t blocks; 112 | uint32_t flags; 113 | unsigned int blkssz; 114 | uint64_t blksize; 115 | uint32_t num_files; 116 | uint32_t num_dirs; 117 | uint32_t free_space_blocks; 118 | uint32_t total_space_blocks; 119 | 120 | uint32_t uid; 121 | uint32_t gid; 122 | uint16_t mode; 123 | 124 | struct udf_sizing sizing[UDF_ALLOC_TYPE_SIZE]; 125 | 126 | int (*write)(struct udf_disc *, struct udf_extent *); 127 | void *write_data; 128 | 129 | struct volStructDesc *udf_vrs[3]; 130 | struct anchorVolDescPtr *udf_anchor[3]; 131 | struct primaryVolDesc *udf_pvd[2]; 132 | struct logicalVolDesc *udf_lvd[2]; 133 | struct partitionDesc *udf_pd[2]; 134 | struct partitionDesc *udf_pd2[2]; 135 | struct unallocSpaceDesc *udf_usd[2]; 136 | struct impUseVolDesc *udf_iuvd[2]; 137 | struct terminatingDesc *udf_td[2]; 138 | struct logicalVolIntegrityDesc *udf_lvid; 139 | 140 | struct sparingTable *udf_stable[4]; 141 | 142 | uint32_t start_block; 143 | uint32_t last_block; 144 | 145 | uint32_t vat_block; 146 | uint32_t *vat; 147 | uint64_t vat_entries; 148 | 149 | short_ad *metadata_filemap[2]; 150 | uint32_t metadata_filemap_count[2]; 151 | 152 | struct fileSetDesc *udf_fsd; 153 | 154 | struct udf_extent *head; 155 | struct udf_extent *tail; 156 | }; 157 | 158 | struct udf_extent 159 | { 160 | enum udf_space_type space_type; 161 | uint32_t start; 162 | uint32_t blocks; 163 | 164 | struct udf_desc *head; 165 | struct udf_desc *tail; 166 | 167 | struct udf_extent *next; 168 | struct udf_extent *prev; 169 | }; 170 | 171 | struct udf_desc 172 | { 173 | uint16_t ident; 174 | uint32_t offset; 175 | uint64_t length; 176 | struct udf_data *data; 177 | 178 | struct udf_desc *next; 179 | struct udf_desc *prev; 180 | }; 181 | 182 | struct udf_data 183 | { 184 | uint64_t length; 185 | void *buffer; 186 | struct udf_data *next; 187 | struct udf_data *prev; 188 | }; 189 | 190 | #define MBR_PARTITION_NOT_BOOTABLE 0x00 191 | #define MBR_PARTITION_TYPE_IFS 0x07 /* Installable File System (IFS), see: https://serverfault.com/a/829172 */ 192 | 193 | struct mbr_partition 194 | { 195 | uint8_t boot_indicator; 196 | uint8_t starting_chs[3]; 197 | uint8_t partition_type; 198 | uint8_t ending_chs[3]; 199 | uint32_t starting_lba; 200 | uint32_t size_in_lba; 201 | } __attribute__ ((packed, may_alias)); 202 | 203 | #define MBR_BOOT_SIGNATURE 0xAA55 204 | 205 | struct mbr 206 | { 207 | unsigned char boot_code[440]; 208 | uint32_t disk_signature; 209 | uint16_t unknown; 210 | struct mbr_partition partitions[4]; 211 | uint16_t boot_signature; 212 | } __attribute__ ((packed, may_alias)); 213 | 214 | /* crc.c */ 215 | extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t); 216 | 217 | /* extent.c */ 218 | struct udf_extent *next_extent(struct udf_extent *, enum udf_space_type); 219 | uint32_t next_extent_size(struct udf_disc *, struct udf_extent *, enum udf_space_type, uint32_t, uint32_t); 220 | uint32_t find_next_extent_size(struct udf_disc *, uint32_t, enum udf_space_type, uint32_t, uint32_t); 221 | struct udf_extent *prev_extent(struct udf_extent *, enum udf_space_type); 222 | uint32_t prev_extent_size(struct udf_extent *, enum udf_space_type, uint32_t, uint32_t); 223 | struct udf_extent *find_extent(struct udf_disc *, uint32_t); 224 | struct udf_extent *set_extent(struct udf_disc *, enum udf_space_type, uint32_t,uint32_t); 225 | void remove_extent(struct udf_disc *, struct udf_extent *); 226 | struct udf_desc *next_desc(struct udf_desc *, uint16_t); 227 | struct udf_desc *find_desc(struct udf_extent *, uint32_t); 228 | struct udf_desc *set_desc(struct udf_extent *, uint16_t, uint32_t, uint32_t, struct udf_data *); 229 | void append_data(struct udf_desc *, struct udf_data *); 230 | struct udf_data *alloc_data(void *, int); 231 | 232 | /* unicode.c */ 233 | extern size_t decode_utf8(const dchars *, char *, size_t, size_t); 234 | extern size_t encode_utf8(dchars *, const char *, size_t); 235 | extern size_t decode_locale(const dchars *, char *, size_t, size_t); 236 | extern size_t encode_locale(dchars *, const char *, size_t); 237 | extern size_t decode_string(struct udf_disc *, const dstring *, char *, size_t, size_t); 238 | extern size_t encode_string(struct udf_disc *, dstring *, const char *, size_t); 239 | 240 | /* misc.c */ 241 | extern const char *appname; 242 | size_t gen_uuid_from_vol_set_ident(char[17], const dstring *, size_t); 243 | uint32_t strtou32(const char *, int, int *); 244 | uint16_t strtou16(const char *, int, int *); 245 | uint32_t randu32(void); 246 | ssize_t read_nointr(int, void *, size_t); 247 | ssize_t write_nointr(int, const void *, size_t); 248 | 249 | #endif /* __LIBUDFFS_H */ 250 | -------------------------------------------------------------------------------- /include/osta_udf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * osta_udf.h 3 | * 4 | * This file is based on OSTA UDF(tm) 2.60 (March 1, 2005) 5 | * http://www.osta.org 6 | * 7 | * Copyright (c) 2001-2004 Ben Fennema 8 | * Copyright (c) 2017-2021 Pali Rohár 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions, and the following disclaimer, 16 | * without modification. 17 | * 2. The name of the author may not be used to endorse or promote products 18 | * derived from this software without specific prior written permission. 19 | * 20 | * Alternatively, this software may be distributed under the terms of the 21 | * GNU Public License ("GPL"). 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 27 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 | * SUCH DAMAGE. 34 | */ 35 | 36 | /** 37 | * @file 38 | * OSTA-UDF defines and structure definitions 39 | */ 40 | 41 | #include "ecma_167.h" 42 | 43 | #ifndef _OSTA_UDF_H 44 | #define _OSTA_UDF_H 1 45 | 46 | /* OSTA CS0 Charspec (UDF 2.60 2.1.2) */ 47 | #define UDF_CHAR_SET_TYPE CHARSPEC_TYPE_CS0 48 | #define UDF_CHAR_SET_INFO "OSTA Compressed Unicode" 49 | 50 | /* Entity Identifier (UDF 2.60 2.1.5) */ 51 | /* Identifiers (UDF 2.60 2.1.5.2) */ 52 | /* Implementation Use Extended Attribute (UDF 2.60 3.3.4.5) */ 53 | /* Virtual Allocation Table (UDF 1.50 2.2.10) */ 54 | /* Logical Volume Extended Information (UDF 1.50 Errata, DCN 5003, 3.3.4.5.1.3) */ 55 | /* OS2EA (UDF 1.50 3.3.4.5.3.1) */ 56 | /* MacUniqueIDTable (UDF 1.50 3.3.4.5.4.3) */ 57 | /* MacResourceFork (UDF 1.50 3.3.4.5.4.4) */ 58 | #define UDF_ID_COMPLIANT "*OSTA UDF Compliant" 59 | #define UDF_ID_LV_INFO "*UDF LV Info" 60 | #define UDF_ID_FREE_EA "*UDF FreeEASpace" 61 | #define UDF_ID_FREE_APP_EA "*UDF FreeAppEASpace" 62 | #define UDF_ID_DVD_CGMS "*UDF DVD CGMS Info" 63 | #define UDF_ID_VAT_LVEXTENSION "*UDF VAT LVExtension" 64 | #define UDF_ID_OS2_EA "*UDF OS/2 EA" 65 | #define UDF_ID_OS2_EA_LENGTH "*UDF OS/2 EALength" 66 | #define UDF_ID_MAC_VOLUME "*UDF Mac VolumeInfo" 67 | #define UDF_ID_MAC_FINDER "*UDF Mac FinderInfo" 68 | #define UDF_ID_MAC_UNIQUE "*UDF Mac UniqueIDTable" 69 | #define UDF_ID_MAC_RESOURCE "*UDF Mac ResourceFork" 70 | #define UDF_ID_OS400_DIRINFO "*UDF OS/400 DirInfo" 71 | #define UDF_ID_VIRTUAL "*UDF Virtual Partition" 72 | #define UDF_ID_SPARABLE "*UDF Sparable Partition" 73 | #define UDF_ID_ALLOC "*UDF Virtual Alloc Tbl" 74 | #define UDF_ID_SPARING "*UDF Sparing Table" 75 | #define UDF_ID_METADATA "*UDF Metadata Partition" 76 | 77 | /* Identifier Suffix (UDF 2.60 2.1.5.3) */ 78 | #define DOMAIN_FLAGS_HARD_WRITE_PROTECT 0x01 79 | #define DOMAIN_FLAGS_SOFT_WRITE_PROTECT 0x02 80 | 81 | struct domainIdentSuffix 82 | { 83 | uint16_t UDFRevision; 84 | uint8_t domainFlags; 85 | uint8_t reserved[5]; 86 | } __attribute__ ((packed, may_alias)); 87 | 88 | struct UDFIdentSuffix 89 | { 90 | uint16_t UDFRevision; 91 | uint8_t OSClass; 92 | uint8_t OSIdentifier; 93 | uint8_t reserved[4]; 94 | } __attribute__ ((packed, may_alias)); 95 | 96 | struct impIdentSuffix 97 | { 98 | uint8_t OSClass; 99 | uint8_t OSIdentifier; 100 | uint8_t impUse[6]; 101 | } __attribute__ ((packed, may_alias)); 102 | 103 | struct appIdentSuffix 104 | { 105 | uint8_t impUse[8]; 106 | } __attribute__ ((packed, may_alias)); 107 | 108 | /* Logical Volume Integrity Descriptor (UDF 2.60 2.2.6) */ 109 | /* Implementation Use (UDF 2.60 2.2.6.4) */ 110 | struct logicalVolIntegrityDescImpUse 111 | { 112 | regid impIdent; 113 | uint32_t numFiles; 114 | uint32_t numDirs; 115 | uint16_t minUDFReadRev; 116 | uint16_t minUDFWriteRev; 117 | uint16_t maxUDFWriteRev; 118 | uint8_t impUse[]; 119 | } __attribute__ ((packed, may_alias)); 120 | 121 | /* Implementation Use Volume Descriptor (UDF 2.60 2.2.7) */ 122 | /* Implementation Use (UDF 2.60 2.2.7.2) */ 123 | struct impUseVolDescImpUse 124 | { 125 | charspec LVICharset; 126 | dstring logicalVolIdent[128]; 127 | dstring LVInfo1[36]; 128 | dstring LVInfo2[36]; 129 | dstring LVInfo3[36]; 130 | regid impIdent; 131 | uint8_t impUse[128]; 132 | } __attribute__ ((packed, may_alias)); 133 | 134 | struct udfPartitionMap2 135 | { 136 | uint8_t partitionMapType; 137 | uint8_t partitionMapLength; 138 | uint8_t reserved1[2]; 139 | regid partIdent; 140 | uint16_t volSeqNum; 141 | uint16_t partitionNum; 142 | } __attribute__ ((packed, may_alias)); 143 | 144 | /* Virtual Partition Map (UDF 2.60 2.2.8) */ 145 | struct virtualPartitionMap 146 | { 147 | uint8_t partitionMapType; 148 | uint8_t partitionMapLength; 149 | uint8_t reserved1[2]; 150 | regid partIdent; 151 | uint16_t volSeqNum; 152 | uint16_t partitionNum; 153 | uint8_t reserved2[24]; 154 | } __attribute__ ((packed, may_alias)); 155 | 156 | /* Sparable Partition Map (UDF 2.60 2.2.9) */ 157 | struct sparablePartitionMap 158 | { 159 | uint8_t partitionMapType; 160 | uint8_t partitionMapLength; 161 | uint8_t reserved1[2]; 162 | regid partIdent; 163 | uint16_t volSeqNum; 164 | uint16_t partitionNum; 165 | uint16_t packetLength; 166 | uint8_t numSparingTables; 167 | uint8_t reserved2[1]; 168 | uint32_t sizeSparingTable; 169 | uint32_t locSparingTable[4]; 170 | } __attribute__ ((packed, may_alias)); 171 | 172 | /* Metadata Partition Map (UDF 2.60 2.2.10) */ 173 | struct metadataPartitionMap 174 | { 175 | uint8_t partitionMapType; 176 | uint8_t partitionMapLength; 177 | uint8_t reserved1[2]; 178 | regid partIdent; 179 | uint16_t volSeqNum; 180 | uint16_t partitionNum; 181 | uint32_t metadataFileLoc; 182 | uint32_t metadataMirrorFileLoc; 183 | uint32_t metadataBitmapFileLoc; 184 | uint32_t allocUnitSize; 185 | uint16_t alignUnitSize; 186 | uint8_t flags; 187 | uint8_t reserved2[5]; 188 | } __attribute__ ((packed, may_alias)); 189 | 190 | /* Virtual Allocation Table (UDF 1.5 2.2.10) */ 191 | struct virtualAllocationTable15 192 | { 193 | /* uint32_t vatEntry[0]; */ 194 | regid vatIdent; 195 | uint32_t previousVATICBLoc; 196 | } __attribute__ ((packed, may_alias)); 197 | 198 | #define ICBTAG_FILE_TYPE_VAT15 0x00U 199 | 200 | /* Virtual Allocation Table (UDF 2.60 2.2.11) */ 201 | struct virtualAllocationTable20 202 | { 203 | uint16_t lengthHeader; 204 | uint16_t lengthImpUse; 205 | dstring logicalVolIdent[128]; 206 | uint32_t previousVATICBLoc; 207 | uint32_t numFiles; 208 | uint32_t numDirs; 209 | uint16_t minUDFReadRev; 210 | uint16_t minUDFWriteRev; 211 | uint16_t maxUDFWriteRev; 212 | uint16_t reserved; 213 | uint8_t impUse[]; 214 | /* uint32_t vatEntry[0]; */ 215 | } __attribute__ ((packed, may_alias)); 216 | 217 | #define ICBTAG_FILE_TYPE_VAT20 0xF8U 218 | 219 | /* Sparing Table (UDF 2.60 2.2.12) */ 220 | struct sparingEntry 221 | { 222 | uint32_t origLocation; 223 | uint32_t mappedLocation; 224 | } __attribute__ ((packed, may_alias)); 225 | 226 | struct sparingTable 227 | { 228 | tag descTag; 229 | regid sparingIdent; 230 | uint16_t reallocationTableLen; 231 | uint16_t reserved; 232 | uint32_t sequenceNum; 233 | struct sparingEntry 234 | mapEntry[]; 235 | } __attribute__ ((packed, may_alias)); 236 | 237 | /* Metadata File (and Metadata Mirror File) (UDF 2.60 2.2.13.1) */ 238 | #define ICBTAG_FILE_TYPE_MAIN 0xFA 239 | #define ICBTAG_FILE_TYPE_MIRROR 0xFB 240 | #define ICBTAG_FILE_TYPE_BITMAP 0xFC 241 | 242 | /* struct long_ad ICB - ADImpUse (UDF 2.60 2.2.4.3) */ 243 | struct allocDescImpUse 244 | { 245 | uint16_t flags; 246 | uint8_t impUse[4]; 247 | } __attribute__ ((packed, may_alias)); 248 | 249 | #define AD_IU_EXT_ERASED 0x0001 250 | 251 | /* Strategy Type (UDF 2.60 6.6) */ 252 | #define ICBTAG_STRATEGY_TYPE_4096 4096 253 | 254 | /* Real-Time Files (UDF 2.60 6.11) */ 255 | #define ICBTAG_FILE_TYPE_REALTIME 0xF9U 256 | 257 | /* Implementation Use Extended Attribute (UDF 2.60 3.3.4.5) */ 258 | /* FreeEASpace (UDF 2.60 3.3.4.5.1.1) */ 259 | struct freeEaSpace 260 | { 261 | uint16_t headerChecksum; 262 | uint8_t freeEASpace[]; 263 | } __attribute__ ((packed, may_alias)); 264 | 265 | /* DVD Copyright Management Information (UDF 2.60 3.3.4.5.1.2) */ 266 | struct DVDCopyrightImpUse 267 | { 268 | uint16_t headerChecksum; 269 | uint8_t CGMSInfo; 270 | uint8_t dataType; 271 | uint8_t protectionSystemInfo[4]; 272 | } __attribute__ ((packed, may_alias)); 273 | 274 | /* Logical Volume Extended Information (UDF 1.50 Errata, DCN 5003, 3.3.4.5.1.3) */ 275 | struct LVExtensionEA 276 | { 277 | uint16_t headerChecksum; 278 | uint64_t verificationID; 279 | uint32_t numFiles; 280 | uint32_t numDirs; 281 | dstring logicalVolIdent[128]; 282 | } __attribute__ ((packed, may_alias)); 283 | 284 | /* Application Use Extended Attribute (UDF 2.60 3.3.4.6) */ 285 | /* FreeAppEASpace (UDF 2.60 3.3.4.6.1) */ 286 | struct freeAppEASpace 287 | { 288 | uint16_t headerChecksum; 289 | uint8_t freeEASpace[]; 290 | } __attribute__ ((packed, may_alias)); 291 | 292 | /* UDF Defined System Stream (UDF 2.60 3.3.7) */ 293 | #define UDF_ID_UNIQUE_ID "*UDF Unique ID Mapping Data" 294 | #define UDF_ID_NON_ALLOC "*UDF Non-Allocatable Space" 295 | #define UDF_ID_POWER_CAL "*UDF Power Cal Table" 296 | #define UDF_ID_BACKUP "*UDF Backup" 297 | 298 | /* UDF Defined Non-System Streams (UDF 2.60 3.3.8) */ 299 | #define UDF_ID_MAC_RESOURCE_FORK_STREAM "*UDF Macintosh Resource Fork" 300 | /* #define UDF_ID_OS2_EA "*UDF OS/2 EA" */ 301 | #define UDF_ID_NT_ACL "*UDF NT ACL" 302 | #define UDF_ID_UNIX_ACL "*UDF UNIX ACL" 303 | 304 | /* Operating System Identifiers (UDF 2.60 6.3) */ 305 | #define UDF_OS_CLASS_UNDEF 0x00U 306 | #define UDF_OS_CLASS_DOS 0x01U 307 | #define UDF_OS_CLASS_OS2 0x02U 308 | #define UDF_OS_CLASS_MAC 0x03U 309 | #define UDF_OS_CLASS_UNIX 0x04U 310 | #define UDF_OS_CLASS_WIN9X 0x05U 311 | #define UDF_OS_CLASS_WINNT 0x06U 312 | #define UDF_OS_CLASS_OS400 0x07U 313 | #define UDF_OS_CLASS_BEOS 0x08U 314 | #define UDF_OS_CLASS_WINCE 0x09U 315 | 316 | #define UDF_OS_ID_UNDEF 0x00U 317 | #define UDF_OS_ID_DOS 0x00U 318 | #define UDF_OS_ID_OS2 0x00U 319 | #define UDF_OS_ID_MAC 0x00U 320 | #define UDF_OS_ID_MAX_OSX 0x01U 321 | #define UDF_OS_ID_UNIX 0x00U 322 | #define UDF_OS_ID_AIX 0x01U 323 | #define UDF_OS_ID_SOLARIS 0x02U 324 | #define UDF_OS_ID_HPUX 0x03U 325 | #define UDF_OS_ID_IRIX 0x04U 326 | #define UDF_OS_ID_LINUX 0x05U 327 | #define UDF_OS_ID_MKLINUX 0x06U 328 | #define UDF_OS_ID_FREEBSD 0x07U 329 | #define UDF_OS_ID_NETBSD 0x08U 330 | #define UDF_OS_ID_WIN9X 0x00U 331 | #define UDF_OS_ID_WINNT 0x00U 332 | #define UDF_OS_ID_OS400 0x00U 333 | #define UDF_OS_ID_BEOS 0x00U 334 | #define UDF_OS_ID_WINCE 0x00U 335 | 336 | #endif /* _OSTA_UDF_H */ 337 | -------------------------------------------------------------------------------- /libudffs/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_LTLIBRARIES = libudffs.la 2 | libudffs_la_SOURCES = crc.c extent.c misc.c unicode.c ../include/libudffs.h ../include/ecma_167.h ../include/osta_udf.h ../include/bswap.h 3 | libudffs_la_LIBADD = @LTLIBOBJS@ 4 | 5 | AM_CPPFLAGS = -I$(top_srcdir)/include 6 | -------------------------------------------------------------------------------- /libudffs/crc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * crc.c 3 | * 4 | * PURPOSE 5 | * Routines to generate, calculate, and test a 16-bit CRC. 6 | * 7 | * DESCRIPTION 8 | * The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories 9 | * and Ned W. Rhodes of Software Systems Group. It has been published in 10 | * "Design and Validation of Computer Protocols", Prentice Hall, 11 | * Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4. 12 | * 13 | * Copyright is held by AT&T. 14 | * 15 | * AT&T gives permission for the free use of the CRC source code. 16 | * 17 | * COPYRIGHT 18 | * This file is distributed under the terms of the GNU General Public 19 | * License (GPL). Copies of the GPL can be obtained from: 20 | * ftp://prep.ai.mit.edu/pub/gnu/GPL 21 | * Each contributing author retains all rights to their own work. 22 | */ 23 | 24 | /** 25 | * @file 26 | * libudffs CRC functions 27 | */ 28 | 29 | #include "ecma_167.h" 30 | 31 | static uint16_t crc_table[256] = { 32 | 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, 33 | 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, 34 | 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, 35 | 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU, 36 | 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U, 37 | 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU, 38 | 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U, 39 | 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU, 40 | 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, 41 | 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU, 42 | 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U, 43 | 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU, 44 | 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U, 45 | 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U, 46 | 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U, 47 | 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U, 48 | 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU, 49 | 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, 50 | 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU, 51 | 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, 52 | 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU, 53 | 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, 54 | 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU, 55 | 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, 56 | 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU, 57 | 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U, 58 | 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU, 59 | 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U, 60 | 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U, 61 | 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U, 62 | 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U, 63 | 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U 64 | }; 65 | 66 | /* 67 | * udf_crc 68 | * 69 | * PURPOSE 70 | * Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial. 71 | * 72 | * DESCRIPTION 73 | * The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. 74 | * The polynomial used is: x^16 + x^12 + x^15 + 1 75 | * 76 | * PRE-CONDITIONS 77 | * data Pointer to the data block. 78 | * size Size of the data block. 79 | * 80 | * POST-CONDITIONS 81 | * CRC of the data block. 82 | * 83 | * HISTORY 84 | * July 21, 1997 - Andrew E. Mileski 85 | * Adapted from OSTA-UDF(tm) 1.50 standard. 86 | */ 87 | extern uint16_t 88 | udf_crc(uint8_t *data, uint32_t size, uint16_t crc) 89 | { 90 | while (size--) 91 | crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8); 92 | 93 | return crc; 94 | } 95 | 96 | /****************************************************************************/ 97 | #if defined(TEST) 98 | 99 | /* 100 | * PURPOSE 101 | * Test udf_crc() 102 | * 103 | * HISTORY 104 | * July 21, 1997 - Andrew E. Mileski 105 | * Adapted from OSTA-UDF(tm) 1.50 standard. 106 | */ 107 | 108 | unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U }; 109 | 110 | int main(void) 111 | { 112 | unsigned short x; 113 | 114 | x = udf_crc16(bytes, sizeof bytes); 115 | printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U); 116 | 117 | return 0; 118 | } 119 | 120 | #endif /* defined(TEST) */ 121 | 122 | /****************************************************************************/ 123 | #if defined(GENERATE) 124 | 125 | /* 126 | * PURPOSE 127 | * Generate a table for fast 16-bit CRC calculations (any polynomial). 128 | * 129 | * DESCRIPTION 130 | * The ITU-T V.41 polynomial is 010041. 131 | * 132 | * HISTORY 133 | * July 21, 1997 - Andrew E. Mileski 134 | * Adapted from OSTA-UDF(tm) 1.50 standard. 135 | */ 136 | 137 | #include 138 | 139 | int main(int argc, char **argv) 140 | { 141 | unsigned long crc, poly; 142 | int n, i; 143 | 144 | /* Get the polynomial */ 145 | sscanf(argv[1], "%lo", &poly); 146 | if (poly & 0xffff0000U){ 147 | fprintf(stderr, "polynomial is too large\en"); 148 | exit(1); 149 | } 150 | 151 | printf("/* CRC 0%o */\n", poly); 152 | 153 | /* Create a table */ 154 | printf("static unsigned short crc_table[256] = {\n"); 155 | for (n = 0; n < 256; n++){ 156 | if (n % 8 == 0) 157 | printf("\t"); 158 | crc = n << 8; 159 | for (i = 0; i < 8; i++){ 160 | if(crc & 0x8000U) 161 | crc = (crc << 1) ^ poly; 162 | else 163 | crc <<= 1; 164 | crc &= 0xFFFFU; 165 | } 166 | if (n == 255) 167 | printf("0x%04xU ", crc); 168 | else 169 | printf("0x%04xU, ", crc); 170 | if(n % 8 == 7) 171 | printf("\n"); 172 | } 173 | printf("};\n"); 174 | 175 | return 0; 176 | } 177 | 178 | #endif /* defined(GENERATE) */ 179 | -------------------------------------------------------------------------------- /libudffs/misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2019 Pali Rohár 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "libudffs.h" 33 | 34 | const char *appname; 35 | 36 | size_t gen_uuid_from_vol_set_ident(char uuid[17], const dstring *vol_set_ident, size_t size) 37 | { 38 | size_t i; 39 | size_t len; 40 | size_t nonhexpos; 41 | unsigned char buf[127*4+1]; 42 | 43 | memset(buf, 0, sizeof(buf)); 44 | 45 | if (size > 0 && vol_set_ident[size-1] > 0 && vol_set_ident[size-1] < size) 46 | len = decode_utf8((dchars *)vol_set_ident, (char *)buf, vol_set_ident[size-1], sizeof(buf)); 47 | else 48 | len = 0; 49 | 50 | if (len < 8) 51 | { 52 | uuid[0] = 0; 53 | return (size_t)-1; 54 | } 55 | 56 | nonhexpos = 16; 57 | for (i = 0; i < 16; ++i) 58 | { 59 | if (!isxdigit(buf[i])) 60 | { 61 | nonhexpos = i; 62 | break; 63 | } 64 | } 65 | 66 | if (nonhexpos < 8) 67 | { 68 | snprintf(uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x", 69 | buf[0], buf[1], buf[2], buf[3], 70 | buf[4], buf[5], buf[6], buf[7]); 71 | } 72 | else if (nonhexpos < 16) 73 | { 74 | for (i = 0; i < 8; ++i) 75 | uuid[i] = tolower(buf[i]); 76 | snprintf(uuid + 8, 9, "%02x%02x%02x%02x", 77 | buf[8], buf[9], buf[10], buf[11]); 78 | } 79 | else 80 | { 81 | for (i = 0; i < 16; ++i) 82 | uuid[i] = tolower(buf[i]); 83 | uuid[16] = 0; 84 | } 85 | 86 | if (nonhexpos < 16) 87 | return nonhexpos; 88 | 89 | return 16; 90 | } 91 | 92 | uint32_t strtou32(const char *str, int base, int *failed) 93 | { 94 | char *endptr = NULL; 95 | long long int ret; 96 | 97 | /* strtou* does not signal underflow, so use signed variant */ 98 | errno = 0; 99 | ret = strtoll(str, &endptr, base); 100 | /* strto* skips leading whitespaces, so detect them via isspace */ 101 | *failed = (!*str || isspace((unsigned char)*str) || *endptr || errno || ret < 0 || ret > UINT32_MAX) ? 1 : 0; 102 | return ret; 103 | } 104 | 105 | uint16_t strtou16(const char *str, int base, int *failed) 106 | { 107 | uint32_t ret; 108 | 109 | ret = strtou32(str, base, failed); 110 | *failed = (*failed || ret > UINT16_MAX) ? 1 : 0; 111 | return ret; 112 | } 113 | 114 | static inline unsigned int intlog2(unsigned int word) 115 | { 116 | unsigned int result = 0; 117 | 118 | while (word >>= 1) 119 | result++; 120 | return result; 121 | } 122 | 123 | uint32_t randu32(void) 124 | { 125 | int fd; 126 | uint32_t value; 127 | unsigned int bits; 128 | unsigned int rand_bits; 129 | 130 | static int srand_done = 0; 131 | 132 | fd = open("/dev/urandom", O_RDONLY); 133 | if (fd >= 0) 134 | { 135 | if (read(fd, &value, sizeof(value)) == sizeof(value)) 136 | { 137 | close(fd); 138 | return value; 139 | } 140 | close(fd); 141 | } 142 | 143 | if (!srand_done) 144 | { 145 | srand(time(NULL) * getpid()); 146 | srand_done = 1; 147 | } 148 | 149 | value = 0; 150 | rand_bits = intlog2((unsigned int)RAND_MAX+1); 151 | for (bits = 0; bits < 32; bits += rand_bits) 152 | { 153 | value <<= rand_bits; 154 | value |= rand(); 155 | } 156 | 157 | return value; 158 | } 159 | 160 | ssize_t read_nointr(int fd, void *buf, size_t count) 161 | { 162 | ssize_t ret; 163 | 164 | do ret = read(fd, buf, count); 165 | while (ret < 0 && errno == EINTR); 166 | 167 | if (ret >= 0 && errno) 168 | errno = 0; 169 | 170 | return ret; 171 | } 172 | 173 | ssize_t write_nointr(int fd, const void *buf, size_t count) 174 | { 175 | ssize_t ret; 176 | 177 | do ret = write(fd, buf, count); 178 | while (ret < 0 && errno == EINTR); 179 | 180 | if (ret >= 0 && errno) 181 | errno = 0; 182 | 183 | return ret; 184 | } 185 | -------------------------------------------------------------------------------- /libudffs/unicode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * unicode.c 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * Copyright (c) 2014-2021 Pali Rohár 6 | * All rights reserved. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | /** 25 | * @file 26 | * libudffs unicode handling functions 27 | */ 28 | 29 | #include "config.h" 30 | 31 | #include "libudffs.h" 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | size_t decode_utf8(const dchars *in, char *out, size_t inlen, size_t outlen) 43 | { 44 | size_t len = 0, i; 45 | unsigned int c; 46 | 47 | if (outlen == 0) 48 | return (size_t)-1; 49 | 50 | if (in[0] != 8 && in[0] != 16) 51 | return (size_t)-1; 52 | 53 | if (in[0] == 16 && (inlen-1) % 2 != 0) 54 | return (size_t)-1; 55 | 56 | for (i=1; i= outlen) 67 | return (size_t)-1; 68 | out[len++] = (uint8_t)c; 69 | } 70 | else if (c < 0x800U) 71 | { 72 | if (len+2 >= outlen) 73 | return (size_t)-1; 74 | out[len++] = (uint8_t)(0xc0 | (c >> 6)); 75 | out[len++] = (uint8_t)(0x80 | (c & 0x3f)); 76 | } 77 | else if (c >= 0xD800 && c <= 0xDBFF && i+1 < inlen && (((unsigned int)in[i] << 8) | in[i+1]) >= 0xDC00 && (((unsigned int)in[i] << 8) | in[i+1]) <= 0xDFFF) 78 | { 79 | c = 0x10000 + ((c - 0xD800) << 10) + ((((unsigned int)in[i] << 8) | in[i+1]) - 0xDC00); 80 | i += 2; 81 | if (len+4 >= outlen) 82 | return (size_t)-1; 83 | out[len++] = (uint8_t)(0xf0 | (c >> 18)); 84 | out[len++] = (uint8_t)(0x80 | ((c >> 12) & 0x3f)); 85 | out[len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f)); 86 | out[len++] = (uint8_t)(0x80 | (c & 0x3f)); 87 | } 88 | else 89 | { 90 | if (len+3 >= outlen) 91 | return (size_t)-1; 92 | out[len++] = (uint8_t)(0xe0 | (c >> 12)); 93 | out[len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f)); 94 | out[len++] = (uint8_t)(0x80 | (c & 0x3f)); 95 | } 96 | } 97 | 98 | out[len] = 0; 99 | return len; 100 | } 101 | 102 | size_t encode_utf8(dchars *out, const char *in, size_t outlen) 103 | { 104 | size_t inlen = strlen(in); 105 | size_t len, i; 106 | int utf_cnt; 107 | uint32_t utf_char, max_val; 108 | unsigned int c; 109 | 110 | len = 1; 111 | out[0] = 8; 112 | max_val = 0x7F; 113 | 114 | try_again: 115 | utf_cnt = 0; 116 | utf_char = 0; 117 | 118 | for (i=0; i max_val) 165 | { 166 | if (max_val == 0x7F) 167 | { 168 | len = 1; 169 | max_val = 0x10FFFF; 170 | out[0] = 0x10; 171 | goto try_again; 172 | } 173 | return (size_t)-1; 174 | } 175 | 176 | if (max_val == 0x10FFFF) 177 | { 178 | if (len + 2 > outlen) 179 | { 180 | len = 1; 181 | max_val = 0xFF; 182 | out[0] = 0x8; 183 | goto try_again; 184 | } 185 | if (utf_char > 0xFFFF) 186 | { 187 | if (len+4 > outlen) 188 | return (size_t)-1; 189 | out[len++] = ((((utf_char - 0x10000) >> 10) + 0xD800) >> 8) & 0xFF; 190 | out[len++] = (((utf_char - 0x10000) >> 10) + 0xD800) & 0xFF; 191 | utf_char = ((utf_char - 0x10000) & 0x3FF) + 0xDC00; 192 | } 193 | out[len++] = utf_char >> 8; 194 | } 195 | if (len + 1 > outlen) 196 | return (size_t)-1; 197 | out[len++] = utf_char & 0xFF; 198 | } 199 | 200 | if (utf_cnt) 201 | { 202 | error_invalid: 203 | fprintf(stderr, "%s: Error: Cannot convert input string from UTF-8 encoding: Invalid or incomplete UTF-8 sequence\n", appname); 204 | exit(1); 205 | } 206 | 207 | return len; 208 | } 209 | 210 | size_t decode_locale(const dchars *in, char *out, size_t inlen, size_t outlen) 211 | { 212 | size_t len, i; 213 | size_t wcslen, clen; 214 | wchar_t *wcs; 215 | mbstate_t ps; 216 | char cbuf[MB_LEN_MAX]; 217 | 218 | if (outlen == 0) 219 | return (size_t)-1; 220 | 221 | if (in[0] == 16 && (inlen-1) % 2 != 0) 222 | return (size_t)-1; 223 | 224 | if (in[0] == 8) 225 | wcslen = (inlen-1); 226 | else if (in[0] == 16) 227 | wcslen = (inlen-1)/2; 228 | else 229 | return (size_t)-1; 230 | 231 | wcs = calloc(wcslen+1, sizeof(wchar_t)); 232 | if (!wcs) 233 | return (size_t)-1; 234 | 235 | wcslen = 0; 236 | for (i=1; i= 0x10FFFF 243 | if (wcs[wcslen] >= 0xD800 && wcs[wcslen] <= 0xDBFF && i+1 < inlen) 244 | { 245 | wchar_t ch = (((wchar_t)in[i] << 8) | in[i+1]); 246 | if (ch >= 0xDC00 && ch <= 0xDFFF) 247 | { 248 | wcs[wcslen] = 0x10000 + ((wcs[wcslen] - 0xD800) << 10) + (ch - 0xDC00); 249 | i += 2; 250 | } 251 | } 252 | #endif 253 | } 254 | ++wcslen; 255 | } 256 | 257 | memset(&ps, 0, sizeof(ps)); 258 | 259 | len = 0; 260 | clen = 0; 261 | for (i=0; i= 0xFFFD 265 | if (clen == (size_t)-1 && errno == EILSEQ) 266 | clen = wcrtomb(cbuf, 0xFFFD, &ps); 267 | #endif 268 | if (clen == (size_t)-1 && errno == EILSEQ) 269 | clen = wcrtomb(cbuf, L'?', &ps); 270 | if (clen == (size_t)-1 && errno == EILSEQ) 271 | clen = wcrtomb(cbuf, L' ', &ps); 272 | if (clen == (size_t)-1) 273 | { 274 | fprintf(stderr, "%s: Error: Cannot convert output string to current locale encoding: %s\n", appname, strerror(errno)); 275 | free(wcs); 276 | exit(1); 277 | } 278 | if (len+clen > outlen) 279 | { 280 | free(wcs); 281 | return (size_t)-1; 282 | } 283 | memcpy(out+len, cbuf, clen); 284 | len += clen; 285 | } 286 | 287 | free(wcs); 288 | 289 | /* Last iteration of above loop should have produced null byte */ 290 | if (clen == 0 || len == 0 || out[len-1] != 0) 291 | { 292 | fprintf(stderr, "%s: Error: Cannot convert output string to current locale encoding: %s\n", appname, strerror(EINVAL)); 293 | exit(1); 294 | } 295 | 296 | return len-1; 297 | } 298 | 299 | #if WCHAR_MAX > 0x10FFFF 300 | #define DCHAR_IN_WCHAR_MAX 0x10FFFF 301 | #else 302 | #define DCHAR_IN_WCHAR_MAX WCHAR_MAX 303 | #endif 304 | 305 | size_t encode_locale(dchars *out, const char *in, size_t outlen) 306 | { 307 | size_t i; 308 | size_t mbslen; 309 | size_t len; 310 | wchar_t max_val; 311 | wchar_t *wcs; 312 | 313 | mbslen = mbstowcs(NULL, in, 0); 314 | if (mbslen == (size_t)-1) 315 | { 316 | fprintf(stderr, "%s: Error: Cannot convert input string from current locale encoding: %s\n", appname, strerror(errno)); 317 | exit(1); 318 | } 319 | 320 | wcs = calloc(mbslen+1, sizeof(wchar_t)); 321 | if (!wcs) 322 | goto error_out; 323 | 324 | if (mbstowcs(wcs, in, mbslen+1) == (size_t)-1) 325 | goto error_out; 326 | 327 | len = 1; 328 | out[0] = 8; 329 | max_val = 0x7F; 330 | 331 | try_again: 332 | for (i=0; i max_val) 335 | { 336 | if (max_val == 0x7F) 337 | { 338 | len = 1; 339 | out[0] = 16; 340 | max_val = DCHAR_IN_WCHAR_MAX; 341 | goto try_again; 342 | } 343 | goto error_out; 344 | } 345 | 346 | if (max_val == DCHAR_IN_WCHAR_MAX) 347 | { 348 | if (len+2 > outlen) 349 | { 350 | len = 1; 351 | out[0] = 8; 352 | max_val = 0xFF; 353 | goto try_again; 354 | } 355 | #if WCHAR_MAX > 0xFFFF 356 | if (wcs[i] > 0xFFFF) 357 | { 358 | if (len+4 > outlen) 359 | goto error_out; 360 | out[len++] = ((((wcs[i] - 0x10000) >> 10) + 0xD800) >> 8) & 0xFF; 361 | out[len++] = (((wcs[i] - 0x10000) >> 10) + 0xD800) & 0xFF; 362 | wcs[i] = ((wcs[i] - 0x10000) & 0x3FF) + 0xDC00; 363 | } 364 | #endif 365 | out[len++] = (wcs[i] >> 8) & 0xFF; 366 | } 367 | 368 | if (len+1 > outlen) 369 | goto error_out; 370 | out[len++] = wcs[i] & 0xFF; 371 | } 372 | 373 | free(wcs); 374 | return len; 375 | 376 | error_out: 377 | free(wcs); 378 | return (size_t)-1; 379 | } 380 | 381 | size_t decode_string(struct udf_disc *disc, const dstring *in, char *out, size_t inlen, size_t outlen) 382 | { 383 | uint32_t flags = disc ? disc->flags : FLAG_LOCALE; 384 | if (in[0] == 0 && outlen) 385 | { 386 | out[0] = 0; 387 | return 0; 388 | } 389 | if (in[inlen-1] == 0 || in[inlen-1] >= inlen) 390 | return (size_t)-1; 391 | inlen = in[inlen-1]; 392 | if (flags & FLAG_UTF8) 393 | return decode_utf8((dchars *)in, out, inlen, outlen); 394 | else if (flags & FLAG_LOCALE) 395 | return decode_locale((dchars *)in, out, inlen, outlen); 396 | else if (flags & (FLAG_UNICODE8 | FLAG_UNICODE16)) 397 | { 398 | size_t i; 399 | if (in[0] != 8 && in[0] != 16) 400 | return (size_t)-1; 401 | if (in[0] == 16 && (inlen-1) % 2 != 0) 402 | return (size_t)-1; 403 | if ((in[0] == 8 && (flags & FLAG_UNICODE8)) || (in[0] == 16 && (flags & FLAG_UNICODE16))) 404 | { 405 | if (inlen > outlen) 406 | return (size_t)-1; 407 | memcpy(out, &in[1], inlen); 408 | if (in[0] == 0x10 && (flags & FLAG_UNICODE16)) 409 | { 410 | if (inlen+1 > outlen) 411 | return (size_t)-1; 412 | out[inlen] = 0; 413 | return inlen+1; 414 | } 415 | return inlen; 416 | } 417 | else if (flags & FLAG_UNICODE16) 418 | { 419 | if (2*(inlen-1)+2 > outlen) 420 | return (size_t)-1; 421 | for (i=1; i outlen) 433 | return (size_t)-1; 434 | for (i=1; iflags : FLAG_LOCALE; 453 | size_t ret = (size_t)-1; 454 | if (outlen == 0) 455 | return (size_t)-1; 456 | if (in[0] == 0) 457 | { 458 | memset(out, 0, outlen); 459 | return 0; 460 | } 461 | if (flags & FLAG_UTF8) 462 | ret = encode_utf8((dchars *)out, in, outlen-1); 463 | else if (flags & FLAG_LOCALE) 464 | ret = encode_locale((dchars *)out, in, outlen-1); 465 | else if (flags & (FLAG_UNICODE8|FLAG_UNICODE16)) 466 | { 467 | size_t inlen = strlen(in); 468 | memset(out, 0, outlen); 469 | if (inlen >= outlen - 2) 470 | return (size_t)-1; 471 | memcpy(&out[1], in, inlen); 472 | if (flags & FLAG_UNICODE8) 473 | out[0] = 0x08; 474 | else 475 | out[0] = 0x10; 476 | ret = inlen + 1; 477 | } 478 | if (ret != (size_t)-1 && ret > 1 && ret < 256) 479 | { 480 | memset(out+ret, 0, outlen-ret-1); 481 | out[outlen-1] = ret; 482 | } 483 | else 484 | { 485 | memset(out, 0, outlen); 486 | ret = (size_t)-1; 487 | } 488 | return ret; 489 | } 490 | -------------------------------------------------------------------------------- /mkudffs/Makefile.am: -------------------------------------------------------------------------------- 1 | sbin_PROGRAMS = mkudffs 2 | mkudffs_LDADD = $(top_builddir)/libudffs/libudffs.la 3 | 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 4 | 5 | AM_CPPFLAGS = -I$(top_srcdir)/include 6 | 7 | install-exec-hook: 8 | cd "$(DESTDIR)$(sbindir)" && $(LN_S) -f mkudffs$(EXEEXT) mkfs.udf$(EXEEXT) 9 | 10 | uninstall-hook: 11 | cd "$(DESTDIR)$(sbindir)" && $(RM) mkfs.udf$(EXEEXT) 12 | -------------------------------------------------------------------------------- /mkudffs/defaults.h: -------------------------------------------------------------------------------- 1 | /* 2 | * defaults.h 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * Copyright (c) 2016-2021 Pali Rohár 6 | * All rights reserved. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | #ifndef _DEFAULTS_H 25 | #define _DEFAULTS_H 1 26 | 27 | extern int default_media[]; 28 | extern struct udf_sizing default_sizing[][UDF_ALLOC_TYPE_SIZE]; 29 | 30 | extern struct primaryVolDesc default_pvd; 31 | extern struct logicalVolDesc default_lvd; 32 | extern struct impUseVolDescImpUse default_iuvdiu; 33 | extern struct impUseVolDesc default_iuvd; 34 | extern struct partitionDesc default_pd; 35 | extern struct unallocSpaceDesc default_usd; 36 | extern struct terminatingDesc default_td; 37 | extern struct logicalVolIntegrityDesc default_lvid; 38 | extern struct logicalVolIntegrityDescImpUse default_lvidiu; 39 | extern struct sparingTable default_stable; 40 | extern struct sparablePartitionMap default_sparmap; 41 | extern struct virtualAllocationTable15 default_vat15; 42 | extern struct virtualAllocationTable20 default_vat20; 43 | extern struct virtualPartitionMap default_virtmap; 44 | extern struct fileSetDesc default_fsd; 45 | extern struct fileEntry default_fe; 46 | extern struct extendedFileEntry default_efe; 47 | extern struct impUseExtAttr default_iuea; 48 | 49 | extern struct mbr default_mbr; 50 | 51 | #endif /* _DEFAULTS_H */ 52 | -------------------------------------------------------------------------------- /mkudffs/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libudffs.h 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * Copyright (c) 2016-2019 Pali Rohár 6 | * All rights reserved. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | #ifndef __FILE_H 25 | #define __FILE_H 26 | 27 | #include "libudffs.h" 28 | 29 | tag query_tag(struct udf_disc *, struct udf_extent *, struct udf_desc *, uint16_t); 30 | extern tag udf_query_tag(struct udf_disc *, uint16_t, uint16_t, uint32_t, struct udf_data *, uint32_t, uint32_t); 31 | 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); 32 | extern struct udf_desc *udf_mkdir(struct udf_disc *, struct udf_extent *, const dchars *, uint8_t, uint32_t, struct udf_desc *); 33 | extern void insert_data(struct udf_disc *disc, struct udf_extent *pspace, struct udf_desc *desc, struct udf_data *data); 34 | extern void insert_fid(struct udf_disc *, struct udf_extent *, struct udf_desc *, struct udf_desc *, const dchars *, uint8_t, uint8_t); 35 | extern void insert_ea(struct udf_disc *disc, struct udf_desc *desc, struct genericFormat *ea, uint32_t length); 36 | extern int udf_alloc_blocks(struct udf_disc *, struct udf_extent *, uint32_t, uint32_t); 37 | 38 | static inline void clear_bits(uint8_t *bitmap, uint32_t offset, uint64_t length) 39 | { 40 | for (;length>0;length--) 41 | { 42 | bitmap[(length+offset-1)/8] &= ~(1 << ((offset+length-1)%8)); 43 | } 44 | } 45 | 46 | static inline struct impUseVolDescImpUse *query_iuvdiu(struct udf_disc *disc) 47 | { 48 | return (struct impUseVolDescImpUse *)disc->udf_iuvd[0]->impUse; 49 | } 50 | 51 | static inline struct logicalVolIntegrityDescImpUse *query_lvidiu(struct udf_disc *disc) 52 | { 53 | return (struct logicalVolIntegrityDescImpUse *)&(disc->udf_lvid->data[le32_to_cpu(disc->udf_lvd[0]->numPartitionMaps) * 2 * sizeof(uint32_t)]); 54 | } 55 | 56 | #endif /* __FILE_H */ 57 | -------------------------------------------------------------------------------- /mkudffs/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * Copyright (c) 2014-2021 Pali Rohár 6 | * All rights reserved. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | /** 25 | * @file 26 | * mkudffs main program and I/O functions 27 | */ 28 | 29 | #include "config.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "mkudffs.h" 49 | #include "defaults.h" 50 | #include "options.h" 51 | 52 | static int valid_offset(int fd, off_t offset) 53 | { 54 | char ch; 55 | 56 | if (lseek(fd, offset, SEEK_SET) < 0) 57 | return 0; 58 | if (read_nointr(fd, &ch, 1) < 1) 59 | return 0; 60 | return 1; 61 | } 62 | 63 | static uint32_t get_blocks(int fd, int blocksize, uint32_t opt_blocks) 64 | { 65 | uint64_t blocks; 66 | #ifdef BLKGETSIZE64 67 | uint64_t size64; 68 | #endif 69 | #ifdef BLKGETSIZE 70 | long size; 71 | #endif 72 | #ifdef FDGETPRM 73 | struct floppy_struct this_floppy; 74 | #endif 75 | struct stat buf; 76 | 77 | if (opt_blocks) 78 | return opt_blocks; 79 | 80 | if (fd <= 0) 81 | return 0; 82 | 83 | #ifdef BLKGETSIZE64 84 | if (ioctl(fd, BLKGETSIZE64, &size64) >= 0) 85 | blocks = size64 / blocksize; 86 | else 87 | #endif 88 | #ifdef BLKGETSIZE 89 | if (ioctl(fd, BLKGETSIZE, &size) >= 0) 90 | blocks = size / (blocksize / 512); 91 | else 92 | #endif 93 | #ifdef FDGETPRM 94 | if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) 95 | blocks = this_floppy.size / (blocksize / 512); 96 | else 97 | #endif 98 | if (fstat(fd, &buf) == 0 && S_ISREG(buf.st_mode)) 99 | blocks = buf.st_size / blocksize; 100 | else 101 | { 102 | off_t high, low; 103 | 104 | for (low=0, high = 1024; valid_offset(fd, high); high *= 2) 105 | low = high; 106 | while (low < high - 1) 107 | { 108 | const off_t mid = (low + high) / 2; 109 | 110 | if (valid_offset(fd, mid)) 111 | low = mid; 112 | else 113 | high = mid; 114 | } 115 | 116 | valid_offset(fd, 0); 117 | blocks = (low + 1) / blocksize; 118 | } 119 | 120 | if (blocks > UINT32_MAX) 121 | { 122 | fprintf(stderr, "%s: Warning: Disk is too big, using only %"PRIu32" blocks\n", appname, UINT32_MAX); 123 | return UINT32_MAX; 124 | } 125 | 126 | return blocks; 127 | } 128 | 129 | static void detect_blocksize(int fd, struct udf_disc *disc, int *blocksize) 130 | { 131 | #ifdef BLKSSZGET 132 | int size; 133 | 134 | if (ioctl(fd, BLKSSZGET, &size) != 0 || size <= 0) 135 | return; 136 | 137 | if (!disc->blkssz) 138 | disc->blkssz = size; 139 | 140 | if (*blocksize != -1) 141 | return; 142 | 143 | if (size < 512 || size > 32768 || (size & (size - 1))) 144 | { 145 | fprintf(stderr, "%s: Warning: Disk logical sector size (%d) is not suitable for UDF\n", appname, size); 146 | return; 147 | } 148 | 149 | disc->blocksize = size; 150 | *blocksize = disc->blocksize; 151 | disc->udf_lvd[0]->logicalBlockSize = cpu_to_le32(disc->blocksize); 152 | #endif 153 | } 154 | 155 | static int is_whole_disk(int fd) 156 | { 157 | struct stat st; 158 | char buf[512]; 159 | DIR *dir; 160 | struct dirent *d; 161 | int maj; 162 | int min; 163 | int has_slave; 164 | int slave_errno; 165 | 166 | if (fstat(fd, &st) != 0) 167 | return -1; 168 | 169 | if (!S_ISBLK(st.st_mode)) 170 | return 1; 171 | 172 | maj = major(st.st_rdev); 173 | min = minor(st.st_rdev); 174 | 175 | if (snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/partition", maj, min) >= (int)sizeof(buf)) 176 | return -1; 177 | 178 | if (stat(buf, &st) == 0) 179 | return 0; 180 | else if (errno != ENOENT) 181 | return -1; 182 | 183 | if (snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/slaves/", maj, min) >= (int)sizeof(buf)) 184 | return -1; 185 | 186 | dir = opendir(buf); 187 | if (!dir && errno != ENOENT) 188 | return -1; 189 | 190 | if (dir) 191 | { 192 | errno = 0; 193 | has_slave = 0; 194 | while ((d = readdir(dir))) 195 | { 196 | if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) 197 | continue; 198 | has_slave = 1; 199 | break; 200 | } 201 | slave_errno = errno; 202 | 203 | closedir(dir); 204 | 205 | if (slave_errno) 206 | return -1; 207 | 208 | if (has_slave) 209 | return 0; 210 | } 211 | 212 | if (snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/", maj, min) >= (int)sizeof(buf)) 213 | return -1; 214 | 215 | if (stat(buf, &st) != 0) 216 | return -1; 217 | 218 | return 1; 219 | } 220 | 221 | static int is_removable_disk(int fd) 222 | { 223 | struct stat st; 224 | char buf[512]; 225 | ssize_t ret; 226 | 227 | if (fstat(fd, &st) != 0) 228 | return -1; 229 | 230 | if (!S_ISBLK(st.st_mode)) 231 | return -1; 232 | 233 | if (snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/removable", major(st.st_rdev), minor(st.st_rdev)) >= (int)sizeof(buf)) 234 | return -1; 235 | 236 | int rem_fd = open(buf, O_RDONLY); 237 | if (rem_fd < 0) 238 | return -1; 239 | 240 | ret = read_nointr(rem_fd, buf, sizeof(buf)-1); 241 | close(rem_fd); 242 | 243 | if (ret < 0) 244 | return -1; 245 | 246 | buf[ret] = 0; 247 | if (strcmp(buf, "1\n") == 0) 248 | return 1; 249 | else if (strcmp(buf, "0\n") == 0) 250 | return 0; 251 | 252 | return -1; 253 | } 254 | 255 | static int write_func(struct udf_disc *disc, struct udf_extent *ext) 256 | { 257 | static char *buffer = NULL; 258 | static size_t bufferlen = 0; 259 | int fd = *(int *)disc->write_data; 260 | ssize_t length, offset; 261 | uint32_t blocks; 262 | struct udf_desc *desc; 263 | struct udf_data *data; 264 | 265 | if (buffer == NULL) 266 | { 267 | bufferlen = disc->blocksize; 268 | buffer = calloc(bufferlen, 1); 269 | if (buffer == NULL) 270 | return -1; 271 | } 272 | 273 | if (!(ext->space_type & (USPACE|RESERVED))) 274 | { 275 | desc = ext->head; 276 | while (desc != NULL) 277 | { 278 | if (!(disc->flags & FLAG_NO_WRITE) || fd >= 0) 279 | { 280 | if (lseek(fd, (off_t)(ext->start + desc->offset) * disc->blocksize, SEEK_SET) < 0) 281 | return -1; 282 | } 283 | data = desc->data; 284 | offset = 0; 285 | while (data != NULL) 286 | { 287 | if (data->length + offset > bufferlen) 288 | { 289 | bufferlen = (data->length + offset + disc->blocksize - 1) & ~(disc->blocksize - 1); 290 | buffer = realloc(buffer, bufferlen); 291 | if (buffer == NULL) 292 | return -1; 293 | } 294 | memcpy(buffer + offset, data->buffer, data->length); 295 | offset += data->length; 296 | data = data->next; 297 | } 298 | length = (offset + disc->blocksize - 1) & ~(disc->blocksize - 1); 299 | if (offset != length) 300 | memset(buffer + offset, 0x00, length - offset); 301 | if (!(disc->flags & FLAG_NO_WRITE)) 302 | { 303 | if (write_nointr(fd, buffer, length) != length) 304 | return -1; 305 | } 306 | desc = desc->next; 307 | } 308 | } 309 | else if (!(disc->flags & FLAG_BOOTAREA_PRESERVE)) 310 | { 311 | length = disc->blocksize; 312 | blocks = ext->blocks; 313 | memset(buffer, 0, length); 314 | if (!(disc->flags & FLAG_NO_WRITE) || fd >= 0) 315 | { 316 | if (lseek(fd, (off_t)(ext->start) * disc->blocksize, SEEK_SET) < 0) 317 | return -1; 318 | } 319 | while (blocks-- > 0) 320 | { 321 | if (!(disc->flags & FLAG_NO_WRITE)) 322 | { 323 | if (write_nointr(fd, buffer, length) != length) 324 | return -1; 325 | } 326 | } 327 | } 328 | return 0; 329 | } 330 | 331 | int main(int argc, char *argv[]) 332 | { 333 | struct udf_disc disc; 334 | struct udf_extent *ext; 335 | char *filename; 336 | char buf[128*3]; 337 | int fd; 338 | int flags; 339 | int create_new_file = 0; 340 | int blocksize = -1; 341 | int media; 342 | size_t len; 343 | 344 | if (fcntl(0, F_GETFL) < 0 && open("/dev/null", O_RDONLY) < 0) 345 | _exit(1); 346 | if (fcntl(1, F_GETFL) < 0 && open("/dev/null", O_WRONLY) < 0) 347 | _exit(1); 348 | if (fcntl(2, F_GETFL) < 0 && open("/dev/null", O_WRONLY) < 0) 349 | _exit(1); 350 | 351 | appname = "mkudffs"; 352 | 353 | if (!setlocale(LC_CTYPE, "")) 354 | fprintf(stderr, "%s: Error: Cannot set locale/codeset, fallback to default 7bit C ASCII\n", appname); 355 | 356 | udf_init_disc(&disc); 357 | parse_args(argc, argv, &disc, &filename, &create_new_file, &blocksize, &media); 358 | 359 | if (disc.flags & FLAG_NO_WRITE) 360 | printf("Note: Not writing to device, just simulating\n"); 361 | 362 | if (!(disc.flags & FLAG_NO_WRITE)) 363 | flags = O_RDWR | O_EXCL; 364 | else 365 | flags = O_RDONLY | O_EXCL; 366 | 367 | fd = open(filename, flags); 368 | if (fd < 0) 369 | { 370 | if (errno != ENOENT) 371 | { 372 | fprintf(stderr, "%s: Error: Cannot open device '%s': %s\n", appname, filename, (errno != EBUSY) ? strerror(errno) : "Device is mounted or mkudffs is already running"); 373 | exit(1); 374 | } 375 | 376 | if (!disc.blocks) 377 | { 378 | fprintf(stderr, "%s: Error: Cannot create new image file '%s': block-count was not specified\n", appname, filename); 379 | exit(1); 380 | } 381 | } 382 | 383 | if (fd >= 0) 384 | detect_blocksize(fd, &disc, &blocksize); 385 | 386 | if (blocksize == -1 && media == MEDIA_TYPE_HD) 387 | { 388 | disc.blocksize = 512; 389 | disc.udf_lvd[0]->logicalBlockSize = cpu_to_le32(disc.blocksize); 390 | } 391 | 392 | disc.blocks = get_blocks(fd, disc.blocksize, disc.blocks); 393 | if (disc.blocks == 0) 394 | { 395 | fprintf(stderr, "%s: Error: Device '%s' is empty\n", appname, filename); 396 | exit(1); 397 | } 398 | 399 | disc.head->blocks = disc.blocks; 400 | disc.write = write_func; 401 | disc.write_data = &fd; 402 | 403 | if (!(disc.flags & FLAG_BOOTAREA_MASK)) 404 | { 405 | if (media != MEDIA_TYPE_HD || disc.start_block) 406 | disc.flags |= FLAG_BOOTAREA_PRESERVE; 407 | else if (fd >= 0 && is_removable_disk(fd) == 0 && is_whole_disk(fd) == 1) 408 | disc.flags |= FLAG_BOOTAREA_MBR; 409 | else 410 | disc.flags |= FLAG_BOOTAREA_ERASE; 411 | } 412 | 413 | printf("filename=%s\n", filename); 414 | 415 | memset(buf, 0, sizeof(buf)); 416 | len = decode_string(&disc, disc.udf_lvd[0]->logicalVolIdent, buf, 128, sizeof(buf)); 417 | printf("label=%s\n", buf); 418 | 419 | memset(buf, 0, sizeof(buf)); 420 | len = gen_uuid_from_vol_set_ident(buf, disc.udf_pvd[0]->volSetIdent, 128); 421 | printf("uuid=%s\n", buf); 422 | 423 | printf("blocksize=%"PRIu32"\n", disc.blocksize); 424 | printf("blocks=%"PRIu32"\n", disc.blocks); 425 | printf("udfrev=%"PRIx16".%02"PRIx16"\n", disc.udf_rev >> 8, disc.udf_rev & 0xFF); 426 | 427 | if (disc.start_block) 428 | printf("startblock=%"PRIu32"\n", disc.start_block); 429 | 430 | split_space(&disc); 431 | 432 | setup_mbr(&disc); 433 | setup_vrs(&disc); 434 | setup_anchor(&disc); 435 | setup_partition(&disc); 436 | setup_vds(&disc); 437 | 438 | if (disc.vat_block) 439 | printf("vatblock=%"PRIu32"\n", disc.vat_block); 440 | 441 | dump_space(&disc); 442 | 443 | if (disc.blocks <= 257) 444 | fprintf(stderr, "%s: Warning: UDF filesystem has less than 258 blocks, it can cause problems\n", appname); 445 | 446 | if (len == (size_t)-1) 447 | fprintf(stderr, "%s: Warning: Volume Set Identifier must be at least 8 characters long\n", appname); 448 | else if (len < 16) 449 | fprintf(stderr, "%s: Warning: First 16 characters of Volume Set Identifier are not hexadecimal lowercase digits\n%s: Warning: This would cause problems for UDF uuid\n", appname, appname); 450 | 451 | if (fd >= 0 && is_whole_disk(fd) == 0) 452 | fprintf(stderr, "%s: Warning: Creating new UDF filesystem on partition, and not on whole disk device\n%s: Warning: UDF filesystem on partition cannot be read on Apple systems\n", appname, appname); 453 | 454 | if (fd < 0 && !(disc.flags & FLAG_NO_WRITE)) 455 | { 456 | // Create new file disk image 457 | fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0660); 458 | if (fd < 0) 459 | { 460 | fprintf(stderr, "%s: Error: Cannot create new image file '%s': %s\n", appname, filename, strerror(errno)); 461 | exit(1); 462 | } 463 | 464 | // If creating new disk image file then shift all blocks to the beginning of the file 465 | if (disc.start_block) 466 | { 467 | for (ext = disc.head; ext != NULL; ext = ext->next) 468 | ext->start -= disc.start_block; 469 | } 470 | } 471 | 472 | if (write_disc(&disc) < 0) 473 | { 474 | fprintf(stderr, "%s: Error: Cannot write to device '%s': %s\n", appname, filename, strerror(errno)); 475 | return 1; 476 | } 477 | 478 | if (!(disc.flags & FLAG_NO_WRITE)) 479 | { 480 | if (fsync(fd) != 0) 481 | { 482 | fprintf(stderr, "%s: Error: Synchronization to device '%s' failed: %s\n", appname, filename, strerror(errno)); 483 | exit(1); 484 | } 485 | } 486 | 487 | if (fd >= 0 && close(fd) != 0 && errno != EINTR) 488 | { 489 | fprintf(stderr, "%s: Error: Closing device '%s' failed: %s\n", appname, filename, strerror(errno)); 490 | exit(1); 491 | } 492 | 493 | return 0; 494 | } 495 | -------------------------------------------------------------------------------- /mkudffs/mkudffs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mkudffs.h 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * Copyright (c) 2016-2021 Pali Rohár 6 | * All rights reserved. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | #ifndef __MKUDFFS_H 25 | #define __MKUDFFS_H 26 | 27 | #include "ecma_167.h" 28 | #include "osta_udf.h" 29 | #include "libudffs.h" 30 | 31 | #define UDF_ID_APPLICATION "*Linux mkudffs " PACKAGE_VERSION 32 | #define UDF_ID_DEVELOPER "*Linux UDFFS" 33 | 34 | #define DEFAULT_HD 0 35 | #define DEFAULT_CD 0 36 | #define DEFAULT_CDR 0 37 | #define DEFAULT_DVD 0 38 | #define DEFAULT_DVDRAM 0 39 | #define DEFAULT_WORM 1 40 | #define DEFAULT_MO 1 41 | #define DEFAULT_CDRW 2 42 | #define DEFAULT_BDR 3 43 | #define DEFAULT_DVDRW 4 44 | #define DEFAULT_DVDR 5 45 | 46 | enum media_type { 47 | MEDIA_TYPE_NONE, 48 | MEDIA_TYPE_HD, 49 | MEDIA_TYPE_DVD, 50 | MEDIA_TYPE_DVDRAM, 51 | MEDIA_TYPE_DVDRW, 52 | MEDIA_TYPE_DVDR, 53 | MEDIA_TYPE_WORM, 54 | MEDIA_TYPE_MO, 55 | MEDIA_TYPE_CDRW, 56 | MEDIA_TYPE_CDR, 57 | MEDIA_TYPE_CD, 58 | MEDIA_TYPE_BDR, 59 | }; 60 | 61 | extern char *udf_space_type_str[UDF_SPACE_TYPE_SIZE]; 62 | 63 | void udf_init_disc(struct udf_disc *); 64 | int udf_set_version(struct udf_disc *, uint16_t); 65 | void split_space(struct udf_disc *); 66 | void dump_space(struct udf_disc *); 67 | int write_disc(struct udf_disc *); 68 | void setup_mbr(struct udf_disc *); 69 | void setup_vrs(struct udf_disc *); 70 | void setup_anchor(struct udf_disc *); 71 | void setup_partition(struct udf_disc *); 72 | int setup_space(struct udf_disc *, struct udf_extent *, uint32_t); 73 | int setup_fileset(struct udf_disc *, struct udf_extent *); 74 | int setup_root(struct udf_disc *, struct udf_extent *); 75 | void calc_space(struct udf_disc *, struct udf_extent *); 76 | void setup_vds(struct udf_disc *); 77 | void setup_pvd(struct udf_disc *, struct udf_extent *, struct udf_extent *, uint32_t); 78 | void setup_lvd(struct udf_disc *, struct udf_extent *, struct udf_extent *, struct udf_extent *, uint32_t); 79 | void setup_pd(struct udf_disc *, struct udf_extent *, struct udf_extent *, uint32_t); 80 | void setup_usd(struct udf_disc *, struct udf_extent *, struct udf_extent *, uint32_t); 81 | void setup_iuvd(struct udf_disc *, struct udf_extent *, struct udf_extent *, uint32_t); 82 | void setup_td(struct udf_disc *, struct udf_extent *, struct udf_extent *, uint32_t); 83 | void setup_lvid(struct udf_disc *, struct udf_extent *); 84 | void setup_stable(struct udf_disc *, struct udf_extent *[4], struct udf_extent *); 85 | void setup_vat(struct udf_disc *, struct udf_extent *); 86 | void add_type1_partition(struct udf_disc *, uint16_t); 87 | void add_type2_sparable_partition(struct udf_disc *, uint16_t, uint8_t, uint16_t); 88 | void add_type2_virtual_partition(struct udf_disc *, uint16_t); 89 | struct sparablePartitionMap *find_type2_sparable_partition(struct udf_disc *, uint16_t); 90 | 91 | #endif /* __MKUDFFS_H */ 92 | -------------------------------------------------------------------------------- /mkudffs/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | * options.h 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * Copyright (c) 2014-2021 Pali Rohár 6 | * All rights reserved. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | #ifndef _OPTIONS_H 25 | #define _OPTIONS_H 1 26 | 27 | void usage(void); 28 | void parse_args(int, char *[], struct udf_disc *, char **, int *, int *, int *); 29 | 30 | /* 31 | * Command line option token values. 32 | * 0x0000-0x00ff Single characters 33 | * 0x1000-0x1fff Long switches (no arg) 34 | * 0x2000-0x2fff Long settings (arg required) 35 | */ 36 | 37 | #define OPT_HELP 0x1000 38 | #define OPT_NO_EFE 0x1001 39 | #define OPT_LOCALE 0x1002 40 | #define OPT_UNICODE8 0x1003 41 | #define OPT_UNICODE16 0x1004 42 | #define OPT_UTF8 0x1005 43 | #define OPT_MEDIA_TYPE 0x1006 44 | #define OPT_CLOSED 0x1007 45 | #define OPT_VAT 0x1008 46 | #define OPT_NEW_FILE 0x1009 47 | #define OPT_NO_WRITE 0x1010 48 | #define OPT_READ_ONLY 0x1011 49 | 50 | #define OPT_BLK_SIZE 0x2000 51 | #define OPT_UDF_REV 0x2001 52 | #define OPT_LVID 0x2002 53 | #define OPT_VID 0x2003 54 | #define OPT_VSID 0x2004 55 | #define OPT_FSID 0x2005 56 | #define OPT_STRATEGY 0x2006 57 | #define OPT_SPARTABLE 0x2007 58 | #define OPT_PACKETLEN 0x2008 59 | #define OPT_SPARSPACE 0x2009 60 | #define OPT_SPACE 0x200A 61 | #define OPT_AD 0x200B 62 | #define OPT_LABEL 0x200C 63 | #define OPT_UUID 0x200D 64 | #define OPT_FULLVSID 0x200E 65 | #define OPT_UID 0x200F 66 | #define OPT_GID 0x2010 67 | #define OPT_MODE 0x2011 68 | #define OPT_BOOTAREA 0x2012 69 | #define OPT_START_BLOCK 0x2013 70 | #define OPT_MIN_BLOCKS 0x2014 71 | #define OPT_OWNER 0x2015 72 | #define OPT_ORG 0x2016 73 | #define OPT_CONTACT 0x2017 74 | 75 | #endif /* _OPTIONS_H */ 76 | -------------------------------------------------------------------------------- /pktsetup/Makefile.am: -------------------------------------------------------------------------------- 1 | sbin_PROGRAMS = pktsetup pktcdvd-check 2 | pktsetup_SOURCES = pktsetup.c 3 | pktcdvd_check_SOURCES = pktcdvd-check.c 4 | EXTRA_DIST = pktsetup.rules 5 | 6 | if UDEVDIR 7 | 8 | install-data-local: 9 | $(MKDIR_P) "$(DESTDIR)$(UDEVDIR)/rules.d" 10 | $(INSTALL_DATA) "$(srcdir)/pktsetup.rules" "$(DESTDIR)$(UDEVDIR)/rules.d/80-pktsetup.rules" 11 | 12 | uninstall-local: 13 | $(RM) "$(DESTDIR)$(UDEVDIR)/rules.d/80-pktsetup.rules" 14 | 15 | endif 16 | -------------------------------------------------------------------------------- /pktsetup/pktcdvd-check.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2021 Pali Rohár 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #include "bswap.h" 34 | 35 | int main(int argc, char *argv[]) { 36 | int fd; 37 | int ret; 38 | int quiet; 39 | char *device; 40 | struct stat st; 41 | int capability; 42 | int mmc_profile; 43 | unsigned char inquiry[36]; 44 | disc_information discinfo; 45 | track_information trackinfo; 46 | struct request_sense sense; 47 | struct feature_header features; 48 | struct cdrom_generic_command cgc; 49 | 50 | if (fcntl(0, F_GETFL) < 0 && open("/dev/null", O_RDONLY) < 0) 51 | _exit(1); 52 | if (fcntl(1, F_GETFL) < 0 && open("/dev/null", O_WRONLY) < 0) 53 | _exit(1); 54 | if (fcntl(2, F_GETFL) < 0 && open("/dev/null", O_WRONLY) < 0) 55 | _exit(1); 56 | 57 | if (argc == 3 && (strcmp(argv[1], "-q") == 0 || strcmp(argv[1], "--quiet") == 0)) { 58 | quiet = 1; 59 | device = argv[2]; 60 | } else if (argc == 2) { 61 | quiet = 0; 62 | device = argv[1]; 63 | } else { 64 | printf("pktcdvd-check from " PACKAGE_NAME " " PACKAGE_VERSION "\n"); 65 | printf("Check if medium in optical device can be used by pktcdvd\n"); 66 | printf("Usage: %s [-q|--quiet] device\n", argv[0]); 67 | return 1; 68 | } 69 | 70 | fd = open(device, O_RDONLY); 71 | if (fd < 0) { 72 | if (!quiet) 73 | fprintf(stderr, "Error: Cannot open device '%s': %s\n", device, strerror(errno)); 74 | return 1; 75 | } 76 | 77 | ret = fstat(fd, &st); 78 | if (ret != 0) { 79 | if (!quiet) 80 | fprintf(stderr, "Error: Cannot stat device '%s': %s\n", device, strerror(errno)); 81 | close(fd); 82 | return 1; 83 | } 84 | 85 | if (!S_ISBLK(st.st_mode)) { 86 | if (!quiet) 87 | fprintf(stderr, "Error: Filepath '%s' is not block device\n", device); 88 | close(fd); 89 | return 1; 90 | } 91 | 92 | /* CDROM_GET_CAPABILITY is not supported by pktcdvd devices therefore this prevent marking pktcdvd devices as compatible */ 93 | capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL); 94 | if (capability < 0) { 95 | if (!quiet) 96 | fprintf(stderr, "Error: Filepath '%s' is not optical device\n", device); 97 | close(fd); 98 | return 1; 99 | } 100 | 101 | if (!(capability & CDC_GENERIC_PACKET)) { 102 | if (!quiet) 103 | printf("Optical device '%s' does not support sending generic packets\n", device); 104 | close(fd); 105 | return 1; 106 | } 107 | 108 | memset(&cgc, 0, sizeof(cgc)); 109 | memset(&sense, 0, sizeof(sense)); 110 | memset(&inquiry, 0, sizeof(inquiry)); 111 | cgc.cmd[0] = GPCMD_INQUIRY; 112 | cgc.cmd[4] = sizeof(inquiry); 113 | cgc.buffer = inquiry; 114 | cgc.buflen = sizeof(inquiry); 115 | cgc.sense = &sense; 116 | cgc.data_direction = CGC_DATA_READ; 117 | cgc.quiet = 1; 118 | cgc.timeout = 500; 119 | 120 | ret = ioctl(fd, CDROM_SEND_PACKET, &cgc); 121 | if (ret != 0) { 122 | if (!quiet) 123 | fprintf(stderr, "Error: INQUIRY with size %hhu on device '%s' failed: %s (0x%02X,0x%02X,0x%02X)\n", cgc.cmd[4], device, strerror(errno), sense.sense_key, sense.asc, sense.ascq); 124 | close(fd); 125 | return 1; 126 | } 127 | 128 | if ((inquiry[0] & 0x1F) != 0x05) { 129 | if (!quiet) 130 | printf("Optical device '%s' is not MMC-compatible\n", device); 131 | close(fd); 132 | return 1; 133 | } 134 | 135 | memset(&cgc, 0, sizeof(cgc)); 136 | memset(&sense, 0, sizeof(sense)); 137 | memset(&features, 0, sizeof(features)); 138 | cgc.cmd[0] = GPCMD_GET_CONFIGURATION; 139 | cgc.cmd[8] = sizeof(features); 140 | cgc.buffer = (unsigned char *)&features; 141 | cgc.buflen = sizeof(features); 142 | cgc.sense = &sense; 143 | cgc.data_direction = CGC_DATA_READ; 144 | cgc.quiet = 1; 145 | cgc.timeout = 500; 146 | 147 | /* GET_CONFIGURATION is not supported by pre-MMC2 drives */ 148 | ret = ioctl(fd, CDROM_SEND_PACKET, &cgc); 149 | if (ret == 0) 150 | mmc_profile = be16_to_cpu(features.curr_profile); 151 | else 152 | mmc_profile = -1; 153 | 154 | memset(&cgc, 0, sizeof(cgc)); 155 | memset(&sense, 0, sizeof(sense)); 156 | memset(&discinfo, 0, sizeof(discinfo)); 157 | cgc.cmd[0] = GPCMD_READ_DISC_INFO; 158 | cgc.cmd[8] = sizeof(discinfo.disc_information_length); 159 | cgc.buffer = (unsigned char *)&discinfo.disc_information_length; 160 | cgc.buflen = sizeof(discinfo.disc_information_length); 161 | cgc.sense = &sense; 162 | cgc.data_direction = CGC_DATA_READ; 163 | cgc.quiet = 1; 164 | cgc.timeout = 500; 165 | 166 | ret = ioctl(fd, CDROM_SEND_PACKET, &cgc); 167 | if (ret != 0) { 168 | if (!quiet) 169 | fprintf(stderr, "Error: READ_DISC_INFO with size %hhu on device '%s' failed: %s (0x%02X,0x%02X,0x%02X)\n", cgc.cmd[8], device, strerror(errno), sense.sense_key, sense.asc, sense.ascq); 170 | close(fd); 171 | return 1; 172 | } 173 | 174 | /* Not all drives have the same disc_info length, so requeue packet with the length the drive tells us it can supply */ 175 | cgc.buffer = (unsigned char *)&discinfo; 176 | cgc.buflen = be16_to_cpu(discinfo.disc_information_length) + sizeof(discinfo.disc_information_length); 177 | if (cgc.buflen > sizeof(discinfo)) 178 | cgc.buflen = sizeof(discinfo); 179 | cgc.cmd[8] = cgc.buflen; 180 | 181 | ret = ioctl(fd, CDROM_SEND_PACKET, &cgc); 182 | if (ret != 0) { 183 | if (!quiet) 184 | fprintf(stderr, "Error: READ_DISC_INFO with size %hhu on device '%s' failed: %s (0x%02X,0x%02X,0x%02X)\n", cgc.cmd[8], device, strerror(errno), sense.sense_key, sense.asc, sense.ascq); 185 | close(fd); 186 | return 1; 187 | } 188 | 189 | memset(&cgc, 0, sizeof(cgc)); 190 | memset(&sense, 0, sizeof(sense)); 191 | memset(&trackinfo, 0, sizeof(trackinfo)); 192 | cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; 193 | cgc.cmd[1] = 1; /* type: 1 */ 194 | cgc.cmd[5] = 1; /* track: 1 */ 195 | cgc.cmd[8] = sizeof(trackinfo.track_information_length); 196 | cgc.buffer = (unsigned char *)&trackinfo.track_information_length; 197 | cgc.buflen = sizeof(trackinfo.track_information_length); 198 | cgc.sense = &sense; 199 | cgc.data_direction = CGC_DATA_READ; 200 | cgc.quiet = 1; 201 | cgc.timeout = 500; 202 | 203 | ret = ioctl(fd, CDROM_SEND_PACKET, &cgc); 204 | if (ret != 0) { 205 | if (!quiet) 206 | fprintf(stderr, "Error: READ_TRACK_RZONE_INFO for type %hhu and track %hhu with size %hhu on device '%s' failed: %s (0x%02X,0x%02X,0x%02X)\n", cgc.cmd[1], cgc.cmd[5], cgc.cmd[8], device, strerror(errno), sense.sense_key, sense.asc, sense.ascq); 207 | close(fd); 208 | return 1; 209 | } 210 | 211 | cgc.buffer = (unsigned char *)&trackinfo; 212 | cgc.buflen = be16_to_cpu(trackinfo.track_information_length) + sizeof(trackinfo.track_information_length); 213 | if (cgc.buflen > sizeof(trackinfo)) 214 | cgc.buflen = sizeof(trackinfo); 215 | cgc.cmd[8] = cgc.buflen; 216 | 217 | ret = ioctl(fd, CDROM_SEND_PACKET, &cgc); 218 | if (ret != 0) { 219 | if (!quiet) 220 | fprintf(stderr, "Error: READ_TRACK_RZONE_INFO for type %hhu and track %hhu with size %hhu on device '%s' failed: %s (0x%02X,0x%02X,0x%02X)\n", cgc.cmd[1], cgc.cmd[5], cgc.cmd[8], device, strerror(errno), sense.sense_key, sense.asc, sense.ascq); 221 | close(fd); 222 | return 1; 223 | } 224 | 225 | close(fd); 226 | 227 | /* Supported media types */ 228 | if (mmc_profile != 0x0A && mmc_profile != 0x12 && mmc_profile != 0x13 && mmc_profile != 0x1A && mmc_profile != -1) { 229 | if (!quiet) 230 | printf("Optical device '%s' does not contain CD-RW nor DVD-RAM nor DVD-RW nor DVD+RW medium\n", device); 231 | return 1; 232 | } 233 | 234 | /* Requirements for CD-RW */ 235 | if (mmc_profile == 0x0A || mmc_profile == -1) { 236 | if (!discinfo.erasable) { 237 | if (!quiet) 238 | printf("%s device '%s' %sis not erasable or the drive is not capable of writing the media\n", (mmc_profile == -1) ? "Optical" : "CD-RW", device, (mmc_profile == -1) ? "is not CD-RW or " : ""); 239 | return 1; 240 | } 241 | if (discinfo.disc_type != 0x20 && discinfo.disc_type != 0x00) { 242 | if (!quiet) 243 | printf("CD-RW device '%s' is not CD-ROM XA Disc nor CD-ROM Disc compatible\n", device); 244 | return 1; 245 | } 246 | if (discinfo.border_status == 2) { 247 | if (!quiet) 248 | printf("CD-RW device '%s' has reserved session\n", device); 249 | return 1; 250 | } 251 | } 252 | 253 | /* Requirements for CD-RW and DVD-RW */ 254 | if (mmc_profile == 0x0A || mmc_profile == -1 || mmc_profile == 0x13) { 255 | if (!trackinfo.packet) { 256 | if (!quiet) 257 | printf("CD-RW/DVD-RW device '%s' is not formatted to packet writing mode\n", device); 258 | return 1; 259 | } 260 | if (!trackinfo.fp) { 261 | if (!quiet) 262 | printf("CD-RW/DVD-RW device '%s' is not formatted to overwritable mode\n", device); 263 | return 1; 264 | } 265 | if (trackinfo.rt && trackinfo.blank) { 266 | if (!quiet) 267 | printf("CD-RW/DVD-RW device '%s' is blank or unformatted\n", device); 268 | return 1; 269 | } 270 | } 271 | 272 | if (be32_to_cpu(trackinfo.fixed_packet_size) == 0 || be32_to_cpu(trackinfo.fixed_packet_size) >= 128) { 273 | if (!quiet) 274 | printf("Optical device '%s' has invalid packet size\n", device); 275 | return 1; 276 | } 277 | 278 | if (trackinfo.data_mode != 1 && trackinfo.data_mode != 2) { 279 | if (!quiet) 280 | printf("Optical device '%s' is not Mode 1 nor Mode 2\n", device); 281 | return 1; 282 | } 283 | 284 | if (!quiet) 285 | printf("Optical device '%s' is compatible with pktcdvd\n", device); 286 | return 0; 287 | } 288 | -------------------------------------------------------------------------------- /pktsetup/pktsetup.rules: -------------------------------------------------------------------------------- 1 | # Skip non-optical drives 2 | SUBSYSTEM!="block", GOTO="pktsetup_end" 3 | ENV{ID_CDROM}!="1", GOTO="pktsetup_end" 4 | 5 | # Remove packet writing mapping when optical drive was removed or when media was removed or eject was requested 6 | ACTION=="remove", GOTO="pktsetup_remove" 7 | ENV{ID_CDROM_MEDIA}!="?*", GOTO="pktsetup_remove" 8 | ENV{DISK_EJECT_REQUEST}=="1", GOTO="pktsetup_remove" 9 | 10 | # Kernel pktcdvd.ko driver supports write operations only for CD-RW, DVD+RW, DVD-RW and DVD-RAM 11 | ENV{ID_CDROM_MEDIA_CD_RW}=="1", GOTO="pktsetup_check" 12 | ENV{ID_CDROM_MEDIA_DVD_PLUS_RW}=="1", GOTO="pktsetup_check" 13 | ENV{ID_CDROM_MEDIA_DVD_RW}=="1", GOTO="pktsetup_check" 14 | ENV{ID_CDROM_MEDIA_DVD_RAM}=="1", GOTO="pktsetup_check" 15 | 16 | # Remove packet writing mapping for other unsupported media types 17 | GOTO="pktsetup_remove" 18 | 19 | LABEL="pktsetup_check" 20 | PROGRAM="/usr/sbin/pktcdvd-check -q $devnode", GOTO="pktsetup_add" 21 | # Remove packet writing mapping for media which does not pass pktcdvd check 22 | GOTO="pktsetup_remove" 23 | 24 | LABEL="pktsetup_add" 25 | RUN+="/usr/sbin/pktsetup -i $major:$minor" 26 | GOTO="pktsetup_end" 27 | 28 | LABEL="pktsetup_remove" 29 | RUN+="/usr/sbin/pktsetup -i -d $major:$minor" 30 | GOTO="pktsetup_end" 31 | 32 | LABEL="pktsetup_end" 33 | -------------------------------------------------------------------------------- /udffsck/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = udffsck 2 | udffsck_SOURCES = main.c 3 | 4 | AM_CPPFLAGS = -I$(top_srcdir)/include 5 | -------------------------------------------------------------------------------- /udffsck/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | * 4 | * Copyright (c) 2001-2002 Ben Fennema 5 | * All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | int main() 24 | { 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /udfinfo/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = udfinfo 2 | udfinfo_LDADD = $(top_builddir)/libudffs/libudffs.la 3 | udfinfo_SOURCES = main.c readdisc.c options.c readdisc.h options.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h ../include/bswap.h 4 | AM_CPPFLAGS = -I$(top_srcdir)/include 5 | -------------------------------------------------------------------------------- /udfinfo/options.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2021 Pali Rohár 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include "libudffs.h" 29 | #include "options.h" 30 | 31 | static struct option long_options[] = { 32 | { "help", no_argument, NULL, OPT_HELP }, 33 | { "blocksize", required_argument, NULL, OPT_BLK_SIZE }, 34 | { "startblock", required_argument, NULL, OPT_START_BLOCK }, 35 | { "lastblock", required_argument, NULL, OPT_LAST_BLOCK }, 36 | { "vatblock", required_argument, NULL, OPT_VAT_BLOCK }, 37 | { "locale", no_argument, NULL, OPT_LOCALE }, 38 | { "u8", no_argument, NULL, OPT_UNICODE8 }, 39 | { "u16", no_argument, NULL, OPT_UNICODE16 }, 40 | { "utf8", no_argument, NULL, OPT_UTF8 }, 41 | { 0, 0, NULL, 0 }, 42 | }; 43 | 44 | static void usage(void) 45 | { 46 | fprintf(stderr, "udfinfo from " PACKAGE_NAME " " PACKAGE_VERSION "\n" 47 | "Usage:\n" 48 | "\tudfinfo [--locale|--u8|--u16|--utf8] [-b|--blocksize=block-size] [--startblock=block] [--lastblock=block] [--vatblock=block] device\n" 49 | ); 50 | exit(1); 51 | } 52 | 53 | void parse_args(int argc, char *argv[], struct udf_disc *disc, char **filename) 54 | { 55 | int failed; 56 | int ret; 57 | 58 | while ((ret = getopt_long(argc, argv, "b:h", long_options, NULL)) != EOF) 59 | { 60 | switch (ret) 61 | { 62 | case OPT_HELP: 63 | case 'h': 64 | usage(); 65 | break; 66 | case OPT_BLK_SIZE: 67 | case 'b': 68 | disc->blocksize = strtou32(optarg, 0, &failed); 69 | if (failed || disc->blocksize < 512 || disc->blocksize > 32768 || (disc->blocksize & (disc->blocksize - 1))) 70 | { 71 | fprintf(stderr, "%s: Error: Invalid value for option --blocksize\n", appname); 72 | exit(1); 73 | } 74 | break; 75 | case OPT_START_BLOCK: 76 | disc->start_block = strtou32(optarg, 0, &failed); 77 | if (failed) 78 | { 79 | fprintf(stderr, "%s: Error: Invalid value for option --startblock\n", appname); 80 | exit(1); 81 | } 82 | break; 83 | case OPT_LAST_BLOCK: 84 | disc->last_block = strtou32(optarg, 0, &failed); 85 | if (failed) 86 | { 87 | fprintf(stderr, "%s: Error: Invalid value for option --lastblock\n", appname); 88 | exit(1); 89 | } 90 | break; 91 | case OPT_VAT_BLOCK: 92 | disc->vat_block = strtou32(optarg, 0, &failed); 93 | if (failed) 94 | { 95 | fprintf(stderr, "%s: Error: Invalid value for option --vatblock\n", appname); 96 | exit(1); 97 | } 98 | break; 99 | case OPT_UNICODE8: 100 | disc->flags &= ~FLAG_CHARSET; 101 | disc->flags |= FLAG_UNICODE8; 102 | break; 103 | case OPT_UNICODE16: 104 | disc->flags &= ~FLAG_CHARSET; 105 | disc->flags |= FLAG_UNICODE16; 106 | break; 107 | case OPT_UTF8: 108 | disc->flags &= ~FLAG_CHARSET; 109 | disc->flags |= FLAG_UTF8; 110 | break; 111 | case OPT_LOCALE: 112 | disc->flags &= ~FLAG_CHARSET; 113 | disc->flags |= FLAG_LOCALE; 114 | break; 115 | default: 116 | usage(); 117 | break; 118 | } 119 | } 120 | 121 | if (optind+1 != argc) 122 | usage(); 123 | 124 | *filename = argv[optind]; 125 | } 126 | -------------------------------------------------------------------------------- /udfinfo/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2021 Pali Rohár 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef OPTIONS_H 20 | #define OPTIONS_H 21 | 22 | struct udf_disc; 23 | 24 | void parse_args(int, char *[], struct udf_disc *, char **); 25 | 26 | /* 27 | * Command line option token values. 28 | * 0x0000-0x00ff Single characters 29 | * 0x1000-0x1fff Long switches (no arg) 30 | * 0x2000-0x2fff Long settings (arg required) 31 | */ 32 | 33 | #define OPT_HELP 0x1000 34 | #define OPT_LOCALE 0x1001 35 | #define OPT_UNICODE8 0x1002 36 | #define OPT_UNICODE16 0x1003 37 | #define OPT_UTF8 0x1004 38 | 39 | #define OPT_BLK_SIZE 0x2000 40 | #define OPT_VAT_BLOCK 0x2001 41 | #define OPT_START_BLOCK 0x2002 42 | #define OPT_LAST_BLOCK 0x2003 43 | 44 | #endif /* OPTIONS_H */ 45 | -------------------------------------------------------------------------------- /udfinfo/readdisc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Pali Rohár 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef READDISC_H 20 | #define READDISC_H 21 | 22 | struct udf_disc; 23 | 24 | int read_disc(int, struct udf_disc *); 25 | 26 | #endif /* READDISC_H */ 27 | -------------------------------------------------------------------------------- /udflabel/Makefile.am: -------------------------------------------------------------------------------- 1 | sbin_PROGRAMS = udflabel 2 | udflabel_LDADD = $(top_builddir)/libudffs/libudffs.la 3 | udflabel_SOURCES = main.c options.c ../udfinfo/readdisc.c options.h ../udfinfo/readdisc.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h ../include/bswap.h 4 | AM_CPPFLAGS = -I$(top_srcdir)/include 5 | -------------------------------------------------------------------------------- /udflabel/options.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2021 Pali Rohár 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #include "libudffs.h" 38 | #include "options.h" 39 | 40 | static struct option long_options[] = { 41 | { "help", no_argument, NULL, OPT_HELP }, 42 | { "blocksize", required_argument, NULL, OPT_BLK_SIZE }, 43 | { "startblock", required_argument, NULL, OPT_START_BLOCK }, 44 | { "lastblock", required_argument, NULL, OPT_LAST_BLOCK }, 45 | { "vatblock", required_argument, NULL, OPT_VAT_BLOCK }, 46 | { "force", no_argument, NULL, OPT_FORCE }, 47 | { "no-write", no_argument, NULL, OPT_NO_WRITE }, 48 | { "uuid", required_argument, NULL, OPT_UUID }, 49 | { "lvid", required_argument, NULL, OPT_LVID }, 50 | { "vid", required_argument, NULL, OPT_VID }, 51 | { "vsid", required_argument, NULL, OPT_VSID }, 52 | { "fsid", required_argument, NULL, OPT_FSID }, 53 | { "fullvsid", required_argument, NULL, OPT_FULLVSID }, 54 | { "owner", required_argument, NULL, OPT_OWNER }, 55 | { "organization", required_argument, NULL, OPT_ORG }, 56 | { "contact", required_argument, NULL, OPT_CONTACT }, 57 | { "appid", required_argument, NULL, OPT_APPID }, 58 | { "impid", required_argument, NULL, OPT_IMPID }, 59 | { "locale", no_argument, NULL, OPT_LOCALE }, 60 | { "u8", no_argument, NULL, OPT_UNICODE8 }, 61 | { "u16", no_argument, NULL, OPT_UNICODE16 }, 62 | { "utf8", no_argument, NULL, OPT_UTF8 }, 63 | { 0, 0, NULL, 0 }, 64 | }; 65 | 66 | static void usage(void) 67 | { 68 | fprintf(stderr, "udflabel from " PACKAGE_NAME " " PACKAGE_VERSION "\n" 69 | "Usage:\n" 70 | "\tudflabel [encoding-options] [block-options] [identifier-options] device [new-label]\n" 71 | "\n" 72 | "When all Identifier Options and new UDF Label are omitted then show current UDF Label.\n" 73 | "Otherwise set new Identifier Options. New UDF Label is synonym for both --lvid and --vid.\n" 74 | "\n" 75 | "Options:\n" 76 | "\t--help, -h Display this help\n" 77 | "\n" 78 | "Block Options:\n" 79 | "\t--blocksize=, -b Size of blocks in bytes (512, 1024, 2048, 4096, 8192, 16384, 32768; default: detect)\n" 80 | "\t--startblock= Block location where the UDF filesystem starts (default: last session from TOC or 0)\n" 81 | "\t--lastblock= Block location where the UDF filesystem ends (default: VAT block or last device block)\n" 82 | "\t--vatblock= Block location of the Virtual Allocation Table (default: detect)\n" 83 | "\t--force Force updating UDF disks without write support (useful only for disk images)\n" 84 | "\t--no-write, -n Not really, do not write to device, just simulate\n" 85 | "\n" 86 | "Identifier Options:\n" 87 | "\t--uuid=, -u New UDF UUID, first 16 characters of Volume Set Identifier\n" 88 | "\t--lvid= New Logical Volume Identifier\n" 89 | "\t--vid= New Volume Identifier\n" 90 | "\t--vsid= New 17.-127. character of Volume Set Identifier\n" 91 | "\t--fsid= New File Set Identifier\n" 92 | "\t--fullvsid= New full Volume Set Identifier, overwrite --uuid and --vsid\n" 93 | "\t--owner= New Owner name\n" 94 | "\t--organization= New Organization name\n" 95 | "\t--contact= New Contact information\n" 96 | "\t--appid= New Application Identifier\n" 97 | "\t--impid= New Developer Identifier for Implementation Identifier\n" 98 | "\n" 99 | "Encoding Options:\n" 100 | "\t--locale Identifier options are encoded according to current locale (default)\n" 101 | "\t--u8 Identifier options are encoded in Latin1\n" 102 | "\t--u16 Identifier options are encoded in UTF-16BE\n" 103 | "\t--utf8 Identifier options are encoded in UTF-8\n" 104 | ); 105 | exit(1); 106 | } 107 | 108 | static void process_uuid_arg(const char *arg, char *new_uuid) 109 | { 110 | int i; 111 | time_t cur_time; 112 | uint32_t uuid_time; 113 | 114 | if (strcmp(arg, "random") == 0) 115 | { 116 | cur_time = time(NULL); 117 | if (cur_time != (time_t)-1 && cur_time >= 0) 118 | uuid_time = cur_time & 0xFFFFFFFF; 119 | else 120 | uuid_time = randu32(); 121 | snprintf(new_uuid, 17, "%08"PRIx32"%08"PRIx32"", uuid_time, randu32()); 122 | return; 123 | } 124 | 125 | if (strlen(arg) != 16) 126 | { 127 | fprintf(stderr, "%s: Error: Option --uuid is not 16 bytes long\n", appname); 128 | exit(1); 129 | } 130 | 131 | for (i = 0; i < 16; ++i) 132 | { 133 | if (!isxdigit((unsigned char)arg[i]) || (!isdigit((unsigned char)arg[i]) && !islower((unsigned char)arg[i]))) 134 | { 135 | fprintf(stderr, "%s: Error: Option --uuid is not in lowercase hexadecimal digit format\n", appname); 136 | exit(1); 137 | } 138 | } 139 | 140 | memcpy(new_uuid, arg, 17); 141 | } 142 | 143 | static void process_vid_lvid_arg(struct udf_disc *disc, int option, const char *arg, dstring *new_lvid, dstring *new_vid) 144 | { 145 | if (option != OPT_VID) 146 | { 147 | if (encode_string(disc, new_lvid, arg, 128) == (size_t)-1) 148 | { 149 | if (option == OPT_LVID) 150 | fprintf(stderr, "%s: Error: Option --lvid is too long\n", appname); 151 | else 152 | fprintf(stderr, "%s: Error: Label is too long\n", appname); 153 | exit(1); 154 | } 155 | } 156 | 157 | if (option != OPT_LVID) 158 | { 159 | if (encode_string(disc, new_vid, arg, 32) == (size_t)-1) 160 | { 161 | if (option == OPT_VID) 162 | { 163 | fprintf(stderr, "%s: Error: Option --vid is too long\n", appname); 164 | exit(1); 165 | } 166 | /* This code was not triggered by --vid option, do not throw error but rather store truncated --lvid */ 167 | memcpy(new_vid, new_lvid, 32); 168 | new_vid[31] = 31; 169 | } 170 | } 171 | } 172 | 173 | void parse_args(int argc, char *argv[], struct udf_disc *disc, char **filename, int *force, dstring *new_lvid, dstring *new_vid, dstring *new_fsid, dstring *new_fullvsid, char *new_uuid, dstring *new_vsid, dstring *new_owner, dstring *new_org, dstring *new_contact, char *new_appid, char *new_impid) 174 | { 175 | int failed; 176 | int ret; 177 | size_t len; 178 | 179 | while ((ret = getopt_long(argc, argv, "b:nu:h", long_options, NULL)) != EOF) 180 | { 181 | switch (ret) 182 | { 183 | case OPT_HELP: 184 | case 'h': 185 | usage(); 186 | break; 187 | case OPT_BLK_SIZE: 188 | case 'b': 189 | disc->blocksize = strtou32(optarg, 0, &failed); 190 | if (failed || disc->blocksize < 512 || disc->blocksize > 32768 || (disc->blocksize & (disc->blocksize - 1))) 191 | { 192 | fprintf(stderr, "%s: Error: Invalid value for option --blocksize\n", appname); 193 | exit(1); 194 | } 195 | break; 196 | case OPT_START_BLOCK: 197 | disc->start_block = strtou32(optarg, 0, &failed); 198 | if (failed) 199 | { 200 | fprintf(stderr, "%s: Error: Invalid value for option --startblock\n", appname); 201 | exit(1); 202 | } 203 | break; 204 | case OPT_LAST_BLOCK: 205 | disc->last_block = strtou32(optarg, 0, &failed); 206 | if (failed) 207 | { 208 | fprintf(stderr, "%s: Error: Invalid value for option --lastblock\n", appname); 209 | exit(1); 210 | } 211 | break; 212 | case OPT_VAT_BLOCK: 213 | disc->vat_block = strtou32(optarg, 0, &failed); 214 | if (failed) 215 | { 216 | fprintf(stderr, "%s: Error: Invalid value for option --vatblock\n", appname); 217 | exit(1); 218 | } 219 | break; 220 | case OPT_FORCE: 221 | *force = 1; 222 | break; 223 | case OPT_NO_WRITE: 224 | case 'n': 225 | disc->flags |= FLAG_NO_WRITE; 226 | break; 227 | case OPT_UUID: 228 | case 'u': 229 | process_uuid_arg(optarg, new_uuid); 230 | new_fullvsid[0] = 0xFF; 231 | break; 232 | case OPT_VID: 233 | case OPT_LVID: 234 | process_vid_lvid_arg(disc, ret, optarg, new_lvid, new_vid); 235 | break; 236 | case OPT_VSID: 237 | len = encode_string(disc, new_vsid, optarg, 128); 238 | if (len == (size_t)-1 || len > 127-16 || (new_vsid[0] == 16 && len > 127-16*2)) 239 | { 240 | fprintf(stderr, "%s: Error: Option --vsid is too long\n", appname); 241 | exit(1); 242 | } 243 | new_fullvsid[0] = 0xFF; 244 | break; 245 | case OPT_FULLVSID: 246 | if (encode_string(disc, new_fullvsid, optarg, 128) == (size_t)-1) 247 | { 248 | fprintf(stderr, "%s: Error: Option --fullvsid is too long\n", appname); 249 | exit(1); 250 | } 251 | new_uuid[0] = 0; 252 | new_vsid[0] = 0xFF; 253 | break; 254 | case OPT_FSID: 255 | if (encode_string(disc, new_fsid, optarg, 32) == (size_t)-1) 256 | { 257 | fprintf(stderr, "%s: Error: Option --fsid is too long\n", appname); 258 | exit(1); 259 | } 260 | break; 261 | case OPT_OWNER: 262 | if (encode_string(disc, new_owner, optarg, 36) == (size_t)-1) 263 | { 264 | fprintf(stderr, "%s: Error: Option --owner is too long\n", appname); 265 | exit(1); 266 | } 267 | break; 268 | case OPT_ORG: 269 | if (encode_string(disc, new_org, optarg, 36) == (size_t)-1) 270 | { 271 | fprintf(stderr, "%s: Error: Option --organization is too long\n", appname); 272 | exit(1); 273 | } 274 | break; 275 | case OPT_CONTACT: 276 | if (encode_string(disc, new_contact, optarg, 36) == (size_t)-1) 277 | { 278 | fprintf(stderr, "%s: Error: Option --contact is too long\n", appname); 279 | exit(1); 280 | } 281 | break; 282 | case OPT_APPID: 283 | case OPT_IMPID: 284 | len = strlen(optarg); 285 | if (len > 23) 286 | { 287 | fprintf(stderr, "%s: Error: Option --%s is too long\n", appname, ret == OPT_APPID ? "appid" : "impid"); 288 | exit(1); 289 | } 290 | if (len > 0) 291 | { 292 | if (len < 2) 293 | { 294 | fprintf(stderr, "%s: Error: Option --%s is too short\n", appname, ret == OPT_APPID ? "appid" : "impid"); 295 | exit(1); 296 | } 297 | if (optarg[0] != '*') 298 | { 299 | fprintf(stderr, "%s: Error: Option --%s does not start with '*'\n", appname, ret == OPT_APPID ? "appid" : "impid"); 300 | exit(1); 301 | } 302 | } 303 | memcpy(ret == OPT_APPID ? new_appid : new_impid, optarg, len < 23 ? len+1 : 23); 304 | for (; len > 0; len--) 305 | { 306 | if ((unsigned char)optarg[len-1] > 127) 307 | { 308 | fprintf(stderr, "%s: Error: Option --%s is not 7bit ASCII string\n", appname, ret == OPT_APPID ? "appid" : "impid"); 309 | exit(1); 310 | } 311 | } 312 | break; 313 | case OPT_UNICODE8: 314 | disc->flags &= ~FLAG_CHARSET; 315 | disc->flags |= FLAG_UNICODE8; 316 | if (strcmp(argv[1], "--u8") != 0) 317 | { 318 | fprintf(stderr, "%s: Error: Option --u8 must be specified as first argument\n", appname); 319 | exit(1); 320 | } 321 | break; 322 | case OPT_UNICODE16: 323 | disc->flags &= ~FLAG_CHARSET; 324 | disc->flags |= FLAG_UNICODE16; 325 | if (strcmp(argv[1], "--u16") != 0) 326 | { 327 | fprintf(stderr, "%s: Error: Option --u16 must be specified as first argument\n", appname); 328 | exit(1); 329 | } 330 | break; 331 | case OPT_UTF8: 332 | disc->flags &= ~FLAG_CHARSET; 333 | disc->flags |= FLAG_UTF8; 334 | if (strcmp(argv[1], "--utf8") != 0) 335 | { 336 | fprintf(stderr, "%s: Error: Option --utf8 must be specified as first argument\n", appname); 337 | exit(1); 338 | } 339 | break; 340 | case OPT_LOCALE: 341 | disc->flags &= ~FLAG_CHARSET; 342 | disc->flags |= FLAG_LOCALE; 343 | if (strcmp(argv[1], "--locale") != 0) 344 | { 345 | fprintf(stderr, "%s: Error: Option --locale must be specified as first argument\n", appname); 346 | exit(1); 347 | } 348 | break; 349 | default: 350 | usage(); 351 | break; 352 | } 353 | } 354 | 355 | if (optind+1 != argc && optind+2 != argc) 356 | usage(); 357 | 358 | *filename = argv[optind]; 359 | 360 | if (optind+2 == argc) 361 | process_vid_lvid_arg(disc, -1, argv[optind+1], new_lvid, new_vid); 362 | } 363 | -------------------------------------------------------------------------------- /udflabel/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2021 Pali Rohár 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef OPTIONS_H 20 | #define OPTIONS_H 21 | 22 | struct udf_disc; 23 | 24 | void parse_args(int, char *[], struct udf_disc *, char **, int *, dstring *, dstring *, dstring *, dstring *, char *, dstring *, dstring *, dstring *, dstring *, char *, char *); 25 | 26 | /* 27 | * Command line option token values. 28 | * 0x0000-0x00ff Single characters 29 | * 0x1000-0x1fff Long switches (no arg) 30 | * 0x2000-0x2fff Long settings (arg required) 31 | */ 32 | 33 | #define OPT_HELP 0x1000 34 | #define OPT_LOCALE 0x1001 35 | #define OPT_UNICODE8 0x1002 36 | #define OPT_UNICODE16 0x1003 37 | #define OPT_UTF8 0x1004 38 | #define OPT_FORCE 0x1005 39 | #define OPT_NO_WRITE 0x1006 40 | 41 | #define OPT_BLK_SIZE 0x2000 42 | #define OPT_VAT_BLOCK 0x2001 43 | #define OPT_UUID 0x2002 44 | #define OPT_LVID 0x2003 45 | #define OPT_VID 0x2004 46 | #define OPT_VSID 0x2005 47 | #define OPT_FSID 0x2006 48 | #define OPT_FULLVSID 0x2007 49 | #define OPT_START_BLOCK 0x2008 50 | #define OPT_LAST_BLOCK 0x2009 51 | #define OPT_OWNER 0x200A 52 | #define OPT_ORG 0x200B 53 | #define OPT_CONTACT 0x200C 54 | #define OPT_APPID 0x200D 55 | #define OPT_IMPID 0x200E 56 | 57 | #endif /* OPTIONS_H */ 58 | -------------------------------------------------------------------------------- /wrudf/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = wrudf 2 | wrudf_LDADD = $(top_builddir)/libudffs/libudffs.la 3 | wrudf_SOURCES = wrudf.c wrudf-cmnd.c wrudf-desc.c wrudf-cdrw.c wrudf-cdr.c ide-pc.c wrudf.h ide-pc.h ../include/ecma_167.h ../include/osta_udf.h ../include/bswap.h 4 | 5 | AM_CPPFLAGS = -I$(top_srcdir)/include 6 | 7 | if USE_READLINE 8 | wrudf_LDADD += $(READLINE_LIBS) 9 | AM_CPPFLAGS += -DUSE_READLINE 10 | endif 11 | -------------------------------------------------------------------------------- /wrudf/ide-pc.h: -------------------------------------------------------------------------------- 1 | /* ide-pc.h 2 | * 3 | * PURPOSE 4 | * Header file for programs using ide-pc.c defined routines 5 | * 6 | * COPYRIGHT 7 | * This file is distributed under the terms of the GNU General Public 8 | * License (GPL). Copies of the GPL can be obtained from: 9 | * ftp://prep.ai.mit.edu/pub/gnu/GPL 10 | * Each contributing author retains all rights to their own work. 11 | * 12 | * (C) 2001 Enno Fennema 13 | * 14 | * HISTORY 15 | * 16 Aug 01 ef Created. 16 | * 17 | */ 18 | 19 | #ifndef _IDE_PC_H 20 | #define _IDE_PC_H 21 | 22 | #include 23 | 24 | struct cdrom_inquiry { 25 | u_char type : 5; /* 0 */ 26 | #define INQ_WORM 4 27 | #define INQ_CDROM 5 28 | u_char qualifier : 3; /* 0 */ 29 | 30 | u_char type_modifier : 7; /* 1 */ 31 | u_char removable : 1; /* 1 */ 32 | 33 | u_char ansi_version : 3; /* 2 */ 34 | u_char ecma_version : 3; /* 2 */ 35 | u_char iso_version : 2; /* 2 */ 36 | 37 | u_char data_format : 4; /* 3 */ 38 | u_char res3_54 : 2; /* 3 */ 39 | u_char termiop : 1; /* 3 */ 40 | u_char aenc : 1; /* 3 */ 41 | 42 | u_char add_len : 8; /* 4 */ 43 | u_char sense_len : 8; /* 5 */ /* only Emulex ??? */ 44 | u_char res2 : 8; /* 6 */ 45 | 46 | u_char softreset : 1; /* 7 */ 47 | u_char cmdque : 1; 48 | u_char res7_2 : 1; 49 | u_char linked : 1; 50 | u_char sync : 1; 51 | u_char wbus16 : 1; 52 | u_char wbus32 : 1; 53 | u_char reladr : 1; /* 7 */ 54 | 55 | char vendor_info[8]; /* 8 */ 56 | char prod_ident[16]; /* 16 */ 57 | char prod_revision[4]; /* 32 */ 58 | char vendor_uniq[20]; /* 36 */ 59 | char reserved[40]; /* 56 to 96 */ 60 | }; 61 | 62 | struct cdrom_discinfo { 63 | u_short data_length; 64 | u_char disc_status :2; 65 | #define DS_EMPTY 0 /* Empty disk */ 66 | #define DS_APPENDABLE 1 /* Incomplete disk (appendable) */ 67 | #define DS_COMPLETE 2 /* Complete disk (closed/no B0 pointer) */ 68 | u_char session_status :2; 69 | #define SS_EMPTY 0 /* Empty session */ 70 | #define SS_APPENDABLE 1 /* Incomplete session */ 71 | #define SS_COMPLETE 3 /* Complete session (needs DS_COMPLETE) */ 72 | u_char erasable:1; 73 | u_char _r1 :3; 74 | 75 | u_char trk0; 76 | u_char nsessions; 77 | u_char trk0_lastsession; 78 | u_char trk1_lastsession; 79 | u_char _r4 :5; 80 | u_char uru :1; 81 | u_char dbc_v :1; 82 | u_char did_v :1; 83 | u_char disc_type; 84 | u_char _r9; 85 | u_char _r10; 86 | u_char _r11; 87 | u_int disc_id; 88 | u_char latest_leadin_msf[4]; 89 | u_char last_leadout_msf[4]; 90 | u_char barcode[8]; 91 | u_char _r32; 92 | u_char n_opc; 93 | }; 94 | 95 | struct cdrom_trackinfo { 96 | u_short data_length; 97 | u_char trk; 98 | u_char session; 99 | u_char _r4; 100 | u_char trk_mode :4; 101 | u_char copy :1; 102 | u_char damage :1; 103 | u_char _r5 :2; 104 | u_char data_mode :4; 105 | u_char fixpkt :1; 106 | u_char packet :1; 107 | u_char blank :1; 108 | u_char rsrvd_trk :1; 109 | u_char nwa_v :1; 110 | u_char _r7 :7; 111 | u_int trk_start; 112 | u_int nwa; 113 | u_int free_blks; 114 | u_int fixpkt_size; 115 | u_int trk_size; 116 | }; 117 | 118 | struct cdrom_buffercapacity { 119 | u_short dataLength; 120 | u_short rsrvd; 121 | u_int totalBufferLength; 122 | u_int freeBufferLength; 123 | }; 124 | 125 | struct cdrom_reccapacity { 126 | u_int lastblock; 127 | u_int blocksize; 128 | }; 129 | 130 | struct cdrom_header { 131 | u_char datamode; 132 | u_char _r234[3]; 133 | int lba; 134 | }; 135 | 136 | #define PGCTL_CURRENT_VALUES 0 137 | #define PGCTL_CHANGE_MASK 1 138 | #define PGCTL_DEFAULT_VALUES 2 139 | #define PGCTL_SAVED_VALUES 3 140 | 141 | typedef struct mode_header { 142 | u_short data_length; // length excl. this field 143 | u_char medium_type; 144 | u_char dev_specific; 145 | u_short r1; 146 | u_short block_desc_length; // 0 147 | } mode_hdr; 148 | 149 | #define GPMODE_READ_ERROR_RECOV_PAGE 0x01 // Read/Write Error Recov in Mt Fuji version 150 | 151 | struct read_error_recovery_params { 152 | u_char page_code :6; // 07h 153 | u_char _r1 :1; 154 | u_char ps :1; 155 | u_char length; 156 | u_char error_recovery_param; 157 | u_char retry_count; 158 | u_char _r2[4]; 159 | }; 160 | 161 | #define GPMODE_CACHE_PAGE 0x08 // Cache control page 162 | 163 | struct cdrom_cacheparams { 164 | u_char page_code :6; // 08h 165 | u_char _r1 :1; 166 | u_char ps :1; 167 | u_char length; 168 | u_char rcd :1; 169 | u_char mf :1; 170 | u_char wce :1; 171 | u_char _r2 :5; 172 | u_short dpftl; 173 | u_short minpf; 174 | u_short maxpf; 175 | u_short maxpfceiling; 176 | }; 177 | 178 | 179 | struct cdrom_writeparams { 180 | u_char page_code :6; 181 | u_char _r1 :1; 182 | u_char ps :1; 183 | u_char page_length; 184 | 185 | u_char write_type :4; 186 | u_char test_write :1; 187 | u_char _r2 :3; 188 | 189 | u_char trk_mode :4; 190 | u_char copy :1; 191 | u_char fp :1; 192 | u_char multi_session :2; 193 | #define MS_NONE 0 /* No B0 pointer. Next session not allowed*/ 194 | #define MS_FINAL 1 /* B0 = FF:FF:FF. Next session not allowed*/ 195 | #define MS_MULTI 3 /* B0 = Next PA. Next session allowed */ 196 | 197 | u_char data_blk_type :4; 198 | #define DB_RAW 0 /* 2352 bytes of raw data */ 199 | #define DB_RAW_PQ 1 /* 2368 bytes (raw data + P/Q Subchannel) */ 200 | #define DB_RAW_PW 2 /* 2448 bytes (raw data + P-W Subchannel) */ 201 | #define DB_RAW_PW_R 3 /* 2448 bytes (raw data + P-W raw Subchannel)*/ 202 | #define DB_RES_4 4 /* - Reserved */ 203 | #define DB_RES_5 5 /* - Reserved */ 204 | #define DB_RES_6 6 /* - Reserved */ 205 | #define DB_VU_7 7 /* - Vendor specific */ 206 | #define DB_ROM_MODE1 8 /* 2048 bytes Mode 1 (ISO/IEC 10149) */ 207 | #define DB_ROM_MODE2 9 /* 2336 bytes Mode 2 (ISO/IEC 10149) */ 208 | #define DB_XA_F1 10 /* 2048 bytes Mode 2? (CD-ROM XA form 1) */ 209 | #define DB_XA_F1_8H 11 /* 2056 bytes Mode 2 (CD-ROM XA form 1) + 8 header bytes */ 210 | #define DB_XA_F2 12 /* 2324 bytes Mode 2 (CD-ROM XA form 2) */ 211 | #define DB_XA_MODE2_MIX 13 /* 2332 bytes Mode 2 (CD-ROM XA 1/2+subhdr) */ 212 | #define DB_RES_14 14 /* - Reserved */ 213 | #define DB_VU_15 15 /* - Vendor specific */ 214 | u_char _r4 :4; 215 | 216 | u_char _r5; 217 | u_char _r6; 218 | u_char host_appl_code :6; 219 | u_char _r7 :2; 220 | u_char session_format; 221 | u_char _r9; 222 | u_int pkt_size __attribute__ ((packed)); 223 | u_short audio_pause; 224 | u_char mcn[16]; 225 | u_char isrc[16]; 226 | u_char subhdr0; 227 | u_char subhdr1; 228 | u_char subhdr2; 229 | u_char subhdr3; 230 | }; 231 | 232 | struct cdrom_capabilities { /* CD Cap / mech status */ 233 | u_char p_code : 6; 234 | u_char p_res : 1; 235 | u_char parsave : 1; 236 | 237 | u_char p_len; /* 0x14 = 20 Bytes */ 238 | 239 | u_char cd_r_read : 1; /* Reads CD-R media */ 240 | u_char cd_rw_read : 1; /* Reads CD-RW media */ 241 | u_char method2 : 1; /* Reads fixed packet method2 media */ 242 | u_char dvd_rom_read : 1; /* Reads DVD ROM media */ 243 | u_char dvd_r_read : 1; /* Reads DVD-R media */ 244 | u_char dvd_ram_read : 1; /* Reads DVD-RAM media */ 245 | u_char res_2_67 : 2; /* Reserved */ 246 | 247 | u_char cd_r_write : 1; /* Supports writing CD-R media */ 248 | u_char cd_rw_write : 1; /* Supports writing CD-RW media */ 249 | u_char test_write : 1; /* Supports emulation write */ 250 | u_char res_3_3 : 1; /* Reserved */ 251 | u_char dvd_r_write : 1; /* Supports writing DVD-R media */ 252 | u_char dvd_ram_write : 1; /* Supports writing DVD-RAM media */ 253 | u_char res_3_67 : 2; /* Reserved */ 254 | 255 | u_char audio_play : 1; /* Supports Audio play operation */ 256 | u_char composite : 1; /* Deliveres composite A/V stream */ 257 | u_char digital_port_2 : 1; /* Supports digital output on port 2 */ 258 | u_char digital_port_1 : 1; /* Supports digital output on port 1 */ 259 | u_char mode_2_form_1 : 1; /* Reads Mode-2 form 1 media (XA) */ 260 | u_char mode_2_form_2 : 1; /* Reads Mode-2 form 2 media */ 261 | u_char multi_session : 1; /* Reads multi-session media */ 262 | u_char res_4 : 1; /* Reserved */ 263 | 264 | u_char cd_da_supported : 1; /* Reads audio data with READ CD cmd */ 265 | u_char cd_da_accurate : 1; /* READ CD data stream is accurate */ 266 | u_char rw_supported : 1; /* Reads R-W sub channel information */ 267 | u_char rw_deint_corr : 1; /* Reads de-interleved R-W sub chan */ 268 | u_char c2_pointers : 1; /* Supports C2 error pointers */ 269 | u_char ISRC : 1; /* Reads ISRC information */ 270 | u_char UPC : 1; /* Reads media catalog number (UPC) */ 271 | u_char read_bar_code : 1; /* Supports reading bar codes */ 272 | 273 | u_char lock : 1; /* PREVENT/ALLOW may lock media */ 274 | u_char lock_state : 1; /* Lock state 0=unlocked 1=locked */ 275 | u_char prevent_jumper : 1; /* State of prev/allow jumper 0=pres */ 276 | u_char eject : 1; /* Ejects disc/cartr with STOP LoEj */ 277 | u_char res_6_4 : 1; /* Reserved */ 278 | u_char loading_type : 3; /* Loading mechanism type */ 279 | #define CAPS_LT_CADDY 0 280 | #define CAPS_LT_TRAY 1 281 | 282 | u_char sep_chan_vol : 1; /* Vol controls each channel separat */ 283 | u_char sep_chan_mute : 1; /* Mute controls each channel separat*/ 284 | u_char disk_present_rep: 1; /* Changer supports disk present rep */ 285 | u_char sw_slot_sel : 1; /* Load empty slot in changer */ 286 | u_char res_7 : 4; /* Reserved */ 287 | 288 | u_short max_read_speed; /* Max. read speed in KB/s */ 289 | u_short num_vol_levels; /* # of supported volume levels */ 290 | u_short buffer_size; /* Buffer size for the data in KB */ 291 | u_short cur_read_speed; /* Current read speed in KB/s */ 292 | 293 | u_char res_16; /* Reserved */ 294 | 295 | u_char res_17_0 : 1; /* Reserved */ 296 | u_char BCK : 1; /* Data valid on falling edge of BCK */ 297 | u_char RCK : 1; /* Set: HIGH high LRCK=left channel */ 298 | u_char LSBF : 1; /* Set: LSB first Clear: MSB first */ 299 | u_char length : 2; /* 0=32BCKs 1=16BCKs 2=24BCKs 3=24I2c*/ 300 | u_char res_17 : 2; /* Reserved */ 301 | 302 | u_short max_write_speed; /* Max. write speed n KB/s */ 303 | u_short cur_write_speed; /* Current write speed in KB/s */ 304 | }; 305 | 306 | 307 | #define BLANK_DISC 0x00 /* Erase the entire disc */ 308 | #define BLANK_MINIMAL 0x01 /* Erase the PMA, 1st session TOC, pregap */ 309 | #define BLANK_TRACK 0x02 /* Erase an incomplete track */ 310 | #define BLANK_UNRESERVE 0x03 /* Unreserve a track */ 311 | #define BLANK_TAIL 0x04 /* Erase the tail of a track: input trackno required */ 312 | #define BLANK_UNCLOSE 0x05 /* Unclose the last session */ 313 | #define BLANK_SESSION 0x06 /* Erase the last session */ 314 | 315 | // #define PGCTL_CURRENT_VALUES 0 316 | // #define PGCTL_CHANGE_MASK 1 317 | // #define PGCTL_DEFAULT_VALUES 2 318 | // #define PGCTL_SAVED_VALUES 3 319 | 320 | void fail(char *fmt, ...); 321 | 322 | struct request_sense *get_sense_data(); 323 | char* get_sense_string(void); 324 | 325 | int blank(int fd, int type, int track); // see BLANK_xxx above 326 | int format(int fd, int session_grow, int size); 327 | int close_track_session(int fd, int close_track, int track); // close_track == 0 --> close session 328 | int synchronize_cache(int fd); 329 | int test_unit_ready(int fd); 330 | 331 | #define DS_OPERATIONAL 0 332 | #define DS_NO_DISC 1 333 | #define DS_TRAY_OPEN 2 334 | #define DS_NOT_READY 3 335 | int getDriveState(int fd); // returns DS_xxx 336 | 337 | int inquiry(int fd, struct cdrom_inquiry *inq); 338 | int mediumRemoval(int fd, int allow); 339 | int read_discinfo(int fd, struct cdrom_discinfo *di); 340 | int read_trackinfo(int fd, struct cdrom_trackinfo *ti, int track); 341 | int read_buffercapacity(int fd, struct cdrom_buffercapacity *bufcap); 342 | int read_reccapacity(int fd, struct cdrom_reccapacity *rc); 343 | int read_header(int fd, struct cdrom_header *hd, u_int block); 344 | int reserve_track(int fd, int size); 345 | 346 | #define SSU_STOP 0 347 | #define SSU_STOP_EJECT 1 348 | #define SSU_START 2 349 | #define SSU_LOAD_START 3 350 | int startStopUnit(int fd, int ssu_action); 351 | 352 | int readCD(int fd, int sectortype, int lba, int nblocks, unsigned char* buf); 353 | int writeCD(int fd, int lba, int nblocks, unsigned char* buf); 354 | 355 | int mode_sense(int fd, u_char **buffer, u_char **mode, u_char pageno, int pgctl); 356 | int mode_select(int fd, u_char *buffer); 357 | 358 | #ifdef MMC2 359 | int verify(int fd, int lba, int nblocks); 360 | #else 361 | int verify(int fd, int sectortype, int lba, int nblocks, char* buf); 362 | #endif 363 | 364 | int set_cdspeed(int fd, int readspeed, int writespeed); 365 | 366 | /* get_write_params sets the pointers to the mode header 'buffer' and the mode page 'wp' */ 367 | int get_writeparams(int fd, u_char **buffer, struct cdrom_writeparams **wp, int pgctl); 368 | 369 | /* to set write params leave buffer and wp as returned by get_write_params */ 370 | int set_writeparams(int fd, u_char *buffer, struct cdrom_writeparams *wp); 371 | int get_capabilities(int fd, u_char **buffer, struct cdrom_capabilities **cap, int pgctl); 372 | 373 | 374 | #endif 375 | 376 | -------------------------------------------------------------------------------- /wrudf/wrudf-cdr.c: -------------------------------------------------------------------------------- 1 | /* wrudf-cdr.c 2 | * 3 | */ 4 | 5 | #include "config.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "wrudf.h" 13 | #include "ide-pc.h" 14 | #include "bswap.h" 15 | 16 | static unsigned char *blockBuffer; 17 | static uint32_t newVATindex; 18 | static uint32_t sizeVAT; 19 | static uint32_t prevVATlbn; 20 | uint64_t CDRuniqueID; // from VAT FE 21 | 22 | 23 | uint32_t newVATentry() { 24 | 25 | if( newVATindex + 10 > (sizeVAT >> 2) ) { // ensure enough spave for regid and prevVATlbn 26 | sizeVAT += 2048; 27 | vat = realloc(vat, sizeVAT); 28 | if( vat == NULL ) 29 | fail("VAT reallocation failed\n"); 30 | } 31 | /* could go through VAT and try to find unused 0xFFFFFFFF entry rather than alloc new one at the end */ 32 | vat[newVATindex] = getNWA() - pd->partitionStartingLocation; 33 | return newVATindex++; 34 | } 35 | 36 | uint32_t getNWA() { 37 | if( devicetype == DISK_IMAGE ) 38 | return lseek(device, 0, SEEK_END) >> 11; 39 | 40 | if( read_trackinfo(device, &ti, lastTrack) ) 41 | printf("Get Track Info failed\n"); 42 | 43 | if( ti.nwa_v ) 44 | return ti.nwa; 45 | else 46 | return INVALID; 47 | } 48 | 49 | uint32_t getMaxVarPktSize() { 50 | struct cdrom_buffercapacity bc; 51 | 52 | if( devicetype == DISK_IMAGE ) 53 | return 1024 * 2048; // nonsense value; just for testing 54 | 55 | read_buffercapacity(device, &bc); 56 | 57 | return ((bc.freeBufferLength >> 11) - 20) << 11; // - 20 :: keep some spare blocks ??? 58 | } 59 | 60 | unsigned char* readCDR(uint32_t lbn, uint16_t partition) { 61 | int stat; 62 | uint32_t pbn = getPhysical(lbn, partition); 63 | 64 | 65 | if( devicetype == DISK_IMAGE ) { 66 | stat = lseek(device, 2048 * pbn, SEEK_SET); 67 | stat = read(device, blockBuffer, 2048); 68 | if( stat != 2048 ) 69 | fail("readCDR(hd) failed %s\n", strerror(errno)); 70 | else 71 | return blockBuffer; 72 | } 73 | 74 | stat = readCD(device, sectortype, pbn, 1, blockBuffer); 75 | 76 | if( stat ) { 77 | if( ! ignoreReadError ) 78 | printf("readCDR: %s\n", get_sense_string()); 79 | return NULL; 80 | } 81 | return blockBuffer; 82 | } 83 | 84 | void 85 | writeHD(uint32_t physical, unsigned char* src) 86 | { 87 | int stat; 88 | 89 | stat = lseek(device, 2048 * physical, SEEK_SET); 90 | stat = write(device, src, 2048); 91 | 92 | if( stat != 2048 ) { 93 | printf("writeHD failed %s\n", strerror(errno)); 94 | } 95 | } 96 | 97 | void syncCDR() { 98 | // uint32_t nwa; 99 | 100 | if( device == DISK_IMAGE ) 101 | return; 102 | 103 | synchronize_cache(device); 104 | // nwa = getNWA(); 105 | // printf("Link from %d to %d\n", nwa-7, nwa-1); 106 | } 107 | 108 | void writeHDlink() { 109 | uint32_t blk = getNWA(); 110 | int i; 111 | 112 | for(i = 0; i < 7; i++ ) 113 | writeHD(blk+i, blockBuffer); 114 | } 115 | 116 | 117 | 118 | /* writeBlockCDR() 119 | * Writes one 2048 byte block 120 | */ 121 | uint32_t 122 | writeCDR(void* src) { 123 | uint32_t physical; 124 | 125 | physical = getNWA(); 126 | // printf("Write CDR sector %d\n", physical); 127 | 128 | if( devicetype == DISK_IMAGE ) 129 | writeHD(physical, src); 130 | else { 131 | writeCD(device, physical, 1, src); 132 | } 133 | return physical; 134 | } 135 | 136 | 137 | /* flagError 138 | * split up extent in (1) good, (2) bad and (3) good subextents. 139 | * In bad extent (2) set logicalBlockNum to zero 140 | * If (1) is empty, maybe (2) can be merged with immediately preceding bad extent 141 | */ 142 | long_ad * 143 | flagError(long_ad *extents, long_ad *ext, uint32_t pbn) 144 | { 145 | uint32_t lbn = pbn - pd->partitionStartingLocation; 146 | int posInExtent = lbn - ext->extLocation.logicalBlockNum + 1; 147 | int blksInExtent = (ext->extLength + 2047) >> 11; 148 | 149 | /* if there is a preceding extent which is bad and 150 | * the current bad block is the first in this extent, 151 | * then add this bad to the preceding extent 152 | */ 153 | if( ext > extents && lbn == ext->extLocation.logicalBlockNum && !ext[-1].extLocation.logicalBlockNum ) { 154 | if( ext[0].extLength < 2048 ) { 155 | ext[-1].extLength += ext[0].extLength; 156 | ext[0].extLength = 0; 157 | } else { 158 | ext[-1].extLength += 2048; 159 | ext[0].extLength -= 2048; 160 | ext[0].extLocation.logicalBlockNum++; 161 | } 162 | return ext - 1; 163 | } 164 | 165 | /* watch one block extents */ 166 | if( blksInExtent == 1 ) { 167 | ext[0].extLocation.logicalBlockNum = 0; 168 | return ext; 169 | } 170 | 171 | /* 1st block of extent is bad */ 172 | if( posInExtent == 1 ) { 173 | memmove(ext+1, ext, extents - ext + 62); 174 | ext[0].extLength = 2048; 175 | ext[0].extLocation.logicalBlockNum = 0; 176 | ext[1].extLength -= 2048; 177 | ext[1].extLocation.logicalBlockNum = lbn + 1; 178 | return ext; 179 | } 180 | 181 | /* last block of extent is bad - watch partial block */ 182 | if( posInExtent == blksInExtent ) { 183 | memmove(ext+1, ext, extents - ext + 62); 184 | ext[1].extLength = ext->extLength - 2048; 185 | ext[1].extLocation.logicalBlockNum = 0; 186 | ext[0].extLength -= ext[1].extLength; 187 | return ext; 188 | } 189 | 190 | /* middle block in extent is bad */ 191 | memmove(ext+2, ext, extents - ext + 61); 192 | memcpy(ext+1, ext, sizeof(long_ad)); 193 | ext[0].extLength = 2048 * posInExtent; 194 | ext[1].extLength = 2048; 195 | ext[1].extLocation.logicalBlockNum = 0; 196 | ext[2].extLength -= ext[0].extLength + 2048; 197 | ext[2].extLocation.logicalBlockNum = lbn + 1; 198 | return ext+1; 199 | } 200 | 201 | int verifyCDR(struct fileEntry *fe) { 202 | long_ad *ext, *extents; 203 | uint32_t processed; 204 | int stat, rv = 0; 205 | uint32_t pbn, pbnFE, rewriteBlkno; 206 | 207 | setStrictRead(1); 208 | extents = ext = (long_ad*)(fe->extendedAttrAndAllocDescs + fe->lengthExtendedAttr); 209 | processed = 0; 210 | pbnFE = vat[fe->descTag.tagLocation] + pd->partitionStartingLocation; 211 | pbn = ext->extLocation.logicalBlockNum + pd->partitionStartingLocation; 212 | 213 | if( (fe->icbTag.flags & ICBTAG_FLAG_AD_MASK) == ICBTAG_FLAG_AD_IN_ICB ) 214 | goto FileEntryOnly; 215 | 216 | do { 217 | if( pbn > pbnFE ) { 218 | if( devicetype == DISK_IMAGE ) { 219 | printf("Verify %d\n", pbn); 220 | stat = 0; 221 | // if( (pbn == 557) || pbn == 565 ) stat = 1; /* for testing only */ 222 | } else 223 | stat = readCD(device, sectortype, pbn, 1, blockBuffer); 224 | 225 | if( stat ) { 226 | printf("readError %d : %s\n", pbn, get_sense_string()); 227 | rv++; 228 | ext = flagError(extents, ext, pbn); 229 | processed = ext->extLength - 2048; 230 | } 231 | } 232 | processed += 2048; 233 | pbn++; 234 | 235 | if( processed == ext->extLength ) { 236 | ext++; 237 | pbn = ext->extLocation.logicalBlockNum + pd->partitionStartingLocation; 238 | processed = 0; 239 | } 240 | } while (processed < ext->extLength); 241 | 242 | FileEntryOnly: 243 | if( rv == 0 ) { /* no errors in data, now verify FileEntry */ 244 | int retries; 245 | 246 | for( retries = 0; retries < 3; retries++ ) { 247 | if( devicetype == DISK_IMAGE ) { 248 | printf("Verify %d\n", pbnFE); 249 | stat = 0; 250 | // if( pbnFE == 552 || pbnFE == 553 ) stat = 1; /* testing only */ 251 | } else 252 | stat = readCD(device, sectortype, pbnFE, 1, blockBuffer); 253 | 254 | if( stat == 0 ) { 255 | setStrictRead(0); 256 | return 0; 257 | } 258 | printf("readError %d : %s\n", pbnFE, get_sense_string()); 259 | pbnFE = getNWA(); 260 | vat[fe->descTag.tagLocation] = pbnFE - pd->partitionStartingLocation; 261 | writeCDR(fe); 262 | } 263 | printf("verifyCDR: verify FE failed 3 times\n"); 264 | } 265 | 266 | setStrictRead(0); 267 | 268 | rewriteBlkno = getNWA() + 1 - pd->partitionStartingLocation; // NWA itself for revised FileEntry 269 | 270 | fe->lengthAllocDescs = 0; 271 | for( ext = extents; ext->extLength; ext++ ) { 272 | fe->lengthAllocDescs += sizeof(long_ad); 273 | if( ext->extLocation.logicalBlockNum != 0 ) 274 | continue; 275 | ext->extLocation.logicalBlockNum = rewriteBlkno; 276 | rewriteBlkno += ext->extLength >> 11; 277 | if( ext->extLength & 2047 ) 278 | break; 279 | } 280 | fe->descTag.descCRCLength = sizeof(struct fileEntry) + fe->lengthExtendedAttr + fe->lengthAllocDescs - 16; 281 | return rv; 282 | } 283 | 284 | void readVATtable() { 285 | uint32_t blkno; 286 | struct fileEntry *fe; 287 | 288 | blkno = getNWA() - (devicetype == DISK_IMAGE ? 1 : 8); 289 | prevVATlbn = blkno; 290 | fe = (struct fileEntry*)readTaggedBlock(blkno, ABSOLUTE); 291 | 292 | if( fe->descTag.tagIdent != TAG_IDENT_FE || fe->icbTag.fileType != 0 ) 293 | fail("VAT ICB not found\n"); 294 | 295 | CDRuniqueID = fe->uniqueID; 296 | sizeVAT = ((fe->informationLength + 4095) & ~2047); 297 | vat = malloc(sizeVAT); 298 | memset(vat, 0xFF, sizeVAT); // later or not at all 299 | newVATindex = (fe->informationLength - 36) >> 2; 300 | 301 | if( sizeof(*fe) + fe->lengthExtendedAttr + fe->informationLength <= 2048 ) { 302 | memcpy(vat, fe->extendedAttrAndAllocDescs + fe->lengthExtendedAttr, fe->informationLength - 36); 303 | } else { 304 | readExtents((char*)vat, 1, fe->extendedAttrAndAllocDescs + fe->lengthExtendedAttr); 305 | } 306 | } 307 | 308 | 309 | void 310 | writeVATtable() 311 | { 312 | regid *id; 313 | struct fileEntry *fe; 314 | uint64_t i; 315 | int stat, retries, size; 316 | uint32_t startBlk; 317 | short_ad *ext; 318 | uint16_t udf_rev_le16; 319 | uint32_t prevVATlbn_le32; 320 | 321 | retries = 0; 322 | 323 | id = (regid*)(&vat[newVATindex]); 324 | memset(id, 0, sizeof(regid)); 325 | strcpy((char *)id->ident, UDF_ID_ALLOC); 326 | udf_rev_le16 = cpu_to_le16(0x150); 327 | memcpy(id->identSuffix, &udf_rev_le16, sizeof(udf_rev_le16)); 328 | id->identSuffix[2] = UDF_OS_CLASS_UNIX; 329 | id->identSuffix[3] = UDF_OS_ID_LINUX; 330 | prevVATlbn_le32 = cpu_to_le32(prevVATlbn); 331 | memcpy((uint8_t *)id+sizeof(*id), &prevVATlbn_le32, sizeof(prevVATlbn_le32)); 332 | 333 | fe = makeFileEntry(); 334 | size = (newVATindex + 9) << 2; 335 | fe->informationLength = cpu_to_le64(size); 336 | fe->descTag.tagSerialNum = lvid->descTag.tagSerialNum; 337 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_VAT15; 338 | fe->fileLinkCount = 0; 339 | 340 | for( retries = 0; retries < 8; retries++ ) { 341 | startBlk = getNWA(); 342 | 343 | if( sizeof(*fe) + size < 2048 ) { 344 | fe->icbTag.flags = ICBTAG_FLAG_AD_IN_ICB; 345 | memcpy(fe->extendedAttrAndAllocDescs, vat, size); 346 | fe->lengthAllocDescs = cpu_to_le32(size); 347 | } else { 348 | fe->logicalBlocksRecorded = (size + 2047) >> 11; 349 | fe->icbTag.flags = ICBTAG_FLAG_AD_SHORT; 350 | ext = (short_ad*)(fe->extendedAttrAndAllocDescs + fe->lengthExtendedAttr); 351 | ext->extLength = size; 352 | ext->extPosition = startBlk - pd->partitionStartingLocation; 353 | fe->lengthAllocDescs = cpu_to_le32(16); 354 | } 355 | 356 | fe->descTag.tagLocation = startBlk - pd->partitionStartingLocation + fe->logicalBlocksRecorded; 357 | fe->descTag.descCRCLength = sizeof(*fe) + fe->lengthExtendedAttr + fe->lengthAllocDescs - sizeof(tag); 358 | setChecksum(&fe->descTag); 359 | 360 | for( i = 0; i < fe->logicalBlocksRecorded; i++ ) 361 | writeCDR(vat + (i<<9)); 362 | 363 | writeCDR(fe); 364 | 365 | setStrictRead(1); 366 | 367 | for( i = 0; i <= fe->logicalBlocksRecorded; i++ ) { // "<=" so including FileEntry 368 | if( devicetype == DISK_IMAGE ) { 369 | printf("Verify %llu\n", (unsigned long long int)(startBlk+i)); 370 | stat = 0; 371 | } else 372 | stat = readCD(device, sectortype, startBlk + i, 1, blockBuffer); 373 | 374 | if( stat != 0 ) { 375 | printf("writeVATtable verifyError %llu : %s\n", (unsigned long long int)(startBlk + i), get_sense_string()); 376 | break; 377 | } 378 | } 379 | if( stat == 0 ) 380 | break; 381 | } 382 | 383 | if( retries == 8 ) 384 | printf("*** writeVATtable rewrite FAILED\nLast VAT was at LBN %d\n", prevVATlbn); 385 | 386 | setStrictRead(0); 387 | } 388 | 389 | 390 | 391 | -------------------------------------------------------------------------------- /wrudf/wrudf-desc.c: -------------------------------------------------------------------------------- 1 | /* wrudf-desc.c 2 | * 3 | * PURPOSE 4 | * Routines to create/find/insert/delete FileIdentDesc's and FileEntries. 5 | * 6 | * COPYRIGHT 7 | * This file is distributed under the terms of the GNU General Public 8 | * License (GPL). Copies of the GPL can be obtained from: 9 | * ftp://prep.ai.mit.edu/pub/gnu/GPL 10 | * 11 | * (C) 2001 Enno Fennema 12 | * 13 | * HISTORY 14 | * 16 Aug 01 ef Created. 15 | */ 16 | 17 | #include "config.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "wrudf.h" 25 | 26 | /* removeFID() 27 | * 28 | * Physically remove a FileIdentDesc from the directory 29 | */ 30 | int 31 | removeFID(Directory *dir, struct fileIdentDesc *fid) 32 | { 33 | uint32_t lenFID = (sizeof(struct fileIdentDesc) + fid->lengthOfImpUse + fid->lengthFileIdent + 3) & ~3; 34 | uint32_t lenMove; 35 | struct fileEntry *fe; 36 | 37 | fe = (struct fileEntry *)dir->fe; 38 | fe->informationLength -= lenFID; 39 | lenMove = fe->informationLength - ((char *)fid - dir->data); 40 | memcpy(fid, (char *)fid + lenFID, lenMove); 41 | dir->dirDirty = 1; 42 | return 0; 43 | } 44 | 45 | /* deleteFID() 46 | * 47 | * Remove an FID from the directory 48 | * If fileLinkCount now zero, deallocate FileEntry and any data extents 49 | */ 50 | int 51 | deleteFID(Directory * dir, struct fileIdentDesc * fid) 52 | { 53 | int rv; 54 | struct fileEntry *fe; 55 | struct fileEntry *dirfe; 56 | struct logicalVolIntegrityDescImpUse *lvidiu; 57 | 58 | dirfe = (struct fileEntry *)dir->fe; 59 | 60 | rv = CMND_OK; 61 | 62 | // if( fid->icb.extLocation.partitionReferenceNum != pd->partitionNumber ) 63 | // return NOT_IN_RW_PARTITION; 64 | 65 | fe = readTaggedBlock(fid->icb.extLocation.logicalBlockNum, fid->icb.extLocation.partitionReferenceNum); 66 | 67 | /* check permission */ 68 | 69 | freeBlock(fid->icb.extLocation.logicalBlockNum, fid->icb.extLocation.partitionReferenceNum); 70 | 71 | if( fe->fileLinkCount > 1 ) { 72 | fe->fileLinkCount--; 73 | setChecksum(fe); 74 | if( medium == CDRW ) 75 | dirtyBlock(fid->icb.extLocation.logicalBlockNum, fid->icb.extLocation.partitionReferenceNum); 76 | else 77 | vat[fid->icb.extLocation.logicalBlockNum] = writeCDR(fe); 78 | } else { 79 | if( medium == CDR ) { 80 | if( fe->icbTag.fileType == ICBTAG_FILE_TYPE_DIRECTORY ) 81 | dirfe->fileLinkCount--; 82 | vat[fid->icb.extLocation.logicalBlockNum] = 0xFFFFFFFF; 83 | } else { 84 | if( fe->icbTag.fileType == ICBTAG_FILE_TYPE_DIRECTORY ) { 85 | dirfe->fileLinkCount--; 86 | lvidiu = (struct logicalVolIntegrityDescImpUse*) 87 | (lvid->data + 2 * sizeof(uint32_t) * lvid->numOfPartitions); 88 | lvidiu->numDirs--; 89 | } else { 90 | lvidiu = (struct logicalVolIntegrityDescImpUse*) 91 | (lvid->data + 2 * sizeof(uint32_t) * lvid->numOfPartitions); 92 | lvidiu->numFiles--; 93 | } 94 | 95 | /* free file data */ 96 | switch( fe->icbTag.flags & ICBTAG_FLAG_AD_MASK ) { 97 | case ICBTAG_FLAG_AD_IN_ICB: 98 | break; 99 | case ICBTAG_FLAG_AD_SHORT: 100 | freeShortExtents((short_ad*)(fe->extendedAttrAndAllocDescs + fe->lengthExtendedAttr)); 101 | break; 102 | case ICBTAG_FLAG_AD_LONG: 103 | freeLongExtents((long_ad*)(fe->extendedAttrAndAllocDescs + fe->lengthExtendedAttr)); 104 | break; 105 | default: 106 | printf("UDF does not use Extended Alloc Descs\n"); 107 | rv = CMND_FAILED; 108 | } 109 | /* free the File Entry itself */ 110 | markBlock(FREE, fid->icb.extLocation.logicalBlockNum); 111 | } 112 | } 113 | 114 | removeFID(dir, fid); 115 | dir->dirDirty = 1; 116 | 117 | return rv; 118 | } 119 | 120 | struct fileIdentDesc* 121 | findFileIdentDesc(Directory *dir, char* name) 122 | { 123 | uint64_t i; 124 | char *data; 125 | struct fileEntry *fe; 126 | struct fileIdentDesc *fid; 127 | dchars uName[256]; 128 | size_t uLen; 129 | 130 | uLen = encode_locale(uName, name, 256); 131 | if (uLen == (size_t)-1) 132 | return NULL; 133 | 134 | data = dir->data; 135 | fe = (struct fileEntry *)dir->fe; 136 | 137 | for( i = 0; i < fe->informationLength; 138 | i += (sizeof(struct fileIdentDesc) + fid->lengthOfImpUse + fid->lengthFileIdent + 3) & ~3 ) { 139 | 140 | fid = (struct fileIdentDesc*)(data + i); 141 | 142 | if( fid->descTag.tagIdent == TAG_IDENT_TE ) 143 | return NULL; 144 | 145 | if( fid->descTag.tagIdent == TAG_IDENT_IE ) { 146 | printf("Indirect Entry not yet implemented\n"); 147 | continue; 148 | } 149 | if( fid->descTag.tagIdent != TAG_IDENT_FID ) 150 | fail("Unknown tag id %08X in directory\n", fid->descTag.tagIdent); 151 | 152 | // check CRC 153 | 154 | if( fid->fileCharacteristics == FID_FILE_CHAR_PARENT) 155 | continue; 156 | 157 | if( fid->lengthFileIdent == uLen 158 | && memcmp( fid->impUseAndFileIdent, uName, fid->lengthFileIdent) == 0 ) 159 | return fid; 160 | } 161 | return NULL; 162 | } 163 | 164 | 165 | /* 166 | * Return pointer to new FileEntry in a 2k allocated block to be free'd when no longer required. 167 | * Only basic data is filled in. 168 | */ 169 | struct fileEntry* 170 | makeFileEntry() 171 | { 172 | struct fileEntry *fe = (struct fileEntry*) calloc(2048, 1); 173 | struct logicalVolHeaderDesc* lvhd = (struct logicalVolHeaderDesc*)lvid->logicalVolContentsUse; 174 | 175 | updateTimestamp(0,0); 176 | fe->descTag.tagIdent = TAG_IDENT_FE; 177 | fe->descTag.descVersion = 2; 178 | fe->descTag.tagSerialNum = lvd->descTag.tagSerialNum; 179 | fe->icbTag.strategyType = 4; 180 | fe->icbTag.numEntries = 1; 181 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_REGULAR; 182 | /* User has all permission; Group/Others Read/Exec */ 183 | fe->permissions = FE_PERM_U_READ | FE_PERM_U_WRITE | FE_PERM_U_DELETE | FE_PERM_U_CHATTR | FE_PERM_U_EXEC | 184 | FE_PERM_G_READ | FE_PERM_G_EXEC | FE_PERM_O_READ | FE_PERM_O_EXEC; 185 | fe->fileLinkCount = 1; 186 | fe->accessTime = timeStamp; 187 | fe->modificationTime = timeStamp; 188 | fe->attrTime = timeStamp; 189 | fe->impIdent = entityWRUDF; 190 | fe->uniqueID = lvhd->uniqueID++; 191 | return fe; 192 | } 193 | 194 | 195 | /* 196 | * Return pointer to new FileIdentDesc in an allocated block to be free'd when no longer required. 197 | * Does NOT fill: descTag.checksum, descTag.tagLocation, icbTag.characteristics, icb 198 | */ 199 | struct fileIdentDesc* 200 | makeFileIdentDesc(char* name) 201 | { 202 | dchars uName[256]; 203 | size_t uLen; 204 | struct fileIdentDesc *fid; 205 | 206 | fid = (struct fileIdentDesc*) calloc(512,1); 207 | fid->descTag.tagIdent = TAG_IDENT_FID; 208 | fid->descTag.descVersion = 2; 209 | fid->descTag.tagSerialNum = lvd->descTag.tagSerialNum; 210 | fid->fileVersionNum = 1; 211 | fid->icb.extLength = 2048; 212 | 213 | if( name[0] != 0 ) { /* FID to parent directory has no name */ 214 | uLen = encode_locale(uName, name, 256); 215 | if (uLen == (size_t)-1) { 216 | uLen = 1; 217 | uName[0] = 0x8; 218 | } 219 | fid->lengthFileIdent = uLen; 220 | memcpy(fid->impUseAndFileIdent + fid->lengthOfImpUse, uName, fid->lengthFileIdent); 221 | } 222 | return fid; 223 | } 224 | 225 | 226 | int 227 | insertFileIdentDesc(Directory *dir, struct fileIdentDesc* fid) 228 | { 229 | uint32_t lenFid; 230 | struct fileEntry *fe; 231 | 232 | lenFid = (sizeof(struct fileIdentDesc) + fid->lengthOfImpUse + fid->lengthFileIdent + 3) & ~3; 233 | fid->descTag.descCRCLength = lenFid - sizeof(tag); 234 | setChecksum(fid); 235 | 236 | fe = (struct fileEntry *)dir->fe; 237 | 238 | if( fe->informationLength + lenFid > dir->dataSize ) { 239 | if( !(dir->data = realloc(dir->data, dir->dataSize + 2048)) ) { 240 | fail("Realloc directory data failed\n"); 241 | } 242 | dir->dataSize += 2048; 243 | } 244 | 245 | memcpy(dir->data + fe->informationLength, fid, lenFid); 246 | fe->informationLength += lenFid; 247 | dir->dirDirty = 1; 248 | return CMND_OK; 249 | } 250 | -------------------------------------------------------------------------------- /wrudf/wrudf.h: -------------------------------------------------------------------------------- 1 | /* wrudf.h 2 | * 3 | * PURPOSE 4 | * The header file for wrudf.c and related source files. 5 | * 6 | * COPYRIGHT 7 | * This file is distributed under the terms of the GNU General Public 8 | * License (GPL). Copies of the GPL can be obtained from: 9 | * ftp://prep.ai.mit.edu/pub/gnu/GPL 10 | * Each contributing author retains all rights to their own work. 11 | * 12 | * (C) 2001 Enno Fennema 13 | * 14 | * HISTORY 15 | * 16 Aug 01 ef created. 16 | */ 17 | 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "ecma_167.h" 25 | #include "osta_udf.h" 26 | #include "libudffs.h" 27 | 28 | struct generic_desc 29 | { 30 | tag descTag; 31 | uint32_t volDescSeqNum; 32 | }; 33 | 34 | extern char* hdWorkingDir; 35 | extern int ignoreReadError; 36 | extern int device; 37 | extern int devicetype; 38 | #define DISK_IMAGE 0xAA 39 | 40 | enum MEDIUM { CDR = 1, CDRW }; 41 | 42 | extern enum MEDIUM medium; 43 | 44 | // #define CDR 'R' 45 | // #define CDRW 'W' 46 | 47 | extern uint32_t trackSize; 48 | 49 | #ifdef USE_READLINE 50 | extern char *line; 51 | #else 52 | extern char line[256]; 53 | #endif 54 | 55 | extern regid entityWRUDF; 56 | extern timestamp timeStamp; 57 | 58 | enum RV { CMND_OK, CMND_FAILED, WRONG_NO_ARGS, CMND_ARG_INVALID, NOT_IN_RW_PARTITION, 59 | DIR_INVALID, EXISTING_DIR, EXISTING_FILE, DELETED_DIR, DELETED_FILE, DOES_NOT_EXIST, 60 | DIR_NOT_EMPTY, PERMISSION_DENIED, IS_DIRECTORY }; 61 | 62 | enum CMND { CMND_CP = 50, CMND_RM, CMND_MKDIR, CMND_RMDIR, CMND_LSC, CMND_LSH, CMND_CDC, CMND_CDH, CMND_QUIT }; 63 | 64 | extern int cmndc; 65 | extern char** cmndv; 66 | 67 | extern uint32_t options; 68 | #define OPT_DUMMY 0x01 69 | #define OPT_FORCE 0x02 70 | #define OPT_RECURSIVE 0x04 71 | 72 | extern int spaceMapDirty, usdDirty, sparingTableDirty; 73 | 74 | extern struct logicalVolDesc *lvd; 75 | extern struct partitionDesc *pd; /* The (re)writable partition descriptor */ 76 | extern uint16_t virtualPartitionNum; 77 | extern uint32_t *vat; 78 | extern struct unallocSpaceDesc *usd; 79 | extern struct spaceBitmapDesc *spaceMap; 80 | extern struct logicalVolIntegrityDesc *lvid; 81 | extern struct fileSetDesc *fsd; 82 | extern unsigned int usedSparingEntries; 83 | extern struct sparingTable *st; 84 | 85 | typedef struct _dir_ { 86 | struct _dir_ *parent, *child; 87 | uint32_t dataSize; 88 | char *data; 89 | long_ad icb; /* icb of this directory itself */ 90 | char *name; 91 | uint32_t dirDirty; 92 | uint8_t fe[2048]; 93 | } Directory; 94 | 95 | extern Directory *rootDir, *curDir; 96 | 97 | 98 | /*wrudf.c */ 99 | #ifdef USE_READLINE 100 | char* readLine(char *prompt); 101 | #endif 102 | 103 | /* wrudf-cmnd.c */ 104 | int updateDirectory(Directory* dir); 105 | Directory *readDirectory(Directory *parentDir, long_ad *icb, char* name); 106 | 107 | int cpCommand(void); 108 | int rmCommand(void); 109 | int mkdirCommand(void); 110 | int rmdirCommand(void); 111 | int cdcCommand(void); 112 | int cdhCommand(void); 113 | int lscCommand(void); 114 | int lshCommand(void); 115 | 116 | /* wrudf-desc.c */ 117 | struct fileIdentDesc* makeFileIdentDesc(char* name); 118 | struct fileIdentDesc* findFileIdentDesc(Directory *dir, char* name); 119 | int deleteFID(Directory *dir, struct fileIdentDesc *fid); 120 | int removeFID(Directory *dir, struct fileIdentDesc *fid); 121 | int insertFileIdentDesc(Directory *dir, struct fileIdentDesc* fid); 122 | struct fileEntry* makeFileEntry(); 123 | 124 | 125 | /* wrudf-cdrw.c */ 126 | enum markAction { FREE, ALLOC }; 127 | void markBlock(enum markAction action, uint32_t blkno); 128 | 129 | extern int lastTrack; 130 | extern int sectortype; 131 | extern struct cdrom_trackinfo ti; 132 | 133 | int getExtents(uint32_t requestedLength, short_ad *extents); 134 | int freeShortExtents(short_ad* extent); 135 | int freeLongExtents(long_ad* extent); 136 | 137 | void getUnallocSpaceExtent(uint32_t requestLength, uint32_t requestAfter, extent_ad *alloc); 138 | 139 | void setChecksum(void *descriptor); 140 | void updateTimestamp(time_t t, uint32_t ut); /* current time if t = 0 */ 141 | void setStrictRead(int yes); 142 | uint32_t getPhysical(uint32_t lbn, uint16_t part); 143 | void updateSparingTable(); 144 | 145 | #define ABSOLUTE 0xFFFF /* ignore partition, process physical blocknumber */ 146 | /* actually 0xFFFF is a perfectly valid partition number 147 | * could make part a uint32_t and use 0xFFFFFFFF 148 | * or have write absolute block routine 149 | */ 150 | 151 | #define INVALID 0xFFFFFFFF 152 | 153 | void* readBlock(uint32_t lbn, uint16_t part); 154 | void freeBlock(uint32_t lbn, uint16_t part); 155 | void dirtyBlock(uint32_t lbn, uint16_t part); 156 | void writeBlock(uint32_t lbn, uint16_t part, void* src); 157 | void* readSingleBlock(uint32_t pbn); 158 | void* readTaggedBlock(uint32_t lbn, uint16_t part); 159 | int readExtents(char* dest, int usesShort, void* extents); 160 | int writeExtents(char* src, int usesShort, void* extents); 161 | 162 | int initIO(char *filename); 163 | int closeIO(); 164 | 165 | /* wrudf-cdr.c */ 166 | uint32_t newVATentry(); 167 | uint32_t getNWA(); 168 | uint32_t getMaxVarPktSize(); 169 | uint32_t writeCDR(void* src); 170 | void syncCDR(); 171 | void writeHDlink(); 172 | unsigned char* readCDR(uint32_t lbn, uint16_t partition); 173 | int verifyCDR(struct fileEntry *fe); 174 | void readVATtable(); 175 | void writeVATtable(); 176 | 177 | /* ide-pc.h */ 178 | void fail(char* fmt, ...); 179 | --------------------------------------------------------------------------------