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