/* $NetBSD$ */ /* * File "udfdump.c" is part of the UDFclient toolkit. * File $Id: udfdump.c,v 1.67 2007/12/09 21:35:12 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006 Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include "udf.h" #include "udf_bswap.h" /* switches */ /* #define DEBUG(a) (a) */ #define DEBUG(a) if (0) { a; } int dump_sequential = 0; int dump_directory_trees = 0; /* include the dump parts ... in order to get a more sane splitting */ extern void udf_dump_descriptor(union dscrptr *dscrpt); extern void udf_dump_alive_sets(void); extern void udf_dump_root_dir(struct udf_mountpoint *mountpoint); /* globals */ extern int udf_verbose; extern int uscsilib_verbose; /* main discdump routine */ void udf_dump_sequential(int alt_sector_size, char *dev_name) { struct udf_discinfo *disc; union dscrptr *dscr; uint64_t sec_num; uint32_t sector_size, size, dscr_len; uint8_t *sector; int error; udf_verbose = UDF_VERBLEV_ACTIONS; printf("Opening disc:\n"); error = udf_open_disc(dev_name, &disc); if (error) return; if (alt_sector_size) disc->sector_size = alt_sector_size; sector = calloc(1, 65*1024); assert(sector); printf("Sequential dump of device/file (sector size %d)\n", disc->sector_size); sec_num = 0; sector_size = disc->sector_size; do { size = 1; error = udf_read_physical_sectors(disc, sec_num, size, "sector", sector); if (!error) { dscr = (union dscrptr *) sector; if (!udf_check_tag(dscr)) { if (udf_rw16(dscr->tag.id) <= TAGID_MAX) { dscr_len = udf_rw16(dscr->tag.desc_crc_len); if (dscr_len > sector_size) { size = (dscr_len + sector_size -1) / sector_size; error = udf_read_physical_sectors(disc, sec_num, size, "sector", sector); if (error) break; } if (!udf_check_tag_payload(dscr)) { printf("%8d ", (int) sec_num); udf_dump_descriptor(dscr); } } } } else { if (error == ENOENT) break; printf("\nRead error : %s\n", strerror(error)); } sec_num++; printf("\r%08d ", (int) sec_num); fflush(stdout); } while (1); printf("\n"); } void udf_dump_disc(struct udf_discinfo *disc, int min_session_number, int max_session_number) { struct udf_mountpoint *mountpoint; printf("Dumping directory tree for each non obsolete logical volume's fileset\n"); SLIST_FOREACH(mountpoint, &udf_mountables, all_next) { printf("\n"); printf("Directory tree of mount point %s\n", mountpoint->mount_name); udf_dump_root_dir(mountpoint); } } int usage(char *program) { fprintf(stderr, "Usage %s [options] devicename [devicename]*)\n", program); fprintf(stderr, "-S dump device sequential\n" "-t dump complete directory contents\n" "-b blocksize use alternative sectorsize; use only on files/discs\n" "-u level UDF system verbose level\n" "-D verbose SCSI command errors\n" "-r range only use UDF sessions range like -3,4-5 or 6-\n" ); return 1; } int main(int argc, char *argv[]) { struct udf_discinfo *disc; char *progname, *range; uint32_t alt_sector_size; int min_session_number, max_session_number; int flag, error; progname = argv[0]; if (argc == 1) return usage(progname); dump_sequential = 0; dump_directory_trees = 0; range = NULL; alt_sector_size = 0; while ((flag = getopt(argc, argv, "u:r:b:DSt")) != -1) { switch (flag) { case 'u' : udf_verbose = atoi(optarg); break; case 'r' : range = strdup(optarg); if (udf_check_session_range(range)) { fprintf(stderr, "Invalid range %s\n", range); return usage(progname); } break; case 'b' : alt_sector_size = atoi(optarg); break; case 'D' : uscsilib_verbose = 1; break; case 'S' : dump_sequential = 1; break; case 't' : dump_directory_trees = 1; break; default : return usage(progname); } } argv += optind; argc -= optind; if (dump_sequential) { if (argc != 1) return usage(progname); udf_dump_sequential(alt_sector_size, *argv); return 0; } if (argc == 0) return usage(progname); min_session_number = 0; max_session_number = 999; /* all other arguments are devices */ while (argc) { printf("Opening device %s\n\n", *argv); error = udf_mount_disc(*argv, range, alt_sector_size, UDF_MNT_RDONLY, &disc); if (error) { fprintf(stderr, "Can't open my device; bailing out : %s\n", strerror(error)); exit(1); } argv++; argc--; if (udf_verbose) printf("\n\n"); } printf("Resulting list of alive sets :\n\n"); udf_dump_alive_sets(); if (dump_directory_trees) { printf("Dump tree of disc %s\n", disc->dev->dev_name); SLIST_FOREACH(disc, &udf_discs_list, next_disc) { udf_dump_disc(disc, min_session_number, max_session_number); printf("\n"); } } printf("Closing discs\n"); SLIST_FOREACH(disc, &udf_discs_list, next_disc) { udf_close_disc(disc); } return 0; }