changeset 193:37f78f986a0a

grokdsn: tree dump implemented
author Michael Spacefalcon <falcon@ivan.Harhan.ORG>
date Wed, 07 Jan 2015 08:09:30 +0000
parents 5d84f63eff72
children 805e99848aea
files miscprog/grokdsn.c
diffstat 1 files changed, 120 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/miscprog/grokdsn.c	Wed Jan 07 07:12:51 2015 +0000
+++ b/miscprog/grokdsn.c	Wed Jan 07 08:09:30 2015 +0000
@@ -47,11 +47,31 @@
 	uint32_t	fat_secids[HEADER_MFAT_ENTRIES];
 };
 
+struct dir_entry {
+	uint16_t	uni_name[32];
+	uint16_t	name_len;
+	u_char		type;
+	u_char		color;
+	uint32_t	left_child;
+	uint32_t	right_child;
+	uint32_t	subtree_dirid;
+	u_char		uid[16];
+	u_char		user_flags[4];
+	u_char		time_creat[8];
+	u_char		time_lastmod[8];
+	uint32_t	content_secid;
+	uint32_t	content_bytes;
+	u_char		rsvd[4];
+};
+
 char *dsnfilename;
 u_char *filemapping;
 struct cdf_header *cdf_header;
 unsigned total_sectors, fat_nsectors;
 
+#define	MAX_DIR_SECTORS	64
+unsigned dir_nsectors, dir_secids[MAX_DIR_SECTORS];
+
 open_and_mmap_file()
 {
 	int fd;
@@ -175,6 +195,100 @@
 	return(0);
 }
 
+locate_dir_sectors()
+{
+	int sec, next, num;
+
+	sec = le32toh(cdf_header->dir_start);
+	for (num = 0; sec >= 0; sec = next) {
+		if (num >= MAX_DIR_SECTORS) {
+			fprintf(stderr, "error: MAX_DIR_SECTORS exceeded\n");
+			exit(1);
+		}
+		dir_secids[num++] = sec;
+		next = get_fat_entry(sec);
+	}
+	dir_nsectors = num;
+	return(0);
+}
+
+u_char *
+get_dir_sector(dir_sec_no)
+	unsigned dir_sec_no;
+{
+	unsigned secid;
+
+	if (dir_sec_no > dir_nsectors) {
+		fprintf(stderr,
+		"error: request for dir sector #%u; we only have %u in total\n",
+			dir_sec_no, dir_nsectors);
+		exit(1);
+	}
+	secid = dir_secids[dir_sec_no];
+	return get_sector_ptr(secid);
+}
+
+struct dir_entry *
+get_dir_entry(dirid)
+	unsigned dirid;
+{
+	unsigned dir_sec_no, entry_in_sec;
+	struct dir_entry *dir_sector;
+
+	dir_sec_no = dirid / 4;
+	entry_in_sec = dirid % 4;
+	dir_sector = (struct dir_entry *) get_dir_sector(dir_sec_no);
+	return dir_sector + entry_in_sec;
+}
+
+dump_dir_entry(rec, indent)
+	struct dir_entry *rec;
+{
+	int i, u;
+
+	for (i = indent; i; i--)
+		putchar(' ');
+	for (i = 0; i < 32; i++) {
+		u = le16toh(rec->uni_name[i]);
+		if (u == 0)
+			break;
+		if (u >= ' ' && u <= '~')
+			putchar(u);
+		else
+			printf("<%04X>", u);
+	}
+	printf(" (type %02X, length %u)\n", rec->type, rec->content_bytes);
+	return(0);
+}
+
+dump_dir_level(dirid, indent)
+	unsigned dirid;
+{
+	struct dir_entry *rec;
+	int32_t ndir;
+
+	rec = get_dir_entry(dirid);
+	ndir = le32toh(rec->left_child);
+	if (ndir >= 0)
+		dump_dir_level(ndir, indent);
+	dump_dir_entry(rec, indent);
+	ndir = le32toh(rec->right_child);
+	if (ndir >= 0)
+		dump_dir_level(ndir, indent);
+	ndir = le32toh(rec->subtree_dirid);
+	if (ndir >= 0)
+		dump_dir_level(ndir, indent + 2);
+	return(0);
+}
+
+dump_dir_tree()
+{
+	init_fat_access();
+	locate_dir_sectors();
+	dump_dir_level(0, 0);
+	return(0);
+}
+
 main(argc, argv)
 	char **argv;
 {
@@ -182,6 +296,10 @@
 		fprintf(stderr, "error: struct cdf_header is misdefined\n");
 		exit(1);
 	}
+	if (sizeof(struct dir_entry) != 128) {
+		fprintf(stderr, "error: struct dir_entry is misdefined\n");
+		exit(1);
+	}
 	if (argc < 3) {
 		fprintf(stderr, "usage: %s binfile.dsn <op> [args]\n", argv[0]);
 		exit(1);
@@ -192,6 +310,8 @@
 		return dump_cdf_header();
 	if (!strcmp(argv[2], "fatchain"))
 		return dump_fat_chain(argv[3]);
+	if (!strcmp(argv[2], "ls"))
+		return dump_dir_tree();
 	fprintf(stderr, "error: \"%s\" is not a recognized command\n", argv[2]);
 	exit(1);
 }