| @@ -1,17 +1,17 @@ | | | @@ -1,17 +1,17 @@ |
1 | /* $NetBSD: newfs_udf.c,v 1.12 2011/05/26 07:59:08 reinoud Exp $ */ | | 1 | /* $NetBSD: newfs_udf.c,v 1.13 2013/07/02 14:59:01 reinoud Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2006, 2008 Reinoud Zandijk | | 4 | * Copyright (c) 2006, 2008, 2013 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 |
| @@ -85,26 +85,27 @@ int udf_do_newfs(void); | | | @@ -85,26 +85,27 @@ int udf_do_newfs(void); |
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 | int imagefile_secsize; /* for files */ |
98 | | | 99 | |
99 | int wrtrack_skew; | | 100 | int wrtrack_skew; |
100 | int meta_perc = UDF_META_PERC; | | 101 | int meta_perc = UDF_META_PERC; |
101 | float meta_fract = (float) UDF_META_PERC / 100.0; | | 102 | float meta_fract = (float) UDF_META_PERC / 100.0; |
102 | | | 103 | |
103 | | | 104 | |
104 | /* shared structure between udf_create.c users */ | | 105 | /* shared structure between udf_create.c users */ |
105 | struct udf_create_context context; | | 106 | struct udf_create_context context; |
106 | struct udf_disclayout layout; | | 107 | struct udf_disclayout layout; |
107 | | | 108 | |
108 | | | 109 | |
109 | /* queue for temporary storage of sectors to be written out */ | | 110 | /* queue for temporary storage of sectors to be written out */ |
110 | struct wrsect { | | 111 | struct wrsect { |
| @@ -273,73 +274,88 @@ udf_dump_discinfo(struct mmc_discinfo *d | | | @@ -273,73 +274,88 @@ udf_dump_discinfo(struct mmc_discinfo *d |
273 | printf("\n"); | | 274 | printf("\n"); |
274 | printf("\tlast_possible_lba %d\n", di->last_possible_lba); | | 275 | printf("\tlast_possible_lba %d\n", di->last_possible_lba); |
275 | printf("\n"); | | 276 | printf("\n"); |
276 | } | | 277 | } |
277 | #else | | 278 | #else |
278 | #define udf_dump_discinfo(a); | | 279 | #define udf_dump_discinfo(a); |
279 | #endif | | 280 | #endif |
280 | | | 281 | |
281 | /* --------------------------------------------------------------------- */ | | 282 | /* --------------------------------------------------------------------- */ |
282 | | | 283 | |
283 | static int | | 284 | static int |
284 | udf_update_discinfo(struct mmc_discinfo *di) | | 285 | udf_update_discinfo(struct mmc_discinfo *di) |
285 | { | | 286 | { |
| | | 287 | struct stat st; |
286 | struct disklabel disklab; | | 288 | struct disklabel disklab; |
287 | struct partition *dp; | | 289 | struct partition *dp; |
288 | struct stat st; | | 290 | off_t size, sectors, secsize; |
289 | int partnr, error; | | 291 | int partnr, error; |
290 | | | 292 | |
291 | memset(di, 0, sizeof(struct mmc_discinfo)); | | 293 | memset(di, 0, sizeof(struct mmc_discinfo)); |
292 | | | 294 | |
293 | /* check if we're on a MMC capable device, i.e. CD/DVD */ | | 295 | /* check if we're on a MMC capable device, i.e. CD/DVD */ |
294 | error = ioctl(fd, MMCGETDISCINFO, di); | | 296 | error = ioctl(fd, MMCGETDISCINFO, di); |
295 | if (error == 0) | | 297 | if (error == 0) |
296 | return 0; | | 298 | return 0; |
297 | | | 299 | |
298 | /* | | 300 | /* (re)fstat the file */ |
299 | * disc partition support; note we can't use DIOCGPART in userland so | | | |
300 | * get disc label and use the stat info to get the partition number. | | | |
301 | */ | | | |
302 | if (ioctl(fd, DIOCGDINFO, &disklab) == -1) { | | | |
303 | /* failed to get disclabel! */ | | | |
304 | perror("disklabel"); | | | |
305 | return errno; | | | |
306 | } | | | |
307 | | | | |
308 | /* get disk partition it refers to */ | | | |
309 | fstat(fd, &st); | | 301 | fstat(fd, &st); |
310 | partnr = DISKPART(st.st_rdev); | | 302 | |
311 | dp = &disklab.d_partitions[partnr]; | | 303 | if (S_ISREG(st.st_mode)) { |
| | | 304 | /* file support; we pick the minimum sector size allowed */ |
| | | 305 | size = st.st_size; |
| | | 306 | secsize = imagefile_secsize; |
| | | 307 | sectors = size / secsize; |
| | | 308 | } else { |
| | | 309 | /* |
| | | 310 | * disc partition support; note we can't use DIOCGPART in userland so |
| | | 311 | * get disc label and use the stat info to get the partition number. |
| | | 312 | */ |
| | | 313 | if (ioctl(fd, DIOCGDINFO, &disklab) == -1) { |
| | | 314 | /* failed to get disclabel! */ |
| | | 315 | perror("disklabel"); |
| | | 316 | return errno; |
| | | 317 | } |
| | | 318 | |
| | | 319 | /* get disk partition it refers to */ |
| | | 320 | fstat(fd, &st); |
| | | 321 | partnr = DISKPART(st.st_rdev); |
| | | 322 | dp = &disklab.d_partitions[partnr]; |
| | | 323 | |
| | | 324 | /* TODO problem with last_possible_lba on resizable VND; request */ |
| | | 325 | if (dp->p_size == 0) { |
| | | 326 | perror("faulty disklabel partition returned, check label\n"); |
| | | 327 | return EIO; |
| | | 328 | } |
| | | 329 | |
| | | 330 | sectors = dp->p_size; |
| | | 331 | secsize = disklab.d_secsize; |
| | | 332 | } |
312 | | | 333 | |
313 | /* set up a disc info profile for partitions */ | | 334 | /* set up a disc info profile for partitions */ |
314 | di->mmc_profile = 0x01; /* disc type */ | | 335 | di->mmc_profile = 0x01; /* disc type */ |
315 | di->mmc_class = MMC_CLASS_DISC; | | 336 | di->mmc_class = MMC_CLASS_DISC; |
316 | di->disc_state = MMC_STATE_CLOSED; | | 337 | di->disc_state = MMC_STATE_CLOSED; |
317 | di->last_session_state = MMC_STATE_CLOSED; | | 338 | di->last_session_state = MMC_STATE_CLOSED; |
318 | di->bg_format_state = MMC_BGFSTATE_COMPLETED; | | 339 | di->bg_format_state = MMC_BGFSTATE_COMPLETED; |
319 | di->link_block_penalty = 0; | | 340 | di->link_block_penalty = 0; |
320 | | | 341 | |
321 | di->mmc_cur = MMC_CAP_RECORDABLE | MMC_CAP_REWRITABLE | | | 342 | di->mmc_cur = MMC_CAP_RECORDABLE | MMC_CAP_REWRITABLE | |
322 | MMC_CAP_ZEROLINKBLK | MMC_CAP_HW_DEFECTFREE; | | 343 | MMC_CAP_ZEROLINKBLK | MMC_CAP_HW_DEFECTFREE; |
323 | di->mmc_cap = di->mmc_cur; | | 344 | di->mmc_cap = di->mmc_cur; |
324 | di->disc_flags = MMC_DFLAGS_UNRESTRICTED; | | 345 | di->disc_flags = MMC_DFLAGS_UNRESTRICTED; |
325 | | | 346 | |
326 | /* TODO problem with last_possible_lba on resizable VND; request */ | | 347 | di->last_possible_lba = sectors - 1; |
327 | if (dp->p_size == 0) { | | 348 | di->sector_size = secsize; |
328 | perror("faulty disklabel partition returned, check label\n"); | | | |
329 | return EIO; | | | |
330 | } | | | |
331 | di->last_possible_lba = dp->p_size - 1; | | | |
332 | di->sector_size = disklab.d_secsize; | | | |
333 | | | 349 | |
334 | di->num_sessions = 1; | | 350 | di->num_sessions = 1; |
335 | di->num_tracks = 1; | | 351 | di->num_tracks = 1; |
336 | | | 352 | |
337 | di->first_track = 1; | | 353 | di->first_track = 1; |
338 | di->first_track_last_session = di->last_track_last_session = 1; | | 354 | di->first_track_last_session = di->last_track_last_session = 1; |
339 | | | 355 | |
340 | return 0; | | 356 | return 0; |
341 | } | | 357 | } |
342 | | | 358 | |
343 | | | 359 | |
344 | static int | | 360 | static int |
345 | udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti) | | 361 | udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti) |
| @@ -1427,50 +1443,53 @@ a_udf_version(const char *s, const char | | | @@ -1427,50 +1443,53 @@ a_udf_version(const char *s, const char |
1427 | uint32_t version; | | 1443 | uint32_t version; |
1428 | | | 1444 | |
1429 | if (parse_udfversion(s, &version)) | | 1445 | if (parse_udfversion(s, &version)) |
1430 | errx(1, "unknown %s id %s; specify as hex or float", id_type, s); | | 1446 | errx(1, "unknown %s id %s; specify as hex or float", id_type, s); |
1431 | return version; | | 1447 | return version; |
1432 | } | | 1448 | } |
1433 | | | 1449 | |
1434 | /* --------------------------------------------------------------------- */ | | 1450 | /* --------------------------------------------------------------------- */ |
1435 | | | 1451 | |
1436 | static void | | 1452 | static void |
1437 | usage(void) | | 1453 | usage(void) |
1438 | { | | 1454 | { |
1439 | (void)fprintf(stderr, "Usage: %s [-cFM] [-L loglabel] " | | 1455 | (void)fprintf(stderr, "Usage: %s [-cFM] [-L loglabel] " |
1440 | "[-P discid] [-S setlabel] [-s size] [-p perc] " | | 1456 | "[-P discid] [-S sectorsize] [-s size] [-p perc] " |
1441 | "[-t gmtoff] [-v min_udf] [-V max_udf] special\n", getprogname()); | | 1457 | "[-t gmtoff] [-v min_udf] [-V max_udf] special\n", getprogname()); |
1442 | exit(EXIT_FAILURE); | | 1458 | exit(EXIT_FAILURE); |
1443 | } | | 1459 | } |
1444 | | | 1460 | |
1445 | | | 1461 | |
1446 | int | | 1462 | int |
1447 | main(int argc, char **argv) | | 1463 | main(int argc, char **argv) |
1448 | { | | 1464 | { |
1449 | struct tm *tm; | | 1465 | struct tm *tm; |
1450 | struct stat st; | | 1466 | struct stat st; |
1451 | time_t now; | | 1467 | time_t now; |
1452 | char scrap[255]; | | 1468 | off_t setsize; |
| | | 1469 | char scrap[255], *colon; |
1453 | int ch, req_enable, req_disable, force; | | 1470 | int ch, req_enable, req_disable, force; |
1454 | int error; | | 1471 | int error; |
1455 | | | 1472 | |
1456 | setprogname(argv[0]); | | 1473 | setprogname(argv[0]); |
1457 | | | 1474 | |
1458 | /* initialise */ | | 1475 | /* initialise */ |
1459 | format_str = strdup(""); | | 1476 | format_str = strdup(""); |
1460 | req_enable = req_disable = 0; | | 1477 | req_enable = req_disable = 0; |
1461 | format_flags = FORMAT_INVALID; | | 1478 | format_flags = FORMAT_INVALID; |
1462 | force = 0; | | 1479 | force = 0; |
1463 | check_surface = 0; | | 1480 | check_surface = 0; |
| | | 1481 | setsize = 0; |
| | | 1482 | imagefile_secsize = 512; /* minimum allowed sector size */ |
1464 | | | 1483 | |
1465 | srandom((unsigned long) time(NULL)); | | 1484 | srandom((unsigned long) time(NULL)); |
1466 | udf_init_create_context(); | | 1485 | udf_init_create_context(); |
1467 | context.app_name = APP_NAME; | | 1486 | context.app_name = APP_NAME; |
1468 | context.impl_name = IMPL_NAME; | | 1487 | context.impl_name = IMPL_NAME; |
1469 | context.app_version_main = APP_VERSION_MAIN; | | 1488 | context.app_version_main = APP_VERSION_MAIN; |
1470 | context.app_version_sub = APP_VERSION_SUB; | | 1489 | context.app_version_sub = APP_VERSION_SUB; |
1471 | | | 1490 | |
1472 | /* minimum and maximum UDF versions we advise */ | | 1491 | /* minimum and maximum UDF versions we advise */ |
1473 | context.min_udf = 0x201; | | 1492 | context.min_udf = 0x201; |
1474 | context.max_udf = 0x201; | | 1493 | context.max_udf = 0x201; |
1475 | | | 1494 | |
1476 | /* use user's time zone as default */ | | 1495 | /* use user's time zone as default */ |
| @@ -1502,75 +1521,126 @@ main(int argc, char **argv) | | | @@ -1502,75 +1521,126 @@ main(int argc, char **argv) |
1502 | meta_fract = (float) meta_perc/100.0; | | 1521 | meta_fract = (float) meta_perc/100.0; |
1503 | break; | | 1522 | break; |
1504 | case 'v' : | | 1523 | case 'v' : |
1505 | context.min_udf = a_udf_version(optarg, "min_udf"); | | 1524 | context.min_udf = a_udf_version(optarg, "min_udf"); |
1506 | if (context.min_udf > context.max_udf) | | 1525 | if (context.min_udf > context.max_udf) |
1507 | context.max_udf = context.min_udf; | | 1526 | context.max_udf = context.min_udf; |
1508 | break; | | 1527 | break; |
1509 | case 'V' : | | 1528 | case 'V' : |
1510 | context.max_udf = a_udf_version(optarg, "max_udf"); | | 1529 | context.max_udf = a_udf_version(optarg, "max_udf"); |
1511 | if (context.min_udf > context.max_udf) | | 1530 | if (context.min_udf > context.max_udf) |
1512 | context.min_udf = context.max_udf; | | 1531 | context.min_udf = context.max_udf; |
1513 | break; | | 1532 | break; |
1514 | case 'P' : | | 1533 | case 'P' : |
| | | 1534 | /* check if there is a ':' in the name */ |
| | | 1535 | if ((colon = strstr(optarg, ":"))) { |
| | | 1536 | if (context.volset_name) |
| | | 1537 | free(context.volset_name); |
| | | 1538 | *colon = 0; |
| | | 1539 | context.volset_name = strdup(optarg); |
| | | 1540 | optarg = colon+1; |
| | | 1541 | } |
| | | 1542 | if (context.primary_name) |
| | | 1543 | free(context.primary_name); |
| | | 1544 | if ((strstr(optarg, ":"))) { |
| | | 1545 | perror("primary name can't have ':' in its name"); |
| | | 1546 | return EXIT_FAILURE; |
| | | 1547 | } |
1515 | context.primary_name = strdup(optarg); | | 1548 | context.primary_name = strdup(optarg); |
1516 | break; | | 1549 | break; |
1517 | case 's' : | | 1550 | case 's' : |
1518 | /* TODO size argument; recordable emulation */ | | 1551 | /* support for files, set file size */ |
| | | 1552 | /* XXX support for formatting recordables on vnd/file? */ |
| | | 1553 | if (dehumanize_number(optarg, &setsize) < 0) { |
| | | 1554 | perror("can't parse size argument"); |
| | | 1555 | return EXIT_FAILURE; |
| | | 1556 | } |
| | | 1557 | setsize = MAX(0, setsize); |
1519 | break; | | 1558 | break; |
1520 | case 'S' : | | 1559 | case 'S' : |
1521 | if (context.volset_name) free(context.volset_name); | | 1560 | imagefile_secsize = a_num(optarg, "secsize"); |
1522 | context.volset_name = strdup(optarg); | | 1561 | imagefile_secsize = MAX(512, imagefile_secsize); |
1523 | break; | | 1562 | break; |
1524 | case 't' : | | 1563 | case 't' : |
1525 | /* time zone overide */ | | 1564 | /* time zone overide */ |
1526 | context.gmtoff = a_num(optarg, "gmtoff"); | | 1565 | context.gmtoff = a_num(optarg, "gmtoff"); |
1527 | break; | | 1566 | break; |
1528 | default : | | 1567 | default : |
1529 | usage(); | | 1568 | usage(); |
1530 | /* NOTREACHED */ | | 1569 | /* NOTREACHED */ |
1531 | } | | 1570 | } |
1532 | } | | 1571 | } |
1533 | | | 1572 | |
1534 | if (optind + 1 != argc) | | 1573 | if (optind + 1 != argc) |
1535 | usage(); | | 1574 | usage(); |
1536 | | | 1575 | |
1537 | /* get device and directory specifier */ | | 1576 | /* get device and directory specifier */ |
1538 | dev = argv[optind]; | | 1577 | dev = argv[optind]; |
1539 | | | 1578 | |
1540 | /* open device */ | | 1579 | /* open device */ |
1541 | if ((fd = open(dev, O_RDWR, 0)) == -1) { | | 1580 | if ((fd = open(dev, O_RDWR, 0)) == -1) { |
1542 | perror("can't open device"); | | 1581 | /* check if we need to create a file */ |
1543 | return EXIT_FAILURE; | | 1582 | fd = open(dev, O_RDONLY, 0); |
| | | 1583 | if (fd > 0) { |
| | | 1584 | perror("device is there but can't be opened for read/write"); |
| | | 1585 | return EXIT_FAILURE; |
| | | 1586 | } |
| | | 1587 | if (!force) { |
| | | 1588 | perror("can't open device"); |
| | | 1589 | return EXIT_FAILURE; |
| | | 1590 | } |
| | | 1591 | if (setsize == 0) { |
| | | 1592 | perror("need to create image file but no size specified"); |
| | | 1593 | return EXIT_FAILURE; |
| | | 1594 | } |
| | | 1595 | /* need to create a file */ |
| | | 1596 | fd = open(dev, O_RDWR | O_CREAT | O_TRUNC, 0777); |
| | | 1597 | if (fd == -1) { |
| | | 1598 | perror("can't create image file"); |
| | | 1599 | return EXIT_FAILURE; |
| | | 1600 | } |
1544 | } | | 1601 | } |
1545 | | | 1602 | |
1546 | /* stat the device */ | | 1603 | /* stat the device */ |
1547 | if (fstat(fd, &st) != 0) { | | 1604 | if (fstat(fd, &st) != 0) { |
1548 | perror("can't stat the device"); | | 1605 | perror("can't stat the device"); |
1549 | close(fd); | | 1606 | close(fd); |
1550 | return EXIT_FAILURE; | | 1607 | return EXIT_FAILURE; |
1551 | } | | 1608 | } |
1552 | | | 1609 | |
| | | 1610 | if (S_ISREG(st.st_mode)) { |
| | | 1611 | if (setsize == 0) |
| | | 1612 | setsize = st.st_size; |
| | | 1613 | /* sanitise arguments */ |
| | | 1614 | imagefile_secsize &= ~511; |
| | | 1615 | setsize &= ~(imagefile_secsize-1); |
| | | 1616 | |
| | | 1617 | if (ftruncate(fd, setsize)) { |
| | | 1618 | perror("can't resize file"); |
| | | 1619 | return EXIT_FAILURE; |
| | | 1620 | } |
| | | 1621 | } |
| | | 1622 | |
1553 | /* formatting can only be done on raw devices */ | | 1623 | /* formatting can only be done on raw devices */ |
1554 | if (!S_ISCHR(st.st_mode)) { | | 1624 | if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) { |
1555 | printf("%s is not a raw device\n", dev); | | 1625 | printf("%s is not a raw device\n", dev); |
1556 | close(fd); | | 1626 | close(fd); |
1557 | return EXIT_FAILURE; | | 1627 | return EXIT_FAILURE; |
1558 | } | | 1628 | } |
1559 | | | 1629 | |
1560 | /* just in case something went wrong, synchronise the drive's cache */ | | 1630 | /* just in case something went wrong, synchronise the drive's cache */ |
1561 | udf_synchronise_caches(); | | 1631 | udf_synchronise_caches(); |
1562 | | | 1632 | |
1563 | /* get disc information */ | | 1633 | /* get 'disc' information */ |
1564 | error = udf_update_discinfo(&mmc_discinfo); | | 1634 | error = udf_update_discinfo(&mmc_discinfo); |
1565 | if (error) { | | 1635 | if (error) { |
1566 | perror("can't retrieve discinfo"); | | 1636 | perror("can't retrieve discinfo"); |
1567 | close(fd); | | 1637 | close(fd); |
1568 | return EXIT_FAILURE; | | 1638 | return EXIT_FAILURE; |
1569 | } | | 1639 | } |
1570 | | | 1640 | |
1571 | /* derive disc identifiers when not specified and check given */ | | 1641 | /* derive disc identifiers when not specified and check given */ |
1572 | error = udf_proces_names(); | | 1642 | error = udf_proces_names(); |
1573 | if (error) { | | 1643 | if (error) { |
1574 | /* error message has been printed */ | | 1644 | /* error message has been printed */ |
1575 | close(fd); | | 1645 | close(fd); |
1576 | return EXIT_FAILURE; | | 1646 | return EXIT_FAILURE; |