diff options
Diffstat (limited to 'disk-utils/isosize.c')
-rw-r--r-- | disk-utils/isosize.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/disk-utils/isosize.c b/disk-utils/isosize.c new file mode 100644 index 0000000..85a549a --- /dev/null +++ b/disk-utils/isosize.c @@ -0,0 +1,217 @@ +/* + * 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 <num>] <filename> + * 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 <num>" is + * given. In the latter case the length in bytes divided + * by <num> is given + * + * Version 2.03 2000/12/21 + * - add "-d <num>" option and use long long to fix things > 2 GB + * Version 2.02 2000/10/11 + * - error messages on IO failures [D. Gilbert] + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include "nls.h" +#include "c.h" +#include "strutils.h" +#include "closestream.h" + +#define ISOSIZE_EXIT_ALLFAILED 32 +#define ISOSIZE_EXIT_SOMEOK 64 + +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); +} + +static int isosize(int argc, char *filenamep, int xflag, long divisor) +{ + int fd, nsecs, ssize, rc = -1; + unsigned char volume_space_size[8]; + unsigned char logical_block_size[4]; + + if ((fd = open(filenamep, O_RDONLY)) < 0) { + warn(_("cannot open %s"), filenamep); + goto done; + } + if (is_iso(fd)) + warnx(_("%s: might not be an ISO filesystem"), filenamep); + + if (pread(fd, volume_space_size, sizeof(volume_space_size), 0x8050) != sizeof(volume_space_size) || + pread(fd, logical_block_size, sizeof(logical_block_size), 0x8080) != sizeof(logical_block_size)) { + if (errno) + warn(_("read error on %s"), filenamep); + else + warnx(_("read error on %s"), filenamep); + goto done; + } + + nsecs = isonum_733(volume_space_size, xflag); + /* isonum_723 returns nowadays always 2048 */ + ssize = isonum_723(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); + } + + rc = 0; +done: + if (fd >= 0) + close(fd); + return rc; +} + +static void __attribute__((__noreturn__)) usage(void) +{ + + fputs(USAGE_HEADER, stdout); + fprintf(stdout, + _(" %s [options] <iso9660_image_file> ...\n"), + program_invocation_short_name); + + fputs(USAGE_SEPARATOR, stdout); + fputs(_("Show the length of an ISO-9660 filesystem.\n"), stdout); + + fputs(USAGE_OPTIONS, stdout); + fputs(_(" -d, --divisor=<number> divide the amount of bytes by <number>\n"), stdout); + fputs(_(" -x, --sectors show sector count and size\n"), stdout); + + printf(USAGE_HELP_OPTIONS(25)); + printf(USAGE_MAN_TAIL("isosize(8)")); + + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + int j, ct_err = 0, 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(); + default: + errtryhelp(EXIT_FAILURE); + } + } + + ct = argc - optind; + + if (ct <= 0) { + warnx(_("no device specified")); + errtryhelp(EXIT_FAILURE); + } + + for (j = optind; j < argc; j++) { + if (isosize(ct, argv[j], xflag, divisor) != 0) + ct_err++; + } + + return ct == ct_err ? ISOSIZE_EXIT_ALLFAILED : /* all failed */ + ct_err ? ISOSIZE_EXIT_SOMEOK : /* some ok */ + EXIT_SUCCESS; /* all success */ +} |