/* * isosize.c - Andries Brouwer, 000608 * * use header info to find size of iso9660 file system * output a number - useful in scripts * * Synopsis: * isosize [-x] [-d ] * where "-x" gives length in sectors and sector size while * without this argument the size is given in bytes * without "-x" gives length in bytes unless "-d " is * given. In the latter case the length in bytes divided * by is given * * Version 2.03 2000/12/21 * - add "-d " option and use long long to fix things > 2 GB * Version 2.02 2000/10/11 * - error messages on IO failures [D. Gilbert] * */ #include #include #include #include #include #include #include "nls.h" #include "c.h" #include "strutils.h" #include "closestream.h" #define ISODCL(from, to) (to - from + 1) static int is_iso(int fd) { char label[8]; if (pread(fd, &label, 8, 0x8000) == -1) return 1; return memcmp(&label, &"\1CD001\1", 8); } static int isonum_721(unsigned char *p) { return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); } static int isonum_722(unsigned char *p) { return ((p[1] & 0xff) | ((p[0] & 0xff) << 8)); } static int isonum_723(unsigned char *p, int xflag) { int le = isonum_721(p); int be = isonum_722(p + 2); if (xflag && le != be) /* translation is useless */ warnx("723error: le=%d be=%d", le, be); return (le); } static int isonum_731(unsigned char *p) { return ((p[0] & 0xff) | ((p[1] & 0xff) << 8) | ((p[2] & 0xff) << 16) | ((p[3] & 0xff) << 24)); } static int isonum_732(unsigned char *p) { return ((p[3] & 0xff) | ((p[2] & 0xff) << 8) | ((p[1] & 0xff) << 16) | ((p[0] & 0xff) << 24)); } static int isonum_733(unsigned char *p, int xflag) { int le = isonum_731(p); int be = isonum_732(p + 4); if (xflag && le != be) /* translation is useless */ warnx("733error: le=%d be=%d", le, be); return (le); } struct iso_primary_descriptor { unsigned char type [ISODCL ( 1, 1)]; /* 711 */ unsigned char id [ISODCL ( 2, 6)]; unsigned char version [ISODCL ( 7, 7)]; /* 711 */ unsigned char unused1 [ISODCL ( 8, 8)]; unsigned char system_id [ISODCL ( 9, 40)]; /* auchars */ unsigned char volume_id [ISODCL ( 41, 72)]; /* duchars */ unsigned char unused2 [ISODCL ( 73, 80)]; unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ unsigned char unused3 [ISODCL ( 89, 120)]; unsigned char volume_set_size [ISODCL ( 121, 124)]; /* 723 */ unsigned char volume_sequence_number [ISODCL ( 125, 128)]; /* 723 */ unsigned char logical_block_size [ISODCL ( 129, 132)]; /* 723 */ unsigned char path_table_size [ISODCL ( 133, 140)]; /* 733 */ unsigned char type_l_path_table [ISODCL ( 141, 144)]; /* 731 */ unsigned char opt_type_l_path_table [ISODCL ( 145, 148)]; /* 731 */ unsigned char type_m_path_table [ISODCL ( 149, 152)]; /* 732 */ unsigned char opt_type_m_path_table [ISODCL ( 153, 156)]; /* 732 */ unsigned char root_directory_record [ISODCL ( 157, 190)]; /* 9.1 */ unsigned char volume_set_id [ISODCL ( 191, 318)]; /* duchars */ unsigned char publisher_id [ISODCL ( 319, 446)]; /* achars */ unsigned char preparer_id [ISODCL ( 447, 574)]; /* achars */ unsigned char application_id [ISODCL ( 575, 702)]; /* achars */ unsigned char copyright_file_id [ISODCL ( 703, 739)]; /* 7.5 dchars */ unsigned char abstract_file_id [ISODCL ( 740, 776)]; /* 7.5 dchars */ unsigned char bibliographic_file_id [ISODCL ( 777, 813)]; /* 7.5 dchars */ unsigned char creation_date [ISODCL ( 814, 830)]; /* 8.4.26.1 */ unsigned char modification_date [ISODCL ( 831, 847)]; /* 8.4.26.1 */ unsigned char expiration_date [ISODCL ( 848, 864)]; /* 8.4.26.1 */ unsigned char effective_date [ISODCL ( 865, 881)]; /* 8.4.26.1 */ unsigned char file_structure_version [ISODCL ( 882, 882)]; /* 711 */ unsigned char unused4 [ISODCL ( 883, 883)]; unsigned char application_data [ISODCL ( 884, 1395)]; unsigned char unused5 [ISODCL (1396, 2048)]; }; static void isosize(int argc, char *filenamep, int xflag, long divisor) { int fd, nsecs, ssize; struct iso_primary_descriptor ipd; if ((fd = open(filenamep, O_RDONLY)) < 0) err(EXIT_FAILURE, _("cannot open %s"), filenamep); if (is_iso(fd)) warnx(_("%s: might not be an ISO filesystem"), filenamep); if (lseek(fd, 16 << 11, 0) == (off_t) - 1) err(EXIT_FAILURE, _("seek error on %s"), filenamep); if (read(fd, &ipd, sizeof(ipd)) <= 0) err(EXIT_FAILURE, _("read error on %s"), filenamep); nsecs = isonum_733(ipd.volume_space_size, xflag); /* isonum_723 returns nowadays always 2048 */ ssize = isonum_723(ipd.logical_block_size, xflag); if (1 < argc) printf("%s: ", filenamep); if (xflag) { printf(_("sector count: %d, sector size: %d\n"), nsecs, ssize); } else { long long product = nsecs; if (divisor == 0) printf("%lld\n", product * ssize); else if (divisor == ssize) printf("%d\n", nsecs); else printf("%lld\n", (product * ssize) / divisor); } close(fd); } static void __attribute__((__noreturn__)) usage(FILE *out) { fputs(USAGE_HEADER, out); fprintf(out, _(" %s [options] \n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, out); fputs(_("Show the length of an ISO-9660 filesystem.\n"), out); fputs(USAGE_OPTIONS, out); fputs(_(" -d, --divisor= divide the amount of bytes by \n"), out); fputs(_(" -x, --sectors show sector count and size\n"), out); fputs(USAGE_SEPARATOR, out); fputs(USAGE_HELP, out); fputs(USAGE_VERSION, out); fprintf(out, USAGE_MAN_TAIL("isosize(8)")); exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } int main(int argc, char **argv) { int j, ct, opt, xflag = 0; long divisor = 0; static const struct option longopts[] = { {"divisor", required_argument, NULL, 'd'}, {"sectors", no_argument, NULL, 'x'}, {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); while ((opt = getopt_long(argc, argv, "d:xVh", longopts, NULL)) != -1) switch (opt) { case 'd': divisor = strtol_or_err(optarg, _("invalid divisor argument")); break; case 'x': xflag = 1; break; case 'V': printf(UTIL_LINUX_VERSION); return EXIT_SUCCESS; case 'h': usage(stdout); default: errtryhelp(EXIT_FAILURE); } ct = argc - optind; if (ct <= 0) usage(stderr); for (j = optind; j < argc; j++) isosize(ct, argv[j], xflag, divisor); return EXIT_SUCCESS; }