summaryrefslogtreecommitdiff
path: root/tools/cdcat.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /tools/cdcat.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'tools/cdcat.c')
-rw-r--r--tools/cdcat.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/tools/cdcat.c b/tools/cdcat.c
new file mode 100644
index 0000000..329fd17
--- /dev/null
+++ b/tools/cdcat.c
@@ -0,0 +1,373 @@
+/*
+ * cdcat: get and replace files inside an ISO-9660 CDROM image
+ * Based on cdcat by Robert Nordier
+ *
+ * Copyright (c) 2011 Giuseppe Gatta
+ *
+ * Copyright (c) 2007 Robert Nordier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted subject to the following conditions:
+ *
+ *1. Existing copyright notices in source and other files must be
+ * retained.
+ *
+ *2. Redistributions in whatever form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS
+ * 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.
+ */
+
+#define CDCAT_VERSION "0.5"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+enum
+{
+ cdrom_mode_1,
+ cdrom_mode_1_raw,
+ cdrom_mode_2,
+};
+
+enum
+{
+ cdcat_oper_read,
+ cdcat_oper_write,
+ cdcat_oper_showoffset
+};
+
+int cdcat_cdrom_mode = cdrom_mode_1;
+int cdcat_oper = cdcat_oper_read;
+
+#define SECSIZ 2048
+#define NAMLEN 255
+
+#define sw(x,y) ((x)<<8|(y))
+#define cv4(x) ((*(unsigned char*)(x)) | ((*(unsigned char*)(x+1))<<8) | \
+ ((*(unsigned char*)(x+2))<<16) | ((*(unsigned char*)(x+3))<<24))
+
+/* ISO 9660 Primary Volume Descriptor */
+static char cdmagic[] = {1, 'C', 'D', '0', '0', '1', 1, 0};
+
+struct cddir {
+ unsigned char len_dr; /* length of directory record */
+ unsigned char len_ear; /* extended attribute record length */
+ unsigned char ext[8]; /* location of extent */
+ unsigned char size[8]; /* data length */
+ unsigned char time[7]; /* recording date and time */
+ unsigned char flags; /* file flags */
+ unsigned char fus; /* file unit size */
+ unsigned char gap; /* interleave gap size */
+ unsigned char vsn[4]; /* volume sequence number */
+ unsigned char len_fi; /* length of file identifier */
+ unsigned char fi[1]; /* file identifier ... */
+};
+
+struct dir {
+ unsigned int ext; /* starting block number */
+ unsigned int size; /* file size */
+ int type; /* file type ('d' or '-') */
+ char name[NAMLEN + 1]; /* file name */
+};
+
+static char *fn; /* special file name */
+static int fd; /* special file descriptor */
+
+int cdcat(char *);
+void loaddir(struct cddir *, struct dir *);
+void susp(unsigned char *, int, struct dir *);
+int readblk(void *, unsigned int);
+void writeblk(void *, unsigned int);
+void error(char *);
+
+void cdcat_print_usage()
+{
+ fprintf(stderr, "usage: cdcat <options> iso-image [path]\n");
+ fprintf(stderr, "\n"
+ "cdcat can be used to explore an ISO9660 filesystem image\n"
+ "If path is not specified the root directory is listed, if it's a directory "
+ "the directory is listed or if it's a file the file is printed to standard output\n"
+ "The Rock Ridge extensions to the ISO9660 filesystem standard are supported\n"
+ "Original program (c) 2007 Robert Nordier.\n"
+ "\n"
+ "Options:\n"
+ "-help - This screen\n"
+ "-mode1 - The image is raw and has Mode 1 sectors\n"
+ "-mode2 - The image is raw and has Mode 2 sectors (like PlayStation dumps)\n"
+ "-replace - If [path] is specified, the data of the file is\n"
+ " replaced with input from standard input\n"
+ "-showoffset - Show file offset in image\n"
+ "-version - Display version\n\n");
+}
+
+int main(int argc, char **argv)
+{
+ char *path;
+ int e;
+ int nargc;
+ int x;
+
+ for(x = 1; x < argc; x++)
+ {
+ if(strcmp(argv[x], "--") == 0 || argv[x][0] != '-')
+ break;
+
+ if(strcmp(argv[x], "-mode2") == 0 || strcmp(argv[x], "--mode2") == 0)
+ cdcat_cdrom_mode = cdrom_mode_2;
+ else if(strcmp(argv[x], "-mode1") == 0 || strcmp(argv[x], "--mode1") == 0)
+ cdcat_cdrom_mode = cdrom_mode_1_raw;
+ else if(strcmp(argv[x], "--help") == 0 || strcmp(argv[x], "-help") == 0)
+ {
+ cdcat_print_usage();
+ return 0;
+ }
+ else if(strcmp(argv[x], "--version") == 0 || strcmp(argv[x], "-version") == 0)
+ {
+ printf("cdcat version "CDCAT_VERSION"\n");
+ return 0;
+ }
+ else if(strcmp(argv[x], "--replace") == 0 || strcmp(argv[x], "-replace") == 0)
+ cdcat_oper = cdcat_oper_write;
+ else if(strcmp(argv[x], "--showoffset") == 0 || strcmp(argv[x], "-showoffset") == 0)
+ cdcat_oper = cdcat_oper_showoffset;
+ else
+ {
+ printf("Invalid option %s! Aborting.\n", argv[x]);
+ return -1;
+ }
+ }
+
+ nargc = argc-(x-1);
+
+ if (nargc != 2 && nargc != 3) {
+ cdcat_print_usage();
+ exit(2);
+ }
+
+ fn = argv[x];
+
+ if ((fd = open(argv[x], cdcat_oper==cdcat_oper_read?O_RDONLY:O_RDWR)) == -1)
+ error("cannot open");
+ path = argv[x+1] ? argv[x+1] : "";
+
+ if ((e = cdcat(path)) != 0)
+ fprintf(stderr, "cdcat: %s: Not found\n", path);
+ return e;
+}
+
+int cdcat(char *path)
+{
+ unsigned char buf[SECSIZ];
+ char name[NAMLEN + 1];
+ struct cddir *dp, *tp;
+ struct dir xd;
+ char *p, *q;
+ unsigned ext, size, bx, bn, x, i;
+ int type, n;
+
+ /*
+ * find primary volume descriptor
+ * and thence root directory
+ */
+ bx = 64;
+ for (bn = 16; bn < bx; bn++) {
+ readblk(buf, bn);
+ if (strcmp((char *)buf, cdmagic) == 0)
+ break;
+ }
+ if (bn == bx)
+ error("Invalid argument");
+ dp = (struct cddir *)&buf[156];
+ loaddir(dp, &xd);
+
+ /*
+ * lookup, list, print ...
+ */
+ for (p = path; dp; p = q) {
+ while (*p == '/')
+ p++;
+ for (q = p; *q && *q != '/'; q++);
+ if ((n = q - p)) {
+ if (n > NAMLEN)
+ n = NAMLEN;
+ memcpy(name, p, n);
+ name[n] = 0;
+ }
+ ext = xd.ext;
+ size = xd.size;
+ type = xd.type;
+ dp = NULL;
+ bx = ext + (size + (SECSIZ - 1)) / SECSIZ;
+ for (bn = ext; !dp && bn < bx; bn++) {
+ if (type == 'd')
+ {
+ readblk(buf, bn);
+
+ for (i = 0; !dp && buf[i]; i += buf[i]) {
+ tp = (struct cddir *)(buf + i);
+ loaddir(tp, &xd);
+ if (n == 0)
+ printf("%10u %c %s\n",
+ xd.size, xd.type, xd.name);
+ else if (strcmp(name, xd.name) == 0)
+ dp = tp;
+ }
+ }
+ else {
+ if(cdcat_oper == cdcat_oper_read)
+ {
+ readblk(buf, bn);
+ x = size < SECSIZ ? size : SECSIZ;
+ for (i = 0; i < x; i++)
+ putchar(buf[i]);
+ size -= x;
+ }else if(cdcat_oper == cdcat_oper_write)
+ {
+ x = size < SECSIZ ? size : SECSIZ;
+ for (i = 0; i < x; i++)
+ buf[i] = getchar();
+
+ writeblk(buf, bn);
+
+ size -= x;
+ }else if(cdcat_oper == cdcat_oper_showoffset)
+ {
+ printf("%d\n", readblk(buf, bn));
+ goto cdcat_end;
+ }
+ }
+ }
+ }
+cdcat_end:
+ return n != 0;
+}
+
+/*
+ * Gather together the directory information that interests us.
+ * Any and all of this may be altered by a suitable SUSP field.
+ */
+void loaddir(struct cddir *dp, struct dir *xp)
+{
+ int c;
+
+ xp->ext = cv4(dp->ext);
+ xp->size = cv4(dp->size);
+ xp->type = dp->flags & 2 ? 'd' : '-';
+ xp->name[0] = 0;
+ if (dp->fi[0] != 0) {
+ c = dp->len_fi | 1;
+ susp(dp->fi + c, dp->len_dr - 33 - c, xp);
+ }
+ if (xp->name[0] == 0)
+ {
+ if (dp->fi[0] == 0 || dp->fi[0] == 1)
+ strcpy(xp->name, dp->fi[0] == 0 ? "." : "..");
+ else
+ {
+ memcpy(xp->name, dp->fi, dp->len_fi);
+ xp->name[dp->len_fi] = 0;
+ }
+ }
+}
+
+/*
+ * SUSP/RRIP support: allowing UNIX-style file names and directories
+ * nested more than eight deep (among other things).
+ */
+void susp(unsigned char *sp, int n, struct dir *xp)
+{
+ unsigned char buf[SECSIZ];
+ unsigned char *p;
+ int i, j;
+
+ for (p = sp; p < sp + n && *p;) {
+ if (p[3] != 1)
+ return;
+ switch (sw(p[0], p[1])) {
+ /* continuation area */
+ case sw('C', 'E'):
+ readblk(buf, cv4(&p[4]));
+ sp = buf + cv4(&p[12]);
+ n = cv4(&p[20]);
+ p = sp;
+ continue;
+ /* child link */
+ case sw('C', 'L'):
+ xp->ext = cv4(&p[4]);
+ xp->size = SECSIZ;
+ xp->type = 'd';
+ break;
+ /* alternate name */
+ case sw('N', 'M'):
+ for (j = 0; xp->name[j]; j++);
+ for (i = 5; i < p[2]; i++)
+ xp->name[j++] = p[i];
+ xp->name[j] = 0;
+ break;
+ }
+ p += p[2];
+ }
+}
+
+int readblk(void *buf, unsigned int blkno)
+{
+ int r;
+
+ switch(cdcat_cdrom_mode)
+ {
+ case cdrom_mode_1:
+ r = lseek(fd, blkno * SECSIZ, 0);
+ break;
+ case cdrom_mode_1_raw:
+ r = lseek(fd, (blkno * 2352) + 16, 0);
+ break;
+ case cdrom_mode_2:
+ r = lseek(fd, (blkno * 2352) + 24, 0);
+ break;
+ }
+
+ if (read(fd, buf, SECSIZ) != SECSIZ)
+ error("read error");
+
+ return r;
+}
+
+void writeblk(void *buf, unsigned int blkno)
+{
+ switch(cdcat_cdrom_mode)
+ {
+ case cdrom_mode_1:
+ lseek(fd, blkno * SECSIZ, 0);
+ break;
+ case cdrom_mode_1_raw:
+ lseek(fd, (blkno * 2352) + 16, 0);
+ break;
+ case cdrom_mode_2:
+ lseek(fd, (blkno * 2352) + 24, 0);
+ break;
+ }
+
+ if (write(fd, buf, SECSIZ) != SECSIZ)
+ error("write error");
+}
+
+void error(char *msg)
+{
+ fprintf(stderr, "cdcat: %s: %s\n", fn, msg);
+ exit(2);
+}